Newer
Older
dub_jkp / source / dub / compilers / compiler.d
  1. /**
  2. Compiler settings and abstraction.
  3.  
  4. Copyright: © 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.compiler;
  9.  
  10. import dub.compilers.dmd;
  11. import dub.compilers.gdc;
  12. import dub.compilers.ldc;
  13.  
  14. import std.algorithm;
  15. import std.array;
  16. import vibe.data.json;
  17. import vibe.inet.path;
  18.  
  19.  
  20. static this()
  21. {
  22. registerCompiler(new DmdCompiler);
  23. registerCompiler(new GdcCompiler);
  24. registerCompiler(new LdcCompiler);
  25. }
  26.  
  27.  
  28. Compiler getCompiler(string name)
  29. {
  30. foreach( c; s_compilers )
  31. if( c.name == name )
  32. return c;
  33.  
  34. // try to match names like gdmd or gdc-2.61
  35. if( name.canFind("dmd") ) return getCompiler("dmd");
  36. if( name.canFind("gdc") ) return getCompiler("gdc");
  37. if( name.canFind("ldc") ) return getCompiler("ldc");
  38. throw new Exception("Unknown compiler: "~name);
  39. }
  40.  
  41. void registerCompiler(Compiler c)
  42. {
  43. s_compilers ~= c;
  44. }
  45.  
  46.  
  47. interface Compiler {
  48. @property string name() const;
  49.  
  50. BuildPlatform determinePlatform(ref BuildSettings settings, string compiler_binary, string arch_override = null);
  51.  
  52. /// Replaces high level fields with low level fields and converts
  53. /// dmd flags to compiler-specific flags
  54. void prepareBuildSettings(ref BuildSettings settings, BuildSetting supported_fields = BuildSetting.all);
  55.  
  56. /// Adds the appropriate flag to set a target path
  57. void setTarget(ref BuildSettings settings, Path binary_path);
  58. }
  59.  
  60.  
  61. /// BuildPlatform specific settings, like needed libraries or additional
  62. /// include paths.
  63. struct BuildSettings {
  64. string[] dflags;
  65. string[] lflags;
  66. string[] libs;
  67. string[] files;
  68. string[] copyFiles;
  69. string[] versions;
  70. string[] importPaths;
  71. string[] stringImportPaths;
  72.  
  73. void parse(in Json root, BuildPlatform platform)
  74. {
  75. addDFlags(getPlatformField(root, "dflags", platform));
  76. addLFlags(getPlatformField(root, "lflags", platform));
  77. addLibs(getPlatformField(root, "libs", platform));
  78. addFiles(getPlatformField(root, "files", platform));
  79. addCopyFiles(getPlatformField(root, "copyFiles", platform));
  80. addVersions(getPlatformField(root, "versions", platform));
  81. addImportDirs(getPlatformField(root, "importPaths", platform));
  82. addStringImportDirs(getPlatformField(root, "stringImportPaths", platform));
  83. }
  84.  
  85. void addDFlags(string[] value...) { add(dflags, value); }
  86. void addLFlags(string[] value...) { add(lflags, value); }
  87. void addLibs(string[] value...) { add(libs, value); }
  88. void addFiles(string[] value...) { add(files, value); }
  89. void addCopyFiles(string[] value...) { add(copyFiles, value); }
  90. void addVersions(string[] value...) { add(versions, value); }
  91. void addImportDirs(string[] value...) { add(importPaths, value); }
  92. void addStringImportDirs(string[] value...) { add(stringImportPaths, value); }
  93.  
  94. // Adds vals to arr without adding duplicates.
  95. private void add(ref string[] arr, string[] vals)
  96. {
  97. foreach( v; vals ){
  98. bool found = false;
  99. foreach( i; 0 .. arr.length )
  100. if( arr[i] == v ){
  101. found = true;
  102. break;
  103. }
  104. if( !found ) arr ~= v;
  105. }
  106. }
  107.  
  108. // Parses json and returns the values of the corresponding field
  109. // by the platform.
  110. private string[] getPlatformField(in Json json, string name, BuildPlatform platform)
  111. const {
  112. auto ret = appender!(string[])();
  113. foreach( suffix; getPlatformSuffixIterator(platform) ){
  114. foreach( j; json[name~suffix].opt!(Json[]) )
  115. ret.put(j.get!string);
  116. }
  117. return ret.data;
  118. }
  119. }
  120.  
  121. /// Represents a platform a package can be build upon.
  122. struct BuildPlatform {
  123. /// e.g. ["posix", "windows"]
  124. string[] platform;
  125. /// e.g. ["x86", "x64"]
  126. string[] architecture;
  127. /// e.g. "dmd"
  128. string compiler;
  129. }
  130.  
  131. enum BuildSetting {
  132. dflags = 1<<0,
  133. lflags = 1<<1,
  134. libs = 1<<2,
  135. files = 1<<3,
  136. copyFiles = 1<<4,
  137. versions = 1<<5,
  138. importPaths = 1<<6,
  139. stringImportPaths = 1<<7,
  140. none = 0,
  141. commandLine = dflags|copyFiles,
  142. commandLineSeparate = commandLine|lflags,
  143. all = dflags|lflags|libs|files|copyFiles|versions|importPaths|stringImportPaths
  144. }
  145.  
  146. private {
  147. Compiler[] s_compilers;
  148. }
  149.  
  150. /// Based on the BuildPlatform, creates an iterator with all suffixes.
  151. ///
  152. /// Suffixes are build upon the following scheme, where each component
  153. /// is optional (indicated by []), but the order is obligatory.
  154. /// "[-platform][-architecture][-compiler]"
  155. ///
  156. /// So the following strings are valid suffixes:
  157. /// "-windows-x86-dmd"
  158. /// "-dmd"
  159. /// "-arm"
  160. ///
  161. int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform)
  162. {
  163. int iterator(scope int delegate(ref string s) del)
  164. {
  165. auto c = platform.compiler;
  166. int delwrap(string s) { return del(s); }
  167. if( auto ret = delwrap(null) ) return ret;
  168. if( auto ret = delwrap("-"~c) ) return ret;
  169. foreach( p; platform.platform ){
  170. if( auto ret = delwrap("-"~p) ) return ret;
  171. if( auto ret = delwrap("-"~p~"-"~c) ) return ret;
  172. foreach( a; platform.architecture ){
  173. if( auto ret = delwrap("-"~p~"-"~a) ) return ret;
  174. if( auto ret = delwrap("-"~p~"-"~a~"-"~c) ) return ret;
  175. }
  176. }
  177. foreach( a; platform.architecture ){
  178. if( auto ret = delwrap("-"~a) ) return ret;
  179. if( auto ret = delwrap("-"~a~"-"~c) ) return ret;
  180. }
  181. return 0;
  182. }
  183. return &iterator;
  184. }