GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing dlang.org — Conditional Compilation - D Programming Language Language Reference
Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page.
Requires a signed-in GitHub account. This works well for small changes.
If you'd like to make larger changes you may want to consider using
a local clone.
Conditional Compilation Contents
Conditional compilation is the process of selecting which code to compile and which code to not compile. ConditionalDeclaration:
Condition DeclarationBlock
Condition DeclarationBlock else DeclarationBlock
Condition : DeclDefsopt
Condition DeclarationBlock else : DeclDefsopt
ConditionalStatement:
Condition NoScopeNonEmptyStatement
Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement
If the Condition is satisfied, then the following DeclarationBlock or Statement is compiled in. If it is not satisfied, the DeclarationBlock or Statement after the optional else is compiled in. Any DeclarationBlock or Statement that is not compiled in still must be syntactically correct. No new scope is introduced, even if the DeclarationBlock or Statement is enclosed by { }. ConditionalDeclarations and ConditionalStatements can be nested. The StaticAssert can be used to issue errors at compilation time for branches of the conditional compilation that are errors. Condition comes in the following forms: Condition:
VersionCondition
DebugCondition
StaticIfCondition
Version ConditionVersionCondition:
version ( Identifier )
version ( unittest )
version ( assert )
Versions enable multiple versions of a module to be implemented with a single source file. The VersionCondition is satisfied if Identifier matches a version identifier. The version identifier can be set on the command line by the -version switch or in the module itself with a VersionSpecification, or they can be predefined by the compiler. Version identifiers are in their own unique name space, they do not conflict with debug identifiers or other symbols in the module. Version identifiers defined in one module have no influence over other imported modules. int k; version (Demo) // compile in this code block for the demo version { int i; int k; // error, k already defined i = 3; } x = i; // uses the i declared above version (X86) { ... // implement custom inline assembler version } else { ... // use default, but slow, version } version (unittest) is satisfied if and only if the code is compiled with unit tests enabled (the -unittest option on dmd). Version SpecificationVersionSpecification:
version = Identifier ;
A version specification defines a specific version identifier. This makes it straightforward to group a set of features under one major version, for example: version (ProfessionalEdition) { version = FeatureA; version = FeatureB; version = FeatureC; } version (HomeEdition) { version = FeatureA; } ... version (FeatureB) { ... implement Feature B ... } Version identifiers may not be forward referenced: version (Foo) { int x; } version = Foo; // error, Foo already used VersionSpecifications may only appear at module scope, and may not be generated with a MixinExpression. While the debug and version conditions superficially behave the same, they are intended for very different purposes. Debug statements are for adding debug code that is removed for the release version. Version statements are to aid in portability and multiple release versions. Here's an example of a full version as opposed to a demo version: class Foo { int a, b; version (full) { int extrafunctionality() { ... return 1; // extra functionality is supported } } else // demo { int extrafunctionality() { return 0; // extra functionality is not supported } } } Various different version builds can be built with a parameter to version: version (identifier) // add in version code if version // keyword is identifier { ... version code ... } This is presumably set by the command line as -version=identifier. Predefined VersionsSeveral environmental version identifiers and identifier name spaces are predefined for consistent usage. Version identifiers do not conflict with other identifiers in the code, they are in a separate name space. Predefined version identifiers are global, i.e. they apply to all modules being compiled and imported.
The following identifiers are defined, but are deprecated:
Others will be added as they make sense and new implementations appear. To allow for future growth of the language, the version identifier namespace beginning with "D_" is reserved for identifiers indicating D language specification or new feature conformance. Further, all identifiers derived from the ones listed above by appending any character(s) are reserved. This means that e.g. ARM_foo and Windows_bar are reserved while foo_ARM and bar_Windows are not. Predefined version identifiers from this list cannot be set from the command line or from version statements. (This prevents things like both Windows and linux being simultaneously set.) Compiler vendor specific versions can be predefined if the trademarked vendor identifier prefixes it, as in: version (DigitalMars_funky_extension)
{
...
}
It is important to use the right version identifier for the right purpose. For example, use the vendor identifier when using a vendor specific feature. Use the operating system identifier when using an operating system specific feature, etc. Debug ConditionDebugCondition:
debug
debug ( Identifier )
Two versions of programs are commonly built, a release build and a debug build. The debug build includes extra error checking code, test harnesses, pretty-printing code, etc. The debug statement conditionally compiles in its statement body. It is D's way of what in C is done with #ifdef DEBUG / #endif pairs. The debug condition is satisfied when the -debug switch is passed to the compiler. The debug ( Identifier ) condition is satisfied when the debug identifier matches Identifier. class Foo { int a, b; debug: int flag; } Debug StatementA ConditionalStatement that has a DebugCondition is called a DebugStatement. DebugStatements have relaxed semantic checks in that pure, @nogc, nothrow and @safe checks are not done. Neither do DebugStatements influence the inference of pure, @nogc, nothrow and @safe attributes. Undefined Behavior: Since these checks are bypassed, it is up to the programmer
to ensure the code is correct. For example, throwing an exception in a nothrow
function is undefined behavior.
Best Practices: This enables the easy insertion of code to provide debugging help,
by bypassing the otherwise stringent attribute checks.
Never ship release code that has DebugStatements enabled.
Debug SpecificationDebugSpecification:
debug = Identifier ;
Debug identifiers are set either by the command line switch -debug=identifier or by a DebugSpecification. Debug specifications only affect the module they appear in, they do not affect any imported modules. Debug identifiers are in their own namespace, independent from version identifiers and other symbols. It is illegal to forward reference a debug specification: debug (foo) writeln("Foo"); debug = foo; // error, foo used before set DebugSpecifications may only appear at module scope, and may not be generated with a MixinExpression. Various different debug builds can be built with a parameter to debug: debug (identifier) { } // add in debug code if debug keyword is identifier These are presumably set on the command line, e.g. -debug=identifier. Static If ConditionStaticIfCondition:
static if ( AssignExpression )
AssignExpression is implicitly converted to a boolean type, and is evaluated at compile time. The condition is satisfied if it evaluates to true. It is not satisfied if it evaluates to false. It is an error if AssignExpression cannot be implicitly converted to a boolean type or if it cannot be evaluated at compile time. StaticIfConditions can appear in module, class, template, struct, union, or function scope. In function scope, the symbols referred to in the AssignExpression can be any that can normally be referenced by an expression at that point. const int i = 3; int j = 4; static if (i == 3) // ok, at module scope int x; class C { const int k = 5; static if (i == 3) // ok int x; else long x; static if (j == 3) // error, j is not a constant int y; static if (k == 5) // ok, k is in current scope int z; } template Int(int i) { static if (i == 32) alias Int = int; else static if (i == 16) alias Int = short; else static assert(0); // not supported } Int!(32) a; // a is an int Int!(16) b; // b is a short Int!(17) c; // error, static assert trips A StaticIfCondition differs from an IfStatement in the following ways:
Static ForeachStaticForeachDeclaration:
StaticForeach DeclarationBlock
StaticForeach : DeclDefsopt
StaticForeachStatement:
StaticForeach NoScopeNonEmptyStatement
StaticForeach:
static AggregateForeach
static RangeForeach
static foreach expands its DeclarationBlock or DeclDefs into a series of declarations, each of which may reference any ForeachType symbols declared.
static foreach (i; [0, 1, 2, 3]) { pragma(msg, i); } static foreach supports multiple ForeachType variables in cases where the corresponding foreach statement supports them. (In this case, static foreach generates a compile-time sequence of tuples, and the tuples are subsequently unpacked during iteration). static foreach (i, v; ['a', 'b', 'c', 'd']) { static assert(i + 'a' == v); } Like bodies of ConditionalDeclarations, a static foreach body does not introduce a new scope. Therefore, it can be used to add declarations to an existing scope: import std.range : iota; static foreach (i; iota(0, 3)) { mixin(`enum x`, i, ` = i;`); } pragma(msg, x0, " ", x1," ", x2); // 0 1 2 Inside a function, if a new scope is desired for each expansion, use another set of braces: void fun() { static foreach (s; ["hi", "hey", "hello"]) {{ enum len = s.length; // local to each iteration static assert(len <= 5); }} static assert(!is(typeof(len))); } static AggregateForeach supports sequence expansion like foreach, as well as unpacking ForeachTuplePatterns. break and continueAs static foreach is a code generation construct and not a loop, break and continue cannot be used to change control flow within it. Instead of breaking or continuing a suitable enclosing statement, such an usage yields an error (this is to prevent misunderstandings). int test(int x) { int r = -1; switch(x) { static foreach (i; 0 .. 5) { case i: r = i; break; // error } default: break; } return r; } static foreach (i; 0 .. 10) { static assert(test(i) == (i < 5 ? i : -1)); } An explicit break/continue label can be used to avoid this limitation. (Note that static foreach itself cannot be broken nor continued even if it is explicitly labeled.) int test(int x) { int r = -1; Lswitch: switch(x) { static foreach (i; 0 .. 5) { case i: r = i; break Lswitch; } default: break; } return r; } static foreach (i; 0 .. 10) { static assert(test(i) == (i < 5 ? i : -1)); } Static AssertStaticAssert:
static assert ( ArgumentList ) ;
The first AssignExpression is evaluated at compile time, and converted to a boolean value. If the value is true, the static assert is ignored. If the value is false, an error diagnostic is issued and the compile fails. On failure, any subsequent AssignExpressions will each be converted to string and then concatenated. The resulting string will be printed out along with the error diagnostic. Unlike AssertExpressions, StaticAsserts are always checked and evaluated by the compiler unless they appear in an unsatisfied conditional. void foo() { if (0) { assert(0); // never trips static assert(0); // always trips } version (BAR) { } else { static assert(0); // trips when version BAR is not defined } } StaticAssert is useful tool for drawing attention to conditional configurations not supported in the code. Copyright © 1999-2026 by the D Language Foundation | Page generated by
Ddoc on Mon Nov 9 05:59:19 2026
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |