diff --git a/source/app.d b/source/app.d index 8a2a377..40c581d 100644 --- a/source/app.d +++ b/source/app.d @@ -129,7 +129,7 @@ dub.update(annotate ? UpdateOptions.JustAnnotate : UpdateOptions.None); } - assert(build_config.length == 0, "Build configurations not yet supported."); + enforce(build_config.length == 0 || dub.configurations.canFind(build_config), "Unknown build configuration: "~build_config); //Added check for existance of [AppNameInPackagejson].d //If exists, use that as the starting file. @@ -154,10 +154,31 @@ } } - flags ~= "-w"; - flags ~= "-property"; - flags ~= dub.getDflags(build_platform); - flags ~= getPackagesAsVersion(dub); + auto settings = dub.getBuildSettings(build_platform, build_config); + 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."); + settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); + settings.libs = null; + } + } + + flags ~= settings.dflags; + flags ~= settings.lflags.map!(f => "-L"~f)().array(); + flags ~= settings.importPath.map!(f => "-I"~f)().array(); + flags ~= settings.stringImportPath.map!(f => "-J"~f)().array(); + flags ~= settings.versions.map!(f => "-version="~f)().array(); flags ~= (mainsrc).toNativeString(); string dflags = environment.get("DFLAGS"); @@ -173,7 +194,9 @@ } } - if( build_type.length ) logInfo("Building configuration "~build_type); + if( build_config.length ) logInfo("Building configuration "~build_config~", build type "~build_type); + else logInfo("Building default configuration, build type "~build_type); + logInfo("Running %s", "rdmd " ~ dflags ~ " " ~ join(flags, " ")); auto rdmd_pid = spawnProcess("rdmd " ~ dflags ~ " " ~ join(flags, " ")); auto result = rdmd_pid.wait(); @@ -199,7 +222,7 @@ } catch(Throwable e) { - logError("Error executing command '%s': %s\n", cmd, e.msg); + logError("Error: %s\n", e.msg); logDebug("Full exception: %s", sanitizeUTF8(cast(ubyte[])e.toString())); logInfo("Run 'dub help' for usage information."); return 1; @@ -256,7 +279,7 @@ string[] ret; string[string] pkgs = dub.installedPackages(); foreach(id, vers; pkgs) - ret ~= "-version=VPM_package_" ~ stripDlangSpecialChars(id); + ret ~= "VPM_package_" ~ stripDlangSpecialChars(id); return ret; } diff --git a/source/dub/dub.d b/source/dub/dub.d index 2781809..2b7f8f3 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -129,46 +129,42 @@ /// Returns the applications name. @property string name() const { return m_main ? m_main.name : "app"; } - @property string[] configurations() const { return m_main ? m_main.configurations : null; } + @property string[] configurations() + const { + string[] ret; + if( m_main ) ret = m_main.configurations; + foreach( p; m_packages ){ + auto cfgs = p.configurations; + foreach( c; cfgs ) + if( !ret.canFind(c) ) ret ~= c; + } + return ret; + } /// Returns the DFLAGS - string[] getDflags(BuildPlatform platform) + BuildSettings getBuildSettings(BuildPlatform platform, string config) const { - auto ret = appender!(string[])(); - string[] libs; - if( m_main ){ - processVars(ret, ".", m_main.getDflags(platform)); - libs ~= m_main.getLibs(platform); + BuildSettings ret; + + void addImportPath(string path, bool src) + { + if( !exists(path) ) return; + if( src ) ret.addImportDirs([path]); + else ret.addStringImportDirs([path]); } - ret.put("-Isource"); - ret.put("-Jviews"); + + if( m_main ) processVars(ret, ".", m_main.getBuildSettings(platform, config)); + addImportPath("source", true); + addImportPath("views", false); + foreach( string s, pkg; m_packages ){ auto pack_path = ".dub/modules/"~pkg.name; - void addPath(string prefix, string name){ - auto path = pack_path~"/"~name; - if( exists(path) ) - ret.put(prefix ~ path); - } - processVars(ret, pack_path, pkg.getDflags(platform)); - libs ~= pkg.getLibs(platform); - addPath("-I", "source"); - addPath("-J", "views"); + processVars(ret, pack_path, pkg.getBuildSettings(platform, config)); + addImportPath(pack_path ~ "/source", true); + addImportPath(pack_path ~ "/views", false); } - if( libs.length ){ - try { - logDebug("Trying to use pkg-config to resolve library flags for %s.", libs); - auto libflags = execute("pkg-config", "--libs" ~ libs.map!(l => "lib"~l)().array()); - enforce(libflags.status == 0, "pkg-config exited with error code "~to!string(libflags.status)); - ret.put(libflags.output.split().map!(f => "-L"~f)().array()); - } catch( Exception e ){ - logDebug("pkg-config failed: %s", e.msg); - logDebug("Falling back to direct -lxyz flags."); - ret.put(libs.map!(l => "-L-l"~l)().array()); - } - } - - return ret.data(); + return ret; } /// Actions which can be performed to update the application. @@ -444,7 +440,7 @@ /// Returns a list of flags which the application needs to be compiled /// properly. - string[] getDflags(BuildPlatform platform) { return m_app.getDflags(platform); } + BuildSettings getBuildSettings(BuildPlatform platform, string config) { return m_app.getBuildSettings(platform, config); } /// Lists all installed modules void list() { @@ -666,6 +662,23 @@ } } +private void processVars(ref BuildSettings dst, string project_path, BuildSettings settings) +{ + dst.addDFlags(processVars(project_path, settings.dflags)); + dst.addLFlags(processVars(project_path, settings.lflags)); + dst.addLibs(processVars(project_path, settings.libs)); + dst.addVersions(processVars(project_path, settings.versions)); + dst.addImportDirs(processVars(project_path, settings.importPath)); // TODO: prepend project_path to relative paths here + dst.addStringImportDirs(processVars(project_path, settings.stringImportPath)); // TODO: prepend project_path to relative paths here +} + +private string[] processVars(string project_path, string[] vars) +{ + auto ret = appender!(string[])(); + processVars(ret, project_path, vars); + return ret.data; + +} private void processVars(ref Appender!(string[]) dst, string project_path, string[] vars) { foreach( var; vars ){ diff --git a/source/dub/package_.d b/source/dub/package_.d index d0569b8..344fe86 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -22,6 +22,65 @@ string compiler; } +struct BuildSettings { + string[] dflags; + string[] lflags; + string[] libs; + string[] versions; + string[] importPath; + string[] stringImportPath; + + void parse(in Json root, BuildPlatform platform) + { + addDFlags(getPlatformField(root, "dflags", platform)); + addLFlags(getPlatformField(root, "lflags", platform)); + addLibs(getPlatformField(root, "libs", platform)); + addVersions(getPlatformField(root, "versions", platform)); + addImportDirs(getPlatformField(root, "importPath", platform)); + addStringImportDirs(getPlatformField(root, "stringImportPath", platform)); + } + + void addDFlags(string[] value) { add(dflags, value); } + void addLFlags(string[] value) { add(lflags, value); } + void addLibs(string[] value) { add(libs, value); } + void addVersions(string[] value) { add(versions, value); } + void addImportDirs(string[] value) { add(importPath, value); } + void addStringImportDirs(string[] value) { add(stringImportPath, value); } + + 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; + } + } + + private string[] getPlatformField(in Json json, string name, BuildPlatform platform) + const { + auto c = platform.compiler; + + auto ret = appender!(string[])(); + // TODO: turn these loops around and iterate over m_metas fields instead for efficiency reason + foreach( j; json[name].opt!(Json[]) ) ret.put(j.get!string); + foreach( j; json[name~"-"~c].opt!(Json[]) ) ret.put(j.get!string); + foreach( p; platform.platform ){ + foreach( j; json[name~"-"~p].opt!(Json[]) ) ret.put(j.get!string); + foreach( j; json[name~"-"~p~"-"~c].opt!(Json[]) ) ret.put(j.get!string); + foreach( a; platform.architecture ){ + foreach( j; json[name~"-"~p~"-"~a].opt!(Json[]) ) ret.put(j.get!string); + foreach( j; json[name~"-"~p~"-"~a~"-"~c].opt!(Json[]) ) ret.put(j.get!string); + } + } + return ret.data; + + } +} + /// Representing an installed package // Json file example: // { @@ -69,28 +128,19 @@ return ret.data; } - string[] getPlatformField(string name, BuildPlatform platform) + BuildSettings getBuildSettings(BuildPlatform platform, string config) const { - auto c = platform.compiler; - - auto ret = appender!(string[])(); - // TODO: turn these loops around and iterate over m_metas fields instead for efficiency reason - foreach( j; m_meta[name].opt!(Json[]) ) ret.put(j.get!string); - foreach( j; m_meta[name~"-"~c].opt!(Json[]) ) ret.put(j.get!string); - foreach( p; platform.platform ){ - foreach( j; m_meta[name~"-"~p].opt!(Json[]) ) ret.put(j.get!string); - foreach( j; m_meta[name~"-"~p~"-"~c].opt!(Json[]) ) ret.put(j.get!string); - foreach( a; platform.architecture ){ - foreach( j; m_meta[name~"-"~p~"-"~a].opt!(Json[]) ) ret.put(j.get!string); - foreach( j; m_meta[name~"-"~p~"-"~a~"-"~c].opt!(Json[]) ) ret.put(j.get!string); - } + BuildSettings ret; + ret.parse(m_meta, platform); + if( config.length ){ + auto pcs = "configurations" in m_meta; + if( !pcs ) return ret; + auto pc = config in *pcs; + if( !pc ) return ret; + ret.parse(*pc, platform); } - return ret.data; - + return ret; } - - string[] getDflags(BuildPlatform platform) const { return getPlatformField("dflags", platform); } - string[] getLibs(BuildPlatform platform) const { return getPlatformField("libs", platform); } string info() const { string s;