diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index eb589f2..bd4d217 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -599,7 +599,7 @@ } // apply both top level and configuration level forced dependency build settings - void applyDependencyBuildSettings (const BuildSettingsTemplate[string] configured_dbs) + void applyDependencyBuildSettings (const RecipeDependency[string] configured_dbs) { BuildSettings[string] dependencyBuildSettings; foreach (key, value; configured_dbs) @@ -608,15 +608,15 @@ if (auto target = key in targets) { // get platform specific build settings and process dub variables (BuildSettingsTemplate => BuildSettings) - value.getPlatformSettings(buildSettings, genSettings.platform, target.pack.path); + value.settings.getPlatformSettings(buildSettings, genSettings.platform, target.pack.path); buildSettings.processVars(m_project, target.pack, buildSettings, genSettings, true); dependencyBuildSettings[key] = buildSettings; } } applyForcedSettings(*roottarget, targets, dependencyBuildSettings); } - applyDependencyBuildSettings(rootPackage.recipe.buildSettings.dependencyBuildSettings); - applyDependencyBuildSettings(rootPackage.getBuildSettings(genSettings.config).dependencyBuildSettings); + applyDependencyBuildSettings(rootPackage.recipe.buildSettings.dependencies); + applyDependencyBuildSettings(rootPackage.getBuildSettings(genSettings.config).dependencies); // remove targets without output foreach (name; targets.keys) diff --git a/source/dub/package_.d b/source/dub/package_.d index b39e99a..eee21cf 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -556,12 +556,17 @@ const(Dependency[string]) getDependencies(string config) const { Dependency[string] ret; - foreach (k, v; m_info.buildSettings.dependencies) - ret[k] = v; + foreach (k, v; m_info.buildSettings.dependencies) { + // DMD bug: Not giving `Dependency` here leads to RangeError + Dependency dep = v; + ret[k] = dep; + } foreach (ref conf; m_info.configurations) if (conf.name == config) { - foreach (k, v; conf.buildSettings.dependencies) - ret[k] = v; + foreach (k, v; conf.buildSettings.dependencies) { + Dependency dep = v; + ret[k] = dep; + } break; } return ret; diff --git a/source/dub/recipe/json.d b/source/dub/recipe/json.d index 9c9c7f6..7993fa2 100644 --- a/source/dub/recipe/json.d +++ b/source/dub/recipe/json.d @@ -173,14 +173,7 @@ enforce(pkg !in bs.dependencies, "The dependency '"~pkg~"' is specified more than once." ); bs.dependencies[pkg] = Dependency.fromJson(verspec); if (verspec.type == Json.Type.object) - { - BuildSettingsTemplate dbs; - dbs.parseJson(verspec, package_name); - // Only create an entry if there's an actual BuildSetting - // defined by the user. - if (dbs !is BuildSettingsTemplate.init) - bs.dependencyBuildSettings[pkg] = dbs; - } + bs.dependencies[pkg].settings.parseJson(verspec, package_name); } break; case "systemDependencies": diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d index bca20d7..c388a89 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -242,12 +242,57 @@ } } +/** + * A dependency with possible `BuildSettingsTemplate` + * + * Currently only `dflags` is taken into account, but the parser accepts any + * value that is in `BuildSettingsTemplate`. + * This feature was originally introduced to support `-preview`, as setting + * a `-preview` in `dflags` does not propagate down to dependencies. + */ +public struct RecipeDependency +{ + /// The dependency itself + public Dependency dependency; + + /// Additional dflags, if any + public BuildSettingsTemplate settings; + + /// Convenience alias as most uses just want to deal with the `Dependency` + public alias dependency this; +} + +/// Type used to avoid a breaking change when `Dependency[string]` +/// was changed to `RecipeDependency[string]` +private struct RecipeDependencyAA +{ + /// The underlying data, `public` as `alias this` to `private` field doesn't + /// always work. + public RecipeDependency[string] data; + + /// Expose base function, e.g. `clear` + alias data this; + + /// Supports assignment from a `RecipeDependency` (used in the parser) + public void opIndexAssign(RecipeDependency dep, string key) + pure nothrow + { + this.data[key] = dep; + } + + /// Supports assignment from a `Dependency`, used in user code mostly + public void opIndexAssign(Dependency dep, string key) + pure nothrow + { + this.data[key] = RecipeDependency(dep); + } +} + /// This keeps general information about how to build a package. /// It contains functions to create a specific BuildSetting, targeted at /// a certain BuildPlatform. struct BuildSettingsTemplate { - Dependency[string] dependencies; - BuildSettingsTemplate[string] dependencyBuildSettings; + RecipeDependencyAA dependencies; string systemDependencies; TargetType targetType = TargetType.autodetect; string targetPath; diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d index beb1b2d..a082f7f 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -207,10 +207,7 @@ bs.dependencies[pkg] = dep; BuildSettingsTemplate dbs; - parseBuildSettings(t, dbs, package_name); - // Don't create unneeded entries - if (dbs !is BuildSettingsTemplate.init) - bs.dependencyBuildSettings[pkg] = dbs; + parseBuildSettings(t, bs.dependencies[pkg].settings, package_name); } private void parseConfiguration(Tag t, ref ConfigurationInfo ret, string package_name) @@ -271,8 +268,8 @@ ); if (d.optional) attribs ~= new Attribute(null, "optional", Value(true)); auto t = new Tag(null, "dependency", [Value(pack)], attribs); - if (pack in bs.dependencyBuildSettings) - t.add(bs.dependencyBuildSettings[pack].toSDL()); + if (d.settings !is typeof(d.settings).init) + t.add(d.settings.toSDL()); ret ~= t; } if (bs.systemDependencies !is null) add("systemDependencies", bs.systemDependencies); @@ -553,7 +550,7 @@ assert(rec.buildSettings.dependencies.length == 2); assert(rec.buildSettings.dependencies["projectname:subpackage1"].optional == false); assert(rec.buildSettings.dependencies["projectname:subpackage1"].path == NativePath(".")); - assert(rec.buildSettings.dependencyBuildSettings["projectname:subpackage1"].dflags == ["":["-g", "-debug"]]); + assert(rec.buildSettings.dependencies["projectname:subpackage1"].settings.dflags == ["":["-g", "-debug"]]); assert(rec.buildSettings.dependencies["somedep"].version_.toString() == "1.0.0"); assert(rec.buildSettings.dependencies["somedep"].optional == true); assert(rec.buildSettings.dependencies["somedep"].path.empty);