Skip to content

Commit

Permalink
Add betterC probing for performance and for applications without drun…
Browse files Browse the repository at this point in the history
…time
  • Loading branch information
etcimon committed Jan 4, 2024
1 parent c045231 commit 2250725
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 55 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 11 additions & 9 deletions source/dub/compilers/compiler.d
Original file line number Diff line number Diff line change
Expand Up @@ -177,27 +177,29 @@ 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();
string betterC_flag = "-betterC";
if (compiler_binary == "gdc")
betterC_flag = "-fno-druntime";

auto result = execute(compiler_binary ~ args ~ fil.toNativeString());
auto result = execute(compiler_binary ~ args ~ betterC_flag ~ fil.toNativeString());
enforce!CompilerInvocationException(result.status == 0,
format("Failed to invoke the compiler %s to determine the build platform: %s",
compiler_binary, result.output));
BuildPlatform build_platform;

auto build_platform = readPlatformJsonProbe(result.output);
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);
`Toolchain requirements might be ineffective`, build_platform.compiler);
}
else {
build_platform.compilerVersion = ver;
Expand Down
117 changes: 71 additions & 46 deletions source/dub/compilers/utils.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -269,77 +269,102 @@ 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);

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;
}
85 changes: 85 additions & 0 deletions source/dub/platform.d
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 2250725

Please sign in to comment.