Another major release of DMD, this time 2.078.0, has been packaged and delivered in time for the new year. See the full changelog at dlang.org and download the compiler for your platform either from the main download page or the 2.078.0 release directory.
This release brings a number of quality-of-life improvements, fixing some minor annoyances and inconsistencies, three of which are targeted at smoothing out the experience of programming in D without DRuntime.
C runtime construction and destruction
D has included static constructors and destructors, both as aggregate type members and at module level, for most of its existence. The former are called in lexical order as DRuntime goes through its initialization routine, and the latter are called in reverse lexical order as the runtime shuts down. But when programming in an environment without DRuntime, such as when using the
-betterC compiler switch, or using a stubbed-out runtime, static construction and destruction are not available.
DMD 2.078.0 brings static module construction and destruction to those environments in the form of two new pragmas,
pragma(crt_destructor) respectively. The former causes any function to which it’s applied to be executed before the C
main, and the latter after the C
main, as in this example:
// Compile with: dmd crun1.d
// Alternatively: dmd -betterC crun1.d
// Each of the following functions should have
// C linkage (cdecl).
The compiler requires that any function annotated with the new pragmas be declared with the
extern(C) linkage attribute. In this example, though it isn’t required,
main is also declared as
extern(C). The colon syntax on line 8 applies the attribute to every function that follows, up to the end of the module or until a new linkage attribute appears.
In a normal D program, the C
main is the entry point for DRuntime and is generated by the compiler. When the C runtime calls the C
main, the D runtime does its initialization, which includes starting up the GC, executing static constructors, gathering command-line arguments into a string array, and calling the application’s
main function, a.k.a. D
When a D module’s
main is annotated with
extern(C), it essentially replaces DRuntime’s implementation, as the compiler will never generate a C
main function for the runtime in that case. If
-betterC is not supplied on the command line, or an alternative implementation is not provided, DRuntime itself is still available and can be manually initialized and terminated.
The example above is intended to clearly show that the
crt_constructor pragma will cause
init to execute before the C
main and the
fini to run after. This introduces new options for scenarios where DRuntime is unavailable. However, take away the
main and the same execution order will print to the command line:
// Compile with: dmd crun2.d
extern(C) void init()
extern(C) void fini()
import std.stdio : writeln;
The difference is that the C
main now belongs to DRuntime and our main is the D
main. The execution order is:
fini. This means
init is effectively called before DRuntime is initialized and
fini after it terminates. Because this example uses the DRuntime function
writeln, it can’t be compiled with
You may discover that
writeln works if you import it at the top of the module and substitute it for
puts in the example. However, always remember that even though DRuntime may be available, it’s not in a valid state when a
crt_constructor and a
crt_destructor are executed.
One of the limitations in
-betterC mode has been the absence of RAII. In normal D code,
struct destructors are executed when an instance goes out of scope. This has always depended on DRuntime, and since the runtime isn’t available in
-betterC mode, neither are
struct destructors. With DMD 2.078.0, the are in the preceding sentence becomes were.
// Compile with: dmd -betterC destruct.d
import core.stdc.stdio : puts;
extern(C) void main()
Interestingly, this is implemented in terms of
try..finally, so a side-effect is that
-betterC mode now supports
// Compile with: dmd -betterC cleanup1.d
extern(C) void main()
// acquire resources here
ints = cast(int*)malloc(int.sizeof * 10);
// release resources here
scope(exit) feature is also implemented in terms of
try..finally, this is now possible in
-betterC mode also:
// Compile with: dmd -betterC cleanup2.d
extern(C) void main()
auto ints1 = cast(int*)malloc(int.sizeof * 10);
auto ints2 = cast(int*)malloc(int.sizeof * 10);
Note that exceptions are not implemented for
-betterC mode, so there’s no
One of the seemingly obscure features dependent upon DRuntime is the
ModuleInfo type. It’s a type that works quietly behind the scenes as one of the enabling mechanisms of reflection and most D programmers will likely never hear of it. That is, unless they start trying to stub out their own minimal runtime. That’s when linker errors start cropping up complaining about the missing
ModuleInfo type, since the compiler will have generated an instance of it for each module in the program.
DMD 2.078.0 changes things up. The compiler is aware of the presence of the runtime implementation at compile time, so it can see whether or not the current implementation provides a
ModuleInfo declaration. If it does, instances will be generated as appropriate. If it doesn’t, then the instances won’t be generated. This makes it just that much easier to stub out your own runtime, which is something you’d want to do if you were, say, writing a kernel in D.
Other notable changes
New users of DMD on Windows will now have an easier time getting a 64-bit environment set up. It’s still necessary to install the Microsoft build tools, but now DMD will detect the installation of either the Microsoft Build Tools package or Visual Studio at runtime when either
-m32mscoff is specified on the command line. Previously, configuration was handled automatically only by the installer; manual installs had to be configured manually.
DRuntime has been enhanced to allow more fine-grained control over unit tests. Of particular note is the
--DRT-testmode flag which can be passed to any D executable. With the argument
"run-main", the current default, any unit tests present will be run and then
main will execute if they all pass; with
"test-or-main", the planned default beginning with DMD 2.080.0, any unit tests present will run and the program will exit with a summary of the results, otherwise
main will execute; with
main will not be executed, but test results will still be summarized if present.
Onward into 2018
This is the first DMD release of 2018. We can’t wait to see what the next 12 months bring for the D programming language community. From everyone at the D Language Foundation, we hope you have a very Happy New Year!