Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve user experience with ldc2, incl. cross-compilation #1755

Merged
merged 8 commits into from
Aug 25, 2019
2 changes: 1 addition & 1 deletion source/dub/compilers/compiler.d
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ interface Compiler {

/// 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;
Expand Down
26 changes: 14 additions & 12 deletions source/dub/compilers/dmd.d
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ config /etc/dmd.conf
);
}

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);

Expand Down Expand Up @@ -163,9 +163,11 @@ config /etc/dmd.conf
}

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)) {
Expand All @@ -178,10 +180,8 @@ config /etc/dmd.conf
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);
Expand Down Expand Up @@ -248,9 +248,10 @@ config /etc/dmd.conf
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");
Expand Down Expand Up @@ -280,7 +281,8 @@ config /etc/dmd.conf
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;

Expand Down
7 changes: 4 additions & 3 deletions source/dub/compilers/gdc.d
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class GDCCompiler : Compiler {
);
}

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);

Expand Down Expand Up @@ -121,7 +121,7 @@ class GDCCompiler : Compiler {
}

if (!(fields & BuildSetting.libs)) {
resolveLibs(settings);
resolveLibs(settings, platform);
settings.addDFlags(settings.libs.map!(l => "-l"~l)().array());
}

Expand Down Expand Up @@ -222,7 +222,8 @@ class GDCCompiler : Compiler {
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);
Expand Down
86 changes: 52 additions & 34 deletions source/dub/compilers/ldc.d
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ class LDCCompiler : Compiler {
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"]),
Expand Down Expand Up @@ -80,10 +80,15 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
{
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);

Expand All @@ -94,7 +99,7 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
);
}

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);

Expand Down Expand Up @@ -133,7 +138,7 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
}

if (!(fields & BuildSetting.libs)) {
resolveLibs(settings);
resolveLibs(settings, platform);
settings.addLFlags(settings.libs.map!(l => "-l"~l)().array());
}

Expand Down Expand Up @@ -169,26 +174,30 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
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";
}
Expand Down Expand Up @@ -231,7 +240,21 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)

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
Expand All @@ -244,28 +267,23 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu)
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=");
}
}
}
48 changes: 24 additions & 24 deletions source/dub/compilers/utils.d
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,36 @@ void enforceBuildRequirements(ref BuildSettings settings)
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"));
}


Expand All @@ -80,7 +79,7 @@ unittest {
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;
Expand All @@ -90,7 +89,8 @@ void resolveLibs(ref BuildSettings settings)
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) {
Expand Down
3 changes: 0 additions & 3 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ import std.range : assumeSorted, empty;
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)
{
Expand Down
Loading