diff --git a/.gitignore b/.gitignore index 47dcf7dc4..e81592682 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ __dummy.html /bin/dub-test-library /bin/libdub.a /bin/dub-* +/bin/dub.* # Ignore files or directories created by the test suite. *.exe diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index 6a0014ece..a00c24ca4 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -177,24 +177,21 @@ interface Compiler { args = arguments for the probe compilation arch_override = special handler for x86_mscoff */ - protected final BuildPlatform probePlatform(string compiler_binary, string[] args, - string arch_override) + protected final BuildPlatform probePlatform(string compiler_binary, string[] args, string arch_override) { - import dub.compilers.utils : generatePlatformProbeFile, readPlatformJsonProbe; + import dub.compilers.utils : generatePlatformProbeFile, readPlatformSDLProbe; import std.string : format, strip; - auto fil = generatePlatformProbeFile(); + NativePath fil = generatePlatformProbeFile(); auto result = execute(compiler_binary ~ args ~ fil.toNativeString()); enforce!CompilerInvocationException(result.status == 0, format("Failed to invoke the compiler %s to determine the build platform: %s", compiler_binary, result.output)); - - auto build_platform = readPlatformJsonProbe(result.output); + BuildPlatform build_platform = readPlatformSDLProbe(result.output); + string ver = determineVersion(compiler_binary, result.output).strip; build_platform.compilerBinary = compiler_binary; - auto ver = determineVersion(compiler_binary, result.output) - .strip; if (ver.empty) { logWarn(`Could not probe the compiler version for "%s". ` ~ `Toolchain requirements might be ineffective`, build_platform.compiler); diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index b3bb1e64a..2b8addf7b 100644 --- a/source/dub/compilers/utils.d +++ b/source/dub/compilers/utils.d @@ -8,7 +8,7 @@ module dub.compilers.utils; import dub.compilers.buildsettings; -import dub.platform : BuildPlatform, archCheck, compilerCheck, platformCheck; +import dub.platform : BuildPlatform, archCheck, compilerCheckPragmas, platformCheck, pragmaGen; import dub.internal.vibecompat.inet.path; import dub.internal.logging; @@ -269,77 +269,101 @@ private enum probeEndMark = "__dub_probe_end__"; NativePath generatePlatformProbeFile() { import dub.internal.vibecompat.core.file; - import dub.internal.vibecompat.data.json; import dub.internal.utils; import std.string : format; - // try to not use phobos in the probe to avoid long import times - enum probe = q{ - module dub_platform_probe; - - template toString(int v) { enum toString = v.stringof; } - string stringArray(string[] ary) { - string res; - foreach (i, e; ary) { - if (i) - res ~= ", "; - res ~= '"' ~ e ~ '"'; - } - return res; - } + enum moduleInfo = q{ + module object; + alias string = const(char)[]; + }; - pragma(msg, `%1$s` - ~ '\n' ~ `{` - ~ '\n' ~ ` "compiler": "`~ determineCompiler() ~ `",` - ~ '\n' ~ ` "frontendVersion": ` ~ toString!__VERSION__ ~ `,` - ~ '\n' ~ ` "compilerVendor": "` ~ __VENDOR__ ~ `",` - ~ '\n' ~ ` "platform": [` - ~ '\n' ~ ` ` ~ determinePlatform().stringArray - ~ '\n' ~ ` ],` - ~ '\n' ~ ` "architecture": [` - ~ '\n' ~ ` ` ~ determineArchitecture().stringArray - ~ '\n' ~ ` ],` - ~ '\n' ~ `}` - ~ '\n' ~ `%2$s`); - - string[] determinePlatform() { %3$s } - string[] determineArchitecture() { %4$s } - string determineCompiler() { %5$s } - - }.format(probeBeginMark, probeEndMark, platformCheck, archCheck, compilerCheck); + // avoid druntime so that this compiles without a compiler's builtin object.d + enum probe = q{ + %1$s + pragma(msg, `%2$s`); + pragma(msg, `\n`); + pragma(msg, `compiler`); + %6$s + pragma(msg, `\n`); + pragma(msg, `frontendVersion "`); + pragma(msg, __VERSION__.stringof); + pragma(msg, `"\n`); + pragma(msg, `compilerVendor "`); + pragma(msg, __VENDOR__); + pragma(msg, `"\n`); + pragma(msg, `platform`); + %4$s + pragma(msg, `\n`); + pragma(msg, `architecture `); + %5$s + pragma(msg, `\n`); + pragma(msg, `%3$s`); + }.format(moduleInfo, probeBeginMark, probeEndMark, pragmaGen(platformCheck), pragmaGen(archCheck), compilerCheckPragmas); auto path = getTempFile("dub_platform_probe", ".d"); writeFile(path, probe); - return path; } + /** - Processes the JSON output generated by compiling the platform probe file. + Processes the SDL output generated by compiling the platform probe file. See_Also: `generatePlatformProbeFile`. */ -BuildPlatform readPlatformJsonProbe(string output) +BuildPlatform readPlatformSDLProbe(string output) { - import std.algorithm : map; + import std.algorithm : map, max, splitter, joiner, count, filter; import std.array : array; import std.exception : enforce; + import std.range : front; + import std.ascii : newline; import std.string; + import dub.internal.sdlang.parser; + import dub.internal.sdlang.ast; + import std.conv; // work around possible additional output of the compiler - auto idx1 = output.indexOf(probeBeginMark); - auto idx2 = output.lastIndexOf(probeEndMark); + auto idx1 = output.indexOf(probeBeginMark ~ newline ~ "\\n"); + auto idx2 = output[max(0, idx1) .. $].indexOf(probeEndMark) + idx1; enforce(idx1 >= 0 && idx1 < idx2, "Unexpected platform information output - does not contain a JSON object."); - output = output[idx1+probeBeginMark.length .. idx2]; + output = output[idx1 + probeBeginMark.length .. idx2].replace(newline, "").replace("\\n", "\n"); - import dub.internal.vibecompat.data.json; - auto json = parseJsonString(output); + output = output.splitter("\n").filter!((e) => e.length > 0) + .map!((e) { + if (e.count("\"") == 0) + { + return e ~ ` ""`; + } + return e; + }) + .joiner("\n").array().to!string; BuildPlatform build_platform; - build_platform.platform = json["platform"].get!(Json[]).map!(e => e.get!string()).array(); - build_platform.architecture = json["architecture"].get!(Json[]).map!(e => e.get!string()).array(); - build_platform.compiler = json["compiler"].get!string; - build_platform.frontendVersion = json["frontendVersion"].get!int; + Tag sdl = parseSource(output); + + foreach (n; sdl.all.tags) + { + switch (n.name) + { + default: + break; + case "platform": + build_platform.platform = n.values.map!(e => e.toString()).array(); + break; + case "architecture": + build_platform.architecture = n.values.map!(e => e.toString()).array(); + break; + case "compiler": + build_platform.compiler = n.values.front.toString(); + break; + case "frontendVersion": + build_platform.frontendVersion = n.values.front.toString() + .filter!((e) => e >= '0' && e <= '9').array().to!string + .to!int; + break; + } + } return build_platform; } diff --git a/source/dub/platform.d b/source/dub/platform.d index 07a5357a7..2a178c3be 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -115,6 +115,21 @@ enum string compilerCheck = q{ else return null; }; +/// private +enum string compilerCheckPragmas = q{ + version(DigitalMars) pragma(msg, ` "dmd"`); + else version(GNU) pragma(msg, ` "gdc"`); + else version(LDC) pragma(msg, ` "ldc"`); + else version(SDC) pragma(msg, ` "sdc"`); +}; + +/// private, converts the above appender strings to pragmas +string pragmaGen(string str) { + import std.string : replace; + return str.replace("return ret;", "").replace("string[] ret;", "").replace(`["`, `"`).replace(`", "`,`" "`).replace(`"]`, `"`).replace(`;`, "`);").replace("ret ~= ", "pragma(msg, ` "); +} + + /** Determines the full build platform used for the current build. Note that the `BuildPlatform.compilerBinary` field will be left empty.