diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index f3359b9..aff0e2f 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -207,7 +207,8 @@ } version(VISUALD_SEPERATE_PROJECT_FILES){ - auto files = pack.getBuildSettings(settings.platform, m_app.getPackageConfig(pack, settings.platform, settings.config)); + auto configs = m_app.getPackageConfigs(settings.platform, settings.config); + auto files = pack.getBuildSettings(settings.platform, configs[pack.name]); files.sourceFiles ~= pack.packageInfoFile.toNativeString(); diff --git a/source/dub/package_.d b/source/dub/package_.d index 077290e..239c881 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -161,7 +161,7 @@ } /// Returns all BuildSettings for the given platform and config. - BuildSettings getBuildSettings(BuildPlatform platform, string config) + BuildSettings getBuildSettings(in BuildPlatform platform, string config) const { logDebug("Using config %s for %s", config, this.name); foreach(ref conf; m_info.configurations){ @@ -175,8 +175,23 @@ assert(false, "Unknown configuration for "~m_info.name~": "~config); } + string getSubConfiguration(string config, in Package dependency, in BuildPlatform platform) + const { + bool found = false; + foreach(ref c; m_info.configurations){ + if( c.name == config ){ + if( auto pv = dependency.name in c.buildSettings.subConfigurations ) return *pv; + found = true; + break; + } + } + assert(found, "Invliad configuration "~config~" for "~this.name); + if( auto pv = dependency.name in m_info.buildSettings.subConfigurations ) return *pv; + return null; + } + /// Returns the default configuration to build for the given platform - string getDefaultConfiguration(BuildPlatform platform, bool is_main_package = false) + string getDefaultConfiguration(in BuildPlatform platform, bool is_main_package = false) const { foreach(ref conf; m_info.configurations){ if( !conf.matchesPlatform(platform) ) continue; @@ -348,7 +363,7 @@ return ret; } - bool matchesPlatform(BuildPlatform platform) + bool matchesPlatform(in BuildPlatform platform) const { if( platforms.empty ) return true; foreach(p; platforms) @@ -362,6 +377,7 @@ TargetType targetType = TargetType.autodetect; string targetPath; string targetName; + string[string] subConfigurations; string[][string] dflags; string[][string] lflags; string[][string] libs; @@ -399,6 +415,10 @@ enforce(suffix.empty, "targetName does not support platform customization."); this.targetName = value.get!string; break; + case "subConfigurations": + enforce(suffix.empty, "subConfigurations does not support platform customization."); + this.subConfigurations = deserializeJson!(string[string])(value); + break; case "dflags": this.dflags[suffix] = deserializeJson!(string[])(value); break; case "lflags": this.lflags[suffix] = deserializeJson!(string[])(value); break; case "libs": this.libs[suffix] = deserializeJson!(string[])(value); break; @@ -442,7 +462,7 @@ return ret; } - void getPlatformSettings(ref BuildSettings dst, BuildPlatform platform, Path base_path) + void getPlatformSettings(ref BuildSettings dst, in BuildPlatform platform, Path base_path) const { dst.targetType = this.targetType; dst.targetPath = this.targetPath; @@ -483,7 +503,7 @@ getPlatformSetting!("postBuildCommands", "addPostBuildCommands")(dst, platform); } - void getPlatformSetting(string name, string addname)(ref BuildSettings dst, BuildPlatform platform) + void getPlatformSetting(string name, string addname)(ref BuildSettings dst, in BuildPlatform platform) const { foreach(suffix, values; __traits(getMember, this, name)){ if( matchesPlatform(suffix, platform) ) @@ -493,7 +513,7 @@ } -private bool matchesPlatform(string suffix, BuildPlatform platform) +private bool matchesPlatform(string suffix, in BuildPlatform platform) { if( suffix.length == 0 ) return true; // TODO: optimize @@ -514,7 +534,7 @@ /// "-dmd" /// "-arm" /// -private int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform) +private int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(in BuildPlatform platform) { int iterator(scope int delegate(ref string s) del) { diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 129bff0..71aa3d6 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -357,7 +357,7 @@ logInfo("Uninstalled package: '"~pack.name~"'"); } - void addLocalPackage(in Path path, in Version ver, LocalPackageType type) + Package addLocalPackage(in Path path, in Version ver, LocalPackageType type) { Package[]* packs = getLocalPackageList(type); auto info = jsonFromFile(path ~ PackageJsonFilename, false); @@ -369,13 +369,17 @@ foreach( p; *packs ){ if( p.path == path ){ enforce(p.ver == ver, "Adding local twice with different versions is not allowed."); - return; + return p; } } - *packs ~= new Package(info, InstallLocation.local, path); + auto pack = new Package(info, InstallLocation.local, path); + + *packs ~= pack; writeLocalPackageList(type); + + return pack; } void removeLocalPackage(in Path path, LocalPackageType type) diff --git a/source/dub/project.d b/source/dub/project.d index 0e3c0f5..7139ba1 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -44,6 +44,7 @@ Package m_main; //Package[string] m_packages; Package[] m_dependencies; + Package[][Package] m_dependees; } this(PackageManager package_manager, Path project_path) @@ -98,13 +99,10 @@ if( ret ) return; } - foreach(d; p.dependencies.byKey) - foreach(dp; m_dependencies) - if( dp.name == d ){ - perform_rec(dp); - if( ret ) return; - break; - } + foreach(d; p.dependencies.byKey){ + perform_rec(getDependency(d)); + if( ret ) return; + } if( children_first ){ ret = del(p); @@ -117,6 +115,14 @@ return &iterator; } + inout(Package) getDependency(string name) + inout { + foreach(dp; m_dependencies) + if( dp.name == name ) + return dp; + assert(false, "Unknown dependency"); + } + string getDefaultConfiguration(BuildPlatform platform) const { return m_main.getDefaultConfiguration(platform, true); @@ -161,21 +167,23 @@ { logDebug("Collecting dependencies for %s", pack.name); foreach( name, vspec; pack.dependencies ){ + Package p; if( !vspec.path.empty ){ Path path = vspec.path; if( !path.absolute ) path = pack.path ~ path; logDebug("Adding local %s %s", path, vspec.version_); - m_packageManager.addLocalPackage(path, vspec.version_, LocalPackageType.temporary); + p = m_packageManager.addLocalPackage(path, vspec.version_, LocalPackageType.temporary); } else { - auto p = m_packageManager.getBestPackage(name, vspec); - if( !m_dependencies.canFind(p) ){ - logDebug("Found dependency %s %s: %s", name, vspec.toString(), p !is null); - if( p ){ - m_dependencies ~= p; - collectDependenciesRec(p); - } + p = m_packageManager.getBestPackage(name, vspec); + } + if( !m_dependencies.canFind(p) ){ + logDebug("Found dependency %s %s: %s", name, vspec.toString(), p !is null); + if( p ){ + m_dependencies ~= p; + collectDependenciesRec(p); } } + m_dependees[p] ~= pack; //enforce(p !is null, "Failed to resolve dependency "~name~" "~vspec.toString()); } } @@ -187,21 +195,46 @@ @property string[] configurations() const { return m_main.configurations; } - string getPackageConfig(in Package pack, BuildPlatform platform, string config) + /// Returns a map with the configuration for all packages in the dependency tree. + string[string] getPackageConfigs(in BuildPlatform platform, string config) const { - if( pack is m_main ) return config; - else { - // TODO: check the dependees for special wishes in terms on the configuration - return pack.getDefaultConfiguration(platform, false); + string[string] configs; + void determineConfigsRec(in Package p, bool use_default){ + if( p.name !in configs ){ + if( use_default ) configs[p.name] = p.getDefaultConfiguration(platform); + else return; + } + auto pconf = configs[p.name]; + foreach(dn; p.dependencies.byKey){ + auto dep = getDependency(dn); + auto conf = p.getSubConfiguration(config, dep, platform); + if( !conf.empty ){ + if( auto pc = dn in configs ){ + enforce(*pc == conf, format("Conflicting configurations detected for %s: %s vs. %s", dn, *pc, conf)); + } else { + configs[dn] = conf; + determineConfigsRec(dep, use_default); + } + } else if( use_default && dn !in configs ){ + configs[dn] = dep.getDefaultConfiguration(platform); + determineConfigsRec(dep, use_default); + } + } } + + configs[m_main.name] = config; + determineConfigsRec(m_main, false); // first only match all explicit selections + determineConfigsRec(m_main, true); // then fill up the rest with default configurations + return configs; } /// Returns the DFLAGS - void addBuildSettings(ref BuildSettings dst, BuildPlatform platform, string config) + void addBuildSettings(ref BuildSettings dst, in BuildPlatform platform, string config) const { + auto configs = getPackageConfigs(platform, config); + foreach(pkg; this.getTopologicalPackageList()){ - auto pkgconf = getPackageConfig(pkg, platform, config); - auto psettings = pkg.getBuildSettings(platform, pkgconf); + auto psettings = pkg.getBuildSettings(platform, configs[pkg.name]); processVars(dst, pkg.path.toNativeString(), psettings); if( pkg is m_main ){ dst.targetType = psettings.targetType;