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.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 GdcCompiler : Compiler { 27 private static immutable s_options = [ 28 tuple(BuildOptions.debug_, ["-fdebug"]), 29 tuple(BuildOptions.release, ["-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.noBoundsChecks, ["-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 79 if (!(fields & BuildSetting.versions)) { 80 settings.addDFlags(settings.versions.map!(s => "-fversion="~s)().array()); 81 settings.versions = null; 82 } 83 84 if (!(fields & BuildSetting.debugVersions)) { 85 settings.addDFlags(settings.debugVersions.map!(s => "-fdebug="~s)().array()); 86 settings.debugVersions = null; 87 } 88 89 if (!(fields & BuildSetting.importPaths)) { 90 settings.addDFlags(settings.importPaths.map!(s => "-I"~s)().array()); 91 settings.importPaths = null; 92 } 93 94 if (!(fields & BuildSetting.stringImportPaths)) { 95 settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); 96 settings.stringImportPaths = null; 97 } 98 99 if (!(fields & BuildSetting.sourceFiles)) { 100 settings.addDFlags(settings.sourceFiles); 101 settings.sourceFiles = null; 102 } 103 104 if (!(fields & BuildSetting.lflags)) { 105 foreach( f; settings.lflags ) 106 settings.addDFlags(["-Xlinker", f]); 107 settings.lflags = null; 108 } 109 110 assert(fields & BuildSetting.dflags); 111 assert(fields & BuildSetting.copyFiles); 112 } 113 114 void extractBuildOptions(ref BuildSettings settings) 115 { 116 Appender!(string[]) newflags; 117 next_flag: foreach (f; settings.dflags) { 118 foreach (t; s_options) 119 if (t[1].canFind(f)) { 120 settings.options |= t[0]; 121 continue next_flag; 122 } 123 if (f.startsWith("-fversion=")) settings.addVersions(f[10 .. $]); 124 else if (f.startsWith("-fdebug=")) settings.addDebugVersions(f[8 .. $]); 125 else newflags ~= f; 126 } 127 settings.dflags = newflags.data; 128 } 129 130 void setTarget(ref BuildSettings settings, in BuildPlatform platform) 131 { 132 final switch (settings.targetType) { 133 case TargetType.autodetect: assert(false, "Invalid target type: autodetect"); 134 case TargetType.none: assert(false, "Invalid target type: none"); 135 case TargetType.sourceLibrary: assert(false, "Invalid target type: sourceLibrary"); 136 case TargetType.executable: break; 137 case TargetType.library: 138 case TargetType.staticLibrary: 139 settings.addDFlags("-c"); 140 break; 141 case TargetType.dynamicLibrary: 142 settings.addDFlags("-shared", "-fPIC"); 143 break; 144 } 145 146 auto tpath = Path(settings.targetPath) ~ getTargetFileName(settings, platform); 147 settings.addDFlags("-o", 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(settings.dflags.map!(s => escape(s)), "\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, "GDC 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 } 167 168 private string escape(string str) 169 { 170 auto ret = appender!string(); 171 foreach (char ch; str) { 172 switch (ch) { 173 default: ret.put(ch); break; 174 case '\\': ret.put(`\\`); break; 175 case ' ': ret.put(`\ `); break; 176 } 177 } 178 return ret.data; 179 }