GDC(1)

πŸ“¦
version 14.4.0 Β· 2 versions
, in ubuntu stonking

okay so before we even get into it: this is gdc(1), the GNU manual's page for gdc β€” and yeah it's long, so hydrate πŸ’§ because we are going through EVERYTHING. no skimming, no skipping, that's the rule. let's go πŸ’…

πŸŽ€ NAME πŸŽ€

gdc β€” a GCC-based compiler for the D language. that's it, that's the whole vibe. it's the D-language compiler, and it's built on GCC, and it slays ✨


🌸 SYNOPSIS 🌸

okay so here's the shape of a basic invocation, bestie β€” look at it, it's giving options-on-options πŸ’–

gdc [-c|-S] [-g] [-pg]
    [-Olevel] [-Wwarn...]
    [-Idir...] [-Ldir...]
    [-foption...] [-mmachine-option...]
    [-o outfile] [@file] infile...

and real talk: that's only the most useful ones up there. the rest of them are allll the way down below, so keep scrolling, i promise it's worth it πŸ”₯


πŸ¦‹ DESCRIPTION πŸ¦‹

the gdc command is the GNU compiler for the D language, and here's the thing β€” it supports so many of the same options as gcc 🫢 that's the whole family resemblance. but this manual? this manual only documents the options that are specific to gdc. so if you're looking for some generic GCC flag, go read the gcc page, because this one isn't the one, bestie πŸ’€


✨ OPTIONS ✨

πŸ—‚οΈ Input and Output files

okay so plot twist: for any given input file, the file name suffix decides what kind of compilation happens. the compiler looks at the ending and goes "oh, i know what this is." here's the roster of supported input file name flavors πŸ‘‘

  • file.d β€” D source files. your classic.
  • file.dd β€” Ddoc source files.
  • file.di β€” D interface files.

you can absolutely drop more than one input file on the gdc command line, and each one gets compiled separately during the compilation process, no drama. BUT if you also pass an -o file option, then all the input files get compiled together into one single output file named file. and yes, that's allowed even when you're using -S or -c 🫑

now, a D interface file? it contains only what an import of the module actually needs, rather than the whole entire implementation of that module. little guy, minimal energy. you can make them with gdc from a D source file by using the -H option πŸŽ€ and when the compiler goes to resolve an import declaration, it searches for matching .di files first, and only then for .d.

a Ddoc source file, meanwhile, contains code in the D macro processor language. it's primarily designed for producing user documentation from embedded comments, with a slight affinity towards HTML generation 🌈 and heads up: if a .d source file starts with the string "Ddoc", then it gets treated as general purpose documentation, not as a D source file. so, you know, be careful about naming a file like that πŸ™ˆ

⚑ Runtime Options

these options affect the runtime behavior of programs compiled with gdc. buckle up, there's a bunch πŸ’–

  • -fall-instantiations β€” generate code for all template instantiations. the default template emission strategy is to not generate code for declarations that were either instantiated speculatively (like from __traits(compiles, ...)) or that come from an imported module that isn't being compiled.
  • -fno-assert β€” turn off code generation for assert contracts. bye bye asserts πŸ‘‹
  • -fno-bounds-check β€” turns off array bounds checking for all functions, which can improve performance for code that uses arrays extensively. but bestie, listen to me: note that this can result in unpredictable behavior if the code in question actually does violate array bounds constraints 😭 it is safe to use this option if you are sure that your code never throws a RangeError. that's the deal, that's the trade.
  • -fbounds-check=value β€” an alternative to -fbounds-check that gives you more control over where bounds checking is turned on or off. here are the values it supports:
    • on β€” turns on array bounds checking for all functions.
    • safeonly β€” turns on array bounds checking only for @safe functions.
    • off β€” turns off array bounds checking completely. gone. not a vibe check survived πŸ’€
  • -fno-builtin β€” don't recognize built-in functions unless they begin with the prefix __builtin_. by default, the compiler will recognize when a function in the core.stdc package is a built-in function. so this one makes it stop doing that little trick.
  • -fcheckaction=value β€” this option controls what code is generated on an assertion, bounds check, or final switch failure. the values it supports:
    • context β€” throw an AssertError with extra context information.
    • halt β€” halt the program execution. just. stop. πŸ›‘
    • throw β€” throw an AssertError β€” and this one is the default.
  • -fdebug β€” turns on compilation of conditional debug code into the program. the -fdebug option by itself sets the debug level to 1.
  • -fdebug=value β€” turns on compilation of conditional debug code into the program, and lets you enable debug code that's identified by any of the following values:
    • ident β€” turns on compilation of any debug code identified by ident.
  • -fno-druntime β€” implements https://dlang.org/spec/betterc.html. assumes that compilation targets an environment without a D runtime library. this is equivalent to compiling with the following options:
gdc -nophoboslib -fno-exceptions -fno-moduleinfo -fno-rtti
  • -fextern-std=standard β€” sets the C++ name mangling compatibility to the version identified by standard. the supported values:
    • c++98, c++03 β€” sets __traits(getTargetInfo, "cppStd") to 199711.
    • c++11 β€” sets __traits(getTargetInfo, "cppStd") to 201103.
    • c++14 β€” sets __traits(getTargetInfo, "cppStd") to 201402.
    • c++17 β€” sets __traits(getTargetInfo, "cppStd") to 201703. this is the default ✨
    • c++20 β€” sets __traits(getTargetInfo, "cppStd") to 202002.
  • -fno-invariants β€” turns off code generation for class invariant contracts.
  • -fmain β€” generates a default main() function when compiling. this is useful when unittesting a library, because it enables running the unittests in a library without having to manually define an entry-point function 🫢 heads up though: this option does nothing when main is already defined in user code.
  • -fno-moduleinfo β€” turns off generation of the ModuleInfo and related functions that would become unreferenced without it, which may allow linking to programs not written in D. the functions that are not be generated include module constructors and destructors (static this and static ~this), unittest code, and DSO registry functions for dynamically linked code. that's a lot of things suddenly missing, so know what you're doing πŸ‘€
  • -fonly=filename β€” tells the compiler to parse and run semantic analysis on all modules on the command line, but only generate code for the module specified by filename. one gets the spotlight, the rest are just vibing in the background.
  • -fno-postconditions β€” turns off code generation for postcondition out contracts.
  • -fno-preconditions β€” turns off code generation for precondition in contracts.
  • -fpreview=id β€” turns on an upcoming D language change identified by id. here are the values it supports:
    • all β€” turns on all upcoming D language features. the whole buffet πŸ“
    • bitfields β€” implements bit-fields in D.
    • dip1000 β€” implements https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md (Scoped pointers).
    • dip1008 β€” implements https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1008.md (Allow exceptions in @nogc code).
    • dip1021 β€” implements https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md (Mutable function arguments).
    • dip25 β€” implements https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md (Sealed references).
    • dtorfields β€” turns on generation for destructing fields of partially constructed objects.
    • fieldwise β€” turns on generation of struct equality to use field-wise comparisons.
    • fixaliasthis β€” implements new lookup rules that check the current scope for alias this before searching in upper scopes.
    • fiximmutableconv β€” disallows unsound immutable conversions that were formerly incorrectly permitted. formerly incorrectly permitted!! that's a whole confession 😭
    • in β€” implements in parameters to mean scope const [ref] and accepts rvalues.
    • inclusiveincontracts β€” implements in contracts of overridden methods to be a superset of parent contract.
    • nosharedaccess β€” turns off and disallows all access to shared memory objects. no shared access, no exceptions, we respect the boundary πŸ’…
    • rvaluerefparam β€” implements rvalue arguments to ref parameters.
    • systemvariables β€” disables access to variables marked @system from @safe code.
  • -frelease β€” turns on compiling in release mode, which means not emitting runtime checks for contracts and asserts. array bounds checking is not done for @system and @trusted functions, and assertion failures are undefined behavior 🚨 this is equivalent to compiling with the following options:
gdc -fno-assert -fbounds-check=safe -fno-invariants \
    -fno-postconditions -fno-preconditions -fno-switch-errors
  • -frevert= β€” turns off a D language feature identified by id. the values it supports:
  • -fno-rtti β€” turns off generation of run-time type information for all user defined types. and here's the consequence, no sugarcoating: any code that uses features of the language that require access to this information will result in an error πŸ’€
  • -fno-switch-errors β€” this option controls what code is generated when no case is matched in a final switch statement. the default run time behavior is to throw a SwitchError. turning off -fswitch-errors means that instead the execution of the program is immediately halted. like, lights out.
  • -funittest β€” turns on compilation of unittest code, and turns on the version(unittest) identifier. this implies -fassert ✨
  • -fversion=value β€” turns on compilation of conditional version code into the program identified by any of the following values:
    • ident β€” turns on compilation of version code identified by ident.
  • -fno-weak-templates β€” turns off emission of declarations that can be defined in multiple objects as weak symbols. the default is to emit all public symbols as weak, unless the target lacks support for weak symbols. disabling this option means that common symbols are instead put in COMDAT or become private. pick your fighter 🀺

these options specify directories to search for files, libraries, and other parts of the compiler. the "where do i look for stuff" category πŸŽ€

  • -Idir β€” specify a directory to use when searching for imported modules at compile time. you can stack multiple -I options, and the paths are searched in the same order you gave them.
  • -Jdir β€” specify a directory to use when searching for files in string imports at compile time. and real talk: this switch is required in order to use import(file) expressions. multiple -J options can be used, and the paths are searched in the same order. no -J, no string imports, periodt πŸ’…
  • -Ldir β€” when the compiler is linking, this says "hey, go look in dir for libraries too", exactly like it does for gcc. πŸ’…
  • -Bdir β€” tells gdc where to find its own stuff: the executables, the libraries, the source files, the data files of the compiler itself. Same energy as gcc. Like, this is where the compiler's own snack drawer lives πŸŽ€
  • -fmodule-file=module=spec β€” okay so this one is the ✨path remapping✨ option. If a module you import matches all of module, or at least the leftmost chunk of it, then the file path in spec is what gets used to find the D sources. You reach for this when your source file paths and names do not line up with the package/module hierarchy. Bestie, look at this:
gdc test.d -fmodule-file=A.B=foo.d -fmodule-file=C=bar

So that right there tells the compiler: when you're importing A.B, go search every import path for the source file foo.d, and when you're importing C, go search the directory bar/. And here's what that looks like from the D code's side:

module test;
import A.B;     // Matches A.B, searches for foo.d
import C.D.E;   // Matches C, searches for bar/D/E.d
import A.B.C;   // No match, searches for A/B/C.d

See how A.B.C doesn't match, because that leftmost-part match is doing the work. iykyk πŸ¦‹

  • -imultilib dir β€” use dir as the subdirectory of the gcc directory that holds the target-specific D sources and interfaces.
  • -iprefix prefix β€” sets prefix as the prefix for the gcc directory that holds target-specific D sources and interfaces. If your prefix is a directory, please include the trailing /, no cap.
  • -nostdinc β€” do not go poking around the standard system directories for D source and interface files. The only directories that get searched are the ones you gave with -I options (plus the directory of the current file, if that applies). Like, you're locking the front door but leaving the side gate open 🌸

πŸ”₯ Code Generation πŸ”₯

Besides the metric ton of gcc options that control code generation, gdc has a bunch of its own. Let's go πŸ’–

  • -H β€” generates D interface files for every module being compiled. The compiler figures out the output file name from the name of the input file: strip out any directory components, strip the suffix, then slap a .di suffix on it. Slay.
  • -Hd dir β€” identical to -H, except the interface files get written to the directory dir. You can pair it with -Hf file so you can set the output file and the directory path independently of each other.
  • -Hf file β€” same as -H but the interface files go to file. Pair it with -Hd dir if you want the output file and the directory path set independently.
  • -M β€” spits out the module dependencies of every source file being compiled, in a format make can actually eat. The compiler outputs one make rule containing the object file name for that source file, a colon, then the names of all the imported files. Makefile bestie behavior 🫢
  • -MM β€” same as -M but it stays quiet about imported modules that come from the D standard library package directories.
  • -MF file β€” when used with -M or -MM, this says which file to write the dependencies to. And when used with the driver options -MD or -MMD, -MF overrides the default dependency output file.
  • -MG β€” this one exists purely for compatibility with gcc, and the compiler just ignores it. It's giving decorative πŸŽ€
  • -MP β€” outputs a phony target for each dependency other than the modules being compiled, which makes each of them depend on nothing.
  • -MT target β€” changes the target of the rule that dependency generation emits, to be exactly the string you type. Want multiple targets? Either pass them all as a single argument to -MT, or just use multiple -MT options. Your call πŸ’…
  • -MQ target β€” same as -MT, but it quotes any characters that are special to make.
  • -MD β€” this is equivalent to -M -MF file. The driver works out file by removing any directory components and the suffix from the input file, then adding a .deps suffix.
  • -MMD β€” like -MD, but it does not mention imported modules from the D standard library package directories.
  • -X β€” outputs info describing the contents of all the source files being compiled, in JSON format, to a file. The driver works out file by removing any directory components and the suffix from the input file, then adding a .json suffix.
  • -Xf file β€” same as -X, but all the JSON contents get written to the specified file.
  • -fdoc β€” generates "Ddoc" documentation and writes it to a file. The compiler works out file by removing any directory components and the suffix from the input file, then adding a .html suffix.
  • -fdoc-dir=dir β€” same as -fdoc, but the documentation gets written to directory dir. You can use it with -fdoc-file=file to set the output file and the directory path independently.
  • -fdoc-file=file β€” same as -fdoc, but the documentation gets written to file. Use it with -fdoc-dir=dir to set the output file and the directory path independently.
  • -fdoc-inc=file β€” names file as a Ddoc macro file to be read. You can stack multiple -fdoc-inc options, and the files get read and processed in the exact order you list them.
  • -fdump-c++-spec=file β€” for D source files, generate the corresponding C++ declarations into file.
  • -fdump-c++-spec-verbose β€” used together with -fdump-c++-spec= above, this adds comments for ignored declarations in the generated C++ header.
  • -fsave-mixins=file β€” generates the code expanded from D "mixin" statements and writes the processed sources to file. This is genuinely so useful for debugging compilation errors, and it gives debuggers source to show when they ask for it. πŸ’€πŸ”

🌈 Warnings 🌈

Warnings are diagnostic messages. They report constructions that aren't inherently erroneous but that are risky, or that suggest there's probably a bug lurking in your program. Unless you specify -Werror, they do not stop the program from compiling. Just saying, bestie.

  • -Wall β€” turns on all warning messages. Warnings are not a defined part of the D language, and every construct that might produce one of these warnings is valid code. So like… valid, but sus πŸ™ˆ
  • -Walloca β€” warns on every single use of "alloca" in the source.
  • -Walloca-larger-than=n β€” warns on unbounded uses of alloca, and on bounded uses of alloca whose bound could be larger than n bytes. And -Wno-alloca-larger-than disables the -Walloca-larger-than warning, and is equivalent to -Walloca-larger-than=SIZE_MAX or larger.
  • -Wno-builtin-declaration-mismatch β€” warns if a built-in function gets declared with a signature that doesn't match.
  • -Wcast-result β€” warns about casts that will produce a null or zero result. Right now this only happens for casting between an imaginary and a non-imaginary data type, or casting between a D and a C++ class.
  • -Wno-deprecated β€” do not warn about usage of deprecated features and symbols that have "deprecated" attributes.
  • -Werror β€” turns all warnings into errors. Everything is a problem now ✨
  • -Wextra β€” enables some extra warning flags that -Wall does not turn on:
-Waddress -Wcast-result -Wmismatched-special-enum -Wunknown-pragmas
  • -Wmismatched-special-enum β€” warns when an enum the compiler recognizes as special is declared with a different size than the built-in type it's representing.
  • -Wspeculative β€” lists all error messages from speculative compiles, like "__traits(compiles, ...)". Heads up though: this option does not report messages as warnings, so these messages never become errors even when the -Werror option is also in play.
  • -Wunknown-pragmas β€” warns when a pragma() shows up that gdc doesn't understand. Fun difference: with -fignore-unknown-pragmas, a pragma that is part of the D language but just not implemented by the compiler won't get reported. Different vibes entirely.
  • -Wno-varargs β€” do not warn on questionable usage of the macros used to handle variable arguments, like "va_start".
  • -fno-ignore-unknown-pragmas β€” do not recognize unsupported pragmas. Any pragma() encountered that isn't part of the D language turns into an error. And ngl, this option is now deprecated and will be removed in a future release. ⚠️
  • -fmax-errors=n β€” caps the maximum number of error messages at n, and once you hit that, gdc bails out instead of trying to keep processing the source code. If n is 0 (which is the default), there's no limit on how many error messages get produced. Chaos mode: default πŸ’…
  • -fsyntax-only β€” checks the code for syntax errors but doesn't actually compile it. You can run this together with -fdoc or -H to generate files for each module present on the command-line, but no other output file.
  • -ftransition=id β€” reports extra info about D language changes identified by id. Here are the supported values:
    • all β€” list information on all D language transitions.
    • complex β€” list all usages of complex or imaginary types.
    • field β€” list all non-mutable fields which occupy an object instance.
    • in β€” list all usages of "in" on parameter.
    • nogc β€” list all hidden GC allocations.
    • templates β€” list statistics on template instantiations.
    • tls β€” list all variables going into thread local storage.

πŸŽ€ Options for Linking πŸŽ€

These options come into play when the compiler links object files into an executable output file. If the compiler is not doing a link step, they're meaningless. Like, they're just sitting there. Cute but useless πŸ“

  • -defaultlib=libname β€” specify the library to use instead of libphobos when linking. Any options specifying the linkage of libphobos, like -static-libphobos or -shared-libphobos, get ignored.
  • -debuglib=libname β€” specify the debug library to use instead of libphobos when linking. This option does nothing at all unless the -g option was also given on the command line. And yeah, options specifying the linkage of libphobos, like -static-libphobos or -shared-libphobos, get ignored.
  • -nophoboslib β€” do not use the Phobos or D runtime library when linking. Options specifying the linkage of libphobos, like -static-libphobos or -shared-libphobos, get ignored. The standard system libraries are used normally, unless -nostdlib or -nodefaultlibs is used.
  • -shared-libphobos β€” on systems that provide libgphobos and libgdruntime as both a shared and a static library, this option forces the shared version to be used. If no shared version was built when the compiler was configured, this option has no effect. Zero. None. 🫠
  • -static-libphobos β€” on systems that provide libgphobos and libgdruntime as both a shared and a static library, this option forces the static version to be used. If no static version was built when the compiler was configured, this option has no effect.

πŸ‘‘ Developer Options πŸ‘‘

This section describes command-line options that are primarily of interest to developers or language tooling. The niche girlies. The tooling girlies. We see you πŸ’œ


  • -fdump-d-original β€” drops the internal front-end AST after the "semantic3" stage. bestie this one is literally only for debugging the GNU D compiler itself, so unless you're out here fixing gdc, it's giving "not for you" πŸ™ˆ
  • -v β€” dumps all the tea about what the compiler's language-processing stages are doing while your source program compiles ✨ that means: it lists every module that gets processed through the "parse", "semantic", "semantic2", and "semantic3" stages; every "import" module and its file paths; and every "function" body that's being compiled. maximum transparency, no secrets, we love her for that πŸ’…

🌈 SEE ALSO 🌈

okay so if you wanna go deeper (and you should, she's iconic), go read gpl(7), gfdl(7), fsf-funding(7), gcc(1), plus the Info entries for gdc and gcc πŸ“šπŸ«Ά


Copyright (c) 2006-2024 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the man page gfdl(7).


and that's a wrap on the whole page, bestie πŸ’– you just read the GDC(1) manual β€” that's source/version gcc-14.4.0, dated 2026-06-26 β€” go compile something cute, you ate that fr fr πŸ‘‘βœ¨

πŸ“¦ where this page comes from