cmFastbuildNormalTargetGenerator.cxx 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmFastbuildNormalTargetGenerator.h"
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstddef>
  7. #include <functional>
  8. #include <iterator>
  9. #include <map>
  10. #include <sstream>
  11. #include <string>
  12. #include <unordered_map>
  13. #include <unordered_set>
  14. #include <utility>
  15. #include <cm/memory>
  16. #include <cm/optional>
  17. #include <cm/string_view>
  18. #include <cmext/string_view>
  19. #include "cmsys/FStream.hxx"
  20. #include "cmCommonTargetGenerator.h"
  21. #include "cmCryptoHash.h"
  22. #include "cmFastbuildTargetGenerator.h"
  23. #include "cmGeneratedFileStream.h"
  24. #include "cmGeneratorExpression.h"
  25. #include "cmGeneratorTarget.h"
  26. #include "cmGlobalCommonGenerator.h"
  27. #include "cmGlobalFastbuildGenerator.h"
  28. #include "cmLinkLineComputer.h"
  29. #include "cmLinkLineDeviceComputer.h"
  30. #include "cmList.h"
  31. #include "cmListFileCache.h"
  32. #include "cmLocalCommonGenerator.h"
  33. #include "cmLocalFastbuildGenerator.h"
  34. #include "cmLocalGenerator.h"
  35. #include "cmMakefile.h"
  36. #include "cmOSXBundleGenerator.h"
  37. #include "cmObjectLocation.h"
  38. #include "cmOutputConverter.h"
  39. #include "cmSourceFile.h"
  40. #include "cmState.h"
  41. #include "cmStateDirectory.h"
  42. #include "cmStateSnapshot.h"
  43. #include "cmStateTypes.h"
  44. #include "cmStringAlgorithms.h"
  45. #include "cmSystemTools.h"
  46. #include "cmTarget.h"
  47. #include "cmTargetDepend.h"
  48. #include "cmValue.h"
  49. #include "cmake.h"
  50. namespace {
  51. std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
  52. std::string const COMPILE_OPTIONS("COMPILE_OPTIONS");
  53. std::string const COMPILE_FLAGS("COMPILE_FLAGS");
  54. std::string const CMAKE_LANGUAGE("CMAKE");
  55. std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
  56. std::string const CMAKE_UNITY_BUILD("CMAKE_UNITY_BUILD");
  57. std::string const CMAKE_UNITY_BUILD_BATCH_SIZE("CMAKE_UNITY_BUILD_BATCH_SIZE");
  58. std::string const UNITY_BUILD("UNITY_BUILD");
  59. std::string const UNITY_BUILD_BATCH_SIZE("UNITY_BUILD_BATCH_SIZE");
  60. std::string const SKIP_UNITY_BUILD_INCLUSION("SKIP_UNITY_BUILD_INCLUSION");
  61. std::string const UNITY_GROUP("UNITY_GROUP");
  62. #ifdef _WIN32
  63. char const kPATH_SLASH = '\\';
  64. #else
  65. char const kPATH_SLASH = '/';
  66. #endif
  67. } // anonymous namespace
  68. cmFastbuildNormalTargetGenerator::cmFastbuildNormalTargetGenerator(
  69. cmGeneratorTarget* gt, std::string configParam)
  70. : cmFastbuildTargetGenerator(gt, std::move(configParam))
  71. , RulePlaceholderExpander(
  72. this->LocalCommonGenerator->CreateRulePlaceholderExpander())
  73. , ObjectOutDir(this->GetGlobalGenerator()->ConvertToFastbuildPath(
  74. this->GeneratorTarget->GetObjectDirectory(Config)))
  75. , Languages(GetLanguages())
  76. , CompileObjectCmakeRules(GetCompileObjectCommand())
  77. , CudaCompileMode(this->GetCudaCompileMode())
  78. {
  79. LogMessage(cmStrCat("objectOutDir: ", ObjectOutDir));
  80. this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(gt);
  81. this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
  82. // Quotes to account for potential spaces.
  83. RulePlaceholderExpander->SetTargetImpLib(
  84. "\"" FASTBUILD_DOLLAR_TAG "TargetOutputImplib" FASTBUILD_DOLLAR_TAG "\"");
  85. for (auto const& lang : Languages) {
  86. TargetIncludesByLanguage[lang] = this->GetIncludes(lang, Config);
  87. LogMessage("targetIncludes for lang " + lang + " = " +
  88. TargetIncludesByLanguage[lang]);
  89. for (auto const& arch : this->GetArches()) {
  90. auto& flags = CompileFlagsByLangAndArch[std::make_pair(lang, arch)];
  91. this->LocalCommonGenerator->GetTargetCompileFlags(
  92. this->GeneratorTarget, Config, lang, flags, arch);
  93. LogMessage(
  94. cmStrCat("Lang: ", lang, ", arch: ", arch, ", flags: ", flags));
  95. }
  96. }
  97. }
  98. std::string cmFastbuildNormalTargetGenerator::DetectCompilerFlags(
  99. cmSourceFile const& srcFile, std::string const& arch)
  100. {
  101. std::string const language = srcFile.GetLanguage();
  102. cmGeneratorExpressionInterpreter genexInterpreter(
  103. this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
  104. std::vector<std::string> sourceIncludesVec;
  105. if (cmValue cincludes = srcFile.GetProperty(INCLUDE_DIRECTORIES)) {
  106. this->LocalGenerator->AppendIncludeDirectories(
  107. sourceIncludesVec,
  108. genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), srcFile);
  109. }
  110. std::string sourceIncludesStr = this->LocalGenerator->GetIncludeFlags(
  111. sourceIncludesVec, this->GeneratorTarget, language, Config, false);
  112. LogMessage(cmStrCat("sourceIncludes = ", sourceIncludesStr));
  113. std::string compileFlags =
  114. CompileFlagsByLangAndArch[std::make_pair(language, arch)];
  115. this->GeneratorTarget->AddExplicitLanguageFlags(compileFlags, srcFile);
  116. if (cmValue const cflags = srcFile.GetProperty(COMPILE_FLAGS)) {
  117. this->LocalGenerator->AppendFlags(
  118. compileFlags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
  119. }
  120. if (cmValue const coptions = srcFile.GetProperty(COMPILE_OPTIONS)) {
  121. this->LocalGenerator->AppendCompileOptions(
  122. compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
  123. }
  124. // Source includes take precedence over target includes.
  125. this->LocalGenerator->AppendFlags(compileFlags, sourceIncludesStr);
  126. this->LocalGenerator->AppendFlags(compileFlags,
  127. TargetIncludesByLanguage[language]);
  128. if (language == "Fortran") {
  129. this->AppendFortranFormatFlags(compileFlags, srcFile);
  130. this->AppendFortranPreprocessFlags(compileFlags, srcFile);
  131. }
  132. LogMessage(cmStrCat("compileFlags = ", compileFlags));
  133. return compileFlags;
  134. }
  135. void cmFastbuildNormalTargetGenerator::SplitLinkerFromArgs(
  136. std::string const& command, std::string& outLinkerExecutable,
  137. std::string& outLinkerArgs) const
  138. {
  139. #ifdef _WIN32
  140. std::vector<std::string> args;
  141. std::string tmp;
  142. cmSystemTools::SplitProgramFromArgs(command, tmp, outLinkerArgs);
  143. // cmLocalGenerator::GetStaticLibraryFlags seems to add empty quotes when
  144. // appending "STATIC_LIBRARY_FLAGS_DEBUG"...
  145. cmSystemTools::ReplaceString(outLinkerArgs, "\"\"", "");
  146. cmSystemTools::ParseWindowsCommandLine(command.c_str(), args);
  147. outLinkerExecutable = std::move(args[0]);
  148. #else
  149. cmSystemTools::SplitProgramFromArgs(command, outLinkerExecutable,
  150. outLinkerArgs);
  151. #endif
  152. }
  153. void cmFastbuildNormalTargetGenerator::GetLinkerExecutableAndArgs(
  154. std::string const& command, std::string& outLinkerExecutable,
  155. std::string& outLinkerArgs)
  156. {
  157. if (command.empty()) {
  158. return;
  159. }
  160. LogMessage("Link Command: " + command);
  161. auto const& compilers = this->GetGlobalGenerator()->Compilers;
  162. auto const linkerLauncherVarName = FASTBUILD_LINKER_LAUNCHER_PREFIX +
  163. this->GeneratorTarget->GetLinkerLanguage(Config);
  164. auto const iter = compilers.find(linkerLauncherVarName);
  165. // Tested in "RunCMake.LinkerLauncher" test.
  166. if (iter != compilers.end()) {
  167. LogMessage("Linker launcher: " + iter->first);
  168. outLinkerExecutable = iter->second.Executable;
  169. outLinkerArgs = cmStrCat(iter->second.Args, " ", command);
  170. } else {
  171. SplitLinkerFromArgs(command, outLinkerExecutable, outLinkerArgs);
  172. }
  173. LogMessage("Linker Exe: " + outLinkerExecutable);
  174. LogMessage("Linker args: " + outLinkerArgs);
  175. }
  176. bool cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(
  177. std::string& command, std::string const& arch,
  178. cmGeneratorTarget::Names const& targetNames)
  179. {
  180. std::string const linkLanguage =
  181. this->GeneratorTarget->GetLinkerLanguage(Config);
  182. if (linkLanguage.empty()) {
  183. cmSystemTools::Error("CMake can not determine linker language for "
  184. "target: " +
  185. this->GeneratorTarget->GetName());
  186. return false;
  187. }
  188. LogMessage("linkLanguage: " + linkLanguage);
  189. std::string linkLibs;
  190. std::string targetFlags;
  191. std::string linkFlags;
  192. std::string frameworkPath;
  193. // Tested in "RunCMake.StandardLinkDirectories" test.
  194. std::string linkPath;
  195. std::unique_ptr<cmLinkLineComputer> const linkLineComputer =
  196. this->GetGlobalGenerator()->CreateLinkLineComputer(
  197. this->LocalGenerator,
  198. this->GetLocalGenerator()->GetStateSnapshot().GetDirectory());
  199. this->LocalCommonGenerator->GetTargetFlags(
  200. linkLineComputer.get(), Config, linkLibs, targetFlags, linkFlags,
  201. frameworkPath, linkPath, this->GeneratorTarget);
  202. // cmLocalGenerator::GetStaticLibraryFlags seems to add empty quotes when
  203. // appending "STATIC_LIBRARY_FLAGS_DEBUG"...
  204. cmSystemTools::ReplaceString(linkFlags, "\"\"", "");
  205. LogMessage("linkLibs: " + linkLibs);
  206. LogMessage("targetFlags: " + targetFlags);
  207. LogMessage("linkFlags: " + linkFlags);
  208. LogMessage("frameworkPath: " + frameworkPath);
  209. LogMessage("linkPath: " + linkPath);
  210. LogMessage("MANIFESTS: " + this->GetManifests(Config));
  211. cmComputeLinkInformation* linkInfo =
  212. this->GeneratorTarget->GetLinkInformation(Config);
  213. if (!linkInfo) {
  214. return false;
  215. }
  216. // Tested in "RunCMake.RuntimePath" test.
  217. std::string const rpath = linkLineComputer->ComputeRPath(*linkInfo);
  218. LogMessage("RPath: " + rpath);
  219. if (!linkFlags.empty()) {
  220. linkFlags += " ";
  221. }
  222. linkFlags += cmJoin({ rpath, frameworkPath, linkPath }, " ");
  223. cmStateEnums::TargetType const targetType = this->GeneratorTarget->GetType();
  224. // Add OS X version flags, if any.
  225. if (targetType == cmStateEnums::SHARED_LIBRARY ||
  226. targetType == cmStateEnums::MODULE_LIBRARY) {
  227. this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
  228. this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
  229. }
  230. // Add Arch flags to link flags for binaries
  231. if (targetType == cmStateEnums::SHARED_LIBRARY ||
  232. targetType == cmStateEnums::MODULE_LIBRARY ||
  233. targetType == cmStateEnums::EXECUTABLE) {
  234. this->LocalCommonGenerator->AddArchitectureFlags(
  235. linkFlags, this->GeneratorTarget, linkLanguage, Config, arch);
  236. this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags(
  237. linkFlags, this->GetGeneratorTarget(), linkLanguage);
  238. }
  239. cmRulePlaceholderExpander::RuleVariables vars;
  240. vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
  241. vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
  242. vars.Config = Config.c_str();
  243. vars.Language = linkLanguage.c_str();
  244. std::string const manifests =
  245. cmJoin(this->GetManifestsAsFastbuildPath(), " ");
  246. vars.Manifests = manifests.c_str();
  247. std::string const stdLibString = this->Makefile->GetSafeDefinition(
  248. cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES"));
  249. LogMessage(cmStrCat("Target type: ", this->GeneratorTarget->GetType()));
  250. if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
  251. this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
  252. this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
  253. vars.Objects = FASTBUILD_1_0_INPUT_PLACEHOLDER;
  254. vars.LinkLibraries = stdLibString.c_str();
  255. } else {
  256. vars.Objects = FASTBUILD_1_INPUT_PLACEHOLDER;
  257. }
  258. vars.ObjectDir = FASTBUILD_DOLLAR_TAG "TargetOutDir" FASTBUILD_DOLLAR_TAG;
  259. vars.Target = FASTBUILD_2_INPUT_PLACEHOLDER;
  260. std::string install_dir;
  261. std::string target_so_name;
  262. if (this->GeneratorTarget->HasSOName(Config)) {
  263. vars.SONameFlag = this->Makefile->GetSONameFlag(
  264. this->GeneratorTarget->GetLinkerLanguage(Config));
  265. target_so_name =
  266. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(targetNames.SharedObject);
  267. vars.TargetSOName = target_so_name.c_str();
  268. // Tested in "RunCMake.RuntimePath / RunCMake.INSTALL_NAME_DIR"
  269. // tests.
  270. install_dir = this->LocalGenerator->ConvertToOutputFormat(
  271. this->GeneratorTarget->GetInstallNameDirForBuildTree(Config),
  272. cmOutputConverter::SHELL);
  273. vars.TargetInstallNameDir = install_dir.c_str();
  274. } else {
  275. vars.TargetSOName = "";
  276. }
  277. vars.TargetPDB = FASTBUILD_DOLLAR_TAG "LinkerPDB" FASTBUILD_DOLLAR_TAG;
  278. // Setup the target version.
  279. std::string targetVersionMajor;
  280. std::string targetVersionMinor;
  281. {
  282. std::ostringstream majorStream;
  283. std::ostringstream minorStream;
  284. int major;
  285. int minor;
  286. this->GeneratorTarget->GetTargetVersion(major, minor);
  287. majorStream << major;
  288. minorStream << minor;
  289. targetVersionMajor = majorStream.str();
  290. targetVersionMinor = minorStream.str();
  291. }
  292. vars.TargetVersionMajor = targetVersionMajor.c_str();
  293. vars.TargetVersionMinor = targetVersionMinor.c_str();
  294. vars.Defines =
  295. FASTBUILD_DOLLAR_TAG "CompileDefineFlags" FASTBUILD_DOLLAR_TAG;
  296. vars.Flags = targetFlags.c_str();
  297. vars.LinkFlags = linkFlags.c_str();
  298. vars.LanguageCompileFlags = "";
  299. std::string const linker = this->GeneratorTarget->GetLinkerTool(Config);
  300. vars.Linker = linker.c_str();
  301. std::string const targetSupportPath = this->ConvertToFastbuildPath(
  302. this->GetGeneratorTarget()->GetCMFSupportDirectory());
  303. vars.TargetSupportDir = targetSupportPath.c_str();
  304. LogMessage("linkFlags: " + linkFlags);
  305. LogMessage("linker: " + linker);
  306. std::string linkRule = GetLinkCommand();
  307. ApplyLinkRuleLauncher(linkRule);
  308. RulePlaceholderExpander->ExpandRuleVariables(
  309. dynamic_cast<cmLocalFastbuildGenerator*>(this->LocalCommonGenerator),
  310. linkRule, vars);
  311. command = std::move(linkRule);
  312. LogMessage(cmStrCat("Expanded link command: ", command));
  313. return true;
  314. }
  315. void cmFastbuildNormalTargetGenerator::ApplyLinkRuleLauncher(
  316. std::string& command)
  317. {
  318. std::string const val = this->GetLocalGenerator()->GetRuleLauncher(
  319. this->GetGeneratorTarget(), "RULE_LAUNCH_LINK", Config);
  320. if (cmNonempty(val)) {
  321. LogMessage("RULE_LAUNCH_LINK: " + val);
  322. command = cmStrCat(val, " ", command);
  323. }
  324. }
  325. void cmFastbuildNormalTargetGenerator::ApplyLWYUToLinkerCommand(
  326. FastbuildLinkerNode& linkerNode)
  327. {
  328. cmValue const lwyuCheck =
  329. this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
  330. if (this->UseLWYU && lwyuCheck) {
  331. LogMessage("UseLWYU=true");
  332. std::string args = " -E __run_co_compile --lwyu=";
  333. args += this->GetLocalGenerator()->EscapeForShell(*lwyuCheck);
  334. args += cmStrCat(
  335. " --source=",
  336. this->ConvertToFastbuildPath(this->GetGeneratorTarget()->GetFullPath(
  337. Config, cmStateEnums::RuntimeBinaryArtifact,
  338. /*realname=*/true)));
  339. LogMessage("LWUY args: " + args);
  340. linkerNode.LinkerStampExe = cmSystemTools::GetCMakeCommand();
  341. linkerNode.LinkerStampExeArgs = std::move(args);
  342. }
  343. }
  344. std::string cmFastbuildNormalTargetGenerator::ComputeDefines(
  345. cmSourceFile const& srcFile)
  346. {
  347. std::string const language = srcFile.GetLanguage();
  348. std::set<std::string> defines;
  349. cmGeneratorExpressionInterpreter genexInterpreter(
  350. this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
  351. if (auto compile_defs = srcFile.GetProperty(COMPILE_DEFINITIONS)) {
  352. this->GetLocalGenerator()->AppendDefines(
  353. defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
  354. }
  355. std::string defPropName = "COMPILE_DEFINITIONS_";
  356. defPropName += cmSystemTools::UpperCase(Config);
  357. if (auto config_compile_defs = srcFile.GetProperty(defPropName)) {
  358. this->GetLocalGenerator()->AppendDefines(
  359. defines,
  360. genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
  361. }
  362. std::string definesString = this->GetDefines(language, Config);
  363. LogMessage(cmStrCat("TARGET DEFINES = ", definesString));
  364. this->GetLocalGenerator()->JoinDefines(defines, definesString, language);
  365. LogMessage(cmStrCat("DEFINES = ", definesString));
  366. return definesString;
  367. }
  368. void cmFastbuildNormalTargetGenerator::ComputePCH(
  369. cmSourceFile const& srcFile, FastbuildObjectListNode& node,
  370. std::set<std::string>& createdPCH)
  371. {
  372. if (srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
  373. return;
  374. }
  375. // We have already computed PCH for this node.
  376. if (!node.PCHOptions.empty() || !node.PCHInputFile.empty() ||
  377. !node.PCHOutputFile.empty()) {
  378. return;
  379. }
  380. std::string const language = srcFile.GetLanguage();
  381. cmGeneratorExpressionInterpreter genexInterpreter(
  382. this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
  383. //.cxx
  384. std::string const pchSource =
  385. this->GeneratorTarget->GetPchSource(Config, language);
  386. //.hxx
  387. std::string const pchHeader =
  388. this->GeneratorTarget->GetPchHeader(Config, language);
  389. //.pch
  390. std::string const pchFile =
  391. this->GeneratorTarget->GetPchFile(Config, language);
  392. if (pchHeader.empty() || pchFile.empty()) {
  393. return;
  394. }
  395. // In "RunCMake.GenEx-TARGET_PROPERTY" test we call set
  396. // CMAKE_PCH_EXTENSION="", so pchHeader becomes same as pchFile...
  397. if (pchHeader == pchFile) {
  398. LogMessage("pchHeader == pchFile > skipping");
  399. LogMessage("pchHeader: " + pchHeader);
  400. LogMessage("pchFile: " + pchFile);
  401. return;
  402. }
  403. node.PCHOutputFile =
  404. this->GetGlobalGenerator()->ConvertToFastbuildPath(pchFile);
  405. // Tell the ObjectList how to use PCH.
  406. std::string const pchUseOption =
  407. this->GeneratorTarget->GetPchUseCompileOptions(Config, language);
  408. LogMessage(cmStrCat("pchUseOption: ", pchUseOption));
  409. std::string origCompileOptions = node.CompilerOptions;
  410. for (auto const& opt :
  411. cmList{ genexInterpreter.Evaluate(pchUseOption, COMPILE_OPTIONS) }) {
  412. node.CompilerOptions += " ";
  413. node.CompilerOptions += opt;
  414. }
  415. if (!createdPCH.emplace(node.PCHOutputFile).second) {
  416. LogMessage(node.PCHOutputFile + " is already created by this target");
  417. return;
  418. }
  419. // Short circuit if the PCH has already been created by another target.
  420. if (!this->GeneratorTarget->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM")
  421. .empty()) {
  422. LogMessage(cmStrCat("PCH: ", node.PCHOutputFile,
  423. " already created by another target"));
  424. return;
  425. }
  426. node.PCHInputFile =
  427. this->GetGlobalGenerator()->ConvertToFastbuildPath(pchSource);
  428. std::string const pchCreateOptions =
  429. this->GeneratorTarget->GetPchCreateCompileOptions(Config, language);
  430. LogMessage(cmStrCat("pchCreateOptions: ", pchCreateOptions));
  431. char const* sep = "";
  432. for (auto const& opt : cmList{
  433. genexInterpreter.Evaluate(pchCreateOptions, COMPILE_OPTIONS) }) {
  434. node.PCHOptions += sep;
  435. node.PCHOptions += opt;
  436. sep = " ";
  437. }
  438. // Reuse compiler options for PCH options.
  439. node.PCHOptions += origCompileOptions;
  440. if (this->Makefile->GetSafeDefinition("CMAKE_" + language +
  441. "_COMPILER_ID") == "MSVC") {
  442. cmSystemTools::ReplaceString(node.PCHOptions,
  443. FASTBUILD_2_INPUT_PLACEHOLDER,
  444. FASTBUILD_3_INPUT_PLACEHOLDER);
  445. }
  446. LogMessage("PCH Source: " + pchSource);
  447. LogMessage("node.PCHInputFile: " + node.PCHInputFile);
  448. LogMessage("node.PCHOutputFile: " + node.PCHOutputFile);
  449. LogMessage("node.PCHOptions: " + node.PCHOptions);
  450. LogMessage("node.CompilerOptions: " + node.CompilerOptions);
  451. }
  452. void cmFastbuildNormalTargetGenerator::EnsureDirectoryExists(
  453. std::string const& path) const
  454. {
  455. if (cmSystemTools::FileIsFullPath(path.c_str())) {
  456. cmSystemTools::MakeDirectory(path.c_str());
  457. } else {
  458. auto* gg = this->GetGlobalGenerator();
  459. std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
  460. // Also ensures there is a trailing slash.
  461. fullPath += path;
  462. cmSystemTools::MakeDirectory(fullPath);
  463. }
  464. }
  465. void cmFastbuildNormalTargetGenerator::EnsureParentDirectoryExists(
  466. std::string const& path) const
  467. {
  468. this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
  469. }
  470. std::vector<std::string>
  471. cmFastbuildNormalTargetGenerator::GetManifestsAsFastbuildPath() const
  472. {
  473. std::vector<cmSourceFile const*> manifest_srcs;
  474. this->GeneratorTarget->GetManifests(manifest_srcs, Config);
  475. std::vector<std::string> manifests;
  476. manifests.reserve(manifest_srcs.size());
  477. for (auto& manifest_src : manifest_srcs) {
  478. std::string str = this->ConvertToFastbuildPath(
  479. cmSystemTools::ConvertToOutputPath(manifest_src->GetFullPath()));
  480. LogMessage("Manifest: " + str);
  481. manifests.emplace_back(std::move(str));
  482. }
  483. return manifests;
  484. }
  485. void cmFastbuildNormalTargetGenerator::GenerateModuleDefinitionInfo(
  486. FastbuildTarget& target) const
  487. {
  488. cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
  489. GeneratorTarget->GetModuleDefinitionInfo(Config);
  490. if (mdi && mdi->DefFileGenerated) {
  491. FastbuildExecNode execNode;
  492. execNode.Name = target.Name + "-def-files";
  493. execNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
  494. execNode.ExecArguments =
  495. cmStrCat("-E __create_def ", FASTBUILD_2_INPUT_PLACEHOLDER, " ",
  496. FASTBUILD_1_INPUT_PLACEHOLDER);
  497. std::string const obj_list_file = mdi->DefFile + ".objs";
  498. auto const nm_executable = GetMakefile()->GetDefinition("CMAKE_NM");
  499. if (!nm_executable.IsEmpty()) {
  500. execNode.ExecArguments += " --nm=";
  501. execNode.ExecArguments += ConvertToFastbuildPath(*nm_executable);
  502. }
  503. execNode.ExecOutput = ConvertToFastbuildPath(mdi->DefFile);
  504. execNode.ExecInput.push_back(ConvertToFastbuildPath(obj_list_file));
  505. // RunCMake.AutoExportDll
  506. for (auto const& objList : target.ObjectListNodes) {
  507. execNode.PreBuildDependencies.emplace(objList.Name);
  508. }
  509. // Tested in "RunCMake.AutoExportDll" / "ModuleDefinition" tests.
  510. for (auto& linkerNode : target.LinkerNode) {
  511. linkerNode.Libraries2.emplace_back(execNode.Name);
  512. }
  513. target.PreLinkExecNodes.Nodes.emplace_back(std::move(execNode));
  514. // create a list of obj files for the -E __create_def to read
  515. cmGeneratedFileStream fout(obj_list_file);
  516. // Since we generate this file once during configuration, we should not
  517. // remove it when "clean" is built.
  518. // Tested in "RunCMake.AutoExportDll" / "ModuleDefinition" tests.
  519. this->GetGlobalGenerator()->AllFilesToKeep.insert(obj_list_file);
  520. if (mdi->WindowsExportAllSymbols) {
  521. std::vector<cmSourceFile const*> objectSources;
  522. GeneratorTarget->GetObjectSources(objectSources, Config);
  523. std::map<cmSourceFile const*, cmObjectLocations> mapping;
  524. for (cmSourceFile const* it : objectSources) {
  525. mapping[it];
  526. }
  527. GeneratorTarget->LocalGenerator->ComputeObjectFilenames(mapping, Config,
  528. GeneratorTarget);
  529. std::vector<std::string> objs;
  530. for (cmSourceFile const* it : objectSources) {
  531. auto const& v = mapping[it];
  532. LogMessage("Obj source : " + v.LongLoc.GetPath());
  533. std::string objFile = this->ConvertToFastbuildPath(
  534. GeneratorTarget->GetObjectDirectory(Config) + v.LongLoc.GetPath());
  535. objFile = cmSystemTools::ConvertToOutputPath(objFile);
  536. LogMessage("objFile path: " + objFile);
  537. objs.push_back(objFile);
  538. }
  539. std::vector<cmSourceFile const*> externalObjectSources;
  540. GeneratorTarget->GetExternalObjects(externalObjectSources, Config);
  541. for (cmSourceFile const* it : externalObjectSources) {
  542. objs.push_back(cmSystemTools::ConvertToOutputPath(
  543. this->ConvertToFastbuildPath(it->GetFullPath())));
  544. }
  545. for (std::string const& objFile : objs) {
  546. if (cmHasLiteralSuffix(objFile, ".obj")) {
  547. fout << objFile << "\n";
  548. }
  549. }
  550. }
  551. for (cmSourceFile const* src : mdi->Sources) {
  552. fout << src->GetFullPath() << "\n";
  553. }
  554. }
  555. }
  556. void cmFastbuildNormalTargetGenerator::AddPrebuildDeps(
  557. FastbuildTarget& target) const
  558. {
  559. // All ObjectLists should wait for PRE_BUILD.
  560. for (FastbuildObjectListNode& node : target.ObjectListNodes) {
  561. if (!target.PreBuildExecNodes.Name.empty()) {
  562. node.PreBuildDependencies.emplace(target.PreBuildExecNodes.Name);
  563. }
  564. if (!target.ExecNodes.Name.empty()) {
  565. node.PreBuildDependencies.emplace(target.ExecNodes.Name);
  566. }
  567. }
  568. for (auto& linkerNode : target.LinkerNode) {
  569. // Wait for 'PRE_BUILD' custom commands.
  570. if (!target.PreBuildExecNodes.Name.empty()) {
  571. linkerNode.PreBuildDependencies.emplace(target.PreBuildExecNodes.Name);
  572. }
  573. // Wait for regular custom commands.
  574. if (!target.ExecNodes.Name.empty()) {
  575. linkerNode.PreBuildDependencies.emplace(target.ExecNodes.Name);
  576. }
  577. // All targets that we depend on must be prebuilt.
  578. if (!target.DependenciesAlias.PreBuildDependencies.empty()) {
  579. linkerNode.PreBuildDependencies.emplace(target.DependenciesAlias.Name);
  580. }
  581. }
  582. }
  583. std::set<std::string> cmFastbuildNormalTargetGenerator::GetLanguages()
  584. {
  585. std::set<std::string> result;
  586. this->GetGeneratorTarget()->GetLanguages(result, Config);
  587. for (std::string const& lang : result) {
  588. this->GetGlobalGenerator()->AddCompiler(lang, this->GetMakefile());
  589. }
  590. LogMessage("Languages: " + cmJoin(result, ", "));
  591. return result;
  592. }
  593. std::unordered_map<std::string, std::string>
  594. cmFastbuildNormalTargetGenerator::GetCompileObjectCommand() const
  595. {
  596. std::unordered_map<std::string, std::string> result;
  597. result.reserve(Languages.size());
  598. for (std::string const& lang : Languages) {
  599. std::vector<std::string> commands;
  600. std::string cmakeVar;
  601. cmakeVar = "CMAKE_";
  602. cmakeVar += lang;
  603. cmakeVar += "_COMPILE_OBJECT";
  604. std::string cmakeValue =
  605. LocalCommonGenerator->GetMakefile()->GetSafeDefinition(cmakeVar);
  606. LogMessage(cmakeVar.append(" = ").append(cmakeValue));
  607. result[lang] = std::move(cmakeValue);
  608. }
  609. return result;
  610. }
  611. std::string cmFastbuildNormalTargetGenerator::GetCudaCompileMode() const
  612. {
  613. if (Languages.find("CUDA") == Languages.end()) {
  614. return {};
  615. }
  616. // TODO: unify it with makefile / ninja generators.
  617. std::string cudaCompileMode;
  618. if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
  619. std::string const& rdcFlag =
  620. this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG");
  621. cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, ' ');
  622. }
  623. static std::array<cm::string_view, 4> const compileModes{
  624. { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s }
  625. };
  626. bool useNormalCompileMode = true;
  627. for (cm::string_view mode : compileModes) {
  628. auto propName = cmStrCat("CUDA_", mode, "_COMPILATION");
  629. auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG");
  630. if (this->GeneratorTarget->GetPropertyAsBool(propName)) {
  631. std::string const& flag = this->Makefile->GetRequiredDefinition(defName);
  632. cudaCompileMode = cmStrCat(cudaCompileMode, flag);
  633. useNormalCompileMode = false;
  634. break;
  635. }
  636. }
  637. if (useNormalCompileMode) {
  638. std::string const& wholeFlag =
  639. this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG");
  640. cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag);
  641. }
  642. return cudaCompileMode;
  643. }
  644. std::string cmFastbuildNormalTargetGenerator::GetLinkCommand() const
  645. {
  646. std::string const& linkLanguage = GeneratorTarget->GetLinkerLanguage(Config);
  647. std::string linkCmdVar =
  648. GeneratorTarget->GetCreateRuleVariable(linkLanguage, Config);
  649. std::string res = this->Makefile->GetSafeDefinition(linkCmdVar);
  650. if (res.empty() &&
  651. this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
  652. linkCmdVar = linkCmdVar =
  653. cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE");
  654. res = this->Makefile->GetSafeDefinition(linkCmdVar);
  655. }
  656. LogMessage("Link rule: " + cmStrCat(linkCmdVar, " = ", res));
  657. return res;
  658. }
  659. void cmFastbuildNormalTargetGenerator::AddCompilerLaunchersForLanguages()
  660. {
  661. // General rule for all languages.
  662. std::string const launchCompile = this->GetLocalGenerator()->GetRuleLauncher(
  663. this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE", Config);
  664. // See if we need to use a compiler launcher like ccache or distcc
  665. for (std::string const& language : Languages) {
  666. std::string const compilerLauncher =
  667. cmCommonTargetGenerator::GetCompilerLauncher(language, Config);
  668. LogMessage("compilerLauncher: " + compilerLauncher);
  669. std::vector<std::string> expanded;
  670. cmExpandList(compilerLauncher, expanded);
  671. if (!expanded.empty()) {
  672. std::string const exe = expanded[0];
  673. expanded.erase(expanded.begin());
  674. this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX, exe,
  675. language, cmJoin(expanded, " "));
  676. } else if (!launchCompile.empty()) {
  677. std::string exe;
  678. std::string args;
  679. cmSystemTools::SplitProgramFromArgs(launchCompile, exe, args);
  680. this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX, exe,
  681. language, args);
  682. }
  683. }
  684. }
  685. void cmFastbuildNormalTargetGenerator::AddLinkerLauncher()
  686. {
  687. std::string const linkerLauncher =
  688. cmCommonTargetGenerator::GetLinkerLauncher(Config);
  689. std::vector<std::string> args;
  690. #ifdef _WIN32
  691. cmSystemTools::ParseWindowsCommandLine(linkerLauncher.c_str(), args);
  692. #else
  693. cmSystemTools::ParseUnixCommandLine(linkerLauncher.c_str(), args);
  694. #endif
  695. if (!args.empty()) {
  696. std::string const exe = std::move(args[0]);
  697. args.erase(args.begin());
  698. this->GetGlobalGenerator()->AddLauncher(
  699. FASTBUILD_LINKER_LAUNCHER_PREFIX, exe,
  700. this->GeneratorTarget->GetLinkerLanguage(Config), cmJoin(args, " "));
  701. }
  702. }
  703. void cmFastbuildNormalTargetGenerator::AddCMakeLauncher()
  704. {
  705. // Add CMake launcher (might be used for static analysis).
  706. this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX,
  707. cmSystemTools::GetCMakeCommand(),
  708. CMAKE_LANGUAGE, "");
  709. }
  710. void cmFastbuildNormalTargetGenerator::ComputePaths(
  711. FastbuildTarget& target) const
  712. {
  713. std::string const objPath = GetGeneratorTarget()->GetSupportDirectory();
  714. EnsureDirectoryExists(objPath);
  715. target.Variables["TargetOutDir"] =
  716. cmSystemTools::ConvertToOutputPath(this->ConvertToFastbuildPath(objPath));
  717. if (GeneratorTarget->GetType() <= cmStateEnums::MODULE_LIBRARY) {
  718. std::string const pdbDir = GeneratorTarget->GetPDBDirectory(Config);
  719. LogMessage("GetPDBDirectory: " + pdbDir);
  720. EnsureDirectoryExists(pdbDir);
  721. std::string const linkerPDB =
  722. cmStrCat(pdbDir, '/', this->GeneratorTarget->GetPDBName(Config));
  723. if (!linkerPDB.empty()) {
  724. target.Variables["LinkerPDB"] = cmSystemTools::ConvertToOutputPath(
  725. this->ConvertToFastbuildPath(linkerPDB));
  726. }
  727. }
  728. std::string const compilerPDB = this->ComputeTargetCompilePDB(this->Config);
  729. if (!compilerPDB.empty()) {
  730. LogMessage("ComputeTargetCompilePDB: " + compilerPDB);
  731. std::string compilerPDBArg = cmSystemTools::ConvertToOutputPath(
  732. this->ConvertToFastbuildPath(compilerPDB));
  733. if (cmHasSuffix(compilerPDB, '/')) {
  734. // The compiler will choose the .pdb file name.
  735. this->EnsureDirectoryExists(compilerPDB);
  736. // ConvertToFastbuildPath dropped the trailing slash. Add it back.
  737. // We do this after ConvertToOutputPath so that we can use a forward
  738. // slash in the case that the argument is quoted.
  739. if (cmHasSuffix(compilerPDBArg, '"')) {
  740. // A quoted trailing backslash requires escaping, e.g., `/Fd"dir\\"`,
  741. // but fbuild does not parse such arguments correctly as of 1.15.
  742. // Always use a forward slash.
  743. compilerPDBArg.insert(compilerPDBArg.size() - 1, 1, '/');
  744. } else {
  745. // An unquoted trailing slash or backslash is fine.
  746. compilerPDBArg.push_back(kPATH_SLASH);
  747. }
  748. } else {
  749. // We have an explicit .pdb path with file name.
  750. this->EnsureParentDirectoryExists(compilerPDB);
  751. }
  752. target.Variables["CompilerPDB"] = std::move(compilerPDBArg);
  753. }
  754. std::string const impLibFullPath =
  755. GeneratorTarget->GetFullPath(Config, cmStateEnums::ImportLibraryArtifact);
  756. std::string impLibFile = ConvertToFastbuildPath(impLibFullPath);
  757. cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(impLibFullPath));
  758. if (!impLibFile.empty()) {
  759. cmSystemTools::ConvertToOutputSlashes(impLibFile);
  760. target.Variables["TargetOutputImplib"] = std::move(impLibFile);
  761. }
  762. }
  763. void cmFastbuildNormalTargetGenerator::Generate()
  764. {
  765. this->GeneratorTarget->CheckCxxModuleStatus(Config);
  766. FastbuildTarget fastbuildTarget;
  767. fastbuildTarget.Name = GetTargetName();
  768. fastbuildTarget.BaseName = this->GeneratorTarget->GetName();
  769. LogMessage("<-------------->");
  770. LogMessage("Generate target: " + fastbuildTarget.Name);
  771. LogMessage("Config: " + Config);
  772. LogMessage("Deps: ");
  773. for (cmTargetDepend const& dep : TargetDirectDependencies) {
  774. auto const tname = dep->GetName();
  775. LogMessage(tname);
  776. FastbuildTargetDep targetDep{ tname };
  777. if (dep->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  778. targetDep.Type = FastbuildTargetDepType::ORDER_ONLY;
  779. }
  780. fastbuildTarget.PreBuildDependencies.emplace(std::move(targetDep));
  781. }
  782. ComputePaths(fastbuildTarget);
  783. AddCompilerLaunchersForLanguages();
  784. AddLinkerLauncher();
  785. AddCMakeLauncher();
  786. for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_BUILD).Nodes) {
  787. fastbuildTarget.PreBuildExecNodes.PreBuildDependencies.emplace(cc.Name);
  788. fastbuildTarget.PreBuildDependencies.emplace(cc.Name);
  789. this->GetGlobalGenerator()->AddTarget(std::move(cc));
  790. }
  791. for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_LINK).Nodes) {
  792. cc.PreBuildDependencies.emplace(fastbuildTarget.Name +
  793. FASTBUILD_DEPS_ARTIFACTS_ALIAS_POSTFIX);
  794. fastbuildTarget.PreLinkExecNodes.Nodes.emplace_back(std::move(cc));
  795. }
  796. for (auto& cc : GenerateCommands(FastbuildBuildStep::REST).Nodes) {
  797. fastbuildTarget.ExecNodes.PreBuildDependencies.emplace(cc.Name);
  798. this->GetGlobalGenerator()->AddTarget(std::move(cc));
  799. }
  800. for (auto& cc : GenerateCommands(FastbuildBuildStep::POST_BUILD).Nodes) {
  801. fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
  802. cc.Name);
  803. fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(std::move(cc));
  804. }
  805. GenerateObjects(fastbuildTarget);
  806. std::vector<std::string> objectDepends;
  807. AddObjectDependencies(fastbuildTarget, objectDepends);
  808. GenerateCudaDeviceLink(fastbuildTarget);
  809. GenerateLink(fastbuildTarget, objectDepends);
  810. if (fastbuildTarget.LinkerNode.size() > 1) {
  811. if (!this->GeneratorTarget->IsApple()) {
  812. cmSystemTools::Error(
  813. "Can't handle more than 1 arch on non-Apple target");
  814. return;
  815. }
  816. AddLipoCommand(fastbuildTarget);
  817. }
  818. fastbuildTarget.CopyNodes = std::move(this->CopyNodes);
  819. // Generate symlink commands if real output name differs from "expected".
  820. for (auto& symlink : GetSymlinkExecs()) {
  821. fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
  822. symlink.Name);
  823. fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(std::move(symlink));
  824. }
  825. {
  826. auto appleTextStubCommand = GetAppleTextStubCommand();
  827. if (!appleTextStubCommand.Name.empty()) {
  828. fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
  829. appleTextStubCommand.Name);
  830. fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(
  831. std::move(appleTextStubCommand));
  832. }
  833. }
  834. AddPrebuildDeps(fastbuildTarget);
  835. fastbuildTarget.IsGlobal =
  836. GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET;
  837. fastbuildTarget.ExcludeFromAll =
  838. this->GetGlobalGenerator()->IsExcluded(GeneratorTarget);
  839. if (GeneratorTarget->GetPropertyAsBool("DONT_DISTRIBUTE")) {
  840. fastbuildTarget.AllowDistribution = false;
  841. }
  842. GenerateModuleDefinitionInfo(fastbuildTarget);
  843. // Needs to be called after we've added all PRE-LINK steps (like creation of
  844. // .def files on Windows).
  845. AddLinkerNodeDependencies(fastbuildTarget);
  846. // Must be called after "GenerateObjects", since it also adds Prebuild deps
  847. // to it.
  848. // Also after "GenerateModuleDefinitionInfo", since uses PreLinkExecNodes.
  849. fastbuildTarget.GenerateAliases();
  850. if (!fastbuildTarget.ExecNodes.PreBuildDependencies.empty()) {
  851. fastbuildTarget.DependenciesAlias.PreBuildDependencies.emplace(
  852. fastbuildTarget.ExecNodes.Name);
  853. }
  854. fastbuildTarget.Hidden = false;
  855. fastbuildTarget.BasePath = this->GetMakefile()->GetCurrentSourceDirectory();
  856. this->GetGlobalGenerator()->AddIDEProject(fastbuildTarget, Config);
  857. AddStampExeIfApplicable(fastbuildTarget);
  858. // size 1 means that it's not a multi-arch lib (which can only be the case on
  859. // Darwin).
  860. if (fastbuildTarget.LinkerNode.size() == 1 &&
  861. fastbuildTarget.LinkerNode[0].Type ==
  862. FastbuildLinkerNode::STATIC_LIBRARY &&
  863. !fastbuildTarget.PostBuildExecNodes.Nodes.empty()) {
  864. ProcessPostBuildForStaticLib(fastbuildTarget);
  865. }
  866. AdditionalCleanFiles();
  867. if (!fastbuildTarget.DependenciesAlias.PreBuildDependencies.empty()) {
  868. for (FastbuildObjectListNode& objListNode :
  869. fastbuildTarget.ObjectListNodes) {
  870. objListNode.PreBuildDependencies.emplace(
  871. fastbuildTarget.DependenciesAlias.Name);
  872. }
  873. for (auto& linkerNode : fastbuildTarget.LinkerNode) {
  874. linkerNode.PreBuildDependencies.emplace(
  875. fastbuildTarget.DependenciesAlias.Name);
  876. }
  877. }
  878. this->GetGlobalGenerator()->AddTarget(std::move(fastbuildTarget));
  879. }
  880. void cmFastbuildNormalTargetGenerator::ProcessManifests(
  881. FastbuildLinkerNode& linkerNode) const
  882. {
  883. if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
  884. return;
  885. }
  886. auto manifests = this->GetManifestsAsFastbuildPath();
  887. if (manifests.empty()) {
  888. return;
  889. }
  890. // Manifests should always be in .Libraries2, so we re-link when needed.
  891. // Tested in RunCMake.BuildDepends
  892. for (auto const& manifest : manifests) {
  893. linkerNode.Libraries2.emplace_back(manifest);
  894. }
  895. if (this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID") != "MSVC") {
  896. return;
  897. }
  898. for (auto const& manifest : manifests) {
  899. linkerNode.LinkerOptions =
  900. cmStrCat("/MANIFESTINPUT:", manifest, ' ', linkerNode.LinkerOptions);
  901. }
  902. // /MANIFESTINPUT only works with /MANIFEST:EMBED
  903. linkerNode.LinkerOptions =
  904. cmStrCat("/MANIFEST:EMBED ", linkerNode.LinkerOptions);
  905. }
  906. void cmFastbuildNormalTargetGenerator::AddStampExeIfApplicable(
  907. FastbuildTarget& fastbuildTarget) const
  908. {
  909. LogMessage("AddStampExeIfApplicable(...)");
  910. if (fastbuildTarget.LinkerNode.empty() ||
  911. (fastbuildTarget.LinkerNode[0].Type != FastbuildLinkerNode::EXECUTABLE &&
  912. fastbuildTarget.LinkerNode[0].Type !=
  913. FastbuildLinkerNode::SHARED_LIBRARY)) {
  914. return;
  915. }
  916. // File which executes all POST_BUILD steps.
  917. // We use it in .LinkerStampExeArgs in order to run POST_BUILD steps after
  918. // the compilation.
  919. if (!fastbuildTarget.PostBuildExecNodes.Nodes.empty()) {
  920. std::string const AllPostBuildExecsScriptFile =
  921. cmStrCat(this->Makefile->GetHomeOutputDirectory(), "/CMakeFiles/",
  922. fastbuildTarget.Name,
  923. "-all-postbuild-commands" FASTBUILD_SCRIPT_FILE_EXTENSION);
  924. CollapseAllExecsIntoOneScriptfile(
  925. AllPostBuildExecsScriptFile, fastbuildTarget.PostBuildExecNodes.Nodes);
  926. auto& linkerNode = fastbuildTarget.LinkerNode.back();
  927. // On macOS, a target may have multiple linker nodes (e.g., for different
  928. // architectures). In that case, add the POST_BUILD step to only one node
  929. // to avoid running lipo multiple times.
  930. linkerNode.LinkerStampExe =
  931. cmGlobalFastbuildGenerator::GetExternalShellExecutable();
  932. linkerNode.LinkerStampExeArgs = FASTBUILD_SCRIPT_FILE_ARG;
  933. linkerNode.LinkerStampExeArgs +=
  934. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
  935. AllPostBuildExecsScriptFile);
  936. } else {
  937. LogMessage("No POST_BUILD steps for target: " + fastbuildTarget.Name);
  938. }
  939. }
  940. void cmFastbuildNormalTargetGenerator::ProcessPostBuildForStaticLib(
  941. FastbuildTarget& fastbuildTarget) const
  942. {
  943. // "Library" nodes do not have "LinkerStampExe" property, so we need to be
  944. // clever here: create an alias that will refer to the binary as well as to
  945. // all post-build steps. Also, make sure that post-build steps depend on the
  946. // binary itself.
  947. LogMessage("ProcessPostBuildForStaticLib(...)");
  948. FastbuildAliasNode alias;
  949. alias.Name = std::move(fastbuildTarget.LinkerNode[0].Name);
  950. for (FastbuildExecNode& postBuildExec :
  951. fastbuildTarget.PostBuildExecNodes.Nodes) {
  952. postBuildExec.PreBuildDependencies.emplace(
  953. fastbuildTarget.LinkerNode[0].LinkerOutput);
  954. alias.PreBuildDependencies.emplace(postBuildExec.Name);
  955. }
  956. fastbuildTarget.AliasNodes.emplace_back(std::move(alias));
  957. }
  958. void cmFastbuildNormalTargetGenerator::CollapseAllExecsIntoOneScriptfile(
  959. std::string const& scriptFileName,
  960. std::vector<FastbuildExecNode> const& execs) const
  961. {
  962. cmsys::ofstream scriptFile(scriptFileName.c_str());
  963. if (!scriptFile.is_open()) {
  964. cmSystemTools::Error("Failed to open: " + scriptFileName);
  965. return;
  966. }
  967. LogMessage("Writing collapsed Execs to " + scriptFileName);
  968. auto const shell = cmGlobalFastbuildGenerator::GetExternalShellExecutable();
  969. for (auto const& exec : execs) {
  970. if (exec.ScriptFile.empty()) {
  971. scriptFile << cmSystemTools::ConvertToOutputPath(exec.ExecExecutable)
  972. << " " << exec.ExecArguments << '\n';
  973. } else {
  974. #if defined(_WIN32)
  975. scriptFile << "call "
  976. << cmSystemTools::ConvertToWindowsOutputPath(exec.ScriptFile)
  977. << '\n';
  978. #else
  979. scriptFile << cmSystemTools::ConvertToOutputPath(shell) << " "
  980. << cmSystemTools::ConvertToOutputPath(exec.ScriptFile)
  981. << '\n';
  982. #endif
  983. }
  984. }
  985. }
  986. std::string cmFastbuildNormalTargetGenerator::ComputeCodeCheckOptions(
  987. cmSourceFile const& srcFile)
  988. {
  989. cmValue const srcSkipCodeCheckVal = srcFile.GetProperty("SKIP_LINTING");
  990. bool const skipCodeCheck = srcSkipCodeCheckVal.IsSet()
  991. ? srcSkipCodeCheckVal.IsOn()
  992. : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING");
  993. if (skipCodeCheck) {
  994. return {};
  995. }
  996. std::string compilerLauncher;
  997. std::string staticCheckRule = this->GenerateCodeCheckRules(
  998. srcFile, compilerLauncher, "", Config, nullptr);
  999. LogMessage(cmStrCat("CodeCheck: ", staticCheckRule));
  1000. return staticCheckRule;
  1001. }
  1002. void cmFastbuildNormalTargetGenerator::ComputeCompilerAndOptions(
  1003. std::string const& compilerOptions, std::string const& staticCheckOptions,
  1004. std::string const& language, FastbuildObjectListNode& outObjectList)
  1005. {
  1006. auto& compilers = this->GetGlobalGenerator()->Compilers;
  1007. auto const compilerIter =
  1008. compilers.find(FASTBUILD_COMPILER_PREFIX + language);
  1009. auto const launcherIter =
  1010. compilers.find(FASTBUILD_LAUNCHER_PREFIX + language);
  1011. if (!staticCheckOptions.empty()) {
  1012. // If we want to run static checks - use CMake as a launcher.
  1013. // Tested in "RunCMake.ClangTidy", "RunCMake.IncludeWhatYouUse",
  1014. // "RunCMake.Cpplint", "RunCMake.Cppcheck", "RunCMake.MultiLint" tests.
  1015. outObjectList.Compiler = "." FASTBUILD_LAUNCHER_PREFIX + CMAKE_LANGUAGE;
  1016. outObjectList.CompilerOptions = staticCheckOptions;
  1017. // Add compile command which will be passed to the static analyzer via
  1018. // dash-dash.
  1019. if (compilerIter != compilers.end()) {
  1020. // Wrap in quotes to account for potential spaces in the path.
  1021. outObjectList.CompilerOptions +=
  1022. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
  1023. compilerIter->second.Executable);
  1024. outObjectList.CompilerOptions += compilerOptions;
  1025. }
  1026. } else if (launcherIter != compilers.end()) {
  1027. // Tested in "RunCMake.CompilerLauncher" test.
  1028. outObjectList.Compiler = "." + launcherIter->first;
  1029. outObjectList.CompilerOptions = launcherIter->second.Args;
  1030. auto vars = cmFastbuildNormalTargetGenerator::ComputeRuleVariables();
  1031. vars.Language = language.c_str();
  1032. std::string const targetSupportPath = this->ConvertToFastbuildPath(
  1033. this->GetGeneratorTarget()->GetCMFSupportDirectory());
  1034. vars.TargetSupportDir = targetSupportPath.c_str();
  1035. RulePlaceholderExpander->ExpandRuleVariables(
  1036. LocalCommonGenerator, outObjectList.CompilerOptions, vars);
  1037. // Add compiler executable explicitly to the compile options.
  1038. if (compilerIter != compilers.end()) {
  1039. outObjectList.CompilerOptions += " ";
  1040. // Wrap in quotes to account for potential spaces in the path.
  1041. outObjectList.CompilerOptions +=
  1042. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
  1043. compilerIter->second.Executable);
  1044. outObjectList.CompilerOptions += compilerOptions;
  1045. }
  1046. } else if (compilerIter != compilers.end()) {
  1047. outObjectList.Compiler = "." + compilerIter->first;
  1048. outObjectList.CompilerOptions = compilerOptions;
  1049. }
  1050. LogMessage(cmStrCat(".Compiler = ", outObjectList.Compiler));
  1051. LogMessage(cmStrCat(".CompilerOptions = ", outObjectList.CompilerOptions));
  1052. }
  1053. cmRulePlaceholderExpander::RuleVariables
  1054. cmFastbuildNormalTargetGenerator::ComputeRuleVariables() const
  1055. {
  1056. cmRulePlaceholderExpander::RuleVariables compileObjectVars;
  1057. compileObjectVars.CMTargetName = GeneratorTarget->GetName().c_str();
  1058. compileObjectVars.CMTargetType =
  1059. cmState::GetTargetTypeName(GeneratorTarget->GetType()).c_str();
  1060. compileObjectVars.Source = FASTBUILD_1_INPUT_PLACEHOLDER;
  1061. compileObjectVars.Object = FASTBUILD_2_INPUT_PLACEHOLDER;
  1062. compileObjectVars.ObjectDir =
  1063. FASTBUILD_DOLLAR_TAG "TargetOutDir" FASTBUILD_DOLLAR_TAG;
  1064. compileObjectVars.ObjectFileDir = "";
  1065. compileObjectVars.Flags = "";
  1066. compileObjectVars.Includes = "";
  1067. compileObjectVars.Defines = "";
  1068. compileObjectVars.Includes = "";
  1069. compileObjectVars.TargetCompilePDB =
  1070. FASTBUILD_DOLLAR_TAG "CompilerPDB" FASTBUILD_DOLLAR_TAG;
  1071. compileObjectVars.Config = Config.c_str();
  1072. return compileObjectVars;
  1073. }
  1074. std::vector<std::string> cmFastbuildNormalTargetGenerator::GetSourceProperty(
  1075. cmSourceFile const& srcFile, std::string const& prop) const
  1076. {
  1077. std::vector<std::string> res;
  1078. if (cmValue val = srcFile.GetProperty(prop)) {
  1079. cmExpandList(*val, res);
  1080. return GetGlobalGenerator()->ConvertToFastbuildPath(res);
  1081. }
  1082. return res;
  1083. }
  1084. void cmFastbuildNormalTargetGenerator::AppendExtraResources(
  1085. std::set<std::string>& deps) const
  1086. {
  1087. // Generate Fastbuild's "Copy" commands to copy resources.
  1088. auto const generateCopyCommands =
  1089. [this](std::vector<cmSourceFile const*>& frameworkDeps) {
  1090. this->OSXBundleGenerator->GenerateMacOSXContentStatements(
  1091. frameworkDeps, this->MacOSXContentGenerator.get(), Config);
  1092. };
  1093. std::vector<cmSourceFile const*> headerSources;
  1094. this->GeneratorTarget->GetHeaderSources(headerSources, Config);
  1095. generateCopyCommands(headerSources);
  1096. std::vector<cmSourceFile const*> extraSources;
  1097. this->GeneratorTarget->GetExtraSources(extraSources, Config);
  1098. generateCopyCommands(extraSources);
  1099. std::vector<cmSourceFile const*> externalObjects;
  1100. this->GeneratorTarget->GetExternalObjects(externalObjects, Config);
  1101. generateCopyCommands(externalObjects);
  1102. for (FastbuildCopyNode const& node : this->CopyNodes) {
  1103. LogMessage("Adding resource: " + node.Name);
  1104. deps.emplace(node.Name);
  1105. }
  1106. }
  1107. std::string cmFastbuildNormalTargetGenerator::GetCompileOptions(
  1108. cmSourceFile const& srcFile, std::string const& arch)
  1109. {
  1110. std::string const language = srcFile.GetLanguage();
  1111. cmRulePlaceholderExpander::RuleVariables compileObjectVars =
  1112. ComputeRuleVariables();
  1113. std::string const compilerFlags = DetectCompilerFlags(srcFile, arch);
  1114. std::string const compilerDefines = ComputeDefines(srcFile);
  1115. compileObjectVars.Flags = compilerFlags.c_str();
  1116. compileObjectVars.Defines = compilerDefines.c_str();
  1117. compileObjectVars.Language = language.c_str();
  1118. if (language == "CUDA") {
  1119. compileObjectVars.CudaCompileMode = this->CudaCompileMode.c_str();
  1120. }
  1121. std::string rule = CompileObjectCmakeRules.at(language);
  1122. RulePlaceholderExpander->ExpandRuleVariables(LocalCommonGenerator, rule,
  1123. compileObjectVars);
  1124. std::string compilerExecutable;
  1125. // Remove the compiler from .CompilerOptions, since it would be set as
  1126. // .Compiler in Fastbuild.
  1127. // See https://www.fastbuild.org/docs/functions/objectlist.html for a
  1128. // reference.
  1129. std::string options;
  1130. if (!cmSystemTools::SplitProgramFromArgs(rule, compilerExecutable,
  1131. options)) {
  1132. cmSystemTools::Error(cmStrCat("Failed to split compiler options: ", rule));
  1133. }
  1134. LogMessage("Expanded compile options = " + options);
  1135. LogMessage("Compiler executable = " + compilerExecutable);
  1136. return options;
  1137. }
  1138. std::vector<std::string> cmFastbuildNormalTargetGenerator::GetArches() const
  1139. {
  1140. auto arches = this->GetGeneratorTarget()->GetAppleArchs(Config, {});
  1141. // Don't add any arch-specific logic if arch is only one.
  1142. if (arches.empty() || arches.size() == 1) {
  1143. arches.clear();
  1144. arches.emplace_back();
  1145. }
  1146. return arches;
  1147. }
  1148. void cmFastbuildNormalTargetGenerator::GetCudaDeviceLinkLinkerAndArgs(
  1149. std::string& linker, std::string& args) const
  1150. {
  1151. std::string linkCmd =
  1152. this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_"
  1153. "LIBRARY");
  1154. auto vars = ComputeRuleVariables();
  1155. vars.Language = "CUDA";
  1156. vars.Objects = FASTBUILD_1_INPUT_PLACEHOLDER;
  1157. vars.Target = FASTBUILD_2_INPUT_PLACEHOLDER;
  1158. std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
  1159. new cmLinkLineDeviceComputer(
  1160. this->LocalGenerator,
  1161. this->LocalGenerator->GetStateSnapshot().GetDirectory()));
  1162. std::string linkLibs;
  1163. std::string targetFlags;
  1164. std::string linkFlags;
  1165. std::string frameworkPath;
  1166. std::string linkPath;
  1167. // So that the call to "GetTargetFlags" does not pollute "LinkLibs" and
  1168. // "LinkFlags" with unneeded values.
  1169. std::string dummyLinkLibs;
  1170. std::string dummyLinkFlags;
  1171. this->LocalCommonGenerator->GetDeviceLinkFlags(
  1172. *linkLineComputer, Config, linkLibs, linkFlags, frameworkPath, linkPath,
  1173. this->GeneratorTarget);
  1174. this->LocalCommonGenerator->GetTargetFlags(
  1175. linkLineComputer.get(), Config, dummyLinkLibs, targetFlags, dummyLinkFlags,
  1176. frameworkPath, linkPath, this->GeneratorTarget);
  1177. vars.LanguageCompileFlags = "";
  1178. vars.LinkFlags = linkFlags.c_str();
  1179. vars.LinkLibraries = linkLibs.c_str();
  1180. vars.LanguageCompileFlags = targetFlags.c_str();
  1181. this->RulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  1182. linkCmd, vars);
  1183. SplitLinkerFromArgs(linkCmd, linker, args);
  1184. }
  1185. void cmFastbuildNormalTargetGenerator::GenerateCudaDeviceLink(
  1186. FastbuildTarget& target) const
  1187. {
  1188. auto const arches = this->GetArches();
  1189. if (!requireDeviceLinking(*this->GeneratorTarget, *this->GetLocalGenerator(),
  1190. Config)) {
  1191. return;
  1192. }
  1193. LogMessage("GenerateCudaDeviceLink(...)");
  1194. for (auto const& arch : arches) {
  1195. std::string linker;
  1196. std::string args;
  1197. GetCudaDeviceLinkLinkerAndArgs(linker, args);
  1198. FastbuildLinkerNode deviceLinkNode;
  1199. deviceLinkNode.Name = cmStrCat(target.Name, "_cuda_device_link");
  1200. deviceLinkNode.Type = FastbuildLinkerNode::SHARED_LIBRARY;
  1201. deviceLinkNode.Linker = std::move(linker);
  1202. deviceLinkNode.LinkerOptions = std::move(args);
  1203. // Output
  1204. deviceLinkNode.LinkerOutput = this->ConvertToFastbuildPath(cmStrCat(
  1205. FASTBUILD_DOLLAR_TAG "TargetOutDi"
  1206. "r" FASTBUILD_DOLLAR_TAG "/cmake_device_link",
  1207. (args.empty() ? "" : "_" + arch),
  1208. this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_"
  1209. "EXTENSION")));
  1210. // Input
  1211. for (auto const& objList : target.ObjectListNodes) {
  1212. deviceLinkNode.LibrarianAdditionalInputs.push_back(objList.Name);
  1213. }
  1214. target.CudaDeviceLinkNode.emplace_back(std::move(deviceLinkNode));
  1215. }
  1216. LogMessage("GenerateCudaDeviceLink end");
  1217. }
  1218. void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target)
  1219. {
  1220. this->GetGlobalGenerator()->AllFoldersToClean.insert(ObjectOutDir);
  1221. std::map<std::string, FastbuildObjectListNode> nodesPermutations;
  1222. cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
  1223. std::vector<cmSourceFile const*> objectSources;
  1224. GeneratorTarget->GetObjectSources(objectSources, Config);
  1225. std::set<std::string> createdPCH;
  1226. // Directory level.
  1227. bool useUnity =
  1228. GeneratorTarget->GetLocalGenerator()->GetMakefile()->IsDefinitionSet(
  1229. CMAKE_UNITY_BUILD);
  1230. // Check if explicitly disabled for this target.
  1231. auto const targetProp = GeneratorTarget->GetProperty(UNITY_BUILD);
  1232. if (targetProp.IsSet() && targetProp.IsOff()) {
  1233. useUnity = false;
  1234. }
  1235. // List of sources isolated from the unity build if enabled.
  1236. std::set<std::string> isolatedFromUnity;
  1237. // Mapping from unity group (if any) to sources belonging to that group.
  1238. std::map<std::string, std::vector<std::string>> sourcesWithGroups;
  1239. for (cmSourceFile const* source : objectSources) {
  1240. cmSourceFile const& srcFile = *source;
  1241. std::string const pathToFile = srcFile.GetFullPath();
  1242. if (useUnity) {
  1243. // Check if the source should be added to "UnityInputIsolatedFiles".
  1244. if (srcFile.GetPropertyAsBool(SKIP_UNITY_BUILD_INCLUSION)) {
  1245. isolatedFromUnity.emplace(pathToFile);
  1246. }
  1247. std::string const perFileUnityGroup =
  1248. srcFile.GetSafeProperty(UNITY_GROUP);
  1249. if (!perFileUnityGroup.empty()) {
  1250. sourcesWithGroups[perFileUnityGroup].emplace_back(pathToFile);
  1251. }
  1252. }
  1253. this->GetGlobalGenerator()->AddFileToClean(cmStrCat(
  1254. ObjectOutDir, '/', this->GeneratorTarget->GetObjectName(source)));
  1255. // Do not generate separate node for PCH source file.
  1256. if (this->GeneratorTarget->GetPchSource(Config, srcFile.GetLanguage()) ==
  1257. pathToFile) {
  1258. continue;
  1259. }
  1260. std::string const language = srcFile.GetLanguage();
  1261. LogMessage(
  1262. cmStrCat("Source file: ", this->ConvertToFastbuildPath(pathToFile)));
  1263. LogMessage("Language: " + language);
  1264. std::string const staticCheckOptions = ComputeCodeCheckOptions(srcFile);
  1265. auto const isDisabled = [this](char const* prop) {
  1266. auto const propValue = this->GeneratorTarget->GetProperty(prop);
  1267. return propValue && propValue.IsOff();
  1268. };
  1269. bool const disableCaching = isDisabled("FASTBUILD_CACHING");
  1270. bool const disableDistribution = isDisabled("FASTBUILD_DISTRIBUTION");
  1271. for (auto const& arch : this->GetArches()) {
  1272. std::string const compileOptions = GetCompileOptions(srcFile, arch);
  1273. std::string objOutDirWithPossibleSubdir = ObjectOutDir;
  1274. // If object should be placed in some subdir in the output
  1275. // path. Tested in "SourceGroups" test.
  1276. auto const subdir = cmSystemTools::GetFilenamePath(
  1277. this->GeneratorTarget->GetObjectName(source));
  1278. if (!subdir.empty()) {
  1279. objOutDirWithPossibleSubdir += "/";
  1280. objOutDirWithPossibleSubdir += subdir;
  1281. }
  1282. std::string const objectListHash = hash.HashString(cmStrCat(
  1283. compileOptions, staticCheckOptions, objOutDirWithPossibleSubdir,
  1284. // If file does not need PCH - it must be in another ObjectList.
  1285. srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS"),
  1286. srcFile.GetLanguage()));
  1287. LogMessage("ObjectList Hash: " + objectListHash);
  1288. FastbuildObjectListNode& objectListNode =
  1289. nodesPermutations[objectListHash];
  1290. // Absolute path needed in "RunCMake.SymlinkTrees" test.
  1291. objectListNode.CompilerInputFiles.push_back(pathToFile);
  1292. std::vector<std::string> const outputs =
  1293. GetSourceProperty(srcFile, "OBJECT_OUTPUTS");
  1294. objectListNode.ObjectOutputs.insert(outputs.begin(), outputs.end());
  1295. std::vector<std::string> const depends =
  1296. GetSourceProperty(srcFile, "OBJECT_DEPENDS");
  1297. objectListNode.ObjectDepends.insert(depends.begin(), depends.end());
  1298. // We have already computed properties that are computed below.
  1299. // (.CompilerOptions, .PCH*, etc.). Short circuit this iteration.
  1300. if (!objectListNode.CompilerOptions.empty()) {
  1301. continue;
  1302. }
  1303. if (disableCaching) {
  1304. objectListNode.AllowCaching = false;
  1305. }
  1306. if (disableDistribution) {
  1307. objectListNode.AllowDistribution = false;
  1308. }
  1309. objectListNode.CompilerOutputPath = objOutDirWithPossibleSubdir;
  1310. LogMessage(cmStrCat("Output path: ", objectListNode.CompilerOutputPath));
  1311. ComputeCompilerAndOptions(compileOptions, staticCheckOptions, language,
  1312. objectListNode);
  1313. ComputePCH(*source, objectListNode, createdPCH);
  1314. objectListNode.Name = cmStrCat(this->GetName(), '_', language, "_Objs");
  1315. // TODO: Ask cmake the output objects and group by extension instead
  1316. // of doing this
  1317. if (language == "RC") {
  1318. objectListNode.CompilerOutputExtension = ".res";
  1319. } else {
  1320. if (!arch.empty()) {
  1321. objectListNode.CompilerOutputExtension = cmStrCat('.', arch);
  1322. objectListNode.arch = arch;
  1323. }
  1324. char const* customExt =
  1325. this->GeneratorTarget->GetCustomObjectExtension();
  1326. objectListNode.CompilerOutputExtension +=
  1327. this->GetMakefile()->GetSafeDefinition(
  1328. cmStrCat("CMAKE_", language, "_OUTPUT_EXTENSION"));
  1329. // Tested in "CudaOnly.ExportPTX" test.
  1330. if (customExt) {
  1331. objectListNode.CompilerOutputExtension += customExt;
  1332. }
  1333. }
  1334. }
  1335. }
  1336. int groupNameCount = 0;
  1337. for (auto& val : nodesPermutations) {
  1338. auto& objectListNode = val.second;
  1339. objectListNode.Name = cmStrCat(objectListNode.Name, "_", ++groupNameCount);
  1340. LogMessage(cmStrCat("ObjectList name: ", objectListNode.Name));
  1341. }
  1342. std::vector<FastbuildObjectListNode>& objects = target.ObjectListNodes;
  1343. objects.reserve(nodesPermutations.size());
  1344. for (auto& val : nodesPermutations) {
  1345. auto& node = val.second;
  1346. if (!node.PCHInputFile.empty()) {
  1347. // Node that produces PCH should be the first one, since other nodes
  1348. // might reuse this PCH.
  1349. // Note: we might have several such nodes for different languages.
  1350. objects.insert(objects.begin(), std::move(node));
  1351. } else {
  1352. objects.emplace_back(std::move(node));
  1353. }
  1354. }
  1355. if (useUnity) {
  1356. target.UnityNodes =
  1357. GenerateUnity(objects, isolatedFromUnity, sourcesWithGroups);
  1358. }
  1359. }
  1360. FastbuildUnityNode cmFastbuildNormalTargetGenerator::GetOneUnity(
  1361. std::set<std::string> const& isolatedFiles, std::vector<std::string>& files,
  1362. int unitySize) const
  1363. {
  1364. FastbuildUnityNode result;
  1365. for (auto iter = files.begin(); iter != files.end();) {
  1366. std::string pathToFile = std::move(*iter);
  1367. iter = files.erase(iter);
  1368. // This source must be isolated
  1369. if (isolatedFiles.find(pathToFile) != isolatedFiles.end()) {
  1370. result.UnityInputFiles.emplace_back(pathToFile);
  1371. result.UnityInputIsolatedFiles.emplace_back(std::move(pathToFile));
  1372. } else {
  1373. result.UnityInputFiles.emplace_back(std::move(pathToFile));
  1374. }
  1375. if (int(result.UnityInputFiles.size() -
  1376. result.UnityInputIsolatedFiles.size()) == unitySize) {
  1377. break;
  1378. }
  1379. }
  1380. return result;
  1381. }
  1382. int cmFastbuildNormalTargetGenerator::GetUnityBatchSize() const
  1383. {
  1384. int unitySize = 8;
  1385. try {
  1386. auto const perTargetSize =
  1387. GeneratorTarget->GetSafeProperty(UNITY_BUILD_BATCH_SIZE);
  1388. if (!perTargetSize.empty()) {
  1389. unitySize = std::stoi(perTargetSize);
  1390. }
  1391. // Per-directory level.
  1392. else {
  1393. unitySize = std::stoi(
  1394. GeneratorTarget->GetLocalGenerator()->GetMakefile()->GetDefinition(
  1395. CMAKE_UNITY_BUILD_BATCH_SIZE));
  1396. }
  1397. } catch (...) {
  1398. return unitySize;
  1399. }
  1400. return unitySize;
  1401. }
  1402. std::vector<FastbuildUnityNode>
  1403. cmFastbuildNormalTargetGenerator::GenerateUnity(
  1404. std::vector<FastbuildObjectListNode>& objects,
  1405. std::set<std::string> const& isolatedSources,
  1406. std::map<std::string, std::vector<std::string>> const& sourcesWithGroups)
  1407. {
  1408. int const unitySize = GetUnityBatchSize();
  1409. // Unity of size less than 2 doesn't make sense.
  1410. if (unitySize < 2) {
  1411. return {};
  1412. }
  1413. int unityNumber = 0;
  1414. int unityGroupNumber = 0;
  1415. std::vector<FastbuildUnityNode> result;
  1416. for (FastbuildObjectListNode& obj : objects) {
  1417. // Don't use unity for only 1 file.
  1418. if (obj.CompilerInputFiles.size() < 2) {
  1419. continue;
  1420. }
  1421. std::string const ext =
  1422. cmSystemTools::GetFilenameExtension(obj.CompilerInputFiles[0]);
  1423. // Process groups.
  1424. auto groupedNode = GenerateGroupedUnityNode(
  1425. obj.CompilerInputFiles, sourcesWithGroups, unityGroupNumber);
  1426. // We have at least 2 sources in the group.
  1427. if (groupedNode.UnityInputFiles.size() > 1) {
  1428. groupedNode.UnityOutputPath = obj.CompilerOutputPath;
  1429. obj.CompilerInputUnity.emplace_back(groupedNode.Name);
  1430. groupedNode.UnityOutputPattern = cmStrCat(groupedNode.Name, ext);
  1431. result.emplace_back(std::move(groupedNode));
  1432. }
  1433. // General unity batching of the remaining (non-grouped) sources.
  1434. while (!obj.CompilerInputFiles.empty()) {
  1435. FastbuildUnityNode node =
  1436. GetOneUnity(isolatedSources, obj.CompilerInputFiles, unitySize);
  1437. node.Name = cmStrCat(this->GetName(), "_Unity_", ++unityNumber);
  1438. node.UnityOutputPath = obj.CompilerOutputPath;
  1439. node.UnityOutputPattern = cmStrCat(node.Name, ext);
  1440. // Unity group of size 1 doesn't make sense - just isolate the source.
  1441. if (groupedNode.UnityInputFiles.size() == 1) {
  1442. node.UnityInputIsolatedFiles.emplace_back(
  1443. groupedNode.UnityInputFiles[0]);
  1444. node.UnityInputFiles.emplace_back(
  1445. std::move(groupedNode.UnityInputFiles[0]));
  1446. // Clear so we don't enter here on the next iteration.
  1447. groupedNode.UnityInputFiles.clear();
  1448. }
  1449. // We've got only 1 file left. No need to create a Unity node for it,
  1450. // just return it back to the ObjectList and exit.
  1451. if (node.UnityInputFiles.size() == 1) {
  1452. obj.CompilerInputFiles.emplace_back(
  1453. std::move(node.UnityInputFiles[0]));
  1454. break;
  1455. }
  1456. obj.CompilerInputUnity.emplace_back(node.Name);
  1457. result.emplace_back(std::move(node));
  1458. }
  1459. }
  1460. return result;
  1461. }
  1462. FastbuildUnityNode cmFastbuildNormalTargetGenerator::GenerateGroupedUnityNode(
  1463. std::vector<std::string>& inputFiles,
  1464. std::map<std::string, std::vector<std::string>> const& sourcesWithGroups,
  1465. int& groupId)
  1466. {
  1467. std::vector<FastbuildUnityNode> result;
  1468. for (auto const& item : sourcesWithGroups) {
  1469. auto const& group = item.first;
  1470. auto const& sources = item.second;
  1471. FastbuildUnityNode node;
  1472. // Check if any of the sources belong to this group.
  1473. for (auto const& source : sources) {
  1474. auto const iter =
  1475. std::find(inputFiles.begin(), inputFiles.end(), source);
  1476. if (iter == inputFiles.end()) {
  1477. continue;
  1478. }
  1479. node.Name =
  1480. cmStrCat(this->GetName(), "_Unity_Group_", group, '_', ++groupId);
  1481. node.UnityInputFiles.emplace_back(source);
  1482. // Remove from the general batching.
  1483. inputFiles.erase(
  1484. std::remove(inputFiles.begin(), inputFiles.end(), source),
  1485. inputFiles.end());
  1486. }
  1487. if (!node.UnityInputFiles.empty()) {
  1488. // The unity group belongs to the ObjectLists that we're processing.
  1489. // We've grouped all the sources we could from the current ObjectList.
  1490. return node;
  1491. }
  1492. }
  1493. return {};
  1494. }
  1495. std::string cmFastbuildNormalTargetGenerator::ResolveIfAlias(
  1496. std::string const& targetName) const
  1497. {
  1498. LogMessage("targetName: " + targetName);
  1499. std::map<std::string, std::string> const aliases =
  1500. this->Makefile->GetAliasTargets();
  1501. auto const iter = aliases.find(targetName);
  1502. if (iter != aliases.end()) {
  1503. LogMessage("Non alias name: " + iter->second);
  1504. return iter->second;
  1505. }
  1506. return targetName;
  1507. }
  1508. void cmFastbuildNormalTargetGenerator::AppendExternalObject(
  1509. FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedDeps) const
  1510. {
  1511. // Different aspects of this logic exercised in "ObjectLibrary" and
  1512. // "ExportImport" test. When making changes here - verify that both of those
  1513. // tests are still passing.
  1514. LogMessage("AppendExternalObject(...)");
  1515. std::vector<cmSourceFile const*> extObjects;
  1516. this->GeneratorTarget->GetExternalObjects(extObjects, Config);
  1517. for (cmSourceFile const* src : extObjects) {
  1518. std::string const pathToObj =
  1519. this->ConvertToFastbuildPath(src->GetFullPath());
  1520. LogMessage("EXT OBJ: " + pathToObj);
  1521. std::string const objLibName = ResolveIfAlias(src->GetObjectLibrary());
  1522. LogMessage("GetObjectLibrary: " + objLibName);
  1523. // Tested in "ExternalOBJ" test.
  1524. cmTarget const* target =
  1525. this->GlobalCommonGenerator->FindTarget(objLibName);
  1526. if (objLibName.empty()) {
  1527. linkerNode.LibrarianAdditionalInputs.emplace_back(pathToObj);
  1528. }
  1529. // We know how to generate this target and haven't added this dependency
  1530. // yet.
  1531. else if (target) {
  1532. if (!linkedDeps.emplace(objLibName + FASTBUILD_OBJECTS_ALIAS_POSTFIX)
  1533. .second) {
  1534. LogMessage("Object Target: " + objLibName +
  1535. FASTBUILD_OBJECTS_ALIAS_POSTFIX " already linked");
  1536. continue;
  1537. }
  1538. linkerNode.LibrarianAdditionalInputs.emplace_back(
  1539. objLibName + FASTBUILD_OBJECTS_ALIAS_POSTFIX);
  1540. } else if (linkedDeps.emplace(pathToObj).second) {
  1541. LogMessage("Adding obj dep : " + pathToObj);
  1542. linkerNode.LibrarianAdditionalInputs.emplace_back(pathToObj);
  1543. }
  1544. }
  1545. }
  1546. void cmFastbuildNormalTargetGenerator::AppendExeToLink(
  1547. FastbuildLinkerNode& linkerNode,
  1548. cmComputeLinkInformation::Item const& item) const
  1549. {
  1550. std::string const decorated =
  1551. item.GetFormattedItem(this->ConvertToFastbuildPath(item.Value.Value))
  1552. .Value;
  1553. LogMessage("Linking to executable : " + decorated);
  1554. // Tested in "InterfaceLinkLibrariesDirect" and "Plugin" test.
  1555. linkerNode.LinkerOptions +=
  1556. (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(decorated));
  1557. }
  1558. std::string cmFastbuildNormalTargetGenerator::GetImportedLoc(
  1559. cmComputeLinkInformation::Item const& item) const
  1560. {
  1561. // Link to import library when possible.
  1562. // Tested in "StagingPrefix" test on Windows/MSVC.
  1563. cmStateEnums::ArtifactType const artifact =
  1564. item.Target->HasImportLibrary(Config)
  1565. ? cmStateEnums::ImportLibraryArtifact
  1566. : cmStateEnums::RuntimeBinaryArtifact;
  1567. std::string importedLoc = this->ConvertToFastbuildPath(
  1568. item.Target->GetFullPath(Config, artifact, true));
  1569. LogMessage("ImportedGetLocation: " + importedLoc);
  1570. return importedLoc;
  1571. }
  1572. void cmFastbuildNormalTargetGenerator::AppendTargetDep(
  1573. FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedObjects,
  1574. cmComputeLinkInformation::Item const& item) const
  1575. {
  1576. LogMessage("AppendTargetDep(...)");
  1577. cmStateEnums::TargetType const depType = item.Target->GetType();
  1578. LogMessage("Link dep type: " + std::to_string(depType));
  1579. LogMessage("Target name: " + item.Target->GetName());
  1580. auto const resolvedTargetName = ResolveIfAlias(item.Target->GetName());
  1581. LogMessage("Resolved: " + resolvedTargetName);
  1582. if (depType == cmStateEnums::INTERFACE_LIBRARY) {
  1583. return;
  1584. }
  1585. std::string const feature = item.GetFeatureName();
  1586. if (item.Target->IsImported()) {
  1587. if (feature == "FRAMEWORK") {
  1588. // Use just framework's name. The exact path where to look for the
  1589. // framework will be provided from "frameworkPath" in
  1590. // "cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(...)".
  1591. // Tested in "RunCMake.Framework - ImportedFrameworkConsumption".
  1592. std::string const decorated =
  1593. item.GetFormattedItem(item.Value.Value).Value;
  1594. LogMessage("Adding framework dep <" + decorated + "> to command line");
  1595. linkerNode.LinkerOptions += (" " + decorated);
  1596. return;
  1597. }
  1598. if (depType == cmStateEnums::UNKNOWN_LIBRARY) {
  1599. LogMessage("Unknown library -- adding to LibrarianAdditionalInputs or "
  1600. "Libraries2");
  1601. if (UsingCommandLine) {
  1602. AppendCommandLineDep(linkerNode, item);
  1603. } else {
  1604. AppendLinkDep(linkerNode, GetImportedLoc(item));
  1605. }
  1606. return;
  1607. }
  1608. // Tested in "ExportImport" test.
  1609. if (depType == cmStateEnums::EXECUTABLE) {
  1610. AppendExeToLink(linkerNode, item);
  1611. return;
  1612. }
  1613. // Skip exported objects.
  1614. // Tested in "ExportImport" test.
  1615. if (depType == cmStateEnums::OBJECT_LIBRARY) {
  1616. LogMessage("target : " + item.Target->GetName() +
  1617. " already linked... Skipping");
  1618. return;
  1619. }
  1620. // Tested in "ExportImport" test.
  1621. cmList const list{ GetImportedLoc(item) };
  1622. for (std::string const& linkDep : list) {
  1623. AppendLinkDep(linkerNode, linkDep);
  1624. }
  1625. } else {
  1626. if (depType == cmStateEnums::SHARED_LIBRARY &&
  1627. this->GeneratorTarget->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED")) {
  1628. // It moves the dep outside of FASTBuild control, so the binary won't
  1629. // be re-built if the shared lib has changed.
  1630. // Tested in "BuildDepends" test.
  1631. LogMessage("LINK_DEPENDS_NO_SHARED is set on the target, adding dep" +
  1632. item.Value.Value + " as is");
  1633. linkerNode.LinkerOptions +=
  1634. (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(item.Value.Value));
  1635. return;
  1636. }
  1637. // Just add path to binary artifact to command line (except for OBJECT
  1638. // libraries which we will link directly).
  1639. if (UsingCommandLine && depType != cmStateEnums::OBJECT_LIBRARY) {
  1640. AppendCommandLineDep(linkerNode, item);
  1641. return;
  1642. }
  1643. // This dep has a special way of linking to it (e.g.
  1644. // "CMAKE_LINK_LIBRARY_USING_<FEATURE>").
  1645. bool const isFeature = !feature.empty() && feature != "DEFAULT";
  1646. if (isFeature) {
  1647. std::string const decorated =
  1648. item.GetFormattedItem(this->ConvertToFastbuildPath(item.Value.Value))
  1649. .Value;
  1650. LogMessage("Prepending with feature: " + decorated);
  1651. linkerNode.LinkerOptions += (" " + decorated);
  1652. }
  1653. std::string dep = resolvedTargetName +
  1654. (depType == cmStateEnums::OBJECT_LIBRARY
  1655. ? FASTBUILD_OBJECTS_ALIAS_POSTFIX
  1656. : FASTBUILD_LINK_ARTIFACTS_ALIAS_POSTFIX);
  1657. if (!linkerNode.Arch.empty()) {
  1658. dep += cmStrCat('-', linkerNode.Arch);
  1659. }
  1660. // If we have a special way of linking the dep, we can't have it in
  1661. // ".Libraries" (since there might be multiple such deps, but
  1662. // FASTBuild expands ".Libraries" as a continuous array, so we can't
  1663. // inject any properties in between). Tested in
  1664. // "RunCMake.target_link_libraries-LINK_LIBRARY" test.
  1665. if (isFeature) {
  1666. LogMessage("AppendTargetDep: " + dep + " as prebuild");
  1667. linkerNode.PreBuildDependencies.emplace(dep);
  1668. return;
  1669. }
  1670. if (depType != cmStateEnums::OBJECT_LIBRARY ||
  1671. linkedObjects.emplace(dep).second) {
  1672. AppendLinkDep(linkerNode, dep);
  1673. }
  1674. AppendTransitivelyLinkedObjects(*item.Target, linkedObjects);
  1675. }
  1676. }
  1677. void cmFastbuildNormalTargetGenerator::AppendPrebuildDeps(
  1678. FastbuildLinkerNode& linkerNode,
  1679. cmComputeLinkInformation::Item const& item) const
  1680. {
  1681. if (!item.Target->IsImported()) {
  1682. return;
  1683. }
  1684. // In "RunCMake.FileAPI" imported object library "imported_object_lib" is
  1685. // added w/o import location...
  1686. if (item.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  1687. return;
  1688. }
  1689. cmList const list{ GetImportedLoc(item) };
  1690. for (std::string const& linkDep : list) {
  1691. // In case we know how to generate this file (needed for proper
  1692. // sorting by deps). Tested in "RunCMake.target_link_libraries-ALIAS"
  1693. // test.
  1694. auto fastbuildTarget =
  1695. this->GetGlobalGenerator()->GetTargetByOutputName(linkDep);
  1696. std::string fastbuildTargetName;
  1697. if (fastbuildTarget) {
  1698. fastbuildTargetName = std::move(fastbuildTarget->Name);
  1699. }
  1700. if (!fastbuildTargetName.empty()) {
  1701. LogMessage("Adding dep to " + fastbuildTargetName);
  1702. linkerNode.PreBuildDependencies.insert(std::move(fastbuildTargetName));
  1703. } else {
  1704. if (!cmIsNOTFOUND(linkDep)) {
  1705. LogMessage("Adding dep " + linkDep + " for sorting");
  1706. linkerNode.PreBuildDependencies.insert(linkDep);
  1707. }
  1708. }
  1709. }
  1710. }
  1711. void cmFastbuildNormalTargetGenerator::AppendTransitivelyLinkedObjects(
  1712. cmGeneratorTarget const& target, std::set<std::string>& linkedObjects) const
  1713. {
  1714. std::vector<std::string> objs;
  1715. // Consider that all those object are now linked as well.
  1716. // Tested in "ExportImport" test.
  1717. target.GetTargetObjectNames(Config, objs);
  1718. for (std::string const& obj : objs) {
  1719. std::string const pathToObj = this->ConvertToFastbuildPath(
  1720. cmStrCat(target.GetObjectDirectory(Config), '/', obj));
  1721. linkedObjects.insert(pathToObj);
  1722. }
  1723. // Object libs should not be propagated transitively. It's especially
  1724. // important for LinkObjRHSObject2 test where the absence of the propagation
  1725. // is tested.
  1726. for (auto const& linkedTarget :
  1727. target.Target->GetLinkImplementationEntries()) {
  1728. auto objAlias = linkedTarget.Value + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
  1729. LogMessage("Object target is linked transitively " + objAlias);
  1730. linkedObjects.emplace(std::move(objAlias));
  1731. }
  1732. }
  1733. void cmFastbuildNormalTargetGenerator::AppendCommandLineDep(
  1734. FastbuildLinkerNode& linkerNode,
  1735. cmComputeLinkInformation::Item const& item) const
  1736. {
  1737. LogMessage("AppendCommandLineDep(...)");
  1738. // Tested in:
  1739. // "LinkDirectory" (TargetType::EXECUTABLE),
  1740. // "ObjC.simple-build-test" (TargetType::SHARED_LIBRARY),
  1741. // "XCTest" (TargetType::MODULE_LIBRARY) tests.
  1742. std::string formatted;
  1743. if (item.Target && item.Target->IsImported()) {
  1744. formatted = GetImportedLoc(item);
  1745. } else {
  1746. formatted = item.GetFormattedItem(item.Value.Value).Value;
  1747. }
  1748. formatted = this->ConvertToFastbuildPath(formatted);
  1749. LogMessage("Unknown link dep: " + formatted + ", adding to command line");
  1750. // Only add real artifacts to .Libraries2, otherwise Fastbuild will always
  1751. // consider the target out-of-date (since its input doesn't exist).
  1752. if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes &&
  1753. item.GetFeatureName() == "DEFAULT") {
  1754. linkerNode.LinkerOptions +=
  1755. (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(formatted));
  1756. AppendToLibraries2IfApplicable(linkerNode, std::move(formatted));
  1757. } else {
  1758. // It's some link option, not a path.
  1759. linkerNode.LinkerOptions += (" " + formatted);
  1760. }
  1761. }
  1762. void cmFastbuildNormalTargetGenerator::AppendToLibraries2IfApplicable(
  1763. FastbuildLinkerNode& linkerNode, std::string dep) const
  1764. {
  1765. // Strings like "-framework Cocoa" in .Libraries2 node will always make the
  1766. // target out-of-date (since it never exists).
  1767. if (this->GeneratorTarget->IsApple() &&
  1768. cmSystemTools::StringStartsWith(dep, "-framework")) {
  1769. LogMessage("Not adding framework: " + dep + " to .Libraries2");
  1770. return;
  1771. }
  1772. auto const target = this->GetGlobalGenerator()->GetTargetByOutputName(dep);
  1773. // Fastbuild doesn't support executables in .Libraries2, though we can use
  1774. // Executables via "-bundle_loader" on Apple.
  1775. if (this->GeneratorTarget->IsApple() && target &&
  1776. !target->LinkerNode.empty() &&
  1777. target->LinkerNode[0].Type == FastbuildLinkerNode::EXECUTABLE) {
  1778. LogMessage("Not adding DLL/Executable(" + linkerNode.Name +
  1779. " to .Libraries2");
  1780. return;
  1781. }
  1782. // Additing to .Libraries2 for tracking.
  1783. LogMessage("Adding " + dep + " .Libraries2");
  1784. linkerNode.Libraries2.emplace_back(std::move(dep));
  1785. }
  1786. void cmFastbuildNormalTargetGenerator::AppendLINK_DEPENDS(
  1787. FastbuildLinkerNode& linkerNode) const
  1788. {
  1789. // LINK_DEPENDS and such.
  1790. // Tested in "BuildDepends" test.
  1791. for (std::string const& lang : Languages) {
  1792. for (BT<std::string> const& dep :
  1793. this->GeneratorTarget->GetLinkDepends(Config, lang)) {
  1794. // We can't add "LINK_DEPENDS" to .PreBuildDependencies, since FASTBuild
  1795. // only forces such targets to be built and doesn't force re-linking if
  1796. // they've changed.
  1797. linkerNode.Libraries2.emplace_back(
  1798. this->ConvertToFastbuildPath(dep.Value));
  1799. }
  1800. }
  1801. }
  1802. void cmFastbuildNormalTargetGenerator::AppendLinkDep(
  1803. FastbuildLinkerNode& linkerNode, std::string dep) const
  1804. {
  1805. LogMessage("AppendLinkDep: " + dep +
  1806. " to .LibrarianAdditionalInputs/.Libraries");
  1807. linkerNode.LibrarianAdditionalInputs.emplace_back(std::move(dep));
  1808. }
  1809. void cmFastbuildNormalTargetGenerator::AppendDirectObjectLibs(
  1810. FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedObjects)
  1811. {
  1812. auto const srcs = this->GeneratorTarget->GetSourceFiles(Config);
  1813. for (auto const& entry : srcs) {
  1814. auto const objLib = entry.Value->GetObjectLibrary();
  1815. auto const objPath = entry.Value->GetFullPath();
  1816. LogMessage("Source obj entry: " + objPath);
  1817. if (!objLib.empty()) {
  1818. auto* const objTarget =
  1819. this->LocalGenerator->FindGeneratorTargetToUse(objLib);
  1820. if (objTarget) {
  1821. LogMessage("Imported: " + std::to_string(objTarget->IsImported()));
  1822. std::string fastbuildTarget;
  1823. // If target is imported - we don't have it in our build file, so can't
  1824. // refer to it by name. Use file path to the object then.
  1825. // Tested in "ExportImport" test.
  1826. if (objTarget->IsImported()) {
  1827. fastbuildTarget = entry.Value->GetFullPath();
  1828. } else {
  1829. // Mark all target objects as linked.
  1830. linkedObjects.emplace(this->ConvertToFastbuildPath(objPath));
  1831. fastbuildTarget =
  1832. objTarget->GetName() + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
  1833. }
  1834. if (linkedObjects.emplace(fastbuildTarget).second) {
  1835. LogMessage("Adding object target: " + fastbuildTarget);
  1836. linkerNode.LibrarianAdditionalInputs.emplace_back(
  1837. std::move(fastbuildTarget));
  1838. }
  1839. }
  1840. }
  1841. }
  1842. }
  1843. void cmFastbuildNormalTargetGenerator::AppendLinkDeps(
  1844. std::set<FastbuildTargetDep>& preBuildDeps, FastbuildLinkerNode& linkerNode,
  1845. FastbuildLinkerNode& cudaDeviceLinkLinkerNode)
  1846. {
  1847. std::set<std::string> linkedObjects;
  1848. cmComputeLinkInformation const* linkInfo =
  1849. this->GeneratorTarget->GetLinkInformation(Config);
  1850. if (!linkInfo) {
  1851. return;
  1852. }
  1853. UsingCommandLine = false;
  1854. AppendLINK_DEPENDS(linkerNode);
  1855. // Object libs that are linked directly to target (e.g.
  1856. // add_executable(test_exe archiveObjs)
  1857. AppendDirectObjectLibs(linkerNode, linkedObjects);
  1858. std::size_t numberOfDirectlyLinkedObjects =
  1859. linkerNode.LibrarianAdditionalInputs.size();
  1860. // target_link_libraries.
  1861. cmComputeLinkInformation::ItemVector const items = linkInfo->GetItems();
  1862. LogMessage(cmStrCat("Link items size: ", items.size()));
  1863. for (cmComputeLinkInformation::Item const& item : items) {
  1864. std::string const feature = item.GetFeatureName();
  1865. LogMessage("GetFeatureName: " + feature);
  1866. std::string const formatted =
  1867. item.GetFormattedItem(item.Value.Value).Value;
  1868. if (!feature.empty()) {
  1869. LogMessage("GetFormattedItem: " +
  1870. item.GetFormattedItem(item.Value.Value).Value);
  1871. }
  1872. // We're linked to `$<TARGET_OBJECTS>`.
  1873. // Static libs transitively propagate such deps, see:
  1874. // https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries-via-target-objects
  1875. if (item.ObjectSource &&
  1876. linkerNode.Type != FastbuildLinkerNode::STATIC_LIBRARY) {
  1877. // Tested in "ObjectLibrary" test.
  1878. std::string const libName = item.ObjectSource->GetObjectLibrary();
  1879. std::string dep = libName + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
  1880. if (linkedObjects.emplace(dep).second) {
  1881. FastbuildTargetDep targetDep{ libName };
  1882. targetDep.Type = FastbuildTargetDepType::ORDER_ONLY;
  1883. preBuildDeps.emplace(std::move(targetDep));
  1884. cmTarget const* importedTarget =
  1885. this->LocalGenerator->GetMakefile()->FindImportedTarget(libName);
  1886. // Add direct path to the object for imported target
  1887. // since such targets are not defined in fbuild.bff file.
  1888. if (importedTarget) {
  1889. LogMessage(
  1890. cmStrCat("Adding ", formatted, " to LibrarianAdditionalInputs"));
  1891. linkerNode.LibrarianAdditionalInputs.emplace_back(formatted);
  1892. } else {
  1893. LogMessage(
  1894. cmStrCat("Adding ", dep, " to LibrarianAdditionalInputs"));
  1895. linkerNode.LibrarianAdditionalInputs.emplace_back(std::move(dep));
  1896. }
  1897. }
  1898. } else if (linkerNode.Type == FastbuildLinkerNode::STATIC_LIBRARY) {
  1899. LogMessage("Skipping linking to STATIC_LIBRARY (" + linkerNode.Name +
  1900. ")");
  1901. continue;
  1902. }
  1903. // We're linked to exact target.
  1904. else if (item.Target) {
  1905. AppendTargetDep(linkerNode, linkedObjects, item);
  1906. AppendPrebuildDeps(linkerNode, item);
  1907. if (!item.Target->IsImported() &&
  1908. item.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  1909. ++numberOfDirectlyLinkedObjects;
  1910. cudaDeviceLinkLinkerNode.LibrarianAdditionalInputs.emplace_back(
  1911. cmStrCat(item.Target->GetName(), FASTBUILD_OBJECTS_ALIAS_POSTFIX));
  1912. }
  1913. } else {
  1914. AppendCommandLineDep(linkerNode, item);
  1915. UsingCommandLine = true;
  1916. }
  1917. }
  1918. AppendExternalObject(linkerNode, linkedObjects);
  1919. if (!cudaDeviceLinkLinkerNode.Name.empty()) {
  1920. linkerNode.LibrarianAdditionalInputs.push_back(
  1921. cudaDeviceLinkLinkerNode.Name);
  1922. // CUDA device-link stub needs to go AFTER direct object dependencies, but
  1923. // BEFORE all other dependencies. Needed for the correct left-to-right
  1924. // symbols resolution on Linux.
  1925. std::swap(
  1926. linkerNode.LibrarianAdditionalInputs[numberOfDirectlyLinkedObjects],
  1927. linkerNode.LibrarianAdditionalInputs.back());
  1928. }
  1929. }
  1930. void cmFastbuildNormalTargetGenerator::AddLipoCommand(FastbuildTarget& target)
  1931. {
  1932. static auto const lipo = cmSystemTools::FindProgram("lipo");
  1933. LogMessage("found lipo at " + lipo);
  1934. FastbuildExecNode exec;
  1935. exec.ExecExecutable = lipo;
  1936. exec.ExecOutput = target.RealOutput;
  1937. if (exec.ExecOutput != target.Name) {
  1938. exec.Name = target.Name;
  1939. }
  1940. for (auto const& ArchSpecificTarget : target.LinkerNode) {
  1941. exec.ExecInput.emplace_back(ArchSpecificTarget.LinkerOutput);
  1942. }
  1943. exec.ExecArguments +=
  1944. "-create -output " + target.RealOutput + " " + cmJoin(exec.ExecInput, " ");
  1945. target.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
  1946. exec.ExecOutput);
  1947. target.PostBuildExecNodes.Nodes.emplace_back(std::move(exec));
  1948. }
  1949. void cmFastbuildNormalTargetGenerator::GenerateLink(
  1950. FastbuildTarget& target, std::vector<std::string> const& objectDepends)
  1951. {
  1952. std::string const targetName = this->GetTargetName();
  1953. cmGeneratorTarget::Names const targetNames = DetectOutput();
  1954. LogMessage("targetNames.Real: " + targetNames.Real);
  1955. LogMessage("targetNames.ImportOutput: " + targetNames.ImportOutput);
  1956. LogMessage("targetNames.SharedObject: " + targetNames.SharedObject);
  1957. LogMessage("targetNames.Base: " + targetNames.Base);
  1958. std::vector<std::string> allNodes;
  1959. auto const arches = this->GetArches();
  1960. for (std::size_t i = 0; i < arches.size(); ++i) {
  1961. auto const& arch = arches[i];
  1962. FastbuildLinkerNode linkerNode;
  1963. ProcessManifests(linkerNode);
  1964. // Objects built by the current target.
  1965. for (auto const& objectList : target.ObjectListNodes) {
  1966. if (objectList.arch.empty() || objectList.arch == arch) {
  1967. linkerNode.LibrarianAdditionalInputs.push_back(objectList.Name);
  1968. }
  1969. }
  1970. // Detection of the link command as follows:
  1971. auto const type = this->GeneratorTarget->GetType();
  1972. switch (type) {
  1973. case cmStateEnums::EXECUTABLE: {
  1974. LogMessage("Generating EXECUTABLE");
  1975. linkerNode.Type = FastbuildLinkerNode::EXECUTABLE;
  1976. break;
  1977. }
  1978. case cmStateEnums::MODULE_LIBRARY: {
  1979. LogMessage("Generating MODULE_LIBRARY");
  1980. linkerNode.Type = FastbuildLinkerNode::SHARED_LIBRARY;
  1981. break;
  1982. }
  1983. case cmStateEnums::SHARED_LIBRARY: {
  1984. LogMessage("Generating SHARED_LIBRARY");
  1985. linkerNode.Type = FastbuildLinkerNode::SHARED_LIBRARY;
  1986. break;
  1987. }
  1988. case cmStateEnums::STATIC_LIBRARY: {
  1989. LogMessage("Generating STATIC_LIBRARY");
  1990. linkerNode.Type = FastbuildLinkerNode::STATIC_LIBRARY;
  1991. break;
  1992. }
  1993. case cmStateEnums::OBJECT_LIBRARY: {
  1994. LogMessage("Generating OBJECT_LIBRARY");
  1995. return;
  1996. }
  1997. default: {
  1998. LogMessage("Skipping GenerateLink");
  1999. return;
  2000. }
  2001. }
  2002. std::string const targetOutput =
  2003. ConvertToFastbuildPath(GeneratorTarget->GetFullPath(Config));
  2004. std::string targetOutputReal = ConvertToFastbuildPath(
  2005. GeneratorTarget->GetFullPath(Config, cmStateEnums::RuntimeBinaryArtifact,
  2006. /*realname=*/true));
  2007. LogMessage("targetOutput: " + targetOutput);
  2008. LogMessage("targetOutputReal: " + targetOutputReal);
  2009. std::string const output =
  2010. cmSystemTools::GetFilenameName(targetNames.Output);
  2011. std::string const outputReal =
  2012. cmSystemTools::GetFilenameName(targetNames.Real);
  2013. // Generate "Copy" nodes for copying Framework / Bundle resources.
  2014. AppendExtraResources(linkerNode.PreBuildDependencies);
  2015. if (type == cmStateEnums::EXECUTABLE ||
  2016. type == cmStateEnums::SHARED_LIBRARY) {
  2017. // Tested in "RunCMake.BuildDepends" test (we need to rebuild when
  2018. // manifest changes).
  2019. std::copy(objectDepends.begin(), objectDepends.end(),
  2020. std::back_inserter(linkerNode.Libraries2));
  2021. }
  2022. if (GeneratorTarget->IsAppBundleOnApple()) {
  2023. // Create the app bundle
  2024. std::string outpath = GeneratorTarget->GetDirectory(Config);
  2025. this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
  2026. Config);
  2027. targetOutputReal = outpath;
  2028. targetOutputReal += "/";
  2029. targetOutputReal += outputReal;
  2030. targetOutputReal = this->ConvertToFastbuildPath(targetOutputReal);
  2031. } else if (GeneratorTarget->IsFrameworkOnApple()) {
  2032. // Create the library framework.
  2033. this->OSXBundleGenerator->CreateFramework(
  2034. targetNames.Output, GeneratorTarget->GetDirectory(Config), Config);
  2035. } else if (GeneratorTarget->IsCFBundleOnApple()) {
  2036. // Create the core foundation bundle.
  2037. this->OSXBundleGenerator->CreateCFBundle(
  2038. targetNames.Output, GeneratorTarget->GetDirectory(Config), Config);
  2039. }
  2040. std::string linkCmd;
  2041. if (!DetectBaseLinkerCommand(linkCmd, arch, targetNames)) {
  2042. LogMessage("No linker command detected");
  2043. return;
  2044. }
  2045. std::string executable;
  2046. std::string linkerOptions;
  2047. std::string linkerType = "auto";
  2048. GetLinkerExecutableAndArgs(linkCmd, executable, linkerOptions);
  2049. linkerNode.Compiler = ".Compiler_dummy";
  2050. linkerNode.CompilerOptions = " ";
  2051. linkerNode.Name = targetName;
  2052. linkerNode.LinkerOutput = targetOutputReal;
  2053. this->GetGlobalGenerator()->AddFileToClean(linkerNode.LinkerOutput);
  2054. target.RealOutput = targetOutputReal;
  2055. if (!arch.empty()) {
  2056. linkerNode.Name += cmStrCat('-', arch);
  2057. linkerNode.LinkerOutput += cmStrCat('.', arch);
  2058. linkerNode.Arch = arch;
  2059. }
  2060. linkerNode.Linker = executable;
  2061. linkerNode.LinkerType = linkerType;
  2062. linkerNode.LinkerOptions += linkerOptions;
  2063. // Check if we have CUDA device link stub for this target.
  2064. FastbuildLinkerNode dummyCudaDeviceLinkNode;
  2065. AppendLinkDeps(target.PreBuildDependencies, linkerNode,
  2066. target.CudaDeviceLinkNode.size() > i
  2067. ? target.CudaDeviceLinkNode[i]
  2068. : dummyCudaDeviceLinkNode);
  2069. ApplyLWYUToLinkerCommand(linkerNode);
  2070. // On macOS, only the last LinkerNode performs lipo in POST_BUILD.
  2071. // Make it depend on all previous nodes to ensure correct execution order.
  2072. if (i == arches.size() - 1) {
  2073. for (auto& prevNode : allNodes) {
  2074. linkerNode.PreBuildDependencies.emplace(std::move(prevNode));
  2075. }
  2076. } else {
  2077. allNodes.emplace_back(linkerNode.Name);
  2078. }
  2079. if (!target.ObjectListNodes.empty()) {
  2080. // Just reuse any of compiler options mainly for the correct IDE project
  2081. // generation.
  2082. linkerNode.CompilerOptions = target.ObjectListNodes[0].CompilerOptions;
  2083. }
  2084. target.LinkerNode.emplace_back(std::move(linkerNode));
  2085. }
  2086. }
  2087. std::vector<FastbuildExecNode>
  2088. cmFastbuildNormalTargetGenerator::GetSymlinkExecs() const
  2089. {
  2090. std::vector<FastbuildExecNode> res;
  2091. cmGeneratorTarget::Names const targetNames = DetectOutput();
  2092. LogMessage("targetNames.Real: " + targetNames.Real);
  2093. LogMessage("targetNames.ImportOutput: " + targetNames.ImportOutput);
  2094. LogMessage("targetNames.SharedObject: " + targetNames.SharedObject);
  2095. LogMessage("targetNames.Base: " + targetNames.Base);
  2096. std::string const targetOutput =
  2097. ConvertToFastbuildPath(GeneratorTarget->GetFullPath(Config));
  2098. std::string const targetOutputReal = ConvertToFastbuildPath(
  2099. GeneratorTarget->GetFullPath(Config, cmStateEnums::RuntimeBinaryArtifact,
  2100. /*realname=*/true));
  2101. LogMessage("targetOutput: " + targetOutput);
  2102. LogMessage("targetOutputReal: " + targetOutputReal);
  2103. if (targetOutput != targetOutputReal &&
  2104. !GeneratorTarget->IsFrameworkOnApple()) {
  2105. auto const generateSymlinkCommand = [&](std::string const& from,
  2106. std::string const& to) {
  2107. if (from.empty() || to.empty() || from == to) {
  2108. return;
  2109. }
  2110. LogMessage("Symlinking " + from + " -> " + to);
  2111. FastbuildExecNode postBuildExecNode;
  2112. postBuildExecNode.Name = "cmake_symlink_" + to;
  2113. postBuildExecNode.ExecOutput =
  2114. cmJoin({ GeneratorTarget->GetDirectory(Config), to }, "/");
  2115. postBuildExecNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
  2116. postBuildExecNode.ExecArguments =
  2117. "-E cmake_symlink_executable " +
  2118. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(from) + " " +
  2119. cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
  2120. this->ConvertToFastbuildPath(postBuildExecNode.ExecOutput));
  2121. res.emplace_back(std::move(postBuildExecNode));
  2122. };
  2123. generateSymlinkCommand(targetNames.Real, targetNames.Output);
  2124. generateSymlinkCommand(targetNames.Real, targetNames.SharedObject);
  2125. generateSymlinkCommand(targetNames.ImportReal, targetNames.ImportOutput);
  2126. }
  2127. return res;
  2128. }