diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index 42e6cf9..f81d0cf 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -72,7 +72,7 @@ /// Replaces high level fields with low level fields and converts /// dmd flags to compiler-specific flags - void prepareBuildSettings(ref BuildSettings settings, BuildSetting supported_fields = BuildSetting.all) const; + void prepareBuildSettings(ref BuildSettings settings, in ref BuildPlatform platform, BuildSetting supported_fields = BuildSetting.all) const; /// Removes any dflags that match one of the BuildOptions values and populates the BuildSettings.options field. void extractBuildOptions(ref BuildSettings settings) const; diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index bf06e4c..051e122 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -132,7 +132,7 @@ ); } - void prepareBuildSettings(ref BuildSettings settings, BuildSetting fields = BuildSetting.all) const + void prepareBuildSettings(ref BuildSettings settings, in ref BuildPlatform platform, BuildSetting fields = BuildSetting.all) const { enforceBuildRequirements(settings); @@ -163,9 +163,11 @@ } if (!(fields & BuildSetting.libs)) { - resolveLibs(settings); - version(Windows) settings.addSourceFiles(settings.libs.map!(l => l~".lib")().array()); - else settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); + resolveLibs(settings, platform); + if (platform.platform.canFind("windows")) + settings.addSourceFiles(settings.libs.map!(l => l~".lib")().array()); + else + settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); } if (!(fields & BuildSetting.sourceFiles)) { @@ -178,10 +180,8 @@ settings.lflags = null; } - version (Posix) { - if (settings.options & BuildOption.pic) - settings.addDFlags("-fPIC"); - } + if (platform.platform.canFind("posix") && (settings.options & BuildOption.pic)) + settings.addDFlags("-fPIC"); assert(fields & BuildSetting.dflags); assert(fields & BuildSetting.copyFiles); @@ -248,9 +248,10 @@ settings.addDFlags("-lib"); break; case TargetType.dynamicLibrary: - version (Windows) settings.addDFlags("-shared"); - else version (OSX) settings.addDFlags("-shared"); - else settings.prependDFlags("-shared", "-defaultlib=libphobos2.so"); + if (platform.compiler != "dmd" || platform.platform.canFind("windows") || platform.platform.canFind("osx")) + settings.addDFlags("-shared"); + else + settings.prependDFlags("-shared", "-defaultlib=libphobos2.so"); break; case TargetType.object: settings.addDFlags("-c"); @@ -280,7 +281,8 @@ auto args = ["-of"~tpath.toNativeString()]; args ~= objects; args ~= settings.sourceFiles; - version(linux) args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order by DMD + if (platform.platform.canFind("linux")) + args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order by DMD args ~= lflagsToDFlags(settings.lflags); args ~= settings.dflags.filter!(f => isLinkerDFlag(f)).array; diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index 4a9c0d2..eb753d8 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -85,7 +85,7 @@ ); } - void prepareBuildSettings(ref BuildSettings settings, BuildSetting fields = BuildSetting.all) const + void prepareBuildSettings(ref BuildSettings settings, in ref BuildPlatform platform, BuildSetting fields = BuildSetting.all) const { enforceBuildRequirements(settings); @@ -121,7 +121,7 @@ } if (!(fields & BuildSetting.libs)) { - resolveLibs(settings); + resolveLibs(settings, platform); settings.addDFlags(settings.libs.map!(l => "-l"~l)().array()); } @@ -222,7 +222,8 @@ args = [ "ar", "rcs", tpath ] ~ objects; } else { args = platform.compilerBinary ~ objects ~ settings.sourceFiles ~ settings.lflags ~ settings.dflags.filter!(f => isLinkageFlag(f)).array; - version(linux) args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order by DMD + if (platform.platform.canFind("linux")) + args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order } logDiagnostic("%s", args.join(" ")); invokeTool(args, output_callback); diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index 11c2872..7e77d0e 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -27,15 +27,15 @@ private static immutable s_options = [ tuple(BuildOption.debugMode, ["-d-debug"]), tuple(BuildOption.releaseMode, ["-release"]), - //tuple(BuildOption.coverage, ["-?"]), + tuple(BuildOption.coverage, ["-cov"]), tuple(BuildOption.debugInfo, ["-g"]), tuple(BuildOption.debugInfoC, ["-gc"]), - //tuple(BuildOption.alwaysStackFrame, ["-?"]), + tuple(BuildOption.alwaysStackFrame, ["-disable-fp-elim"]), //tuple(BuildOption.stackStomping, ["-?"]), tuple(BuildOption.inline, ["-enable-inlining", "-Hkeep-all-bodies"]), tuple(BuildOption.noBoundsCheck, ["-boundscheck=off"]), tuple(BuildOption.optimize, ["-O3"]), - //tuple(BuildOption.profile, ["-?"]), + tuple(BuildOption.profile, ["-fdmd-trace-functions"]), tuple(BuildOption.unittests, ["-unittest"]), tuple(BuildOption.verbose, ["-v"]), tuple(BuildOption.ignoreUnknownPragmas, ["-ignore"]), @@ -80,10 +80,15 @@ { string[] arch_flags; switch (arch_override) { - default: throw new Exception("Unsupported architecture: "~arch_override); case "": break; case "x86": arch_flags = ["-march=x86"]; break; case "x86_64": arch_flags = ["-march=x86-64"]; break; + default: + if (arch_override.canFind('-')) + arch_flags = ["-mtriple="~arch_override]; + else + throw new Exception("Unsupported architecture: "~arch_override); + break; } settings.addDFlags(arch_flags); @@ -94,7 +99,7 @@ ); } - void prepareBuildSettings(ref BuildSettings settings, BuildSetting fields = BuildSetting.all) const + void prepareBuildSettings(ref BuildSettings settings, in ref BuildPlatform platform, BuildSetting fields = BuildSetting.all) const { enforceBuildRequirements(settings); @@ -133,7 +138,7 @@ } if (!(fields & BuildSetting.libs)) { - resolveLibs(settings); + resolveLibs(settings, platform); settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); } @@ -169,26 +174,30 @@ const { assert(settings.targetName.length > 0, "No target name set."); + const p = platform.platform; final switch (settings.targetType) { case TargetType.autodetect: assert(false, "Configurations must have a concrete target type."); case TargetType.none: return null; case TargetType.sourceLibrary: return null; case TargetType.executable: - if (platform.platform.canFind("windows")) + if (p.canFind("windows")) return settings.targetName ~ ".exe"; + else if (p.canFind("wasm")) + return settings.targetName ~ ".wasm"; else return settings.targetName; case TargetType.library: case TargetType.staticLibrary: - if (generatesCOFF(platform)) return settings.targetName ~ ".lib"; + if (p.canFind("windows") && !p.canFind("mingw")) + return settings.targetName ~ ".lib"; else return "lib" ~ settings.targetName ~ ".a"; case TargetType.dynamicLibrary: - if (platform.platform.canFind("windows")) + if (p.canFind("windows")) return settings.targetName ~ ".dll"; - else if (platform.platform.canFind("osx")) + else if (p.canFind("osx")) return "lib" ~ settings.targetName ~ ".dylib"; else return "lib" ~ settings.targetName ~ ".so"; case TargetType.object: - if (platform.platform.canFind("windows")) + if (p.canFind("windows")) return settings.targetName ~ ".obj"; else return settings.targetName ~ ".o"; } @@ -231,7 +240,21 @@ void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) { - assert(false, "Separate linking not implemented for LDC"); + import std.string; + auto tpath = NativePath(settings.targetPath) ~ getTargetFileName(settings, platform); + auto args = ["-of"~tpath.toNativeString()]; + args ~= objects; + args ~= settings.sourceFiles; + if (platform.platform.canFind("linux")) + args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order + args ~= lflagsToDFlags(settings.lflags); + args ~= settings.dflags.filter!(f => isLinkerDFlag(f)).array; + + auto res_file = getTempFile("dub-build", ".lnk"); + std.file.write(res_file.toNativeString(), escapeArgs(args).join("\n")); + + logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" ")); + invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback); } string[] lflagsToDFlags(in string[] lflags) const @@ -244,28 +267,23 @@ return args.map!(s => s.canFind(' ') ? "\""~s~"\"" : s); } - private static bool generatesCOFF(in BuildPlatform platform) + private static bool isLinkerDFlag(string arg) { - import std.string : splitLines, strip; - import std.uni : toLower; - - static bool[string] compiler_coff_map; - - if (auto pret = platform.compilerBinary in compiler_coff_map) - return *pret; - - auto result = executeShell(escapeShellCommand([platform.compilerBinary, "-version"])); - enforce (result.status == 0, "Failed to determine linker used by LDC. \"" - ~platform.compilerBinary~" -version\" failed with exit code " - ~result.status.to!string()~"."); - - bool ret = result.output - .splitLines - .find!(l => l.strip.toLower.startsWith("default target:")) - .front - .canFind("msvc"); - - compiler_coff_map[platform.compilerBinary] = ret; - return ret; + switch (arg) { + case "-g", "-gc", "-m32", "-m64", "-shared", "-lib", + "-betterC", "-disable-linker-strip-dead", "-static": + return true; + default: + return arg.startsWith("-L") + || arg.startsWith("-Xcc=") + || arg.startsWith("-defaultlib=") + || arg.startsWith("-flto") + || arg.startsWith("-fsanitize=") + || arg.startsWith("-link-") + || arg.startsWith("-linker=") + || arg.startsWith("-march=") + || arg.startsWith("-mscrtlib=") + || arg.startsWith("-mtriple="); + } } } diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index 03b3c33..da847bc 100644 --- a/source/dub/compilers/utils.d +++ b/source/dub/compilers/utils.d @@ -40,37 +40,36 @@ Linker files include static/dynamic libraries, resource files, object files and DLL definition files. */ -bool isLinkerFile(string f) +bool isLinkerFile(in ref BuildPlatform platform, string f) { import std.path; switch (extension(f)) { default: return false; - version (Windows) { - case ".lib", ".obj", ".res", ".def": - return true; - } else { - case ".a", ".o", ".so", ".dylib": - return true; - } + case ".lib", ".obj", ".res", ".def": + return platform.platform.canFind("windows"); + case ".a", ".o", ".so", ".dylib": + return !platform.platform.canFind("windows"); } } unittest { - version (Windows) { - assert(isLinkerFile("test.obj")); - assert(isLinkerFile("test.lib")); - assert(isLinkerFile("test.res")); - assert(!isLinkerFile("test.o")); - assert(!isLinkerFile("test.d")); - } else { - assert(isLinkerFile("test.o")); - assert(isLinkerFile("test.a")); - assert(isLinkerFile("test.so")); - assert(isLinkerFile("test.dylib")); - assert(!isLinkerFile("test.obj")); - assert(!isLinkerFile("test.d")); - } + BuildPlatform p; + + p.platform = ["windows"]; + assert(isLinkerFile(p, "test.obj")); + assert(isLinkerFile(p, "test.lib")); + assert(isLinkerFile(p, "test.res")); + assert(!isLinkerFile(p, "test.o")); + assert(!isLinkerFile(p, "test.d")); + + p.platform = ["something else"]; + assert(isLinkerFile(p, "test.o")); + assert(isLinkerFile(p, "test.a")); + assert(isLinkerFile(p, "test.so")); + assert(isLinkerFile(p, "test.dylib")); + assert(!isLinkerFile(p, "test.obj")); + assert(!isLinkerFile(p, "test.d")); } @@ -80,7 +79,7 @@ This function tries to invoke "pkg-config" if possible and falls back to direct flag translation if that fails. */ -void resolveLibs(ref BuildSettings settings) +void resolveLibs(ref BuildSettings settings, in ref BuildPlatform platform) { import std.string : format; import std.array : array; @@ -90,7 +89,8 @@ if (settings.targetType == TargetType.library || settings.targetType == TargetType.staticLibrary) { logDiagnostic("Ignoring all import libraries for static library build."); settings.libs = null; - version(Windows) settings.sourceFiles = settings.sourceFiles.filter!(f => !f.endsWith(".lib")).array; + if (platform.platform.canFind("windows")) + settings.sourceFiles = settings.sourceFiles.filter!(f => !f.endsWith(".lib")).array; } version (Posix) { diff --git a/source/dub/dub.d b/source/dub/dub.d index 028066e..c2b75d0 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -32,9 +32,6 @@ import std.string; import std.encoding : sanitize; -// Workaround for libcurl liker errors when building with LDC -version (LDC) pragma(lib, "curl"); - // Set output path and options for coverage reports version (DigitalMars) version (D_Coverage) static if (__VERSION__ >= 2068) { diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 4414bb8..47fcfee 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -27,8 +27,10 @@ import std.string; import std.encoding : sanitize; -version(Windows) enum objSuffix = ".obj"; -else enum objSuffix = ".o"; +string getObjSuffix(in ref BuildPlatform platform) +{ + return platform.platform.canFind("windows") ? ".obj" : ".o"; +} class BuildGenerator : ProjectGenerator { private { @@ -230,7 +232,7 @@ // do not pass all source files to RDMD, only the main source file buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(s => !s.endsWith(".d"))().array(); - settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); + settings.compiler.prepareBuildSettings(buildsettings, settings.platform, BuildSetting.commandLine); auto generate_binary = !buildsettings.dflags.canFind("-o-"); @@ -416,13 +418,14 @@ /// 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). - static string pathToObjName(string path) + static string pathToObjName(in ref BuildPlatform platform, string path) { 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 idx = ret.lastIndexOf('.'); + const objSuffix = getObjSuffix(platform); return idx < 0 ? ret ~ objSuffix : format("%s_%(%02x%)%s", ret[idx+1 .. $], crc32Of(ret[0 .. idx]), objSuffix); } @@ -434,7 +437,7 @@ bs.lflags = null; bs.sourceFiles = [ srcFile ]; bs.targetType = TargetType.object; - gs.compiler.prepareBuildSettings(bs, BuildSetting.commandLine); + gs.compiler.prepareBuildSettings(bs, gs.platform, BuildSetting.commandLine); gs.compiler.setTarget(bs, gs.platform, objPath); gs.compiler.invoke(bs, gs.platform, gs.compileCallback); return objPath; @@ -456,12 +459,13 @@ import std.parallelism, std.range : walkLength; auto lbuildsettings = buildsettings; - auto srcs = buildsettings.sourceFiles.filter!(f => !isLinkerFile(f)); + auto srcs = buildsettings.sourceFiles.filter!(f => !isLinkerFile(settings.platform, f)); auto objs = new string[](srcs.walkLength); void compileSource(size_t i, string src) { logInfo("Compiling %s...", src); - objs[i] = compileUnit(src, pathToObjName(src), buildsettings, settings); + const objPath = pathToObjName(settings.platform, src); + objs[i] = compileUnit(src, objPath, buildsettings, settings); } if (settings.parallelBuild) { @@ -471,44 +475,40 @@ } logInfo("Linking..."); - lbuildsettings.sourceFiles = is_static_library ? [] : lbuildsettings.sourceFiles.filter!(f=> f.isLinkerFile()).array; + lbuildsettings.sourceFiles = is_static_library ? [] : lbuildsettings.sourceFiles.filter!(f => isLinkerFile(settings.platform, f)).array; settings.compiler.setTarget(lbuildsettings, settings.platform); - settings.compiler.prepareBuildSettings(lbuildsettings, BuildSetting.commandLineSeparate|BuildSetting.sourceFiles); + settings.compiler.prepareBuildSettings(lbuildsettings, settings.platform, BuildSetting.commandLineSeparate|BuildSetting.sourceFiles); settings.compiler.invokeLinker(lbuildsettings, settings.platform, objs, settings.linkCallback); - /* - NOTE: for DMD experimental separate compile/link is used, but this is not yet implemented - on the other compilers. Later this should be integrated somehow in the build process - (either in the dub.json, or using a command line flag) - */ - } else if (generate_binary && (settings.buildMode == BuildMode.allAtOnce || settings.compiler.name != "dmd" || is_static_library)) { + // 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)) { // don't include symbols of dependencies (will be included by the top level target) - if (is_static_library) buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !f.isLinkerFile()).array; + if (is_static_library) buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !isLinkerFile(settings.platform, f)).array; // setup for command line settings.compiler.setTarget(buildsettings, settings.platform); - settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); + settings.compiler.prepareBuildSettings(buildsettings, settings.platform, BuildSetting.commandLine); // invoke the compiler settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback); } else { // determine path for the temporary object file - string tempobjname = buildsettings.targetName ~ objSuffix; + string tempobjname = buildsettings.targetName ~ getObjSuffix(settings.platform); NativePath tempobj = NativePath(buildsettings.targetPath) ~ tempobjname; // setup linker command line auto lbuildsettings = buildsettings; - lbuildsettings.sourceFiles = lbuildsettings.sourceFiles.filter!(f => isLinkerFile(f)).array; + lbuildsettings.sourceFiles = lbuildsettings.sourceFiles.filter!(f => isLinkerFile(settings.platform, f)).array; if (generate_binary) settings.compiler.setTarget(lbuildsettings, settings.platform); - settings.compiler.prepareBuildSettings(lbuildsettings, BuildSetting.commandLineSeparate|BuildSetting.sourceFiles); + settings.compiler.prepareBuildSettings(lbuildsettings, settings.platform, BuildSetting.commandLineSeparate|BuildSetting.sourceFiles); // setup compiler command line buildsettings.libs = null; buildsettings.lflags = null; if (generate_binary) buildsettings.addDFlags("-c", "-of"~tempobj.toNativeString()); - buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !isLinkerFile(f)).array; + buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !isLinkerFile(settings.platform, f)).array; - settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); + settings.compiler.prepareBuildSettings(buildsettings, settings.platform, BuildSetting.commandLine); settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback); diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index ddbbc33..1d8990f 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -353,7 +353,7 @@ { auto pdepti = &targets[depname]; configureDependents(*pdepti, targets, level + 1); - mergeFromDependency(pdepti.buildSettings, ti.buildSettings); + mergeFromDependency(pdepti.buildSettings, ti.buildSettings, genSettings.platform); } } @@ -519,7 +519,7 @@ child.addOptions(BuildOptions(parent.options & inheritedBuildOptions)); } - private static void mergeFromDependency(in ref BuildSettings child, ref BuildSettings parent) + private static void mergeFromDependency(in ref BuildSettings child, ref BuildSettings parent, in ref BuildPlatform platform) { import dub.compilers.utils : isLinkerFile; @@ -532,7 +532,7 @@ parent.addStringImportPaths(child.stringImportPaths); // linking of static libraries is done by parent if (child.targetType == TargetType.staticLibrary) { - parent.addSourceFiles(child.sourceFiles.filter!isLinkerFile.array); + parent.addSourceFiles(child.sourceFiles.filter!(f => isLinkerFile(platform, f)).array); parent.addLibs(child.libs); parent.addLFlags(child.lflags); } diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index 87c8e51..df65729 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -194,7 +194,7 @@ addFile(p.recipePath.toNativeString(), false); if (files.targetType == TargetType.staticLibrary) - foreach(s; files.sourceFiles.filter!(s => !isLinkerFile(s))) addFile(s, true); + foreach(s; files.sourceFiles.filter!(s => !isLinkerFile(settings.platform, s))) addFile(s, true); else foreach(s; files.sourceFiles.filter!(s => !s.endsWith(".lib"))) addFile(s, true); diff --git a/source/dub/platform.d b/source/dub/platform.d index 88da7b2..0c27199 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -42,6 +42,7 @@ version(Android) ret ~= "android"; version(Cygwin) ret ~= "cygwin"; version(MinGW) ret ~= "mingw"; + version(WebAssembly) ret ~= "wasm"; return ret; }; diff --git a/source/dub/project.d b/source/dub/project.d index 48b6752..5f94b25 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -790,7 +790,7 @@ else static if (attributeName == "stringImportPaths") bs.stringImportPaths = bs.stringImportPaths.map!(ensureTrailingSlash).array(); - compiler.prepareBuildSettings(bs, BuildSetting.all & ~to!BuildSetting(attributeName)); + compiler.prepareBuildSettings(bs, platform, BuildSetting.all & ~to!BuildSetting(attributeName)); values = bs.dflags; break; @@ -801,7 +801,7 @@ bs.sourceFiles = null; bs.targetType = TargetType.none; // Force Compiler to NOT omit dependency libs when package is a library. - compiler.prepareBuildSettings(bs, BuildSetting.all & ~to!BuildSetting(attributeName)); + compiler.prepareBuildSettings(bs, platform, BuildSetting.all & ~to!BuildSetting(attributeName)); if (bs.lflags) values = compiler.lflagsToDFlags( bs.lflags ); @@ -1026,13 +1026,13 @@ if (projectDescription.rootPackage in projectDescription.targetLookup) { // Copy linker files from sourceFiles to linkerFiles auto target = projectDescription.lookupTarget(projectDescription.rootPackage); - foreach (file; target.buildSettings.sourceFiles.filter!(isLinkerFile)) + foreach (file; target.buildSettings.sourceFiles.filter!(f => isLinkerFile(settings.platform, f))) target.buildSettings.addLinkerFiles(file); // Remove linker files from sourceFiles target.buildSettings.sourceFiles = target.buildSettings.sourceFiles - .filter!(a => !isLinkerFile(a)) + .filter!(a => !isLinkerFile(settings.platform, a)) .array(); projectDescription.lookupTarget(projectDescription.rootPackage) = target; }