diff --git a/build-files.txt b/build-files.txt index 1944066..3a9ec14 100644 --- a/build-files.txt +++ b/build-files.txt @@ -58,6 +58,7 @@ source/dub/internal/sdlang/util.d source/dub/internal/tinyendian.d source/dub/internal/undead/xml.d +source/dub/internal/temp_files.d source/dub/internal/utils.d source/dub/internal/vibecompat/core/file.d source/dub/internal/vibecompat/data/json.d diff --git a/changelog/build-cache.dd b/changelog/build-cache.dd deleted file mode 100644 index a6ee0b7..0000000 --- a/changelog/build-cache.dd +++ /dev/null @@ -1,14 +0,0 @@ -Binary output will now be in a central cache - -Up until now, dub would output build artifact in the package directory. - -This allowed reuse of build artifact for dependencies, but also created -issues with large amount of build artifacts in the packages folder, -preventing the use of read-only location to store packages, -and making garbage collection of build artifacts unreliable. - -Starting from this version, build artifacts will be output by default to -`$HOME/.dub/cache/build/$BASE_PACKAGE_NAME/$PACKAGE_VERSION/[+$SUB_PACKAGE_NAME]` -on Linux, and -`%APPDATA%/cache/build/$BASE_PACKAGE_NAME/$PACKAGE_VERSION/[+$SUB_PACKAGE_NAME]` -on Windows. diff --git a/changelog/metadata-cache.dd b/changelog/metadata-cache.dd deleted file mode 100644 index 69cd539..0000000 --- a/changelog/metadata-cache.dd +++ /dev/null @@ -1,9 +0,0 @@ -DUB API breaking change: `Package.metadataCache` setter and getter have been removed - -Those two functions were used to provide access to the metadata cache file -to the generator. They were never intended for public consumption, -and the JSON file format was not stable. - -Due to the introduction of the build cache, they needed to be removed, -as there was no way to provide a sensible transition path, and they should be unused. -If you have a use case for it, please open an issue in dub repository. \ No newline at end of file diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 61c53e6..8729b63 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -30,12 +30,11 @@ import std.exception; import std.file; import std.getopt; -import std.path : expandTilde, absolutePath, buildNormalizedPath; -import std.process; +import std.path : absolutePath, buildNormalizedPath, expandTilde, setExtension; +import std.process : environment, spawnProcess, wait; import std.stdio; import std.string; import std.typecons : Tuple, tuple; -import std.path: setExtension; /** Retrieves a list of all available commands. @@ -800,7 +799,7 @@ Dub dub; if (options.bare) { - dub = new Dub(NativePath(options.root_path), NativePath(getcwd())); + dub = new Dub(NativePath(options.root_path), getWorkingDirectory()); dub.defaultPlacementLocation = options.placementLocation; return dub; @@ -2250,7 +2249,7 @@ auto source = VersionRange.fromString(free_args[1]); if (existsFile(NativePath(free_args[2]))) { auto target = NativePath(free_args[2]); - if (!target.absolute) target = NativePath(getcwd()) ~ target; + if (!target.absolute) target = getWorkingDirectory() ~ target; dub.packageManager.addOverride_(scope_, pack, source, target); logInfo("Added override %s %s => %s", pack, source, target); } else { @@ -2409,7 +2408,7 @@ { if (!m_testPackage.length) return super.prepareDub(options); - return new Dub(NativePath(options.root_path), NativePath(getcwd())); + return new Dub(NativePath(options.root_path), getWorkingDirectory()); } override int execute(Dub dub, string[] free_args, string[] app_args) @@ -2443,7 +2442,7 @@ auto path = NativePath(free_args[0]); path.normalize(); enforceUsage(!path.empty, "Destination path must not be empty."); - if (!path.absolute) path = NativePath(getcwd()) ~ path; + if (!path.absolute) path = getWorkingDirectory() ~ path; enforceUsage(!path.startsWith(dub.rootPath), "Destination path must not be a sub directory of the tested package!"); setupPackage(dub, null); diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index a8dacd0..ece4884 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -12,6 +12,7 @@ public import dub.platform : BuildPlatform, matchesSpecification; import dub.internal.vibecompat.inet.path; +import dub.internal.vibecompat.core.file; import dub.internal.logging; @@ -108,10 +109,24 @@ void setTarget(ref BuildSettings settings, in BuildPlatform platform, string targetPath = null) const; /// Invokes the compiler using the given flags - void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback); + deprecated("specify the working directory") + final void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) + { + invoke(settings, platform, output_callback, getWorkingDirectory()); + } + + /// ditto + void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd); /// Invokes the underlying linker directly - void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback); + deprecated("specify the working directory") + final void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) + { + invokeLinker(settings, platform, objects, output_callback, getWorkingDirectory()); + } + + /// ditto + void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd); /// Convert linker flags to compiler format string[] lflagsToDFlags(const string[] lflags) const; @@ -124,17 +139,26 @@ This method should be used by `Compiler` implementations to invoke the compiler or linker binary. */ + deprecated("specify the working directory") protected final void invokeTool(string[] args, void delegate(int, string) output_callback, string[string] env = null) { + invokeTool(args, output_callback, getWorkingDirectory(), env); + } + + /// ditto + protected final void invokeTool(string[] args, void delegate(int, string) output_callback, NativePath cwd, string[string] env = null) + { import std.string; int status; if (output_callback) { - auto result = executeShell(escapeShellCommand(args), env); + auto result = executeShell(escapeShellCommand(args), + env, Config.none, size_t.max, cwd.toNativeString()); output_callback(result.status, result.output); status = result.status; } else { - auto compiler_pid = spawnShell(escapeShellCommand(args), env); + auto compiler_pid = spawnShell(escapeShellCommand(args), + env, Config.none, cwd.toNativeString()); status = compiler_pid.wait(); } diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index a181222..2039747 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -360,22 +360,26 @@ settings.addDFlags("-of"~tpath); } - void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) + void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd) { auto res_file = getTempFile("dub-build", ".rsp"); + // clean-up early to avoid build-up of temporaries when invoke is called + // many times in one DUB session. (e.g. when using DUB as a library) + scope (exit) + removeFile(res_file); const(string)[] args = settings.dflags; if (platform.frontendVersion >= 2066) args ~= "-vcolumns"; writeFile(res_file, escapeArgs(args).join("\n")); - logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" ")); + logDiagnostic("[cwd=%s] %s %s", cwd, platform.compilerBinary, escapeArgs(args).join(" ")); string[string] env; foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, cwd, env); } - void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) + void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd) { import std.string; auto tpath = NativePath(settings.targetPath) ~ getTargetFileName(settings, platform); @@ -396,12 +400,12 @@ auto res_file = getTempFile("dub-build", ".lnk"); writeFile(res_file, escapeArgs(args).join("\n")); - logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" ")); + logDiagnostic("[cwd=%s] %s %s", cwd, platform.compilerBinary, escapeArgs(args).join(" ")); string[string] env; foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, cwd, env); } string[] lflagsToDFlags(const string[] lflags) const diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index 9b42b33..d7a8e4c 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -17,7 +17,7 @@ import std.algorithm; import std.array; import std.exception; -import std.process; +import std.process : execute; import std.typecons; @@ -205,7 +205,7 @@ settings.addDFlags("-o", tpath); } - void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) + void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd) { auto res_file = getTempFile("dub-build", ".rsp"); writeFile(res_file, join(settings.dflags.map!(s => escape(s)), "\n")); @@ -215,10 +215,10 @@ foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, cwd, env); } - void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) + void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd) { import std.string; string[] args; @@ -237,7 +237,7 @@ foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool(args, output_callback, env); + invokeTool(args, output_callback, cwd, env); } string[] lflagsToDFlags(const string[] lflags) const diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index f071d7b..6b8f545 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -245,7 +245,7 @@ settings.addDFlags("-of"~tpath); } - void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) + void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd) { auto res_file = getTempFile("dub-build", ".rsp"); const(string)[] args = settings.dflags; @@ -257,10 +257,10 @@ foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, cwd, env); } - void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) + void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd) { import std.string; auto tpath = NativePath(settings.targetPath) ~ getTargetFileName(settings, platform); @@ -280,7 +280,7 @@ foreach (aa; [settings.environments, settings.buildEnvironments]) foreach (k, v; aa) env[k] = v; - invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, cwd, env); } string[] lflagsToDFlags(const string[] lflags) const diff --git a/source/dub/dub.d b/source/dub/dub.d index 2d3df65..7a78711 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -158,7 +158,7 @@ SkipPackageSuppliers skip_registry = SkipPackageSuppliers.none) { m_rootPath = NativePath(root_path); - if (!m_rootPath.absolute) m_rootPath = NativePath(getcwd()) ~ m_rootPath; + if (!m_rootPath.absolute) m_rootPath = getWorkingDirectory() ~ m_rootPath; init(); @@ -384,7 +384,7 @@ @property void rootPath(NativePath root_path) { m_rootPath = root_path; - if (!m_rootPath.absolute) m_rootPath = NativePath(getcwd()) ~ m_rootPath; + if (!m_rootPath.absolute) m_rootPath = getWorkingDirectory() ~ m_rootPath; } /// Returns the name listed in the dub.json of the current @@ -686,6 +686,8 @@ void generateProject(string ide, GeneratorSettings settings) { settings.cache = this.m_dirs.cache; + if (settings.overrideToolWorkingDirectory is NativePath.init) + settings.overrideToolWorkingDirectory = m_rootPath; // With a requested `unittest` config, switch to the special test runner // config (which doesn't require an existing `unittest` configuration). if (settings.config == "unittest") { @@ -705,7 +707,9 @@ void testProject(GeneratorSettings settings, string config, NativePath custom_main_file) { settings.cache = this.m_dirs.cache; - if (!custom_main_file.empty && !custom_main_file.absolute) custom_main_file = getWorkingDirectory() ~ custom_main_file; + if (settings.overrideToolWorkingDirectory is NativePath.init) + settings.overrideToolWorkingDirectory = m_rootPath; + if (!custom_main_file.empty && !custom_main_file.absolute) custom_main_file = m_rootPath ~ custom_main_file; const test_config = m_project.addTestRunnerConfiguration(settings, !m_dryRun, config, custom_main_file); if (!test_config) return; // target type "none" @@ -761,6 +765,9 @@ import std.stdio; import std.ascii : newline; + if (settings.overrideToolWorkingDirectory is NativePath.init) + settings.overrideToolWorkingDirectory = m_rootPath; + // Split comma-separated lists string[] requestedDataSplit = requestedData @@ -1314,8 +1321,8 @@ if (!run) { // TODO: ddox should copy those files itself - version(Windows) runCommand(`xcopy /S /D "`~tool_path~`public\*" docs\`); - else runCommand("rsync -ru '"~tool_path~"public/' docs/"); + version(Windows) runCommand(`xcopy /S /D "`~tool_path~`public\*" docs\`, null, m_rootPath.toNativeString()); + else runCommand("rsync -ru '"~tool_path~"public/' docs/", null, m_rootPath.toNativeString()); } } @@ -1370,6 +1377,7 @@ if (this.defaultPostRunEnvironments) settings.buildSettings.addPostRunEnvironments(this.defaultPostRunEnvironments); settings.run = true; + settings.overrideToolWorkingDirectory = m_rootPath; return settings; } @@ -1888,7 +1896,7 @@ result.systemSettings = NativePath("/var/lib/dub/"); result.userSettings = NativePath(environment.get("HOME")) ~ ".dub/"; if (!result.userSettings.absolute) - result.userSettings = NativePath(getcwd()) ~ result.userSettings; + result.userSettings = getWorkingDirectory() ~ result.userSettings; result.userPackages = result.userSettings; } result.cache = result.userPackages ~ "cache"; diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 74b26c9..cdcad88 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -203,7 +203,7 @@ { import std.path : absolutePath; - auto cwd = NativePath(getcwd()); + auto cwd = settings.toolWorkingDirectory; bool generate_binary = !(buildsettings.options & BuildOption.syntaxOnly); auto build_id = buildsettings.computeBuildID(config, settings); @@ -233,7 +233,9 @@ if (!cached && buildsettings.postBuildCommands.length) { logInfo("Post-build", Color.light_green, "Running commands"); runBuildCommands(CommandType.postBuild, buildsettings.postBuildCommands, pack, m_project, settings, buildsettings, - [["DUB_BUILD_PATH" : target_path is NativePath.init ? "" : target_path.parentPath.toNativeString.absolutePath]]); + [["DUB_BUILD_PATH" : target_path is NativePath.init + ? "" + : target_path.parentPath.toNativeString.absolutePath(settings.toolWorkingDirectory.toNativeString)]]); } return cached; @@ -288,7 +290,7 @@ private void performRDMDBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config, out NativePath target_path) { - auto cwd = NativePath(getcwd()); + auto cwd = settings.toolWorkingDirectory; //Added check for existence of [AppNameInPackagejson].d //If exists, use that as the starting file. NativePath mainsrc; @@ -333,14 +335,14 @@ if (buildsettings.preBuildCommands.length){ logInfo("Pre-build", Color.light_green, "Running commands"); - runCommands(buildsettings.preBuildCommands); + runCommands(buildsettings.preBuildCommands, null, cwd.toNativeString()); } logInfo("Building", Color.light_green, "%s %s [%s]", pack.name.color(Mode.bold), pack.version_, config.color(Color.blue)); logInfo("Running rdmd..."); logDiagnostic("rdmd %s", join(flags, " ")); - auto rdmd_pid = spawnProcess("rdmd" ~ flags); + auto rdmd_pid = spawnProcess("rdmd" ~ flags, null, Config.none, cwd.toNativeString()); auto result = rdmd_pid.wait(); enforce(result == 0, "Build command failed with exit code "~to!string(result)); @@ -353,7 +355,7 @@ private void performDirectBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config, out NativePath target_path) { - auto cwd = NativePath(getcwd()); + auto cwd = settings.toolWorkingDirectory; auto generate_binary = !(buildsettings.options & BuildOption.syntaxOnly); // make file paths relative to shrink the command line @@ -481,13 +483,19 @@ /// Output an unique name to represent the source file. /// Calls with path that resolve to the same file on the filesystem will return the same, /// unless they include different symbolic links (which are not resolved). - + deprecated("Use the overload taking in the current working directory") static string pathToObjName(const scope ref BuildPlatform platform, string path) { + return pathToObjName(platform, path, getWorkingDirectory); + } + + /// ditto + static string pathToObjName(const scope ref BuildPlatform platform, string path, NativePath cwd) + { import std.digest.crc : crc32Of; import std.path : buildNormalizedPath, dirSeparator, relativePath, stripDrive; if (path.endsWith(".d")) path = path[0 .. $-2]; - auto ret = buildNormalizedPath(getcwd(), path).replace(dirSeparator, "."); + auto ret = buildNormalizedPath(cwd.toNativeString(), path).replace(dirSeparator, "."); auto idx = ret.lastIndexOf('.'); const objSuffix = getObjSuffix(platform); return idx < 0 ? ret ~ objSuffix : format("%s_%(%02x%)%s", ret[idx+1 .. $], crc32Of(ret[0 .. idx]), objSuffix); @@ -503,7 +511,7 @@ bs.targetType = TargetType.object; gs.compiler.prepareBuildSettings(bs, gs.platform, BuildSetting.commandLine); gs.compiler.setTarget(bs, gs.platform, objPath); - gs.compiler.invoke(bs, gs.platform, gs.compileCallback); + gs.compiler.invoke(bs, gs.platform, gs.compileCallback, gs.toolWorkingDirectory); return objPath; } @@ -527,7 +535,7 @@ void compileSource(size_t i, string src) { logInfo("Compiling", Color.light_green, "%s", src); - const objPath = pathToObjName(settings.platform, src); + const objPath = pathToObjName(settings.platform, src, settings.toolWorkingDirectory); objs[i] = compileUnit(src, objPath, buildsettings, settings); } @@ -541,7 +549,7 @@ lbuildsettings.sourceFiles = is_static_library ? [] : lbuildsettings.sourceFiles.filter!(f => isLinkerFile(settings.platform, f)).array; settings.compiler.setTarget(lbuildsettings, settings.platform); settings.compiler.prepareBuildSettings(lbuildsettings, settings.platform, BuildSetting.commandLineSeparate|BuildSetting.sourceFiles); - settings.compiler.invokeLinker(lbuildsettings, settings.platform, objs, settings.linkCallback); + settings.compiler.invokeLinker(lbuildsettings, settings.platform, objs, settings.linkCallback, settings.toolWorkingDirectory); // NOTE: separate compile/link is not yet enabled for GDC. } else if (generate_binary && (settings.buildMode == BuildMode.allAtOnce || settings.compiler.name == "gdc" || is_static_library)) { @@ -553,7 +561,7 @@ settings.compiler.prepareBuildSettings(buildsettings, settings.platform, BuildSetting.commandLine); // invoke the compiler - settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback); + settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback, settings.toolWorkingDirectory); } else { // determine path for the temporary object file string tempobjname = buildsettings.targetName ~ getObjSuffix(settings.platform); @@ -573,7 +581,7 @@ settings.compiler.prepareBuildSettings(buildsettings, settings.platform, BuildSetting.commandLine); - settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback); + settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback, settings.toolWorkingDirectory); if (generate_binary) { if (settings.tempBuild) { @@ -581,7 +589,7 @@ } else { logInfo("Linking", Color.light_green, "%s", buildsettings.targetName.color(Mode.bold)); } - settings.compiler.invokeLinker(lbuildsettings, settings.platform, [tempobj.toNativeString()], settings.linkCallback); + settings.compiler.invokeLinker(lbuildsettings, settings.platform, [tempobj.toNativeString()], settings.linkCallback, settings.toolWorkingDirectory); } } } @@ -589,7 +597,7 @@ private void runTarget(NativePath exe_file_path, in BuildSettings buildsettings, string[] run_args, GeneratorSettings settings) { if (buildsettings.targetType == TargetType.executable) { - auto cwd = NativePath(getcwd()); + auto cwd = settings.toolWorkingDirectory; auto runcwd = cwd; if (buildsettings.workingDirectory.length) { runcwd = NativePath(buildsettings.workingDirectory); @@ -735,10 +743,10 @@ auto prj = new Project(pman, pack); final static class TestCompiler : GDCCompiler { - override void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) { + override void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd) { assert(!settings.dflags[].any!(f => f.canFind("bar"))); } - override void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) { + override void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd) { assert(false); } } diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 4c0f994..6aff2d6 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -806,6 +806,7 @@ BuildSettings buildSettings; BuildMode buildMode = BuildMode.separate; int targetExitStatus; + NativePath overrideToolWorkingDirectory; bool combined; // compile all in one go instead of each dependency separately bool filterVersions; @@ -820,6 +821,16 @@ void delegate(int status, string output) compileCallback; void delegate(int status, string output) linkCallback; void delegate(int status, string output) runCallback; + + /// Returns `overrideToolWorkingDirectory` or if that's not set, just the + /// current working directory of the application. This may differ if dub is + /// called with the `--root` parameter or when using DUB as a library. + NativePath toolWorkingDirectory() const + { + return overrideToolWorkingDirectory is NativePath.init + ? getWorkingDirectory() + : overrideToolWorkingDirectory; + } } @@ -1166,10 +1177,10 @@ auto prj = new Project(pman, pack); final static class TestCompiler : GDCCompiler { - override void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) { + override void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback, NativePath cwd) { assert(false); } - override void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) { + override void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback, NativePath cwd) { assert(false); } } diff --git a/source/dub/generators/sublimetext.d b/source/dub/generators/sublimetext.d index d46fbd9..f1d3689 100644 --- a/source/dub/generators/sublimetext.d +++ b/source/dub/generators/sublimetext.d @@ -34,7 +34,7 @@ auto root = Json([ "folders": targets.byValue.map!(f => targetFolderJson(f)).array.Json, - "build_systems": buildSystems(settings.platform), + "build_systems": buildSystems(settings.platform, settings.toolWorkingDirectory.toNativeString()), "settings": [ "include_paths": buildSettings.importPaths.map!Json.array.Json ].Json, ]); @@ -61,7 +61,7 @@ } -private Json buildSystems(BuildPlatform buildPlatform, string workingDiretory = getcwd()) +private Json buildSystems(BuildPlatform buildPlatform, string workingDiretory) { static immutable BUILD_TYPES = [ //"plain", @@ -123,5 +123,5 @@ auto buildPlatform = BuildPlatform(); buildPlatform.architecture ~= "x86_64"; - auto result = buildPlatform.buildSystems.toString; + auto result = buildPlatform.buildSystems(getcwd()).toString; } diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index 9b86ef9..a5feb5f 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -183,7 +183,7 @@ auto sp = NativePath(s); assert(sp.absolute, format("Source path in %s expected to be absolute: %s", packname, s)); //if( !sp.absolute ) sp = pack.path ~ sp; - addSourceFile(sp.relativeTo(getWorkingDirectory() ~ basepath), determineStructurePath(sp, targets[packname]), action); + addSourceFile(sp.relativeTo(settings.toolWorkingDirectory ~ basepath), determineStructurePath(sp, targets[packname]), action); } foreach (p; targets[packname].packages) @@ -245,6 +245,7 @@ void generateProjectConfiguration(Appender!(char[]) ret, string pack, string type, GeneratorSettings settings, in TargetInfo[string] targets) { + auto cwd = settings.toolWorkingDirectory; auto buildsettings = targets[pack].buildSettings.dup; auto basepath = NativePath(".dub/"); @@ -255,7 +256,7 @@ auto ret = new string[settings.length]; foreach (i; 0 .. settings.length) { // \" is interpreted as an escaped " by cmd.exe, so we need to avoid that - auto p = NativePath(settings[i]).relativeTo(getWorkingDirectory() ~ basepath); + auto p = NativePath(settings[i]).relativeTo(cwd ~ basepath); p.endsWithSlash = false; ret[i] = '"' ~ p.toNativeString() ~ '"'; } @@ -328,7 +329,7 @@ // compute directory for intermediate files (need dummy/ because of how -op determines the resulting path) size_t ndummy = 0; foreach (f; buildsettings.sourceFiles) { - auto rpath = NativePath(f).relativeTo(getWorkingDirectory() ~ basepath); + auto rpath = NativePath(f).relativeTo(cwd ~ basepath); size_t nd = 0; foreach (s; rpath.bySegment) if (s == "..") @@ -423,7 +424,7 @@ auto wdir = NativePath(buildsettings.workingDirectory); if (!wdir.absolute) wdir = m_project.rootPackage.path ~ wdir; ret.formattedWrite(" %s\n", - wdir.relativeTo(getWorkingDirectory() ~ basepath).toNativeString()); + wdir.relativeTo(cwd ~ basepath).toNativeString()); ret.put(" \n"); ret.put(" \n"); ret.put(" *.obj;*.cmd;*.build;*.dep\n"); diff --git a/source/dub/init.d b/source/dub/init.d index 5cf47f8..2e835a6 100644 --- a/source/dub/init.d +++ b/source/dub/init.d @@ -16,7 +16,7 @@ import std.exception; import std.file; import std.format; -import std.process; +import std.process : environment; import std.string; diff --git a/source/dub/internal/temp_files.d b/source/dub/internal/temp_files.d new file mode 100644 index 0000000..ddfaf34 --- /dev/null +++ b/source/dub/internal/temp_files.d @@ -0,0 +1,45 @@ +/** + Provides methods to generate temporary file names and folders and + automatically clean them up on program exit. + + Copyright: © 2012 Matthias Dondorff, © 2012-2023 Sönke Ludwig + License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + Authors: Matthias Dondorff, Sönke Ludwig, Jan Jurzitza +*/ +module dub.internal.temp_files; + +import std.file; + +import dub.internal.vibecompat.core.file; + +NativePath getTempDir() +{ + return NativePath(std.file.tempDir()); +} + +NativePath getTempFile(string prefix, string extension = null) +{ + import std.uuid : randomUUID; + import std.array: replace; + + string fileName = prefix ~ "-" ~ randomUUID.toString() ~ extension; + + if (extension !is null && extension == ".d") + fileName = fileName.replace("-", "_"); + + auto path = getTempDir() ~ fileName; + temporary_files ~= path; + return path; +} + +private NativePath[] temporary_files; + +static ~this() +{ + foreach (path; temporary_files) + { + auto spath = path.toNativeString(); + if (spath.exists) + std.file.remove(spath); + } +} diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 538f034..5b68728 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -30,28 +30,7 @@ public import std.net.curl : HTTPStatusException; } - -private NativePath[] temporary_files; - -NativePath getTempDir() -{ - return NativePath(std.file.tempDir()); -} - -NativePath getTempFile(string prefix, string extension = null) -{ - import std.uuid : randomUUID; - import std.array: replace; - - string fileName = prefix ~ "-" ~ randomUUID.toString() ~ extension; - - if (extension !is null && extension == ".d") - fileName = fileName.replace("-", "_"); - - auto path = getTempDir() ~ fileName; - temporary_files ~= path; - return path; -} +public import dub.internal.temp_files; /** * Obtain a lock for a file at the given path. @@ -99,16 +78,6 @@ } } -static ~this() -{ - foreach (path; temporary_files) - { - auto spath = path.toNativeString(); - if (spath.exists) - std.file.remove(spath); - } -} - bool isWritableDir(NativePath p, bool create_if_missing = false) { import std.random; @@ -176,12 +145,24 @@ moveFile(tmppath, path); } -void runCommand(string command, string[string] env = null, string workDir = null) +deprecated("specify a working directory explicitly") +void runCommand(string command, string[string] env = null) +{ + runCommands((&command)[0 .. 1], env, null); +} + +void runCommand(string command, string[string] env, string workDir) { runCommands((&command)[0 .. 1], env, workDir); } -void runCommands(in string[] commands, string[string] env = null, string workDir = null) +deprecated("specify a working directory explicitly") +void runCommands(in string[] commands, string[string] env = null) +{ + runCommands(commands, env, null); +} + +void runCommands(in string[] commands, string[string] env, string workDir) { import std.stdio : stdin, stdout, stderr, File; diff --git a/source/dub/package_.d b/source/dub/package_.d index 48a755d..c77e872 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -418,7 +418,7 @@ */ void addBuildTypeSettings(ref BuildSettings settings, in BuildPlatform platform, string build_type) const { - import std.process; + import std.process : environment; string dflags = environment.get("DFLAGS", ""); settings.addDFlags(dflags.split()); diff --git a/source/dub/project.d b/source/dub/project.d index 3fb66a2..f473839 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -1405,10 +1405,21 @@ } if (i == res.length) //no globbing found in the path return [res]; - import std.path : globMatch; import std.file : dirEntries, SpanMode; - return dirEntries(res[0 .. sepIdx], SpanMode.depth) - .map!(de => de.name) + import std.path : buildNormalizedPath, globMatch, isAbsolute, relativePath; + auto cwd = gsettings.toolWorkingDirectory.toNativeString; + auto path = res[0 .. sepIdx]; + bool prependCwd = false; + if (!isAbsolute(path)) + { + prependCwd = true; + path = buildNormalizedPath(cwd, path); + } + + return dirEntries(path, SpanMode.depth) + .map!(de => prependCwd + ? de.name.relativePath(cwd) + : de.name) .filter!(name => globMatch(name, res)) .array; } diff --git a/source/dub/version_.d b/source/dub/version_.d index efd57b2..4d34bc2 100644 --- a/source/dub/version_.d +++ b/source/dub/version_.d @@ -1,2 +1,2 @@ module dub.version_; -enum dubVersion = "v1.31.0-rc.1"; +enum dubVersion = "v1.31.0"; diff --git a/test/dub-as-a-library-cwd.sh b/test/dub-as-a-library-cwd.sh new file mode 100755 index 0000000..e0faea2 --- /dev/null +++ b/test/dub-as-a-library-cwd.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +. $(dirname "${BASH_SOURCE[0]}")/common.sh +$DUB --root="$CURR_DIR/dub-as-a-library-cwd" diff --git a/test/dub-as-a-library-cwd/.gitignore b/test/dub-as-a-library-cwd/.gitignore new file mode 100644 index 0000000..9a2c0e8 --- /dev/null +++ b/test/dub-as-a-library-cwd/.gitignore @@ -0,0 +1 @@ +/dub-as-a-library-cwd diff --git a/test/dub-as-a-library-cwd/.no_test b/test/dub-as-a-library-cwd/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/dub-as-a-library-cwd/.no_test diff --git a/test/dub-as-a-library-cwd/dub.json b/test/dub-as-a-library-cwd/dub.json new file mode 100644 index 0000000..15adddf --- /dev/null +++ b/test/dub-as-a-library-cwd/dub.json @@ -0,0 +1,8 @@ +{ + "name": "dub-as-a-library-cwd", + "dependencies": { + "dub": { + "path": "../.." + } + } +} diff --git a/test/dub-as-a-library-cwd/source/app.d b/test/dub-as-a-library-cwd/source/app.d new file mode 100644 index 0000000..446c361 --- /dev/null +++ b/test/dub-as-a-library-cwd/source/app.d @@ -0,0 +1,45 @@ +import dub.compilers.buildsettings; +import dub.compilers.compiler; +import dub.dub; +import dub.generators.generator; +import dub.internal.vibecompat.inet.path; +import std.algorithm; +import std.file; +import std.path; +import std.stdio; + +void main(string[] args) +{ + auto project = buildNormalizedPath(getcwd, "subproject"); + chdir(buildNormalizedPath(getcwd, "..")); + + bool found; + + auto dub = new Dub(project, null, SkipPackageSuppliers.none); + dub.packageManager.getOrLoadPackage(NativePath(project)); + dub.loadPackage(); + dub.project.validate(); + + GeneratorSettings gs; + gs.buildType = "debug"; + gs.config = "application"; + gs.compiler = getCompiler(dub.defaultCompiler); + gs.run = false; + gs.force = true; + gs.tempBuild = true; + gs.platform = gs.compiler.determinePlatform(gs.buildSettings, + dub.defaultCompiler, dub.defaultArchitecture); + + gs.compileCallback = (status, output) { + found = output.canFind("FIND_THIS_STRING"); + if (!found) + stderr.writeln("Did not find required string!\nExit status:", + status, "\n\nOutput:\n", output); + }; + + stderr.writeln("Checking if building works from a library in a different cwd:"); + dub.generateProject("build", gs); + stderr.writeln("Success: ", found); + + assert(found); +} diff --git a/test/dub-as-a-library-cwd/subproject/dub.sdl b/test/dub-as-a-library-cwd/subproject/dub.sdl new file mode 100644 index 0000000..cb896c9 --- /dev/null +++ b/test/dub-as-a-library-cwd/subproject/dub.sdl @@ -0,0 +1 @@ +name "subproject" diff --git a/test/dub-as-a-library-cwd/subproject/source/app.d b/test/dub-as-a-library-cwd/subproject/source/app.d new file mode 100644 index 0000000..a891a6f --- /dev/null +++ b/test/dub-as-a-library-cwd/subproject/source/app.d @@ -0,0 +1,11 @@ +module app; + +deprecated("FIND_THIS_STRING") +void foo() +{ +} + +void main(string[] args) +{ + foo(); +}