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 private string dCompileCommand(in string flags = "", 15 in string[] importPaths = [], in string[] stringImportPaths = [], 16 in string projDir = "$project") @safe pure { 17 immutable importParams = importPaths.map!(a => "-I" ~ buildPath(projDir, a)).join(","); 18 immutable stringParams = stringImportPaths.map!(a => "-J" ~ buildPath(projDir, a)).join(","); 19 immutable flagParams = flags.splitter.join(","); 20 return ["_dcompile ", "includes=" ~ importParams, "flags=" ~ flagParams, 21 "stringImports=" ~ stringParams].join(" "); 22 } 23 24 Target[] dCompileGrouped(in string[] srcFiles, in string flags = "", 25 in string[] importPaths = [], in string[] stringImportPaths = [], 26 in string projDir = "$project") @safe { 27 import reggae.config; 28 auto func = perModule ? &dCompilePerModule : &dCompilePerPackage; 29 return func(srcFiles, flags, importPaths, stringImportPaths, projDir); 30 } 31 32 Target[] dCompilePerPackage(in string[] srcFiles, in string flags = "", 33 in string[] importPaths = [], in string[] stringImportPaths = [], 34 in string projDir = "$project") @safe { 35 36 immutable command = dCompileCommand(flags, importPaths, stringImportPaths, projDir); 37 return srcFiles.byPackage.map!(a => Target(a[0].packagePath.objFileName, 38 command, 39 a.map!(a => Target(a)).array)).array; 40 } 41 42 Target[] dCompilePerModule(in string[] srcFiles, in string flags = "", 43 in string[] importPaths = [], in string[] stringImportPaths = [], 44 in string projDir = "$project") @safe { 45 46 immutable command = dCompileCommand(flags, importPaths, stringImportPaths, projDir); 47 return srcFiles.map!(a => dCompile(a, flags, importPaths, stringImportPaths, projDir)).array; 48 } 49 50 51 //@trusted because of join 52 Target dCompile(in string srcFileName, in string flags = "", 53 in string[] importPaths = [], in string[] stringImportPaths = [], 54 in string projDir = "$project") @trusted pure { 55 56 immutable command = dCompileCommand(flags, importPaths, stringImportPaths, projDir); 57 return Target(srcFileName.objFileName, command, [Target(srcFileName)]); 58 } 59 60 /** 61 * Compile-time function to that returns a list of Target objects 62 * corresponding to D source files from a particular directory 63 */ 64 Target[] dObjects(SrcDirs dirs = SrcDirs(), 65 Flags flags = Flags(), 66 ImportPaths includes = ImportPaths(), 67 StringImportPaths stringImports = StringImportPaths(), 68 SrcFiles srcFiles = SrcFiles(), 69 ExcludeFiles excludeFiles = ExcludeFiles()) 70 () { 71 72 Target[] dCompileInner(in string[] files) { 73 return dCompileGrouped(files, flags.value, ["."] ~ includes.value, stringImports.value); 74 } 75 76 return srcObjects!dCompileInner("d", dirs.value, srcFiles.value, excludeFiles.value); 77 } 78 79 //compile-time verson of dExe, to be used with alias 80 //all paths relative to projectPath 81 Target dExe(App app, 82 Flags flags = Flags(), 83 ImportPaths importPaths = ImportPaths(), 84 StringImportPaths stringImportPaths = StringImportPaths(), 85 alias linkWithFunction = () { return cast(Target[])[];}) 86 () { 87 auto linkWith = linkWithFunction(); 88 return dExe(app, flags, importPaths, stringImportPaths, linkWith); 89 } 90 91 92 //regular runtime version of dExe 93 //all paths relative to projectPath 94 //@trusted because of .array 95 Target dExe(in App app, in Flags flags, 96 in ImportPaths importPaths, 97 in StringImportPaths stringImportPaths, 98 in Target[] linkWith) @trusted { 99 100 auto mainObj = dCompile(app.srcFileName, flags.value, importPaths.value, stringImportPaths.value); 101 const output = runDCompiler(buildPath(projectPath, app.srcFileName), flags.value, 102 importPaths.value, stringImportPaths.value); 103 104 const files = dMainDepSrcs(output).map!(a => a.removeProjectPath).array; 105 const dependencies = [mainObj] ~ dCompileGrouped(files, flags.value, 106 importPaths.value, stringImportPaths.value); 107 108 return dLink(app.exeFileName, dependencies ~ linkWith); 109 } 110 111 112 Target dLink(in string exeName, in Target[] dependencies, in string flags = "") @safe pure nothrow { 113 auto cmd = "_dlink"; 114 if(flags != "") cmd ~= " flags=" ~ flags; 115 return Target(exeName, cmd, dependencies); 116 } 117 118 119 //@trusted because of splitter 120 private auto runDCompiler(in string srcFileName, in string flags, 121 in string[] importPaths, in string[] stringImportPaths) @trusted { 122 123 import std.process: execute; 124 import std.exception: enforce; 125 import std.conv:text; 126 127 immutable compiler = "dmd"; 128 const compArgs = [compiler] ~ flags.splitter.array ~ 129 importPaths.map!(a => "-I" ~ buildPath(projectPath, a)).array ~ 130 stringImportPaths.map!(a => "-J" ~ buildPath(projectPath, a)).array ~ 131 ["-o-", "-v", "-c", srcFileName]; 132 const compRes = execute(compArgs); 133 enforce(compRes.status == 0, text("dExe could not run ", compArgs.join(" "), ":\n", compRes.output)); 134 return compRes.output; 135 }