1 module reggae.dub.info; 2 3 import reggae.build; 4 import reggae.rules; 5 import reggae.types; 6 import reggae.sorting; 7 8 public import std.typecons: Yes, No; 9 import std.typecons: Flag; 10 import std.algorithm: map, filter, find, splitter; 11 import std.array: array, join; 12 import std.path: buildPath; 13 import std.traits: isCallable; 14 import std.range: chain; 15 16 struct DubPackage { 17 string name; 18 string path; 19 string mainSourceFile; 20 string targetFileName; 21 string[] dflags; 22 string[] lflags; 23 string[] importPaths; 24 string[] stringImportPaths; 25 string[] files; 26 string targetType; 27 string[] versions; 28 string[] dependencies; 29 string[] libs; 30 bool active; 31 string[] preBuildCommands; 32 } 33 34 bool isStaticLibrary(in string fileName) @safe pure nothrow { 35 import std.path: extension; 36 return fileName.extension == ".a"; 37 } 38 39 struct DubInfo { 40 41 DubPackage[] packages; 42 43 Target[] toTargets(Flag!"main" includeMain = Yes.main, 44 in string compilerFlags = "", 45 Flag!"allTogether" allTogether = No.allTogether) @safe const { 46 47 import reggae.config: options; 48 import std.functional: not; 49 50 Target[] targets; 51 52 // -unittest should only apply to the main package 53 string deUnitTest(T)(in T index, in string flags) { 54 import std.string: replace; 55 return index == 0 56 ? flags 57 : flags.replace("-unittest", "").replace("-main", ""); 58 } 59 60 const(string)[] getVersions(T)(in T index) { 61 import std.algorithm: map; 62 import std.array: array; 63 64 const(string)[] ret = index == 0 65 ? packages[index].allOf!(a => a.versions)(packages) 66 : packages[0].versions ~ packages[index].versions; 67 68 return ret.map!(a => "-version=" ~ a).array; 69 } 70 71 foreach(const i, const dubPackage; packages) { 72 const importPaths = allImportPaths(); 73 const stringImportPaths = dubPackage.allOf!(a => a.packagePaths(a.stringImportPaths))(packages); 74 auto versions = getVersions(i); 75 76 //the path must be explicit for the other packages, implicit for the "main" 77 //package 78 const projDir = i == 0 ? "" : dubPackage.path; 79 80 immutable flags = chain(dubPackage.dflags, 81 versions, 82 [options.dflags], 83 [deUnitTest(i, compilerFlags)]) 84 .join(" "); 85 86 const files = dubPackage.files. 87 filter!(a => includeMain || a != dubPackage.mainSourceFile). 88 filter!(not!isStaticLibrary). 89 map!(a => buildPath(dubPackage.path, a)).array; 90 91 auto func = allTogether ? &dlangPackageObjectFilesTogether : &dlangPackageObjectFiles; 92 targets ~= func(files, flags, importPaths, stringImportPaths, projDir); 93 } 94 95 return targets; 96 } 97 98 ExeName exeName() @safe const pure nothrow { 99 return ExeName(packages[0].targetFileName); 100 } 101 102 string[] mainLinkerFlags() @safe pure nothrow const { 103 import std.array: join; 104 105 const pack = packages[0]; 106 return (pack.targetType == "library" || pack.targetType == "staticLibrary") ? ["-lib"] : []; 107 } 108 109 string[] linkerFlags() @safe const pure nothrow { 110 const allLibs = packages.map!(a => a.libs).join; 111 return 112 allLibs.map!(a => "-L-l" ~ a).array ~ 113 packages.map!(a => a.lflags.map!(b => "-L" ~ b)).join; 114 } 115 116 string[] allImportPaths() @safe nothrow const { 117 import reggae.config: options; 118 119 string[] paths; 120 auto rng = packages.map!(a => a.packagePaths(a.importPaths)); 121 foreach(p; rng) paths ~= p; 122 return paths ~ options.projectPath; 123 } 124 125 Target[] staticLibrarySources() @trusted nothrow const pure { 126 import std.algorithm: filter, map; 127 import std.array: array, join; 128 return packages. 129 map!(a => cast(string[])a.files.filter!isStaticLibrary.array). 130 join. 131 map!(a => Target(a)). 132 array; 133 } 134 } 135 136 137 private auto packagePaths(in DubPackage dubPackage, in string[] paths) @trusted nothrow { 138 return paths.map!(a => buildPath(dubPackage.path, a)).array; 139 } 140 141 //@trusted because of map.array 142 private string[] allOf(alias F)(in DubPackage pack, in DubPackage[] packages) @trusted nothrow { 143 144 import std.algorithm: find; 145 import std.array: array, empty, front; 146 147 string[] result; 148 //foreach(d; [pack.name] ~ pack.dependencies) doesn't compile with CTFE 149 //it seems to have to do with constness, replace string[] with const(string)[] 150 //and it won't compile 151 const dependencies = [pack.name] ~ pack.dependencies; 152 foreach(dependency; dependencies) { 153 154 auto depPack = packages.find!(a => a.name == dependency); 155 if(!depPack.empty) { 156 result ~= F(depPack.front).array; 157 } 158 } 159 return result; 160 }