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 StaticIfConditionVersion Condition
VersionCondition: 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) { int i; int k; i = 3; } x = i;
version (X86) { ... } else { ... }
The 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 ;
The version specification 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 or levels may not be forward referenced:
version (Foo) { int x; } version = Foo;
VersionSpecifications may only appear at module scope.
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; } } else { int extrafunctionality() { return 0; } } }
Various different version builds can be built with a parameter to version:
version(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.
Predefined Version Identifiers Version Identifier Description Host Compiler DigitalMars DMD (Digital Mars D) GNU GDC (GNU D Compiler) LDC LDC (LLVM D Compiler) SDC SDC (Snazzy D Compiler) Target Operating System Windows Microsoft Windows systems Win32 Microsoft 32-bit Windows systems Win64 Microsoft 64-bit Windows systems linux All Linux systems OSX macOS iOS iOS TVOS tvOS WatchOS watchOS VisionOS visionOS FreeBSD FreeBSD OpenBSD OpenBSD NetBSD NetBSD DragonFlyBSD DragonFlyBSD BSD All other BSDs Solaris Solaris Posix All POSIX systems (includes Linux, FreeBSD, OS X, Solaris, etc.) AIX IBM Advanced Interactive eXecutive OS Haiku The Haiku operating system SkyOS The SkyOS operating system SysV3 System V Release 3 SysV4 System V Release 4 Hurd GNU Hurd Android The Android platform Emscripten The Emscripten platform PlayStation The PlayStation platform PlayStation4 The PlayStation 4 platform FreeStanding An environment without an operating system (such as Bare-metal targets) Target Environment Cygwin The Cygwin environment MinGW The MinGW environment CRuntime_Bionic Bionic C runtime CRuntime_DigitalMars DigitalMars C runtime CRuntime_Glibc Glibc C runtime CRuntime_Microsoft Microsoft C runtime CRuntime_Musl musl C runtime CRuntime_Newlib newlib C runtime CRuntime_UClibc uClibc C runtime CRuntime_WASI WASI C runtime CppRuntime_Clang Deprecated, use CppRuntime_LLVM instead CppRuntime_DigitalMars DigitalMars C++ runtime CppRuntime_Gcc Deprecated, use CppRuntime_GNU instead CppRuntime_LLVM LLVM libc++ C++ runtime CppRuntime_GNU GNU libstdc++ C++ runtime CppRuntime_Microsoft Microsoft C++ runtime CppRuntime_Sun Sun C++ runtime Target CPU and Instruction Set X86 Intel and AMD 32-bit processors X86_64 Intel and AMD 64-bit processors ARM The ARM architecture (32-bit) (AArch32 et al) ARM_Thumb ARM in any Thumb mode ARM_SoftFloat The ARM soft floating point ABI ARM_SoftFP The ARM softfp floating point ABI ARM_HardFloat The ARM hardfp floating point ABI AArch64 The Advanced RISC Machine architecture (64-bit) AsmJS The asm.js intermediate programming language AVR 8-bit Atmel AVR Microcontrollers Epiphany The Epiphany architecture PPC The PowerPC architecture, 32-bit PPC_SoftFloat The PowerPC soft float ABI PPC_HardFloat The PowerPC hard float ABI PPC64 The PowerPC architecture, 64-bit IA64 The Itanium architecture (64-bit) MIPS32 The MIPS architecture, 32-bit MIPS64 The MIPS architecture, 64-bit MIPS_O32 The MIPS O32 ABI MIPS_N32 The MIPS N32 ABI MIPS_O64 The MIPS O64 ABI MIPS_N64 The MIPS N64 ABI MIPS_EABI The MIPS EABI MIPS_SoftFloat The MIPS soft-float ABI MIPS_HardFloat The MIPS hard-float ABI MSP430 The MSP430 architecture NVPTX The Nvidia Parallel Thread Execution (PTX) architecture, 32-bit NVPTX64 The Nvidia Parallel Thread Execution (PTX) architecture, 64-bit RISCV32 The RISC-V architecture, 32-bit RISCV64 The RISC-V architecture, 64-bit SPARC The SPARC architecture, 32-bit SPARC_V8Plus The SPARC v8+ ABI SPARC_SoftFloat The SPARC soft float ABI SPARC_HardFloat The SPARC hard float ABI SPARC64 The SPARC architecture, 64-bit S390 The System/390 architecture, 32-bit SystemZ The System Z architecture, 64-bit HPPA The HP PA-RISC architecture, 32-bit HPPA64 The HP PA-RISC architecture, 64-bit SH The SuperH architecture, 32-bit WebAssembly The WebAssembly virtual ISA (instruction set architecture), 32-bit WASI The WebAssembly System Interface Xtensa The Xtensa Architecture, 32-bit Alpha The Alpha architecture Alpha_SoftFloat The Alpha soft float ABI Alpha_HardFloat The Alpha hard float ABI Byte Order (endianess) LittleEndian Byte order, least significant first BigEndian Byte order, most significant first Executable and Link Format ELFv1 Elf version 1 ELFv2 Elf version 2 Miscellaneous D_BetterC D as Better C code (command line switch -betterC) is being generated D_Exceptions Exception handling is supported. Evaluates to false when compiling with command line switch -betterC D_ModuleInfo ModuleInfo is supported. Evaluates to false when compiling with command line switch -betterC D_TypeInfo Runtime type information (a.k.a TypeInfo) is supported. Evaluates to false when compiling with command line switch -betterC D_Coverage Code coverage analysis instrumentation (command line switch -cov) is being generated D_Ddoc Ddoc documentation (command line switch -D) is being generated D_InlineAsm_X86 Inline assembler for X86 is implemented D_InlineAsm_X86_64 Inline assembler for X86-64 is implemented D_LP64 Pointers are 64 bits (command line switch -m64). (Do not confuse this with C's LP64 model) D_X32 Pointers are 32 bits, but words are still 64 bits (x32 ABI) (This can be defined in parallel to X86_64) D_HardFloat The target hardware has a floating-point unit D_SoftFloat The target hardware does not have a floating-point unit D_PIC Position Independent Code (command line switch -fPIC) is being generated D_PIE Position Independent Executable (command line switch -fPIE) is being generated D_SIMD Vector extensions (via __simd) are supported D_AVX AVX Vector instructions are supported D_AVX2 AVX2 Vector instructions are supported D_Version2 This is a D version 2 compiler D_NoBoundsChecks Array bounds checks are disabled (command line switch -boundscheck=off) D_ObjectiveC The target supports interfacing with Objective-C D_ProfileGC GC allocations being profiled (command line switch -profile=gc) D_Optimized Compiling with enabled optimizations (command line switch -O) Core Defined when building the standard runtime Std Defined when building the standard library unittest Unit tests are enabled (command line switch -unittest) assert Checks are being emitted for AssertExpressions D_PreConditions Checks are being emitted for in contracts D_PostConditions Checks are being emitted for out contracts D_Invariants Checks are being emitted for class invariants and struct invariants Special Cases none Never defined; used to just disable a section of code all Always defined; used as the opposite of noneThe following identifiers are defined, but are deprecated:
Predefined Version Identifiers (deprecated) Version Identifier Description darwin The Darwin operating system; use OSX instead Thumb ARM in Thumb mode; use ARM_Thumb instead S390X The System/390X architecture, 64-bit; use SystemZ insteadOthers 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 Statement
A 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 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;
DebugSpecifications may only appear at module scope.
Various different debug builds can be built with a parameter to debug:
debug(identifier) { }
These are presumably set by the command line as and -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) int x; class C { const int k = 5; static if (i == 3) int x; else long x; static if (j == 3) int y; static if (k == 5) 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); } Int!(32) a; Int!(16) b; Int!(17) c;
A StaticIfCondition differs from an IfStatement in the following ways:
StaticForeach: static AggregateForeach static RangeForeach StaticForeachDeclaration: StaticForeach DeclarationBlock StaticForeach : DeclDefsopt StaticForeachStatement: StaticForeach NoScopeNonEmptyStatement
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 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);
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; static assert(len <= 5); }} static assert(!is(typeof(len))); }
static foreach supports sequence expansion like foreach.
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; } 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 Assert
StaticAssert: 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); static assert(0); } version (BAR) { } else { static assert(0); } }
StaticAssert is useful tool for drawing attention to conditional configurations not supported in the code.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4