What's the ascending order for the dub
to build optimized binary below? (e.g. ... debug < plain < release ...)
$ dub build -h
...
-b --build=VALUE Specifies the type of build to perform. Note that
setting the DFLAGS environment variable will override
the build type with custom flags.
Possible names:
debug (default), plain, release, release-debug,
release-nobounds, unittest, profile, profile-gc,
docs, ddox, cov, unittest-cov and custom types
...
The dub build -b release-nobounds
seems derived from dmd -O -release -boundscheck=off
, so what's the equivalent for dub
to build fastest executables?
Those options aren't really about optimizations (and I think it is weird that dub combines them, on dmd itself, those are eight independent switches....), and a lot of people are confused about what they mean, so let me list, using the dmd switch names:
-debug
simply compiles in debug
statements in the code, e.g. debug writeln("foo");
will only write foo if compiled with -debug
. It doesn't do anything else! Importantly, it doesn't include info for debuggers, that is done with -g
(though dub might combine these two options).
-g
adds symbolic debugging info, for programs like gdb
to know function names. This same info is also used on exception stack trace printing, so enabling it will cause the stack traces to show function names too.
-release
disables assert
statements, in
, out
, and invariant
contracts, and automatic array bounds checks in @system
functions (which are the default btw). That's it - it does NOT enable optimizations nor imply the opposite of -debug
, it just skips those assert
-related items. (note that assert(0);
is a special case and is never disabled, but it should never happen anyway - it kills the program.)
-unittest
will compile the unittest
blocks, and run them right before running main
(then main
will still run afterward, like normal).
-profile
adds timing info before and after functions, and writes that info to a log file when the program is complete. Note that it only works with single-thread programs and its logging can significantly slow down the program itself. You'd use it to figure out which functions are called the most and the slowest to know where to focus your optimization efforts.
-cov
adds info to the test log that tells you which lines of your program were actually run, and which weren't.
-profile=gc
does GC-specific profiling, and writes out a log with the timing info.
-D
generates HTML files from the ddoc info in your code while compiling. dub calls this docs
. ddox
is similar, but uses a dub-custom doc generator instead of the default dmd html generator. This is ddoc's output: http://dlang.org/phobos/std_algorithm.html and this is ddox's: http://dlang.org/library/std/algorithm.html
-boundscheck=xxxx
determines where array bounds checking is compiled - safe functions, all functions, or nowhere. (In old versions, this was tied to the -release
switch, but can now be done separately). The default for -release
is @safe
functions, everywhere else, the default is all functions.
Notice that NONE of those were -O
or -inline
! Those are the dmd optimization switches: -O
means to optimize the code and -inline
means to inline functions (it does them separately because sometimes inlining messes up debuggers. The other compilers, gdc and ldc, will inline automatically with their -O
options and generally do a better job of it than dmd anyway.)
Personally, I recommend strongly against using -boundscheck
and -release
- those just hide bugs in most cases without making that big of a difference on final speed. If you find bounds checks in some tight loop are slowing you down, instead of killing it in your entire program with -boundscheck
, instead use .ptr
on the specific accesses that are slow (you can use -profile
to figure out which function to optimize!) Learn more on the tip of the week here: http://arsdnet.net/this-week-in-d/dec-06.html
-release
only makes a significant difference if you are doing tons of expensive asserts... and again, I'd prefer to version out the expensive ones individually instead of disabling everything, including the really quick checks that catch legitimately common bugs.
So, I'd recommend going for just -O
and maybe -inline
for an optimized dmd build. For many (but not all) programs btw, gdc -O
and ldc -O
do a better job than any dmd switch combination - if you are CPU limited, you might want to try them too.
Back to dub. Check out the package format documentation: http://code.dlang.org/package-format?lang=json
Build type release
, so dub build -b release
will pass -O -release -inline
to dmd. Type release-nobounds
adds the nobounds switch too. That's what the dmd docs call the fastest executables, and what I call a buggy mistake.
The best dub option from what I can see (I don't actually use it myself) would be to add buildOptions
to optimize
in the dub config file (dub.json or dub.sdl)
That gives you -O
, then you use stuff like the .ptr
technique or version
on expensive assert
to selectively speed up your hot spots without compromising the anti-bug features in the rest of the program.
Read more dub documentation here:
http://code.dlang.org/package-format?lang=json#build-options