diff --git a/source/dub/description.d b/source/dub/description.d index fb2dc8f..c63ec8f 100644 --- a/source/dub/description.d +++ b/source/dub/description.d @@ -121,6 +121,7 @@ string[] packages; /// All packages contained in this target (e.g. for target type "sourceLibrary") string rootConfiguration; /// Build configuration of the target's root package used for building BuildSettings buildSettings; /// Final build settings to use when building the target + string cacheArtifactPath; /// The full path of the built target in the cache string[] dependencies; /// List of all dependencies of this target (package names) string[] linkDependencies; /// List of all link-dependencies of this target (target names) } diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index d9fe7f2..7cfc7cf 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -263,7 +263,7 @@ m_tempTargetExecutablePath = target_path = getTempDir() ~ format(".dub/build/%s-%s/%s/", packageName, pack.version_, build_id); } else - target_path = packageCache(settings.cache, pack) ~ "build/" ~ build_id; + target_path = targetCacheDir(settings.cache, pack, build_id); if (!settings.force && isUpToDate(target_path, buildsettings, settings, pack, packages, additional_dep_files)) { logInfo("Up-to-date", Color.green, "%s %s: target for configuration [%s] is up to date.", @@ -731,38 +731,6 @@ } } -/** - * Provides a unique (per build) identifier - * - * When building a package, it is important to have a unique but stable - * identifier to differentiate builds and allow their caching. - * This function provides such an identifier. - * Example: - * ``` - * application-debug-linux.posix-x86_64-dmd_v2.100.2-D80285212AEC1FF9855F18AD52C68B9EEB5C7690609C224575F920096FB1965B - * ``` - */ -private string computeBuildID(in BuildSettings buildsettings, string config, GeneratorSettings settings) -{ - const(string[])[] hashing = [ - buildsettings.versions, - buildsettings.debugVersions, - buildsettings.dflags, - buildsettings.lflags, - buildsettings.stringImportPaths, - buildsettings.importPaths, - buildsettings.cImportPaths, - settings.platform.architecture, - [ - (cast(uint)(buildsettings.options & ~BuildOption.color)).to!string, // exclude color option from id - settings.platform.compilerBinary, - settings.platform.compiler, - settings.platform.compilerVersion - ], - ]; - return computeBuildName(config, settings, hashing); -} - private NativePath getMainSourceFile(in Package prj) { foreach (f; ["source/app.d", "src/app.d", "source/"~prj.name~".d", "src/"~prj.name~".d"]) diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index bd9102d..b602142 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -803,6 +803,54 @@ return cachePath ~ pkg.name ~ pkg.version_.toString(); } +/** + * Compute and return the directory where a target should be cached. + * + * Params: + * cachePath = Base path at which the build cache is located, + * e.g. `$HOME/.dub/cache/` + * pkg = The package. Cannot be `null`. + * buildId = The build identifier of the target. + */ +package(dub) NativePath targetCacheDir(NativePath cachePath, in Package pkg, string buildId) +{ + return packageCache(cachePath, pkg) ~ "build" ~ buildId; +} + +/** + * Provides a unique (per build) identifier + * + * When building a package, it is important to have a unique but stable + * identifier to differentiate builds and allow their caching. + * This function provides such an identifier. + * Example: + * ``` + * library-debug-Z7qINYX4IxM8muBSlyNGrw + * ``` + */ +package(dub) string computeBuildID(in BuildSettings buildsettings, string config, GeneratorSettings settings) +{ + import std.conv : to; + + const(string[])[] hashing = [ + buildsettings.versions, + buildsettings.debugVersions, + buildsettings.dflags, + buildsettings.lflags, + buildsettings.stringImportPaths, + buildsettings.importPaths, + buildsettings.cImportPaths, + settings.platform.architecture, + [ + (cast(uint)(buildsettings.options & ~BuildOption.color)).to!string, // exclude color option from id + settings.platform.compilerBinary, + settings.platform.compiler, + settings.platform.compilerVersion, + ], + ]; + + return computeBuildName(config, settings, hashing); +} struct GeneratorSettings { NativePath cache; diff --git a/source/dub/generators/targetdescription.d b/source/dub/generators/targetdescription.d index a84883c..077126e 100644 --- a/source/dub/generators/targetdescription.d +++ b/source/dub/generators/targetdescription.d @@ -45,6 +45,9 @@ d.packages = ti.packages.map!(p => p.name).array; d.rootConfiguration = ti.config; d.buildSettings = ti.buildSettings.dup; + const buildId = computeBuildID(d.buildSettings, ti.config, settings); + const filename = settings.compiler.getTargetFileName(d.buildSettings, settings.platform); + d.cacheArtifactPath = (targetCacheDir(settings.cache, ti.pack, buildId) ~ filename).toNativeString(); d.dependencies = ti.dependencies.dup; d.linkDependencies = ti.linkDependencies.dup; diff --git a/test/pr2644-describe-artifact-path/.gitignore b/test/pr2644-describe-artifact-path/.gitignore new file mode 100644 index 0000000..0c7a7b4 --- /dev/null +++ b/test/pr2644-describe-artifact-path/.gitignore @@ -0,0 +1,2 @@ +dubhome/ +pr2644-describe-artifact-path diff --git a/test/pr2644-describe-artifact-path/.no_test b/test/pr2644-describe-artifact-path/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/pr2644-describe-artifact-path/.no_test diff --git a/test/pr2644-describe-artifact-path/dub.sdl b/test/pr2644-describe-artifact-path/dub.sdl new file mode 100644 index 0000000..4bb3254 --- /dev/null +++ b/test/pr2644-describe-artifact-path/dub.sdl @@ -0,0 +1,2 @@ +name "pr2644-describe-artifact-path"; +targetType "executable"; diff --git a/test/pr2644-describe-artifact-path/source/describe_artifact_path.d b/test/pr2644-describe-artifact-path/source/describe_artifact_path.d new file mode 100644 index 0000000..0e7b2bb --- /dev/null +++ b/test/pr2644-describe-artifact-path/source/describe_artifact_path.d @@ -0,0 +1,61 @@ +module describe_artifact_path; + +import std.path; +import std.file; +import std.process; +import std.stdio; +import std.json; + +void main() +{ + const dubhome = __FILE_FULL_PATH__.dirName().dirName().buildNormalizedPath("dubhome"); + if (exists(dubhome)) + { + rmdirRecurse(dubhome); + } + scope (success) + { + // leave dubhome in the tree for analysis in case of failure + rmdirRecurse(dubhome); + } + + const string[string] env = [ + "DUB_HOME": dubhome, + ]; + const fetchProgram = [ + environment["DUB"], + "fetch", + "gitcompatibledubpackage@1.0.4", + ]; + auto dubFetch = spawnProcess(fetchProgram, stdin, stdout, stderr, env); + wait(dubFetch); + + + const describeProgram = [ + environment["DUB"], + "describe", + "--compiler=" ~ environment["DC"], + "--build=debug", + "--config=lib", + "gitcompatibledubpackage@1.0.4", + ]; + auto result = execute(describeProgram, env); + assert(result.status == 0, "expected dub describe to return zero"); + auto json = parseJSON(result.output); + + auto cacheFile = json["targets"][0]["cacheArtifactPath"].str; + assert(!exists(cacheFile), "found cache file in virgin dubhome"); + + const buildProgram = [ + environment["DUB"], + "build", + "--compiler=" ~ environment["DC"], + "--build=debug", + "--config=lib", + "gitcompatibledubpackage@1.0.4", + ]; + auto dubBuild = spawnProcess(buildProgram, stdin, stdout, stderr, env); + wait(dubBuild); + + assert(exists(cacheFile), "did not find cache file after build"); +}