1 /** 2 High-level rules for compiling D files 3 */ 4 5 module reggae.rules.d; 6 7 import reggae.types; 8 import reggae.build; 9 import reggae.sorting; 10 import reggae.dependencies: dMainDepSrcs; 11 import reggae.rules.common; 12 import std.algorithm; 13 14 //objectFile, objectFiles and link are the only default rules 15 //They work by serialising the rule to use piggy-backing on Target's string 16 //command attribute. It's horrible, but it works with the original decision 17 //of using strings as commands. Should be changed to be a sum type where 18 //a string represents a shell command and other variants call D code. 19 20 //generate object file(s) for a D package. By default generates one per package, 21 //if reggae.config.perModule is true, generates one per module 22 Target[] objectFiles(in string[] srcFiles, in string flags = "", 23 in string[] importPaths = [], in string[] stringImportPaths = [], 24 in string projDir = "$project") @safe pure { 25 import reggae.config; 26 auto func = perModule ? &objectFilesPerModule : &objectFilesPerPackage; 27 return func(srcFiles, flags, importPaths, stringImportPaths, projDir); 28 } 29 30 Target[] objectFilesPerPackage(in string[] srcFiles, in string flags = "", 31 in string[] importPaths = [], in string[] stringImportPaths = [], 32 in string projDir = "$project") @safe pure { 33 34 immutable command = compileCommand(srcFiles[0], flags, importPaths, stringImportPaths, projDir); 35 return srcFiles.byPackage.map!(a => Target(a[0].packagePath.objFileName, 36 command, 37 a.map!(a => Target(a)).array)).array; 38 } 39 40 Target[] objectFilesPerModule(in string[] srcFiles, in string flags = "", 41 in string[] importPaths = [], in string[] stringImportPaths = [], 42 in string projDir = "$project") @safe pure { 43 44 immutable command = compileCommand(srcFiles[0], flags, importPaths, stringImportPaths, projDir); 45 return srcFiles.map!(a => objectFile(a, flags, importPaths, stringImportPaths, projDir)).array; 46 } 47 48 49 /** 50 * Compile-time function to that returns a list of Target objects 51 * corresponding to D source files from a particular directory 52 */ 53 Target[] dObjects(SrcDirs dirs = SrcDirs(), 54 Flags flags = Flags(), 55 ImportPaths includes = ImportPaths(), 56 StringImportPaths stringImports = StringImportPaths(), 57 SrcFiles srcFiles = SrcFiles(), 58 ExcludeFiles excludeFiles = ExcludeFiles()) 59 () { 60 61 Target[] dCompileInner(in string[] files) { 62 return objectFiles(files, flags.value, ["."] ~ includes.value, stringImports.value); 63 } 64 65 return srcObjects!dCompileInner("d", dirs.value, srcFiles.value, excludeFiles.value); 66 } 67 68 //compile-time verson of dExe, to be used with alias 69 //all paths relative to projectPath 70 Target dExe(App app, 71 Flags flags = Flags(), 72 ImportPaths importPaths = ImportPaths(), 73 StringImportPaths stringImportPaths = StringImportPaths(), 74 alias linkWithFunction = () { return cast(Target[])[];}) 75 () { 76 auto linkWith = linkWithFunction(); 77 return dExe(app, flags, importPaths, stringImportPaths, linkWith); 78 } 79 80 81 //regular runtime version of dExe 82 //all paths relative to projectPath 83 //@trusted because of .array 84 Target dExe(in App app, in Flags flags, 85 in ImportPaths importPaths, 86 in StringImportPaths stringImportPaths, 87 in Target[] linkWith) @trusted { 88 89 auto mainObj = objectFile(app.srcFileName, flags.value, importPaths.value, stringImportPaths.value); 90 const output = runDCompiler(buildPath(projectPath, app.srcFileName), flags.value, 91 importPaths.value, stringImportPaths.value); 92 93 const files = dMainDepSrcs(output).map!(a => a.removeProjectPath).array; 94 const dependencies = [mainObj] ~ objectFiles(files, flags.value, 95 importPaths.value, stringImportPaths.value); 96 97 return link(app.exeFileName, dependencies ~ linkWith); 98 } 99 100 101 //@trusted because of splitter 102 private auto runDCompiler(in string srcFileName, in string flags, 103 in string[] importPaths, in string[] stringImportPaths) @trusted { 104 105 import std.process: execute; 106 import std.exception: enforce; 107 import std.conv:text; 108 109 immutable compiler = "dmd"; 110 const compArgs = [compiler] ~ flags.splitter.array ~ 111 importPaths.map!(a => "-I" ~ buildPath(projectPath, a)).array ~ 112 stringImportPaths.map!(a => "-J" ~ buildPath(projectPath, a)).array ~ 113 ["-o-", "-v", "-c", srcFileName]; 114 const compRes = execute(compArgs); 115 enforce(compRes.status == 0, text("dExe could not run ", compArgs.join(" "), ":\n", compRes.output)); 116 return compRes.output; 117 }