cmFastbuildNormalTargetGenerator.cxx 87 KB

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