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(), LinkerFlags linkerFlags = LinkerFlags())() { 50 import std.string: split; 51 52 const config = "unittest" in configToDubInfo ? "unittest" : "default"; 53 54 auto actualCompilerFlags = compilerFlags.value; 55 if("unittest" !in configToDubInfo) actualCompilerFlags ~= " -unittest"; 56 57 const hasMain = configToDubInfo[config].packages[0].mainSourceFile != ""; 58 const extraLinkerFlags = hasMain ? [] : ["-main"]; 59 const actualLinkerFlags = extraLinkerFlags ~ linkerFlags.value.split(" "); 60 61 // since dmd has a bug pertaining to separate compilation and __traits(getUnitTests), 62 // we default here to compiling all-at-once for the unittest build 63 return dubTarget!()(TargetName("ut"), 64 configToDubInfo[config], 65 actualCompilerFlags, 66 actualLinkerFlags, 67 Yes.main, 68 Yes.allTogether); 69 } 70 71 /** 72 Builds a particular dub configuration (executable, unittest, etc.) 73 */ 74 Target dubConfigurationTarget(Configuration config = Configuration("default"), 75 CompilerFlags compilerFlags = CompilerFlags(), 76 LinkerFlags linkerFlags = LinkerFlags(), 77 Flag!"main" includeMain = Yes.main, 78 Flag!"allTogether" allTogether = No.allTogether, 79 alias objsFunction = () { Target[] t; return t; }, 80 ) 81 () if(isCallable!objsFunction) 82 { 83 import std.string: split; 84 85 const dubInfo = configToDubInfo[config.value]; 86 return dubTarget!objsFunction(dubInfo.targetName, 87 dubInfo, 88 compilerFlags.value, 89 linkerFlags.value.split(" "), 90 includeMain, 91 allTogether); 92 } 93 94 95 Target dubTarget(alias objsFunction = () { Target[] t; return t;}) 96 (in TargetName targetName, 97 in DubInfo dubInfo, 98 in string compilerFlags, 99 in string[] linkerFlags = [], 100 in Flag!"main" includeMain = Yes.main, 101 in Flag!"allTogether" allTogether = No.allTogether) 102 { 103 104 import reggae.rules.common: staticLibraryTarget; 105 import std.array: join; 106 import std.path: buildPath; 107 108 const isStaticLibrary = 109 dubInfo.targetType == TargetType.library || 110 dubInfo.targetType == TargetType.staticLibrary; 111 const sharedFlags = dubInfo.targetType == TargetType.dynamicLibrary 112 ? "-shared" 113 : ""; 114 const allLinkerFlags = (linkerFlags ~ dubInfo.linkerFlags ~ sharedFlags).join(" "); 115 auto dubObjs = dubInfo.toTargets(includeMain, compilerFlags, allTogether); 116 auto allObjs = objsFunction() ~ dubObjs; 117 118 const postBuildCommands = dubInfo.postBuildCommands; 119 120 string realName() { 121 // otherwise the target wouldn't be top-level in the presence of 122 // postBuildCommands 123 return postBuildCommands == "" 124 ? targetName.value 125 : buildPath("$project", targetName.value); 126 } 127 128 auto target = isStaticLibrary 129 ? staticLibraryTarget(realName, allObjs)[0] 130 : link(ExeName(realName), 131 allObjs, 132 Flags(allLinkerFlags)); 133 134 return postBuildCommands == "" 135 ? target 136 : Target.phony("postBuild", postBuildCommands, target); 137 } 138 }