Skip to content
Sönke Ludwig edited this page Jun 9, 2015 · 7 revisions

Sdl based package format draft

Introduction

The package format is based on the existing JSON format, but used SDL instead. The new format has a few key advantages:

  • More concise syntax with less puctuation and less quotation marks
  • Lower nesting levels
  • Supports comments

The plan is to keep full support for the JSON based package description and still use it for machine-to-machine communication, but at the same time add the new format as the preferred way for developers to write.

Synopsis

Example of a typical dub.sdl file directly translated from the JSON format specification:

name "myproject"
description "A little web service of mine."
authors "Peter Parker"
homepage "http://myproject.com"
license "GPL v2"
dependency "vibe-d" version=">=0.7.11"

Why SDL

SDL was chosen as the preferred candidate, because it achieves the following goals:

  • Support for unquoted command/key names
  • No root object/table, saving a single level of nesting
  • Natural attribute syntax (e.g. dependency vibe-d path="../vibe.d")
  • Reduces nesting by using multiple tags with the same name (e.g. no "dependencies" table necessary)
  • Supports arbitrary nesting in a way that could be used for natural procedural elements (e.g. if or for)

The main disadvantage of SDL is it's relatively low use in other projects. However, it can be assumed that most users will have to learn a new language in any case, because they are most probably not fluent with any of the other alternatives either.

Another point that is brought up is that the structure of the package description differs from the JSON based one and thus a separate specification is needed. This is true, but it's also maybe the main selling point for introducing a new format in the first place. The deep nesting occurring in the JSON description can be a major distraction and especially attributes can help a lot to avoid that.

Finally, it has been brought up that SDL's support for date/time fields increases the parser complexity. However, those types are not used by DUB and parsers already exist, so that this doesn't make a difference in practice whatsoever.

Global commands

SDL has a structure similar to XML using nodes and attributes. The format we describe here uses nodes with a semantic that is close to a procedural command. The order matters and commands can usually occur multiple times. This is in contrast to the JSON based format, where each field name can only occur once.

The globally available commands are:

Name Arguments Description
name string Name of the package, used to uniquely identify the package
description string Brief description of the package
homepage string URL of the project website
authors string ... List of project authors
copyright string Copyright declaration string
license string License(s) under which the project can be used
subPackage { ... } Defines a new sub-package defined in the same directory as the root project, where each entry is an object of the same format as the global dub.sdl file itself - see the sub package section for more information
configuration string { ... } Defines an explicit build configuration (specified using "--config=...") - see the configurations section for more details
buildType string { ... } Defines or overrides a build type (specified using "--build=...") - see the build settings section for valid contents of T
x:ddoxFilterArgs string ... Specifies a list of command line flags usable for controlling filter behavior for --build=ddox [experimental]

Sub packages

A package may contain an arbitrary number of additional publicly visible packages. These packages can be defined using the "subPackage" command of the main dub.sdl file. They can be referenced by concatenating their name with the name of the main package using a colon as a delimiter (i.e. "main-package-name:sub-package-name").

The typical use for this feature is to split up a library into a number of parts without breaking it up into different code repositories or sub directories:

name "mylib"
targetType "none"
dependency "mylib:component1" version="~master"
dependency "mylib:component2" version="~master"

subPackage {
	name "component1"
	targetType "library"
	sourcePaths "source/component1"
}

subPackage {
	name "component2"
	targetType "library"
	sourcePaths "source/component2"
}

Build settings

Build settings fields influence the command line options passed to the compiler and linker. All fields are optional.

Platform specific settings are supported through the use of a platform attribute. Platform specifications are dash separated lower case platform identifiers, as defined in the D language reference. The order of these suffixes is os-architecture-compiler, where any of these parts can be left off. Examples:

versions "PrintfDebugging"
dflags platform="dmd" "-vtls"
versions platform="x86_64" "UseAmd64Impl"
libs platform="posix" "ssl" "crypto"
sourceFiles platform="windows-x86_64-dmd" "lib/win32/mylib.lib"

Inside of build setting values, it is possible to use variables using dollar notation. $PACKAGE_DIR contains the path to the package itself and all other variables are taken from the program environment.

Name Arguments Description
dependency string version=string ... A single dependency - see next section for how version specifications look like
systemDependencies string A textual description of the required system dependencies (external C libraries) required by the package. This will be visible on the registry and will be displayed in case of linker errors.
targetType string Specifies a specific target type - this command does not support platform specifications
targetName string Sets the base name of the output file; type and platform specific pre- and suffixes are added automatically - this command does not support platform specifications
targetPath string The destination path of the output binary - this command does not support platform specifications
workingDirectory string The directory from which the generated executable will be run (defaults to "targetPath") - this command does not support platform specifications
subConfiguration string string Locks the dependency given in the first argument to the configurations given as the second argument - this command does not support platform specifications
buildRequirements string[] List of required settings for the build process. See the build requirements section for details.
buildOptions string[] List of build option identifiers (corresponding to compiler flags) - see the build options section for details.
dflags string ... Additional flags passed to the D compiler - note that these flags are usually specific to the compiler in use, but a set of flags is automatically translated from DMD to the selected compiler
lflags string ... Additional flags passed to the linker - note that these flags are usually specific to the linker in use
libs string ... A list of external library names - depending on the compiler, these will be converted to the proper linker flag (e.g. "ssl" might get translated to "-L-lssl")
sourceFiles string ... Additional files passed to the compiler - can be useful to add certain configuration dependent source files that are not contained in the general source folder
sourcePaths string ... Allows to customize the path where to look for source files (any folder "source" or "src" is automatically used as a source path if no sourcePaths field is given) - note that you usually also need to define "importPaths" as "sourcePaths" don't influence those
excludedSourceFiles string ... Files that should be removed for the set of already added source files (takes precedence over "sourceFiles" and "sourcePaths")
mainSourceFile string Determines the file that contains the main() function. This field can be used by dub to exclude this file in situations where a different main function is defined (e.g. for "dub test") - this field does not support platform suffixes
copyFiles string ... Files that are copied to the applications directory - typically these are DLLs on Windows
versions string ... A list of D versions to be defined during compilation
debugVersions string ... A list of D debug identifiers to be defined during compilation
importPaths string ... Additional import paths to search for D modules (the soruce/ folder is used by default as a source folder, if it exists)
stringImportPaths string ... Additional import paths to search for string imports/views (the views/ folder is used by default as a string import folder, if it exists)
preGenerateCommands string ... A list of shell commands that is executed before project generation is started
postGenerateCommands string ... A list of shell commands that is executed after project generation is finished
preBuildCommands string ... A list of shell commands that is executed always before the project is built
postBuildCommands string ... A list of shell commands that is executed always after the project is built

Version specifications

Some examples of typical simple version specifications:

  • Require a certain version: "==1.3.0"
  • Require a minimum version: ">=1.3.0"
  • Require a version range: ">=1.3.0 <=1.3.4"
  • Use the GIT master branch: "~master"

Numbered versions are formatted and compared according to the SemVer specification.

In addition to the version, additional fields can be added to further control how a dependency is being searched or used:

  • Use a folder to source a package from: dependency "somedep" version="~master" path="path/to/package"
  • Indicate an optional dependency, so that it is used only if it is already installed: depdendency "somedep" version="~master" optional=true [work in progress]

Target types

The following values are recognized for the "targetType" field:

Value Description
"autodetect" Automatically detects the target type. This is the default global value and causes dub to try and generate "application" and "library" configurations. Use of other values limits the auto-generated configurations to either of the two. This value is not allowed inside of a configuration block.
"none" Does not generate an output file. This is useful for packages that are supposed to drag in other packages using its "dependencies" field.
"executable" Generates an executable binary
"library" Specifies that the package is to be used as a library, without limiting the actual type of library. This should be the default for most libraries.
"sourceLibrary" This target type does not generate a binary, but rather forces dub to add all source files directly to the same compiler invocation as the dependent project.
"staticLibrary" Forces output as a static library container.
"dynamicLibrary" Forces output as a dynamic/shared library.

Build requirements

The following values are recognized as array items in the buildRequirements field:

Value Description
"allowWarnings" Warnings do not abort compilation
"silenceWarnings" Don't show warnings
"disallowDeprecations" Using deprecated features aborts compilation
"silenceDeprecations" Don't show deprecation warnings
"disallowInlining" Avoid function inlining, even in release builds
"disallowOptimization" Avoid optimizations, even in release builds
"requireBoundsCheck" Always perform bounds checks
"requireContracts" Leave assertions and contracts enabled in release builds
"noDefaultFlags" Does not emit any of the default build flags (e.g. -debug, -unittest, -w, -property), but still emits import folder flags and version flags (This flag should never be used for released packages and is indended purely as a development/debugging tool)

Configurations

In addition to platform specific build settings, it is possible to define build configurations. Build configurations add or override build settings to the global ones. To choose a configuration, use dub --config=. By default, the first configuration that matches the target type and build platform is selected automatically. The configurations are defined by adding a "configurations" field.

If no configurations are specified, dub automatically tries to detect the two default configurations "application" and "library". The "application" configuration is only added if at least one of the following files is found: source/app.d, source/.d, src/app.d, src/.d. Those files are expected to contain only the application entry point (usually main()) and are only added to the "application" configuration.

The following example defines "metro-app" and "desktop-app" configurations that are only available on Windows and a "glut-app" configuration that is available on all platforms.

...
name "somepackage"

configuration "metro-app" {
	targetType "executable"
	platforms "windows"
	versions "MetroApp"
	libs "d3d11"
}

configuration "desktop-app" {
	targetType "executable"
	platforms "windows"
	versions "DesktopApp"
	libs "d3d9"
}

configuration "glut-app" {
	targetType "executable"
	versions "GlutApp"
}

You can choose a specific configuration for certain dependencies by using the "subConfigurations" field:

...
dependency "somepackage" version=">=1.0.0"
subConfiguration "somepackage" "glut-app"

If no configuration is specified for a package, the first one that matches the current platform is chosen (see the "platforms" field below).

Configuration block specific commands

In addition to the usual build settings, the following fields are recognized inside of a configuration block:

Name Arguments Description
name [required] string Name of the configuration
platforms string ... A list of platform suffixes (as used for the build settings) to limit on which platforms the configuration applies