1 /** 2 GDC 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.gdc; 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 GdcCompiler : Compiler { 27 private static immutable s_options = [ 28 tuple(BuildOptions.debugMode, ["-fdebug"]), 29 tuple(BuildOptions.releaseMode, ["-frelease"]), 30 tuple(BuildOptions.coverage, ["-fprofile-arcs", "-ftest-coverage"]), 31 tuple(BuildOptions.debugInfo, ["-g"]), 32 tuple(BuildOptions.debugInfoC, ["-g", "-fdebug-c"]), 33 //tuple(BuildOptions.alwaysStackFrame, ["-X"]), 34 //tuple(BuildOptions.stackStomping, ["-X"]), 35 tuple(BuildOptions.inline, ["-finline-functions"]), 36 tuple(BuildOptions.noBoundsCheck, ["-fno-bounds-check"]), 37 tuple(BuildOptions.optimize, ["-O3"]), 38 //tuple(BuildOptions.profile, ["-X"]), 39 tuple(BuildOptions.unittests, ["-funittest"]), 40 tuple(BuildOptions.verbose, ["-fd-verbose"]), 41 tuple(BuildOptions.ignoreUnknownPragmas, ["-fignore-unknown-pragmas"]), 42 tuple(BuildOptions.syntaxOnly, ["-fsyntax-only"]), 43 tuple(BuildOptions.warnings, ["-Wall"]), 44 tuple(BuildOptions.warningsAsErrors, ["-Werror", "-Wall"]), 45 //tuple(BuildOptions.ignoreDeprecations, ["-?"]), 46 //tuple(BuildOptions.deprecationWarnings, ["-?"]), 47 //tuple(BuildOptions.deprecationErrors, ["-?"]), 48 tuple(BuildOptions.property, ["-fproperty"]), 49 ]; 50 51 @property string name() const { return "gdc"; } 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 GDC."); 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 if (!(fields & BuildSetting.libs)) { 77 resolveLibs(settings); 78 settings.addDFlags(settings.libs.map!(l => "-l"~l)().array()); 79 } 80 81 if (!(fields & BuildSetting.versions)) { 82 settings.addDFlags(settings.versions.map!(s => "-fversion="~s)().array()); 83 settings.versions = null; 84 } 85 86 if (!(fields & BuildSetting.debugVersions)) { 87 settings.addDFlags(settings.debugVersions.map!(s => "-fdebug="~s)().array()); 88 settings.debugVersions = null; 89 } 90 91 if (!(fields & BuildSetting.importPaths)) { 92 settings.addDFlags(settings.importPaths.map!(s => "-I"~s)().array()); 93 settings.importPaths = null; 94 } 95 96 if (!(fields & BuildSetting.stringImportPaths)) { 97 settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); 98 settings.stringImportPaths = null; 99 } 100 101 if (!(fields & BuildSetting.sourceFiles)) { 102 settings.addDFlags(settings.sourceFiles); 103 settings.sourceFiles = null; 104 } 105 106 if (!(fields & BuildSetting.lflags)) { 107 foreach( f; settings.lflags ) 108 settings.addDFlags(["-Xlinker", f]); 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("-fversion=")) settings.addVersions(f[10 .. $]); 126 else if (f.startsWith("-fdebug=")) settings.addDebugVersions(f[8 .. $]); 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 settings.addDFlags("-c"); 142 break; 143 case TargetType.dynamicLibrary: 144 settings.addDFlags("-shared", "-fPIC"); 145 break; 146 } 147 148 auto tpath = Path(settings.targetPath) ~ getTargetFileName(settings, platform); 149 settings.addDFlags("-o", 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(settings.dflags.map!(s => escape(s)), "\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, "GDC 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 } 169 170 private string escape(string str) 171 { 172 auto ret = appender!string(); 173 foreach (char ch; str) { 174 switch (ch) { 175 default: ret.put(ch); break; 176 case '\\': ret.put(`\\`); break; 177 case ' ': ret.put(`\ `); break; 178 } 179 } 180 return ret.data; 181 }