1 /** 2 LDC compiler support. 3 4 Copyright: © 2013-2013 rejectedsoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dub.compilers.ldc; 9 10 import dub.compilers.compiler; 11 import dub.internal.std.process; 12 import dub.internal.utils; 13 import dub.internal.vibecompat.core.log; 14 import dub.internal.vibecompat.inet.path; 15 import dub.platform; 16 17 import std.algorithm; 18 import std.array; 19 import std.conv; 20 import std.exception; 21 import std.file; 22 import std.random; 23 import std.typecons; 24 25 26 class LdcCompiler : Compiler { 27 private static immutable s_options = [ 28 tuple(BuildOptions.debug_, ["-d-debug"]), 29 tuple(BuildOptions.release, ["-release"]), 30 //tuple(BuildOptions.coverage, ["-?"]), 31 tuple(BuildOptions.debugInfo, ["-g"]), 32 tuple(BuildOptions.debugInfoC, ["-gc"]), 33 //tuple(BuildOptions.alwaysStackFrame, ["-?"]), 34 //tuple(BuildOptions.stackStomping, ["-?"]), 35 tuple(BuildOptions.inline, ["-enable-inlining"]), 36 tuple(BuildOptions.noBoundsChecks, ["-disable-boundscheck"]), 37 tuple(BuildOptions.optimize, ["-O"]), 38 //tuple(BuildOptions.profile, ["-?"]), 39 tuple(BuildOptions.unittests, ["-unittest"]), 40 tuple(BuildOptions.verbose, ["-v"]), 41 tuple(BuildOptions.ignoreUnknownPragmas, ["-ignore"]), 42 tuple(BuildOptions.syntaxOnly, ["-o-"]), 43 tuple(BuildOptions.warnings, ["-wi"]), 44 tuple(BuildOptions.warningsAsErrors, ["-w"]), 45 tuple(BuildOptions.ignoreDeprecations, ["-d"]), 46 tuple(BuildOptions.deprecationWarnings, ["-dw"]), 47 tuple(BuildOptions.deprecationErrors, ["-de"]), 48 tuple(BuildOptions.property, ["-property"]), 49 ]; 50 51 @property string name() const { return "ldc"; } 52 53 BuildPlatform determinePlatform(ref BuildSettings settings, string compiler_binary, string arch_override) 54 { 55 // TODO: determine platform by invoking the compiler instead 56 BuildPlatform build_platform; 57 build_platform.platform = .determinePlatform(); 58 build_platform.architecture = .determineArchitecture(); 59 build_platform.compiler = this.name; 60 build_platform.compilerBinary = compiler_binary; 61 62 enforce(arch_override.length == 0, "Architecture override not implemented for LDC."); 63 return build_platform; 64 } 65 66 void prepareBuildSettings(ref BuildSettings settings, BuildSetting fields = BuildSetting.all) 67 { 68 enforceBuildRequirements(settings); 69 70 if (!fields & BuildSetting.options) { 71 foreach (t; s_options) 72 if (settings.options & t[0]) 73 settings.addDFlags(t[1]); 74 } 75 76 // since LDC always outputs multiple object files, avoid conflicts by default 77 settings.addDFlags("-oq", "-od=.dub/obj"); 78 79 if (!(fields & BuildSetting.libs)) 80 resolveLibs(settings); 81 82 if (!(fields & BuildSetting.versions)) { 83 settings.addDFlags(settings.versions.map!(s => "-d-version="~s)().array()); 84 settings.versions = null; 85 } 86 87 if (!(fields & BuildSetting.debugVersions)) { 88 settings.addDFlags(settings.debugVersions.map!(s => "-d-debug="~s)().array()); 89 settings.debugVersions = null; 90 } 91 92 if (!(fields & BuildSetting.importPaths)) { 93 settings.addDFlags(settings.importPaths.map!(s => "-I"~s)().array()); 94 settings.importPaths = null; 95 } 96 97 if (!(fields & BuildSetting.stringImportPaths)) { 98 settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); 99 settings.stringImportPaths = null; 100 } 101 102 if (!(fields & BuildSetting.sourceFiles)) { 103 settings.addDFlags(settings.sourceFiles); 104 settings.sourceFiles = null; 105 } 106 107 if (!(fields & BuildSetting.lflags)) { 108 settings.addDFlags(settings.lflags.map!(s => "-L="~s)().array()); 109 settings.lflags = null; 110 } 111 112 assert(fields & BuildSetting.dflags); 113 assert(fields & BuildSetting.copyFiles); 114 } 115 116 void extractBuildOptions(ref BuildSettings settings) 117 { 118 Appender!(string[]) newflags; 119 next_flag: foreach (f; settings.dflags) { 120 foreach (t; s_options) 121 if (t[1].canFind(f)) { 122 settings.options |= t[0]; 123 continue next_flag; 124 } 125 if (f.startsWith("-d-version=")) settings.addVersions(f[11 .. $]); 126 else if (f.startsWith("-d-debug=")) settings.addDebugVersions(f[9 .. $]); 127 else newflags ~= f; 128 } 129 settings.dflags = newflags.data; 130 } 131 132 void setTarget(ref BuildSettings settings, in BuildPlatform platform) 133 { 134 final switch (settings.targetType) { 135 case TargetType.autodetect: assert(false, "Invalid target type: autodetect"); 136 case TargetType.none: assert(false, "Invalid target type: none"); 137 case TargetType.sourceLibrary: assert(false, "Invalid target type: sourceLibrary"); 138 case TargetType.executable: break; 139 case TargetType.library: 140 case TargetType.staticLibrary: 141 assert(false, "No LDC static libraries supported"); 142 case TargetType.dynamicLibrary: 143 assert(false, "No LDC dynamic libraries supported"); 144 } 145 146 auto tpath = Path(settings.targetPath) ~ getTargetFileName(settings, platform); 147 settings.addDFlags("-of"~tpath.toNativeString()); 148 } 149 150 void invoke(in BuildSettings settings, in BuildPlatform platform) 151 { 152 auto res_file = getTempDir() ~ ("dub-build-"~uniform(0, uint.max).to!string~"-.rsp"); 153 std.file.write(res_file.toNativeString(), join(cast(string[])settings.dflags, "\n")); 154 scope (exit) remove(res_file.toNativeString()); 155 156 logDiagnostic("%s %s", platform.compilerBinary, join(cast(string[])settings.dflags, " ")); 157 auto compiler_pid = spawnProcess([platform.compilerBinary, "@"~res_file.toNativeString()]); 158 auto result = compiler_pid.wait(); 159 enforce(result == 0, "LDC compile run failed with exit code "~to!string(result)); 160 } 161 162 void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects) 163 { 164 assert(false, "Separate linking not implemented for GDC"); 165 } 166 }