1 /** 2 High-level rules for building dub projects. The rules in this module 3 only replicate what dub does itself. This allows a reggaefile.d to 4 reuse the information that dub already knows about. 5 */ 6 7 module reggae.rules.dub; 8 9 import reggae.config; // isDubProject 10 11 static if(isDubProject) { 12 13 import reggae.dub.info; 14 import reggae.types; 15 import reggae.build; 16 import reggae.rules.common; 17 import std.typecons; 18 import std.traits; 19 20 /** 21 Builds the main dub target (equivalent of "dub build") 22 */ 23 Target dubDefaultTarget(CompilerFlags compilerFlags = CompilerFlags(), 24 LinkerFlags linkerFlags = LinkerFlags(), 25 Flag!"allTogether" allTogether = No.allTogether) 26 () 27 { 28 import std.string: split; 29 30 enum config = "default"; 31 const dubInfo = configToDubInfo[config]; 32 enum targetName = dubInfo.targetName; 33 enum linkerFlags = dubInfo.mainLinkerFlags ~ linkerFlags.value.split(" "); 34 return dubTarget!(() { Target[] t; return t;}) 35 ( 36 targetName, 37 dubInfo, 38 compilerFlags.value, 39 linkerFlags, 40 Yes.main, 41 allTogether, 42 ); 43 } 44 45 46 /** 47 A target corresponding to `dub test` 48 */ 49 Target dubTestTarget(CompilerFlags compilerFlags = CompilerFlags(), 50 LinkerFlags linkerFlags = LinkerFlags()) 51 () 52 { 53 import std.typecons: No, Yes; 54 static if (__VERSION__ >= 2077) 55 enum allTogether = Yes.allTogether; 56 else 57 enum allTogether = Yes.allTogether; 58 59 return dubTestTarget!(compilerFlags, linkerFlags, allTogether)(); 60 } 61 62 /** 63 A target corresponding to `dub test` 64 */ 65 Target dubTestTarget(CompilerFlags compilerFlags = CompilerFlags(), 66 LinkerFlags linkerFlags = LinkerFlags(), 67 Flag!"allTogether" allTogether) 68 () 69 { 70 import std.string: split; 71 72 const config = "unittest" in configToDubInfo ? "unittest" : "default"; 73 74 auto actualCompilerFlags = compilerFlags.value; 75 if("unittest" !in configToDubInfo) actualCompilerFlags ~= " -unittest"; 76 77 const hasMain = configToDubInfo[config].packages[0].mainSourceFile != ""; 78 const extraLinkerFlags = hasMain ? [] : ["-main"]; 79 const actualLinkerFlags = extraLinkerFlags ~ linkerFlags.value.split(" "); 80 81 // since dmd has a bug pertaining to separate compilation and __traits(getUnitTests), 82 // we default here to compiling all-at-once for the unittest build 83 return dubTarget!()(TargetName("ut"), 84 configToDubInfo[config], 85 actualCompilerFlags, 86 actualLinkerFlags, 87 Yes.main, 88 allTogether); 89 } 90 91 /** 92 Builds a particular dub configuration (executable, unittest, etc.) 93 */ 94 Target dubConfigurationTarget(Configuration config = Configuration("default"), 95 CompilerFlags compilerFlags = CompilerFlags(), 96 LinkerFlags linkerFlags = LinkerFlags(), 97 Flag!"main" includeMain = Yes.main, 98 Flag!"allTogether" allTogether = No.allTogether, 99 alias objsFunction = () { Target[] t; return t; }, 100 ) 101 () if(isCallable!objsFunction) 102 { 103 import std.string: split; 104 105 const dubInfo = configToDubInfo[config.value]; 106 return dubTarget!objsFunction(dubInfo.targetName, 107 dubInfo, 108 compilerFlags.value, 109 linkerFlags.value.split(" "), 110 includeMain, 111 allTogether); 112 } 113 114 115 Target dubTarget(alias objsFunction = () { Target[] t; return t;}) 116 (in TargetName targetName, 117 in DubInfo dubInfo, 118 in string compilerFlags, 119 in string[] linkerFlags = [], 120 in Flag!"main" includeMain = Yes.main, 121 in Flag!"allTogether" allTogether = No.allTogether) 122 { 123 124 import reggae.rules.common: staticLibraryTarget; 125 import reggae.config: options; 126 import reggae.dub.info: DubObjsDir; 127 import std.array: join; 128 import std.path: buildPath; 129 import std.file: getcwd; 130 131 const isStaticLibrary = 132 dubInfo.targetType == TargetType.library || 133 dubInfo.targetType == TargetType.staticLibrary; 134 const sharedFlags = dubInfo.targetType == TargetType.dynamicLibrary 135 ? "-shared" 136 : ""; 137 const allLinkerFlags = (linkerFlags ~ dubInfo.linkerFlags ~ sharedFlags).join(" "); 138 const postBuildCommands = dubInfo.postBuildCommands; 139 140 // otherwise the target wouldn't be top-level in the presence of 141 // postBuildCommands 142 const realName = postBuildCommands == "" 143 ? targetName.value 144 : buildPath("$project", targetName.value); 145 146 auto dubObjs = dubInfo.toTargets(includeMain, 147 compilerFlags, 148 allTogether, 149 DubObjsDir(options.dubObjsDir, realName ~ ".objs")); 150 auto allObjs = objsFunction() ~ dubObjs; 151 152 auto target = isStaticLibrary 153 ? staticLibraryTarget(realName, allObjs)[0] 154 : link(ExeName(realName), 155 allObjs, 156 Flags(allLinkerFlags)); 157 158 return postBuildCommands == "" 159 ? target 160 : Target.phony("postBuild", postBuildCommands, target); 161 } 162 163 private string deabsolutePath(in string path) { 164 version(Windows) throw new Exception("not implemented yet"); 165 return path[1..$]; 166 } 167 168 }