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.utils; 12 import dub.internal.vibecompat.core.log; 13 import dub.internal.vibecompat.inet.path; 14 import dub.platform; 15 16 import std.algorithm; 17 import std.array; 18 import std.conv; 19 import std.exception; 20 import std.file; 21 import std.process; 22 import std.random; 23 import std.typecons; 24 25 26 class LdcCompiler : Compiler { 27 private static immutable s_options = [ 28 tuple(BuildOptions.debugMode, ["-d-debug"]), 29 tuple(BuildOptions.releaseMode, ["-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.noBoundsCheck, ["-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 settings.addLFlags(settings.libs.map!(l => "-l"~l)().array()); 82 } 83 84 if (!(fields & BuildSetting.versions)) { 85 settings.addDFlags(settings.versions.map!(s => "-d-version="~s)().array()); 86 settings.versions = null; 87 } 88 89 if (!(fields & BuildSetting.debugVersions)) { 90 settings.addDFlags(settings.debugVersions.map!(s => "-d-debug="~s)().array()); 91 settings.debugVersions = null; 92 } 93 94 if (!(fields & BuildSetting.importPaths)) { 95 settings.addDFlags(settings.importPaths.map!(s => "-I"~s)().array()); 96 settings.importPaths = null; 97 } 98 99 if (!(fields & BuildSetting.stringImportPaths)) { 100 settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); 101 settings.stringImportPaths = null; 102 } 103 104 if (!(fields & BuildSetting.sourceFiles)) { 105 settings.addDFlags(settings.sourceFiles); 106 settings.sourceFiles = null; 107 } 108 109 if (!(fields & BuildSetting.lflags)) { 110 settings.addDFlags(settings.lflags.map!(s => "-L="~s)().array()); 111 settings.lflags = null; 112 } 113 114 assert(fields & BuildSetting.dflags); 115 assert(fields & BuildSetting.copyFiles); 116 } 117 118 void extractBuildOptions(ref BuildSettings settings) 119 { 120 Appender!(string[]) newflags; 121 next_flag: foreach (f; settings.dflags) { 122 foreach (t; s_options) 123 if (t[1].canFind(f)) { 124 settings.options |= t[0]; 125 continue next_flag; 126 } 127 if (f.startsWith("-d-version=")) settings.addVersions(f[11 .. $]); 128 else if (f.startsWith("-d-debug=")) settings.addDebugVersions(f[9 .. $]); 129 else newflags ~= f; 130 } 131 settings.dflags = newflags.data; 132 } 133 134 void setTarget(ref BuildSettings settings, in BuildPlatform platform) 135 { 136 final switch (settings.targetType) { 137 case TargetType.autodetect: assert(false, "Invalid target type: autodetect"); 138 case TargetType.none: assert(false, "Invalid target type: none"); 139 case TargetType.sourceLibrary: assert(false, "Invalid target type: sourceLibrary"); 140 case TargetType.executable: break; 141 case TargetType.library: 142 case TargetType.staticLibrary: 143 assert(false, "No LDC static libraries supported"); 144 case TargetType.dynamicLibrary: 145 assert(false, "No LDC dynamic libraries supported"); 146 } 147 148 auto tpath = Path(settings.targetPath) ~ getTargetFileName(settings, platform); 149 settings.addDFlags("-of"~tpath.toNativeString()); 150 } 151 152 void invoke(in BuildSettings settings, in BuildPlatform platform) 153 { 154 auto res_file = getTempDir() ~ ("dub-build-"~uniform(0, uint.max).to!string~"-.rsp"); 155 std.file.write(res_file.toNativeString(), join(cast(string[])settings.dflags, "\n")); 156 scope (exit) remove(res_file.toNativeString()); 157 158 logDiagnostic("%s %s", platform.compilerBinary, join(cast(string[])settings.dflags, " ")); 159 auto compiler_pid = spawnProcess([platform.compilerBinary, "@"~res_file.toNativeString()]); 160 auto result = compiler_pid.wait(); 161 enforce(result == 0, "LDC compile run failed with exit code "~to!string(result)); 162 } 163 164 void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects) 165 { 166 assert(false, "Separate linking not implemented for GDC"); 167 } 168 }