Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

DSSS by Example

This document attempts to explain what DSSS is, and how it is useful, by example. Essentially, it will go through several, increasingly-complex examples, describing the process of accomplishing them with and without DSSS.

Documentation on the actual format of dsss.conf files and their options is available in the DSSS distribution in README.software_engineers, and is not explored in depth here.

The Simple Binary

Imagine you've created a simple uncompressor for a hypothetical compression format, dzip. You are trying to decide how you should build your tool, dunzip. This can be done realistically with or without DSSS like so:

Using the Compiler

It is of course possible in this scenario to simply use the compiler, and neither a build tool nor DSSS. Just passing the file into the compiler is sufficient:

$ [g]dmd dunzip.d -ofdunzip
or
$ gdc dunzip.d -o dunzip

Using a Build Tool

Using a build tool with a one-file binary is basically exactly equivalent to just using the compiler:

$ rebuild dunzip.d -ofdunzip
or
$ bud dunzip.d -Tdunzip

Using DSSS

All tools using DSSS require a dsss.conf file. As such, using DSSS involves the extra step of creating this file. In this example, your dsss.conf file looks like this:

name = dunzip
[dunzip.d]
target = dunzip

With this file, building is as simple as:

$ dsss build

This added file may seem like it's not worth the effort, but keep in mind that the exact parameters to the build tool or compiler will need to be saved somewhere, so this isn't necessarily an overhead. Also, as will be expanded on further in this document, dsss.conf is far more flexible.

Less Simple: A Trivial Library

Imagine that dunzip has evolved, and people would like to use it as a library. As such, you divide the 'library' code and 'front-end' code into dunzip.d and main.d, respectively. You don't care to actually compile it into a library file (.a or .lib), so long as it's usable.

Using the Compiler

Installing the library code is as simple as copying the .d file into the include path of the compiler. Unfortunately, doing so is platform-specific. As such, the installation would essentially be manual.

Building the binary itself is still fairly simple:

$ [g]dmd main.d dunzip.d -ofdunzip
or
$ gdc main.d dunzip.d -o dunzip

Using a Build Tool

Installing the library code is still platform-specific and needs to be done manually. However, building the binary is a bit easier, since the dependencies are traced:

$ rebuild main.d -ofdunzip
or
$ bud main.d -Tdunzip

Using DSSS

Here we see the first major advantage of DSSS: This installation process is simple and automated. All you need to do if you used DSSS for the basic binary is to add the library section to your dsss.conf file:

name = dunzip
[dunzip.d]
type = sourcelibrary
[main.d]
target = dunzip

Building is still simple:

$ dsss build

However, installing is no longer manual, but is also trivial:

$ dsss install

Proper Libraries

Let's say you've expanded your dunzip library to support both compressing and uncompressing, and expanded it to include a number of modules. Your tree now looks like this:

main.d
dzip/
dzip/algorithm.d
dzip/block.d
dzip/compress.d
dzip/hash.d
dzip/io.d
dzip/levels.d
dzip/stack.d
dzip/trees.d
dzip/uncompress.d

There are now a large number of modules. Furthermore, you have decided that you'd like to build this into a proper library file, that is a .a or .lib file.

Using the Compiler

At this point, using the compiler directly is ridiculous. Every .d file needs to be passed into the compiler, and maintaining that list as a Makefile or shell script is prone to errors, aside from being platform-specific. Furthermore, creating the library file is not platform-independent. Installing is, of course, even more difficult than before: Now we have to install a large number of .d files and a library file!

Using a Build Tool

To do this with a build tool, a file 'dzip/all.d' would need to be added. With the 'all.d' module, it would be fairly simple to build a library with a build tool:

$ rebuild -lib dzip/all.d -oflibdzip.a
or
$ bud -lib dzip/all.d -Tlibdzip.a

And of course, compiling the binary is still simple:

$ rebuild main.d -ofdzipper
or
$ bud main.d -Tdzipper

Ideally, building against this library would be as simple as importing the proper module. The standard means of accomplishing this is to create a .di (D import) file, and add a special directive to it which will cause the build tool to link in the proper library. You would therefore need to generate a number of .di files, and for every one, add a section something like this:

version (build) {
    pragma(link, "dzip");
}

This can be done in a Makefile or shellscript, but not in a platform-independent way.

Finally, installing is still very manual.

Using DSSS

Here again the advantage of using DSSS is quite clear. There is no need for an all.d file, and nothing is platform-specific. The dsss.conf file is now:

name = dzip
[dzip]
[main.d]
target = dzipper

Building is still simple:

$ dsss build

And installing is also still simple:

$ dsss install

Using the Library

After you went through all the trouble of creating this library, presumably someone will want to use it. So, let's imagine you've written a new tool, dzipserver, which uses your dzip library. It contains only one file, dzipserver.d. As with the simple one-file binary, this can be accomplished with or without DSSS.

Using the Compiler

Linking against libraries is not consistent across platforms. As such, doing this with the compiler is not a very good option.

On Posix:

$ [g]dmd dzipserver.d -ofdzipserver -L-ldzip
or
$ gdc dzipserver.d -o dzipserver -ldzip

On Windows:

$ dmd dzipserver.d -ofdzipserver -L+dzip.lib
or
$ gdmd dzipserver.d -ofdzipserver -L-ldzip

Using a Build Tool

If .di files have been created and installed as described above (which is a manual and platform-specific process), building with a build tool is fairly simple:

$ rebuild dzipserver.d -ofdzipserver
or
$ bud dzipserver.d -Tdzipserver

Using DSSS

Because you're using DSSS, you know that the .di files and library have been installed properly. As such, all you need to do is import the proper modules. The dsss.conf will therefore look like this:

name = dzipserver
[dzipserver.d]
target = dzipserver

As with every other step, building and installing is:

$ dsss build
$ dsss install

However, there's another advantage of DSSS here. Imagine that dzip has been set up in the DSSS networking system, but that it isn't installed on the system you're building dzipserver on. Not only is installing it simple, but the end user doesn't even need to know what it is or where it's from. Installing all the dependencies for a tool is as simple as:

$ dsss net deps

Documentation

As you've written dzip, hopefully you've been writing good ddocs. Now you'd like to generate documentation .html files from them.

Using the Compiler or a Build Tool

Simply adding the proper -D flag to the compiler or build tool's command line is usually sufficient, but has some significant lacks: 1. If you want to use candydoc, you need to set it up yourself. 2. If you have similarly-named modules, they will be given the same .html file name, so one will be missing.

Using DSSS

Making .html documentation from ddocs is trivial with DSSS. Just add --doc to the build line:

$ dsss build --doc

Every module is given a fully qualified filename, so similarly-named modules do not cause a problem. Furthermore, candydoc is included automatically.

Conclusion

This document should have made clear the advantages of using DSSS: Primarily, it allows for much-improved interaction between D libraries, installation, and dependency acquisition. Even for simple tools, it provides the advantage of the simple format of dsss.conf as compared to a Makefile or shell script.

This document has not gone into great detail on the range of features supported by DSSS, only the very most basic and useful ones. More complete documentation is provided with DSSS.