diff --git a/changelog/version-identifier-filter.dd b/changelog/version-identifier-filter.dd new file mode 100644 index 0000000..6f4eb55 --- /dev/null +++ b/changelog/version-identifier-filter.dd @@ -0,0 +1,17 @@ +Added experimental build settings to filter applicable version identifiers + +Those settings allow to filter version identifiers and debug version identifiers +used during building a package. This can improve the build cache efficiency for +libraries that are used by multiple applications with different version +identifiers. + +dub.json: +```json +"-versionFilters": ["Have_vibe_d"] +"-versionFilters-posix": ["UseUnixSockets", "UseMMap"] +``` +dub.sdl: +```sdl +x:versionFilters "Have_vibe_d" +x:versionFilters "UseUnixSockets" "UseMMap" platform="posix" +``` diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d index 0ed9aae..3ba28e1 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -33,6 +33,8 @@ string[] copyFiles; string[] versions; string[] debugVersions; + string[] versionFilters; + string[] debugVersionFilters; string[] importPaths; string[] stringImportPaths; string[] importFiles; @@ -71,6 +73,7 @@ addCopyFiles(bs.copyFiles); addVersions(bs.versions); addDebugVersions(bs.debugVersions); + mergeVersionFilters(bs); addImportPaths(bs.importPaths); addStringImportPaths(bs.stringImportPaths); addImportFiles(bs.importFiles); @@ -83,6 +86,20 @@ addPostRunCommands(bs.postRunCommands); } + void mergeVersionFilters(in ref BuildSettings bs) + { + // only filter version identifiers if they are explicitly listed in both + // build settings, so to avoid incorrect filtering + if (versionFilters.length && bs.versionFilters.length) + addVersionFilters(bs.versionFilters); + else + versionFilters = null; + if (debugVersionFilters.length && bs.debugVersionFilters.length) + addDebugVersionFilters(bs.debugVersionFilters); + else + debugVersionFilters = null; + } + void addDFlags(in string[] value...) { dflags ~= value; } void prependDFlags(in string[] value...) { prepend(dflags, value); } void removeDFlags(in string[] value...) { remove(dflags, value); } @@ -95,6 +112,8 @@ void addCopyFiles(in string[] value...) { add(copyFiles, value); } void addVersions(in string[] value...) { add(versions, value); } void addDebugVersions(in string[] value...) { add(debugVersions, value); } + void addVersionFilters(in string[] value...) { add(versionFilters, value); } + void addDebugVersionFilters(in string[] value...) { add(debugVersionFilters, value); } void addImportPaths(in string[] value...) { add(importPaths, value); } void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); } void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); } @@ -177,9 +196,9 @@ static bool pathMatch(string path, string pattern) { import std.functional : memoize; - + alias nativePath = memoize!((string stringPath) => NativePath(stringPath)); - + return nativePath(path) == nativePath(pattern) || globMatch(path, pattern); } diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 5fbc5b0..8b8b54d 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -160,6 +160,10 @@ compatible. This also transports all Have_dependency_xyz version identifiers to `rootPackage`. + 4. Filter unused versions and debugVersions from all targets. The + filters have previously been upwards inherited (3.) so that versions + used in a dependency are also applied to all dependents. + Note: The upwards inheritance is done at last so that siblings do not influence each other, also see https://github.com/dlang/dub/pull/1128. @@ -323,7 +327,7 @@ bs.addVersions(pkgnames.map!(pn => "Have_" ~ stripDlangSpecialChars(pn)).array); } - // 3. upwards inherit full build configurations (import paths, versions, debugVersions, ...) + // 3. upwards inherit full build configurations (import paths, versions, debugVersions, versionFilters, importPaths, ...) void configureDependents(ref TargetInfo ti, TargetInfo[string] targets, size_t level = 0) { // use `visited` here as pkgs cannot depend on themselves @@ -350,7 +354,27 @@ else destroy(visited); - // 4. override string import files in dependencies + // 4. Filter applicable version and debug version identifiers + foreach (name, ref ti; targets) + { + import std.algorithm.sorting : partition; + + auto bs = &ti.buildSettings; + if (bs.versionFilters.length) + { + auto filtered = bs.versions.partition!(v => bs.versionFilters.canFind(v)); + logDebug("Filtering out unused versions for %s: %s", name, filtered); + bs.versions = bs.versions[0 .. $ - filtered.length]; + } + if (bs.debugVersionFilters.length) + { + auto filtered = bs.debugVersions.partition!(v => bs.debugVersionFilters.canFind(v)); + logDebug("Filtering out unused debug versions for %s: %s", name, filtered); + bs.debugVersions = bs.debugVersions[0 .. $ - filtered.length]; + } + } + + // 5. override string import files in dependencies static void overrideStringImports(ref TargetInfo ti, TargetInfo[string] targets, string[] overrides) { // do not use visited here as string imports can be overridden by *any* parent @@ -406,6 +430,7 @@ parent.addDFlags(child.dflags); parent.addVersions(child.versions); parent.addDebugVersions(child.debugVersions); + parent.mergeVersionFilters(child); parent.addImportPaths(child.importPaths); parent.addStringImportPaths(child.stringImportPaths); // linking of static libraries is done by parent diff --git a/source/dub/project.d b/source/dub/project.d index c441220..746a65f 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -1155,6 +1155,8 @@ dst.addCopyFiles(processVars(project, pack, gsettings, settings.copyFiles, true)); dst.addVersions(processVars(project, pack, gsettings, settings.versions)); dst.addDebugVersions(processVars(project, pack, gsettings, settings.debugVersions)); + dst.addVersionFilters(processVars(project, pack, gsettings, settings.versionFilters)); + dst.addDebugVersionFilters(processVars(project, pack, gsettings, settings.debugVersionFilters)); dst.addImportPaths(processVars(project, pack, gsettings, settings.importPaths, true)); dst.addStringImportPaths(processVars(project, pack, gsettings, settings.stringImportPaths, true)); dst.addPreGenerateCommands(processVars(project, pack, gsettings, settings.preGenerateCommands)); diff --git a/source/dub/recipe/json.d b/source/dub/recipe/json.d index 1078945..418f827 100644 --- a/source/dub/recipe/json.d +++ b/source/dub/recipe/json.d @@ -214,6 +214,8 @@ case "copyFiles": bs.copyFiles[suffix] = deserializeJson!(string[])(value); break; case "versions": bs.versions[suffix] = deserializeJson!(string[])(value); break; case "debugVersions": bs.debugVersions[suffix] = deserializeJson!(string[])(value); break; + case "-versionFilters": bs.versionFilters[suffix] = deserializeJson!(string[])(value); break; + case "-debugVersionFilters": bs.debugVersionFilters[suffix] = deserializeJson!(string[])(value); break; case "importPaths": bs.importPaths[suffix] = deserializeJson!(string[])(value); break; case "stringImportPaths": bs.stringImportPaths[suffix] = deserializeJson!(string[])(value); break; case "preGenerateCommands": bs.preGenerateCommands[suffix] = deserializeJson!(string[])(value); break; @@ -263,6 +265,8 @@ foreach (suffix, arr; bs.copyFiles) ret["copyFiles"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.versions) ret["versions"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.debugVersions) ret["debugVersions"~suffix] = serializeToJson(arr); + foreach (suffix, arr; bs.versionFilters) ret["-versionFilters"~suffix] = serializeToJson(arr); + foreach (suffix, arr; bs.debugVersionFilters) ret["-debugVersionFilters"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.importPaths) ret["importPaths"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.stringImportPaths) ret["stringImportPaths"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.preGenerateCommands) ret["preGenerateCommands"~suffix] = serializeToJson(arr); diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d index 4fd1991..d4382b2 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -152,6 +152,8 @@ string[][string] copyFiles; string[][string] versions; string[][string] debugVersions; + string[][string] versionFilters; + string[][string] debugVersionFilters; string[][string] importPaths; string[][string] stringImportPaths; string[][string] preGenerateCommands; @@ -237,6 +239,8 @@ getPlatformSetting!("copyFiles", "addCopyFiles")(dst, platform); getPlatformSetting!("versions", "addVersions")(dst, platform); getPlatformSetting!("debugVersions", "addDebugVersions")(dst, platform); + getPlatformSetting!("versionFilters", "addVersionFilters")(dst, platform); + getPlatformSetting!("debugVersionFilters", "addDebugVersionFilters")(dst, platform); getPlatformSetting!("importPaths", "addImportPaths")(dst, platform); getPlatformSetting!("stringImportPaths", "addStringImportPaths")(dst, platform); getPlatformSetting!("preGenerateCommands", "addPreGenerateCommands")(dst, platform); diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d index 8d606ce..cecca7c 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -121,7 +121,7 @@ private void parseBuildSettings(Tag settings, ref BuildSettingsTemplate bs, string package_name) { - foreach (setting; settings.tags) + foreach (setting; settings.all.tags) parseBuildSetting(setting, bs, package_name); } @@ -150,6 +150,8 @@ case "copyFiles": setting.parsePlatformStringArray(bs.copyFiles); break; case "versions": setting.parsePlatformStringArray(bs.versions); break; case "debugVersions": setting.parsePlatformStringArray(bs.debugVersions); break; + case "x:versionFilters": setting.parsePlatformStringArray(bs.versionFilters); break; + case "x:debugVersionFilters": setting.parsePlatformStringArray(bs.debugVersionFilters); break; case "importPaths": setting.parsePlatformStringArray(bs.importPaths); break; case "stringImportPaths": setting.parsePlatformStringArray(bs.stringImportPaths); break; case "preGenerateCommands": setting.parsePlatformStringArray(bs.preGenerateCommands); break; @@ -216,9 +218,9 @@ private Tag[] toSDL(in ref BuildSettingsTemplate bs) { Tag[] ret; - void add(string name, string value) { ret ~= new Tag(null, name, [Value(value)]); } - void adda(string name, string suffix, in string[] values) { - ret ~= new Tag(null, name, values[].map!(v => Value(v)).array, + void add(string name, string value, string namespace = null) { ret ~= new Tag(namespace, name, [Value(value)]); } + void adda(string name, string suffix, in string[] values, string namespace = null) { + ret ~= new Tag(namespace, name, values[].map!(v => Value(v)).array, suffix.length ? [new Attribute(null, "platform", Value(suffix[1 .. $]))] : null); } @@ -253,6 +255,8 @@ foreach (suffix, arr; bs.copyFiles) adda("copyFiles", suffix, arr); foreach (suffix, arr; bs.versions) adda("versions", suffix, arr); foreach (suffix, arr; bs.debugVersions) adda("debugVersions", suffix, arr); + foreach (suffix, arr; bs.versionFilters) adda("versionFilters", suffix, arr, "x"); + foreach (suffix, arr; bs.debugVersionFilters) adda("debugVersionFilters", suffix, arr, "x"); foreach (suffix, arr; bs.importPaths) adda("importPaths", suffix, arr); foreach (suffix, arr; bs.stringImportPaths) adda("stringImportPaths", suffix, arr); foreach (suffix, arr; bs.preGenerateCommands) adda("preGenerateCommands", suffix, arr); @@ -392,6 +396,12 @@ versions "version3" debugVersions "debug1" "debug2" debugVersions "debug3" +x:versionFilters "version1" "version2" +x:versionFilters "version3" +x:versionFilters +x:debugVersionFilters "debug1" "debug2" +x:debugVersionFilters "debug3" +x:debugVersionFilters importPaths "import1" "import2" importPaths "import3" stringImportPaths "string1" "string2" @@ -468,6 +478,8 @@ assert(rec.buildSettings.copyFiles == ["": ["copy1", "copy2", "copy3"]]); assert(rec.buildSettings.versions == ["": ["version1", "version2", "version3"]]); assert(rec.buildSettings.debugVersions == ["": ["debug1", "debug2", "debug3"]]); + assert(rec.buildSettings.versionFilters == ["": ["version1", "version2", "version3"]]); + assert(rec.buildSettings.debugVersionFilters == ["": ["debug1", "debug2", "debug3"]]); assert(rec.buildSettings.importPaths == ["": ["import1", "import2", "import3"]]); assert(rec.buildSettings.stringImportPaths == ["": ["string1", "string2", "string3"]]); assert(rec.buildSettings.preGenerateCommands == ["": ["preg1", "preg2", "preg3"]]);