diff --git a/source/app.d b/source/app.d index 6d0b761..62faea9 100644 --- a/source/app.d +++ b/source/app.d @@ -7,6 +7,7 @@ */ module app; +import dub.compilers.compiler; import dub.dependency; import dub.dub; import dub.package_; @@ -45,6 +46,7 @@ bool help, nodeps, annotate; LogLevel loglevel = LogLevel.Info; string build_type = "debug", build_config; + string compiler_name = "dmd"; bool print_platform, print_builds, print_configs; bool install_system = false, install_local = false; string install_version; @@ -57,6 +59,7 @@ "nodeps", &nodeps, "annotate", &annotate, "build", &build_type, + "compiler", &compiler_name, "config", &build_config, "print-builds", &print_builds, "print-configs", &print_configs, @@ -136,6 +139,8 @@ auto def_config = dub.getDefaultConfiguration(build_platform); if( !build_config.length ) build_config = def_config; + auto compiler = getCompiler(compiler_name); + if( print_builds ){ logInfo("Available build types:"); foreach( tp; ["debug", "release", "unittest", "profile"] ) @@ -168,7 +173,7 @@ // Create start script, which will be used by the calling bash/cmd script. // build "rdmd --force %DFLAGS% -I%~dp0..\source -Jviews -Isource @deps.txt %LIBS% source\app.d" ~ application arguments // or with "/" instead of "\" - string[] flags = ["--force", "--build-only"]; + string[] flags = ["--force", "--build-only", "--compiler="~compiler_name]; Path run_exe_file; if( cmd == "build" ){ flags ~= "-of"~(dub.binaryPath~outfile).toNativeString(); @@ -189,29 +194,8 @@ settings.addDFlags(["-w", "-property"]); settings.addVersions(getPackagesAsVersion(dub)); - // TODO: this belongs to the builder/generator - if( settings.libs.length ){ - try { - logDebug("Trying to use pkg-config to resolve library flags for %s.", settings.libs); - auto libflags = execute("pkg-config", "--libs" ~ settings.libs.map!(l => "lib"~l)().array()); - enforce(libflags.status == 0, "pkg-config exited with error code "~to!string(libflags.status)); - settings.addLFlags(libflags.output.split()); - settings.libs = null; - } catch( Exception e ){ - logDebug("pkg-config failed: %s", e.msg); - logDebug("Falling back to direct -lxyz flags."); - version(Windows) settings.addDFlags(settings.libs.map!(l => l~".lib")().array()); - else settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); - settings.libs = null; - } - } - + compiler.prepareBuildSettings(settings, BuildSetting.commandLine); flags ~= settings.dflags; - flags ~= settings.lflags.map!(f => "-L"~f)().array(); - flags ~= settings.importPaths.map!(f => "-I"~f)().array(); - flags ~= settings.stringImportPaths.map!(f => "-J"~f)().array(); - flags ~= settings.versions.map!(f => "-version="~f)().array(); - flags ~= settings.files; flags ~= (mainsrc).toNativeString(); string dflags = environment.get("DFLAGS"); @@ -356,6 +340,8 @@ plain --config=NAME Builds the specified configuration. Configurations can be defined in package.json + --compiler=NAME Uses one of the supported compilers: + dmd (default), gcc, ldc --nodeps Do not check dependencies for 'run' or 'build' --print-builds Prints the list of available build types --print-configs Prints the list of available configurations diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d new file mode 100644 index 0000000..64420f9 --- /dev/null +++ b/source/dub/compilers/compiler.d @@ -0,0 +1,168 @@ +/** + Compiler settings and abstraction. + + Copyright: © 2013 rejectedsoftware e.K. + License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + Authors: Sönke Ludwig +*/ +module dub.compilers.compiler; + +import dub.compilers.dmd; + +import std.array; +import vibe.data.json; + + +static this() +{ + registerCompiler(new DmdCompiler); +} + + +Compiler getCompiler(string name) +{ + foreach( c; s_compilers ) + if( c.name == name ) + return c; + throw new Exception("Unknown compiler: "~name); +} + +void registerCompiler(Compiler c) +{ + s_compilers ~= c; +} + + +interface Compiler { + @property string name() const; + + /// Replaces high level fields with low level fields and converts + /// dmd flags to compiler-specific flags + void prepareBuildSettings(ref BuildSettings settings, BuildSetting supported_fields = BuildSetting.all); +} + + +/// BuildPlatform specific settings, like needed libraries or additional +/// include paths. +struct BuildSettings { + string[] dflags; + string[] lflags; + string[] libs; + string[] files; + string[] copyFiles; + string[] versions; + string[] importPaths; + string[] stringImportPaths; + + void parse(in Json root, BuildPlatform platform) + { + addDFlags(getPlatformField(root, "dflags", platform)); + addLFlags(getPlatformField(root, "lflags", platform)); + addLibs(getPlatformField(root, "libs", platform)); + addFiles(getPlatformField(root, "files", platform)); + addCopyFiles(getPlatformField(root, "copyFiles", platform)); + addVersions(getPlatformField(root, "versions", platform)); + addImportDirs(getPlatformField(root, "importPaths", platform)); + addStringImportDirs(getPlatformField(root, "stringImportPaths", platform)); + } + + void addDFlags(string[] value) { add(dflags, value); } + void addLFlags(string[] value) { add(lflags, value); } + void addLibs(string[] value) { add(libs, value); } + void addFiles(string[] value) { add(files, value); } + void addCopyFiles(string[] value) { add(copyFiles, value); } + void addVersions(string[] value) { add(versions, value); } + void addImportDirs(string[] value) { add(importPaths, value); } + void addStringImportDirs(string[] value) { add(stringImportPaths, value); } + + // Adds vals to arr without adding duplicates. + private void add(ref string[] arr, string[] vals) + { + foreach( v; vals ){ + bool found = false; + foreach( i; 0 .. arr.length ) + if( arr[i] == v ){ + found = true; + break; + } + if( !found ) arr ~= v; + } + } + + // Parses json and returns the values of the corresponding field + // by the platform. + private string[] getPlatformField(in Json json, string name, BuildPlatform platform) + const { + auto ret = appender!(string[])(); + foreach( suffix; getPlatformSuffixIterator(platform) ){ + foreach( j; json[name~suffix].opt!(Json[]) ) + ret.put(j.get!string); + } + return ret.data; + } +} + +/// Represents a platform a package can be build upon. +struct BuildPlatform { + /// e.g. ["posix", "windows"] + string[] platform; + /// e.g. ["x86", "x64"] + string[] architecture; + /// e.g. "dmd" + string compiler; +} + +enum BuildSetting { + dflags = 1<<0, + lflags = 1<<1, + libs = 1<<2, + files = 1<<3, + copyFiles = 1<<4, + versions = 1<<5, + importPaths = 1<<6, + stringImportPaths = 1<<7, + none = 0, + commandLine = dflags|copyFiles, + commandLineSeparate = commandLine|lflags, + all = dflags|lflags|libs|files|copyFiles|versions|importPaths|stringImportPaths +} + +private { + Compiler[] s_compilers; +} + +/// Based on the BuildPlatform, creates an iterator with all suffixes. +/// +/// Suffixes are build upon the following scheme, where each component +/// is optional (indicated by []), but the order is obligatory. +/// "[-platform][-architecture][-compiler]" +/// +/// So the following strings are valid suffixes: +/// "-windows-x86-dmd" +/// "-dmd" +/// "-arm" +/// +int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform) +{ + int iterator(scope int delegate(ref string s) del) + { + auto c = platform.compiler; + int delwrap(string s) { return del(s); } + if( auto ret = delwrap(null) ) return ret; + if( auto ret = delwrap("-"~c) ) return ret; + foreach( p; platform.platform ){ + if( auto ret = delwrap("-"~p) ) return ret; + if( auto ret = delwrap("-"~p~"-"~c) ) return ret; + foreach( a; platform.architecture ){ + if( auto ret = delwrap("-"~p~"-"~a) ) return ret; + if( auto ret = delwrap("-"~p~"-"~a~"-"~c) ) return ret; + } + } + foreach( a; platform.architecture ){ + if( auto ret = delwrap("-"~a) ) return ret; + if( auto ret = delwrap("-"~a~"-"~c) ) return ret; + } + return 0; + } + return &iterator; +} diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d new file mode 100644 index 0000000..307b93f --- /dev/null +++ b/source/dub/compilers/dmd.d @@ -0,0 +1,68 @@ +/** + DMD compiler support. + + Copyright: © 2013 rejectedsoftware e.K. + License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + Authors: Sönke Ludwig +*/ +module dub.compilers.dmd; + +import dub.compilers.compiler; + +import std.algorithm; +import std.array; +import std.conv; +import std.exception; +import stdx.process; +import vibe.core.log; + + +class DmdCompiler : Compiler { + @property string name() const { return "dmd"; } + + void prepareBuildSettings(ref BuildSettings settings, BuildSetting fields = BuildSetting.all) + { + if( !(fields & BuildSetting.libs) ){ + try { + logDebug("Trying to use pkg-config to resolve library flags for %s.", settings.libs); + auto libflags = execute("pkg-config", "--libs" ~ settings.libs.map!(l => "lib"~l)().array()); + enforce(libflags.status == 0, "pkg-config exited with error code "~to!string(libflags.status)); + settings.addLFlags(libflags.output.split()); + } catch( Exception e ){ + logDebug("pkg-config failed: %s", e.msg); + logDebug("Falling back to direct -lxyz flags."); + version(Windows) settings.addFiles(settings.libs.map!(l => l~".lib")().array()); + else settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); + } + settings.libs = null; + } + + if( !(fields & BuildSetting.versions) ){ + settings.addDFlags(settings.versions.map!(s => "-version="~s)().array()); + settings.versions = null; + } + + if( !(fields & BuildSetting.importPaths) ){ + settings.addDFlags(settings.importPaths.map!(s => "-I"~s)().array()); + settings.importPaths = null; + } + + if( !(fields & BuildSetting.stringImportPaths) ){ + settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); + settings.stringImportPaths = null; + } + + if( !(fields & BuildSetting.files) ){ + settings.addDFlags(settings.files); + settings.files = null; + } + + if( !(fields & BuildSetting.lflags) ){ + settings.addDFlags(settings.lflags.map!(f => "-L"~f)().array()); + settings.lflags = null; + } + + assert(fields & BuildSetting.dflags); + assert(fields & BuildSetting.copyFiles); + } +} diff --git a/source/dub/dub.d b/source/dub/dub.d index 90bec38..15f6358 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -7,6 +7,7 @@ */ module dub.dub; +import dub.compilers.compiler; import dub.dependency; import dub.installation; import dub.utils; diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 5e27fcd..9d3a856 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -7,13 +7,16 @@ */ module dub.generators.generator; -import dub.project; -import dub.package_; -import dub.packagemanager; +import dub.compilers.compiler; import dub.generators.monod; import dub.generators.visuald; -import vibe.core.log; +import dub.package_; +import dub.packagemanager; +import dub.project; + import std.exception; +import vibe.core.log; + /// A project generator generates projects :-/ interface ProjectGenerator diff --git a/source/dub/generators/monod.d b/source/dub/generators/monod.d index 1d6590b..c8c2990 100644 --- a/source/dub/generators/monod.d +++ b/source/dub/generators/monod.d @@ -7,6 +7,12 @@ */ module dub.generators.monod; +import dub.compilers.compiler; +import dub.generators.generator; +import dub.package_; +import dub.packagemanager; +import dub.project; + import std.algorithm; import std.array; import std.conv; @@ -17,10 +23,6 @@ import vibe.core.file; import vibe.core.log; -import dub.project; -import dub.package_; -import dub.packagemanager; -import dub.generators.generator; class MonoDGenerator : ProjectGenerator { private { diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index ed31714..684c400 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -7,6 +7,12 @@ */ module dub.generators.visuald; +import dub.compilers.compiler; +import dub.generators.generator; +import dub.package_; +import dub.packagemanager; +import dub.project; + import std.algorithm; import std.array; import std.conv; @@ -17,11 +23,6 @@ import vibe.core.file; import vibe.core.log; -import dub.project; -import dub.package_; -import dub.packagemanager; -import dub.generators.generator; - version = VISUALD_SEPERATE_PROJECT_FILES; //version = VISUALD_SINGLE_PROJECT_FILE; diff --git a/source/dub/package_.d b/source/dub/package_.d index 5ce372b..b949b39 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -7,6 +7,7 @@ */ module dub.package_; +import dub.compilers.compiler; import dub.dependency; import dub.utils; @@ -21,111 +22,6 @@ enum PackageJsonFilename = "package.json"; -/// Represents a platform a package can be build upon. -struct BuildPlatform { - /// e.g. ["posix", "windows"] - string[] platform; - /// e.g. ["x86", "x64"] - string[] architecture; - /// e.g. "dmd" - string compiler; -} - -/// BuildPlatform specific settings, like needed libraries or additional -/// include paths. -struct BuildSettings { - string[] dflags; - string[] lflags; - string[] libs; - string[] files; - string[] copyFiles; - string[] versions; - string[] importPaths; - string[] stringImportPaths; - - void parse(in Json root, BuildPlatform platform) - { - addDFlags(getPlatformField(root, "dflags", platform)); - addLFlags(getPlatformField(root, "lflags", platform)); - addLibs(getPlatformField(root, "libs", platform)); - addFiles(getPlatformField(root, "files", platform)); - addCopyFiles(getPlatformField(root, "copyFiles", platform)); - addVersions(getPlatformField(root, "versions", platform)); - addImportDirs(getPlatformField(root, "importPaths", platform)); - addStringImportDirs(getPlatformField(root, "stringImportPaths", platform)); - } - - void addDFlags(string[] value) { add(dflags, value); } - void addLFlags(string[] value) { add(lflags, value); } - void addLibs(string[] value) { add(libs, value); } - void addFiles(string[] value) { add(files, value); } - void addCopyFiles(string[] value) { add(copyFiles, value); } - void addVersions(string[] value) { add(versions, value); } - void addImportDirs(string[] value) { add(importPaths, value); } - void addStringImportDirs(string[] value) { add(stringImportPaths, value); } - - // Adds vals to arr without adding duplicates. - private void add(ref string[] arr, string[] vals) - { - foreach( v; vals ){ - bool found = false; - foreach( i; 0 .. arr.length ) - if( arr[i] == v ){ - found = true; - break; - } - if( !found ) arr ~= v; - } - } - - // Parses json and returns the values of the corresponding field - // by the platform. - private string[] getPlatformField(in Json json, string name, BuildPlatform platform) - const { - auto ret = appender!(string[])(); - foreach( suffix; getPlatformSuffixIterator(platform) ){ - foreach( j; json[name~suffix].opt!(Json[]) ) - ret.put(j.get!string); - } - return ret.data; - } -} - -/// Based on the BuildPlatform, creates an iterator with all suffixes. -/// -/// Suffixes are build upon the following scheme, where each component -/// is optional (indicated by []), but the order is obligatory. -/// "[-platform][-architecture][-compiler]" -/// -/// So the following strings are valid suffixes: -/// "-windows-x86-dmd" -/// "-dmd" -/// "-arm" -/// -int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform) -{ - int iterator(scope int delegate(ref string s) del) - { - auto c = platform.compiler; - int delwrap(string s) { return del(s); } - if( auto ret = delwrap(null) ) return ret; - if( auto ret = delwrap("-"~c) ) return ret; - foreach( p; platform.platform ){ - if( auto ret = delwrap("-"~p) ) return ret; - if( auto ret = delwrap("-"~p~"-"~c) ) return ret; - foreach( a; platform.architecture ){ - if( auto ret = delwrap("-"~p~"-"~a) ) return ret; - if( auto ret = delwrap("-"~p~"-"~a~"-"~c) ) return ret; - } - } - foreach( a; platform.architecture ){ - if( auto ret = delwrap("-"~a) ) return ret; - if( auto ret = delwrap("-"~a~"-"~c) ) return ret; - } - return 0; - } - return &iterator; -} /// Indicates where a package has been or should be installed to. enum InstallLocation { diff --git a/source/dub/project.d b/source/dub/project.d index 404bea0..2b1031a 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -7,6 +7,7 @@ */ module dub.project; +import dub.compilers.compiler; import dub.dependency; import dub.installation; import dub.utils;