1 module reggae.dub.info; 2 3 import reggae.build; 4 import reggae.rules; 5 import reggae.types; 6 import reggae.config: options; 7 import reggae.sorting; 8 9 public import std.typecons: Yes, No; 10 import std.typecons: Flag; 11 import std.algorithm: map, filter, find, splitter; 12 import std.array: array, join; 13 import std.path: buildPath; 14 import std.traits: isCallable; 15 import std.range: chain; 16 17 struct DubPackage { 18 string name; 19 string path; 20 string mainSourceFile; 21 string targetFileName; 22 string[] flags; 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 } 32 33 struct DubInfo { 34 DubPackage[] packages; 35 36 Target[] toTargets(Flag!"main" includeMain = Yes.main, in string compilerFlags = "") @safe const { 37 Target[] targets; 38 39 foreach(const i, const dubPackage; packages) { 40 const importPaths = allImportPaths(); 41 const stringImportPaths = dubPackage.allOf!(a => a.packagePaths(a.stringImportPaths))(packages); 42 auto versions = dubPackage.allOf!(a => a.versions)(packages).map!(a => "-version=" ~ a); 43 //the path must be explicit for the other packages, implicit for the "main" 44 //package 45 const projDir = i == 0 ? "" : dubPackage.path; 46 47 immutable flags = chain(dubPackage.flags, versions).join(" ") ~ 48 " " ~ options.dflags ~ " " ~ compilerFlags; 49 50 const files = dubPackage. 51 files. 52 filter!(a => includeMain || a != dubPackage.mainSourceFile). 53 map!(a => buildPath(dubPackage.path, a)).array; 54 55 targets ~= dlangPackageObjectFiles(files, flags, importPaths, stringImportPaths, projDir); 56 } 57 58 return targets; 59 } 60 61 //@trusted: array 62 Target mainTarget(string flagsStr = "") @trusted const { 63 string[] libs; 64 foreach(p; packages) { 65 libs ~= p.libs; 66 } 67 68 const pack = packages[0]; 69 auto flags = flagsStr.splitter(" ").array; 70 flags ~= pack.targetType == "library" ? ["-lib"] : []; 71 //hacky hack for dub describe on vibe.d projects 72 flags ~= libs.filter!(a => a != "ev").map!(a => "-L-l" ~ a).array; 73 if(packages[0].targetType == "staticLibrary") flags ~= "-lib"; 74 return link(ExeName(packages[0].targetFileName), 75 toTargets(), 76 Flags(flags.join(" "))); 77 } 78 79 string[] mainTargetImportPaths() @trusted nothrow const { 80 return packages[0].allOf!(a => a.packagePaths(a.importPaths))(packages); 81 } 82 83 string[][] fetchCommands() @safe pure nothrow const { 84 return packages[0].dependencies.map!(a => ["dub", "fetch", a]).array; 85 } 86 87 string[] allImportPaths() @safe nothrow const { 88 string[] paths; 89 auto rng = packages.map!(a => a.packagePaths(a.importPaths)); 90 foreach(p; rng) paths ~= p; 91 return paths ~ options.projectPath; 92 } 93 } 94 95 96 private auto packagePaths(in DubPackage pack, in string[] paths) @trusted nothrow { 97 return paths.map!(a => buildPath(pack.path, a)).array; 98 } 99 100 //@trusted because of map.array 101 private string[] allOf(alias F)(in DubPackage pack, in DubPackage[] packages) @trusted nothrow { 102 string[] paths; 103 //foreach(d; [pack.name] ~ pack.dependencies) doesn't compile with CTFE 104 //it seems to have to do with constness, replace string[] with const(string)[] 105 //and it won't compile 106 string[] dependencies = [pack.name]; 107 dependencies ~= pack.dependencies; 108 foreach(dependency; dependencies) { 109 import std.range; 110 const depPack = packages.find!(a => a.name == dependency).front; 111 paths ~= F(depPack).array; 112 } 113 return paths; 114 }