cmFastbuildNormalTargetGenerator.cxx 88 KB

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