DUB is a standard package manager and build automation system for D. Before DUB appeared in 2012, everyone in D community used different build tools — such as classic Make, DSSS, CDC, xfBuild and custom build scripts, including those written in D itself. I used my own, called Cook, which was my very first public project in D and started as a single-file build script that could be added to any project and run with RDMD. Eventually all these became obsolete, and now D world can’t be imagined without DUB. Today I’m going to show some of its ‘hidden’ features that I use in complex projects.

Platform specific settings

It’s very common to use different build options under different environments. For example, you may want to link against custom *.lib files under Windows, or specify some unusual linker parameters. The same is true for x86/x86_64. DUB allows to do some conditional compilation using optional platform specific settings.

"lflags-windows-x86-dmd": [
"/SUBSYSTEM:WINDOWS:5.01"
]
"lflags-windows-x86_64-dmd": [
"/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"
],
"lflags-windows-x86_64-ldc": [
"-SUBSYSTEM:WINDOWS", "-ENTRY:mainCRTStartup"
],
"lflags-linux-gdc": ["-lz"]

subPackages

Have you ever maintained a project that consisted of multiple separate programs? If so, there’s no need to make each of them a separate package — DUB supports so-called subpackages.

{
"name": "demo",
"dependencies": {
"demo:sample1": "*",
"demo:sample2": "*"
},
"subPackages": [
{
"name": "sample1",
"targetType": "executable",
"targetName": "sample1",
"sourcePaths": ["src/sample1"],
"importPaths": ["src/sample1"],
"dependencies": {
...
}
},
{
"name": "sample2",
"targetType": "executable",
"targetName": "sample2",
"sourcePaths": ["src/sample2"],
"importPaths": ["src/sample2"],
"dependencies": {
...
}
}
]
}

subConfigurations

Similarly, DUB allows multiple configurations of the same package. This is useful to allow a customized build of a dependency.

{
"name": "myGameEngine",
"configurations": [
{
"name": "opengl",
"libs": ["gl"]
},
{
"name": "d3d",
"platforms": ["windows"],
"libs": ["d3d11"]
}
]
}
{
"dependencies": {
"myGameEngine": ">=1.0.0"
},
"subConfigurations": {
"myGameEngine": "opengl"
}
}

stringImportPaths

One of the lesser known features of D is reading string literals from files at compile time (string import), which is very handy for storing large pieces of text:

string s = import("text.txt");
"stringImportPaths": ["myTextDir"]

copyFiles

Another underused great feature of DUB is an ability to copy files from a package to the project.

"copyFiles-windows-x86": ["lib/x86/*.dll"],                           "copyFiles-windows-x86_64": ["lib/x64/*.dll"],

Package Overrides

This is extremely useful for working on several interdependent projects. Imagine that you are writing a game and an engine for it. The engine is a DUB package and lives in a separate repository. How should you develop it locally without pushing changes to remote every time when you want to test unstable features using your game/sandbox? Seems the only solution is to include the entire engine into the game. But with DUB you have a nicer option — package override:

dub add-override myGameEngine ~master path/to/local/repo
"dependencies": {
"myGameEngine": "~master"
}
dub remove-override myGameEngine ~master path/to/local/repo

Application Icon

Compilers usually don’t provide a built-in functionality to set application icon (and version strings) under Windows. The usual way is to compile a resource file (*.res) and link it with the project:

”sourceFiles-windows” : [“application.res”]
"postBuildCommands-windows-x86": [
"$PACKAGE_DIR\\rcedit-x86 \"app.exe\" --set-file-version \"1.0.0.0\" --set-product-version \"1.0.0\" --set-icon \"$PACKAGE_DIR\\icon.ico\""
],

"postBuildCommands-windows-x86_64": [
"$PACKAGE_DIR\\rcedit-x64 \"app.exe\" --set-file-version \"1.0.0.0\" --set-product-version \"1.0.0\" --set-icon \"$PACKAGE_DIR\\icon.ico\""
]

3D game engine developer