1 /** 2 High-level rules for compiling D files. For a D-only application with 3 no dub dependencies, $(D scriptlike) should suffice. If the app depends 4 on dub packages, consult the reggae.rules.dub module instead. 5 */ 6 7 module reggae.rules.d; 8 9 import reggae.types; 10 import reggae.build; 11 import reggae.sorting; 12 import reggae.dependencies: dMainDepSrcs; 13 import reggae.rules.common; 14 import std.algorithm; 15 import std.array; 16 17 18 19 //generate object file(s) for a D package. By default generates one per package, 20 //if reggae.config.perModule is true, generates one per module 21 Target[] dlangPackageObjectFiles(in string[] srcFiles, in string flags = "", 22 in string[] importPaths = [], in string[] stringImportPaths = [], 23 in string projDir = "$project") @safe pure { 24 import reggae.config; 25 auto func = options.perModule ? &dlangPackageObjectFilesPerModule : &dlangPackageObjectFilesPerPackage; 26 return func(srcFiles, flags, importPaths, stringImportPaths, projDir); 27 } 28 29 Target[] dlangPackageObjectFilesPerPackage(in string[] srcFiles, in string flags = "", 30 in string[] importPaths = [], in string[] stringImportPaths = [], 31 in string projDir = "$project") @trusted pure { 32 33 if(srcFiles.empty) return []; 34 const 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[] dlangPackageObjectFilesPerModule(in string[] srcFiles, in string flags = "", 41 in string[] importPaths = [], in string[] stringImportPaths = [], 42 in string projDir = "$project") @trusted pure { 43 return srcFiles.map!(a => objectFile(const SourceFile(a), 44 const Flags(flags), 45 const ImportPaths(importPaths), 46 const StringImportPaths(stringImportPaths), 47 projDir)).array; 48 } 49 50 51 /** 52 Currently only works for D. This convenience rule builds a D scriptlike, automatically 53 calculating which files must be compiled in a similar way to rdmd. 54 All paths are relative to projectPath. 55 This template function is provided as a wrapper around the regular runtime version 56 below so it can be aliased without trying to call it at runtime. Basically, it's a 57 way to use the runtime scriptlike without having define a function in reggaefile.d, 58 i.e.: 59 $(D 60 alias myApp = scriptlike!(...); 61 mixin build!(myApp); 62 ) 63 vs. 64 $(D 65 Build myBuld() { return scriptlike(..); } 66 ) 67 */ 68 Target scriptlike(App app, 69 Flags flags = Flags(), 70 ImportPaths importPaths = ImportPaths(), 71 StringImportPaths stringImportPaths = StringImportPaths(), 72 alias linkWithFunction = () { return cast(Target[])[];}) 73 () @trusted { 74 auto linkWith = linkWithFunction(); 75 import reggae.config; 76 return scriptlike(options.projectPath, app, flags, importPaths, stringImportPaths, linkWith); 77 } 78 79 80 //regular runtime version of scriptlike 81 //all paths relative to projectPath 82 //@trusted because of .array 83 Target scriptlike(in string projectPath, 84 in App app, in Flags flags, 85 in ImportPaths importPaths, 86 in StringImportPaths stringImportPaths, 87 in Target[] linkWith) @trusted { 88 89 if(getLanguage(app.srcFileName.value) != Language.D) 90 throw new Exception("'scriptlike' rule only works with D files"); 91 92 auto mainObj = objectFile(SourceFile(app.srcFileName.value), flags, importPaths, stringImportPaths); 93 const output = runDCompiler(projectPath, buildPath(projectPath, app.srcFileName.value), flags.value, 94 importPaths.value, stringImportPaths.value); 95 96 const files = dMainDepSrcs(output).map!(a => a.removeProjectPath).array; 97 const dependencies = [mainObj] ~ dlangPackageObjectFiles(files, flags.value, 98 importPaths.value, stringImportPaths.value); 99 100 return link(ExeName(app.exeFileName.value), dependencies ~ linkWith); 101 } 102 103 104 //@trusted because of splitter 105 private auto runDCompiler(in string projectPath, 106 in string srcFileName, 107 in string flags, 108 in string[] importPaths, 109 in string[] stringImportPaths) @trusted { 110 111 import std.process: execute; 112 import std.exception: enforce; 113 import std.conv:text; 114 115 immutable compiler = "dmd"; 116 const compArgs = [compiler] ~ flags.splitter.array ~ 117 importPaths.map!(a => "-I" ~ buildPath(projectPath, a)).array ~ 118 stringImportPaths.map!(a => "-J" ~ buildPath(projectPath, a)).array ~ 119 ["-o-", "-v", "-c", srcFileName]; 120 const compRes = execute(compArgs); 121 enforce(compRes.status == 0, text("scriptlike could not run ", compArgs.join(" "), ":\n", compRes.output)); 122 return compRes.output; 123 }