diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index 6a0014ece..85599fcc5 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -178,38 +178,47 @@ interface Compiler { arch_override = special handler for x86_mscoff */ protected final BuildPlatform probePlatform(string compiler_binary, string[] args, - string arch_override) + 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(); + string betterC_flag = "-betterC"; + if (compiler_binary == "gdc") + betterC_flag = "-fno-druntime"; - 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 result_betterC = execute(compiler_binary ~ args ~ betterC_flag ~ fil.toNativeString()); + + BuildPlatform build_platform; + string ver; + build_platform = readPlatformSDLProbe(result_betterC.output); + ver = determineVersion(compiler_binary, result_betterC.output).strip; - auto build_platform = readPlatformJsonProbe(result.output); build_platform.compilerBinary = compiler_binary; - auto ver = determineVersion(compiler_binary, result.output) - .strip; - if (ver.empty) { + if (ver.empty) + { logWarn(`Could not probe the compiler version for "%s". ` ~ - `Toolchain requirements might be ineffective`, build_platform.compiler); + `Toolchain requirements might be ineffective`, build_platform.compiler); } - else { + else + { build_platform.compilerVersion = ver; } // Skip the following check for LDC, emitting a warning if the specified `-arch` // cmdline option does not lead to the same string being found among // `build_platform.architecture`, as it's brittle and doesn't work with triples. - if (build_platform.compiler != "ldc") { + if (build_platform.compiler != "ldc") + { if (arch_override.length && !build_platform.architecture.canFind(arch_override) && !(build_platform.compiler == "dmd" && arch_override.among("x86_omf", "x86_mscoff")) // Will be fixed in determinePlatform - ) { + + + + ) + { logWarn(`Failed to apply the selected architecture %s. Got %s.`, arch_override, build_platform.architecture); } diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index b3bb1e64a..70006bd3e 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, archCheckPragmas, compilerCheckPragmas, platformCheckPragmas; import dub.internal.vibecompat.inet.path; import dub.internal.logging; @@ -269,44 +269,37 @@ 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; + enum moduleInfo = q{ + module object; + alias string = const(char)[]; + }; + // 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; - } - - 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); + %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, platformCheckPragmas, archCheckPragmas, compilerCheckPragmas); auto path = getTempFile("dub_platform_probe", ".d"); writeFile(path, probe); @@ -314,32 +307,65 @@ NativePath generatePlatformProbeFile() 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..16dd60a3d 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -115,6 +115,91 @@ enum string compilerCheck = q{ else return null; }; + +enum string platformCheckPragmas = q{ + version(Windows) pragma(msg, ` "windows"`); + version(linux) pragma(msg, ` "linux"`); + version(Posix) pragma(msg, ` "posix"`); + version(OSX) pragma(msg, ` "osx" "darwin"`); + version(iOS) pragma(msg, ` "ios" "darwin"`); + version(TVOS) pragma(msg, ` "tvos" "darwin"`); + version(WatchOS) pragma(msg, ` "watchos" "darwin"`); + version(FreeBSD) pragma(msg, ` "freebsd"`); + version(OpenBSD) pragma(msg, ` "openbsd"`); + version(NetBSD) pragma(msg, ` "netbsd"`); + version(DragonFlyBSD) pragma(msg, ` "dragonflybsd"`); + version(BSD) pragma(msg, ` "bsd"`); + version(Solaris) pragma(msg, ` "solaris"`); + version(AIX) pragma(msg, ` "aix"`); + version(Haiku) pragma(msg, ` "haiku"`); + version(SkyOS) pragma(msg, ` "skyos"`); + version(SysV3) pragma(msg, ` "sysv3"`); + version(SysV4) pragma(msg, ` "sysv4"`); + version(Hurd) pragma(msg, ` "hurd"`); + version(Android) pragma(msg, ` "android"`); + version(Cygwin) pragma(msg, ` "cygwin"`); + version(MinGW) pragma(msg, ` "mingw"`); + version(PlayStation4) pragma(msg, ` "playstation4"`); + version(WebAssembly) pragma(msg, ` "wasm"`); +}; + +enum string archCheckPragmas = q{ + + version(X86) pragma(msg, ` "x86"`); + // Hack: see #1535 + // Makes "x86_omf" available as a platform specifier in the package recipe + version(X86) version(CRuntime_DigitalMars) pragma(msg, ` "x86_omf"`); + // Hack: see #1059 + // When compiling with --arch=x86_mscoff build_platform.architecture is equal to ["x86"] and canFind below is false. + // This hack prevents unnecessary warning 'Failed to apply the selected architecture x86_mscoff. Got ["x86"]'. + // And also makes "x86_mscoff" available as a platform specifier in the package recipe + version(X86) version(CRuntime_Microsoft) pragma(msg, ` "x86_mscoff"`); + version(X86_64) pragma(msg, ` "x86_64"`); + version(ARM) pragma(msg, ` "arm"`); + version(AArch64) pragma(msg, ` "aarch64"`); + version(ARM_Thumb) pragma(msg, ` "arm_thumb"`); + version(ARM_SoftFloat) pragma(msg, ` "arm_softfloat"`); + version(ARM_HardFloat) pragma(msg, ` "arm_hardfloat"`); + version(PPC) pragma(msg, ` "ppc"`); + version(PPC_SoftFP) pragma(msg, ` "ppc_softfp"`); + version(PPC_HardFP) pragma(msg, ` "ppc_hardfp"`); + version(PPC64) pragma(msg, ` "ppc64"`); + version(IA64) pragma(msg, ` "ia64"`); + version(MIPS) pragma(msg, ` "mips"`); + version(MIPS32) pragma(msg, ` "mips32"`); + version(MIPS64) pragma(msg, ` "mips64"`); + version(MIPS_O32) pragma(msg, ` "mips_o32"`); + version(MIPS_N32) pragma(msg, ` "mips_n32"`); + version(MIPS_O64) pragma(msg, ` "mips_o64"`); + version(MIPS_N64) pragma(msg, ` "mips_n64"`); + version(MIPS_EABI) pragma(msg, ` "mips_eabi"`); + version(MIPS_NoFloat) pragma(msg, ` "mips_nofloat"`); + version(MIPS_SoftFloat) pragma(msg, ` "mips_softfloat"`); + version(MIPS_HardFloat) pragma(msg, ` "mips_hardfloat"`); + version(SPARC) pragma(msg, ` "sparc"`); + version(SPARC_V8Plus) pragma(msg, ` "sparc_v8plus"`); + version(SPARC_SoftFP) pragma(msg, ` "sparc_softfp"`); + version(SPARC_HardFP) pragma(msg, ` "sparc_hardfp"`); + version(SPARC64) pragma(msg, ` "sparc64"`); + version(S390) pragma(msg, ` "s390"`); + version(S390X) pragma(msg, ` "s390x"`); + version(HPPA) pragma(msg, ` "hppa"`); + version(HPPA64) pragma(msg, ` "hppa64"`); + version(SH) pragma(msg, ` "sh"`); + version(SH64) pragma(msg, ` "sh64"`); + version(Alpha) pragma(msg, ` "alpha"`); + version(Alpha_SoftFP) pragma(msg, ` "alpha_softfp"`); + version(Alpha_HardFP) pragma(msg, ` "alpha_hardfp"`); +}; + +/// 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"`); +}; + /** Determines the full build platform used for the current build. Note that the `BuildPlatform.compilerBinary` field will be left empty.