| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948 | 
							- /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 
-    file LICENSE.rst or https://cmake.org/licensing for details.  */
 
- #include "cmFastbuildNormalTargetGenerator.h"
 
- #include <algorithm>
 
- #include <cstddef>
 
- #include <iterator>
 
- #include <map>
 
- #include <sstream>
 
- #include <string>
 
- #include <unordered_map>
 
- #include <unordered_set>
 
- #include <utility>
 
- #include <cm/memory>
 
- #include <cm/optional>
 
- #include "cmsys/FStream.hxx"
 
- #include "cmAlgorithms.h"
 
- #include "cmCommonTargetGenerator.h"
 
- #include "cmCryptoHash.h"
 
- #include "cmFastbuildTargetGenerator.h"
 
- #include "cmGeneratedFileStream.h"
 
- #include "cmGeneratorExpression.h"
 
- #include "cmGeneratorTarget.h"
 
- #include "cmGlobalCommonGenerator.h"
 
- #include "cmGlobalFastbuildGenerator.h"
 
- #include "cmLinkLineComputer.h"
 
- #include "cmList.h"
 
- #include "cmListFileCache.h"
 
- #include "cmLocalCommonGenerator.h"
 
- #include "cmLocalFastbuildGenerator.h"
 
- #include "cmLocalGenerator.h"
 
- #include "cmMakefile.h"
 
- #include "cmOSXBundleGenerator.h"
 
- #include "cmObjectLocation.h"
 
- #include "cmOutputConverter.h"
 
- #include "cmSourceFile.h"
 
- #include "cmState.h"
 
- #include "cmStateDirectory.h"
 
- #include "cmStateSnapshot.h"
 
- #include "cmStateTypes.h"
 
- #include "cmStringAlgorithms.h"
 
- #include "cmSystemTools.h"
 
- #include "cmTarget.h"
 
- #include "cmTargetDepend.h"
 
- #include "cmValue.h"
 
- #include "cmake.h"
 
- namespace {
 
- std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
 
- std::string const COMPILE_OPTIONS("COMPILE_OPTIONS");
 
- std::string const COMPILE_FLAGS("COMPILE_FLAGS");
 
- std::string const CMAKE_LANGUAGE("CMAKE");
 
- std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
 
- } // anonymous namespace
 
- cmFastbuildNormalTargetGenerator::cmFastbuildNormalTargetGenerator(
 
-   cmGeneratorTarget* gt, std::string configParam)
 
-   : cmFastbuildTargetGenerator(gt, std::move(configParam))
 
-   , RulePlaceholderExpander(
 
-       this->LocalCommonGenerator->CreateRulePlaceholderExpander())
 
-   , ObjectOutDir(this->GetGlobalGenerator()->ConvertToFastbuildPath(
 
-       this->GeneratorTarget->GetObjectDirectory(Config)))
 
-   , Languages(GetLanguages())
 
-   , CompileObjectCmakeRules(GetCompileObjectCommand())
 
- {
 
-   LogMessage(cmStrCat("objectOutDir: ", ObjectOutDir));
 
-   this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(gt);
 
-   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 
-   // Quotes to account for potential spaces.
 
-   RulePlaceholderExpander->SetTargetImpLib(
 
-     "\"" FASTBUILD_DOLLAR_TAG "TargetOutputImplib" FASTBUILD_DOLLAR_TAG "\"");
 
-   for (auto const& lang : Languages) {
 
-     TargetIncludesByLanguage[lang] = this->GetIncludes(lang, Config);
 
-     LogMessage("targetIncludes for lang " + lang + " = " +
 
-                TargetIncludesByLanguage[lang]);
 
-     for (auto const& arch : this->GetArches()) {
 
-       auto& flags = CompileFlagsByLangAndArch[std::make_pair(lang, arch)];
 
-       this->LocalCommonGenerator->GetTargetCompileFlags(
 
-         this->GeneratorTarget, Config, lang, flags, arch);
 
-       LogMessage(
 
-         cmStrCat("Lang: ", lang, ", arch: ", arch, ", flags: ", flags));
 
-     }
 
-   }
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::DetectCompilerFlags(
 
-   cmSourceFile const& srcFile, std::string const& arch)
 
- {
 
-   std::string const language = srcFile.GetLanguage();
 
-   cmGeneratorExpressionInterpreter genexInterpreter(
 
-     this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
 
-   std::vector<std::string> sourceIncludesVec;
 
-   if (cmValue cincludes = srcFile.GetProperty(INCLUDE_DIRECTORIES)) {
 
-     this->LocalGenerator->AppendIncludeDirectories(
 
-       sourceIncludesVec,
 
-       genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), srcFile);
 
-   }
 
-   std::string sourceIncludesStr = this->LocalGenerator->GetIncludeFlags(
 
-     sourceIncludesVec, this->GeneratorTarget, language, Config, false);
 
-   LogMessage(cmStrCat("sourceIncludes = ", sourceIncludesStr));
 
-   std::string compileFlags =
 
-     CompileFlagsByLangAndArch[std::make_pair(language, arch)];
 
-   this->GeneratorTarget->AddExplicitLanguageFlags(compileFlags, srcFile);
 
-   if (cmValue const cflags = srcFile.GetProperty(COMPILE_FLAGS)) {
 
-     this->LocalGenerator->AppendFlags(
 
-       compileFlags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
 
-   }
 
-   if (cmValue const coptions = srcFile.GetProperty(COMPILE_OPTIONS)) {
 
-     this->LocalGenerator->AppendCompileOptions(
 
-       compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
 
-   }
 
-   // Source includes take precedence over target includes.
 
-   this->LocalGenerator->AppendFlags(compileFlags, sourceIncludesStr);
 
-   this->LocalGenerator->AppendFlags(compileFlags,
 
-                                     TargetIncludesByLanguage[language]);
 
-   if (language == "Fortran") {
 
-     this->AppendFortranFormatFlags(compileFlags, srcFile);
 
-     this->AppendFortranPreprocessFlags(compileFlags, srcFile);
 
-   }
 
-   LogMessage(cmStrCat("compileFlags = ", compileFlags));
 
-   return compileFlags;
 
- }
 
- void cmFastbuildNormalTargetGenerator::GetLinkerExecutableAndArgs(
 
-   std::string const& command, std::string& outLinkerExecutable,
 
-   std::string& outLinkerArgs)
 
- {
 
-   if (command.empty()) {
 
-     return;
 
-   }
 
-   LogMessage("Link Command: " + command);
 
-   auto const& compilers = this->GetGlobalGenerator()->Compilers;
 
-   auto const linkerLauncherVarName = FASTBUILD_LINKER_LAUNCHER_PREFIX +
 
-     this->GeneratorTarget->GetLinkerLanguage(Config);
 
-   auto const iter = compilers.find(linkerLauncherVarName);
 
-   // Tested in "RunCMake.LinkerLauncher" test.
 
-   if (iter != compilers.end()) {
 
-     LogMessage("Linker launcher: " + iter->first);
 
-     outLinkerExecutable = iter->second.Executable;
 
-     outLinkerArgs = cmStrCat(iter->second.Args, " ", command);
 
-   } else {
 
- #ifdef _WIN32
 
-     std::vector<std::string> args;
 
-     std::string tmp;
 
-     cmSystemTools::SplitProgramFromArgs(command, tmp, outLinkerArgs);
 
-     // cmLocalGenerator::GetStaticLibraryFlags seems to add empty quotes when
 
-     // appending "STATIC_LIBRARY_FLAGS_DEBUG"...
 
-     cmSystemTools::ReplaceString(outLinkerArgs, "\"\"", "");
 
-     cmSystemTools::ParseWindowsCommandLine(command.c_str(), args);
 
-     outLinkerExecutable = std::move(args[0]);
 
- #else
 
-     cmSystemTools::SplitProgramFromArgs(command, outLinkerExecutable,
 
-                                         outLinkerArgs);
 
- #endif
 
-   }
 
-   LogMessage("Linker Exe: " + outLinkerExecutable);
 
-   LogMessage("Linker args: " + outLinkerArgs);
 
- }
 
- bool cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(
 
-   std::string& command, std::string const& arch,
 
-   cmGeneratorTarget::Names const& targetNames)
 
- {
 
-   std::string const linkLanguage =
 
-     this->GeneratorTarget->GetLinkerLanguage(Config);
 
-   if (linkLanguage.empty()) {
 
-     cmSystemTools::Error("CMake can not determine linker language for "
 
-                          "target: " +
 
-                          this->GeneratorTarget->GetName());
 
-     return false;
 
-   }
 
-   LogMessage("linkLanguage: " + linkLanguage);
 
-   std::string linkLibs;
 
-   std::string targetFlags;
 
-   std::string linkFlags;
 
-   std::string frameworkPath;
 
-   // Tested in "RunCMake.StandardLinkDirectories" test.
 
-   std::string linkPath;
 
-   std::unique_ptr<cmLinkLineComputer> const linkLineComputer =
 
-     this->GetGlobalGenerator()->CreateLinkLineComputer(
 
-       this->LocalGenerator,
 
-       this->GetLocalGenerator()->GetStateSnapshot().GetDirectory());
 
-   this->LocalCommonGenerator->GetTargetFlags(
 
-     linkLineComputer.get(), Config, linkLibs, targetFlags, linkFlags,
 
-     frameworkPath, linkPath, this->GeneratorTarget);
 
-   // cmLocalGenerator::GetStaticLibraryFlags seems to add empty quotes when
 
-   // appending "STATIC_LIBRARY_FLAGS_DEBUG"...
 
-   cmSystemTools::ReplaceString(linkFlags, "\"\"", "");
 
-   LogMessage("linkLibs: " + linkLibs);
 
-   LogMessage("targetFlags: " + targetFlags);
 
-   LogMessage("linkFlags: " + linkFlags);
 
-   LogMessage("frameworkPath: " + frameworkPath);
 
-   LogMessage("linkPath: " + linkPath);
 
-   LogMessage("MANIFESTS: " + this->GetManifests(Config));
 
-   cmComputeLinkInformation* linkInfo =
 
-     this->GeneratorTarget->GetLinkInformation(Config);
 
-   if (!linkInfo) {
 
-     return false;
 
-   }
 
-   // Tested in "RunCMake.RuntimePath" test.
 
-   std::string const rpath = linkLineComputer->ComputeRPath(*linkInfo);
 
-   LogMessage("RPath: " + rpath);
 
-   if (!linkFlags.empty()) {
 
-     linkFlags += " ";
 
-   }
 
-   linkFlags += cmJoin({ rpath, frameworkPath, linkPath }, " ");
 
-   cmStateEnums::TargetType const targetType = this->GeneratorTarget->GetType();
 
-   // Add OS X version flags, if any.
 
-   if (targetType == cmStateEnums::SHARED_LIBRARY ||
 
-       targetType == cmStateEnums::MODULE_LIBRARY) {
 
-     this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
 
-     this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
 
-   }
 
-   // Add Arch flags to link flags for binaries
 
-   if (targetType == cmStateEnums::SHARED_LIBRARY ||
 
-       targetType == cmStateEnums::MODULE_LIBRARY ||
 
-       targetType == cmStateEnums::EXECUTABLE) {
 
-     this->LocalCommonGenerator->AddArchitectureFlags(
 
-       linkFlags, this->GeneratorTarget, linkLanguage, Config, arch);
 
-     this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags(
 
-       linkFlags, this->GetGeneratorTarget(), linkLanguage);
 
-   }
 
-   cmRulePlaceholderExpander::RuleVariables vars;
 
-   vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
 
-   vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
 
-   vars.Language = linkLanguage.c_str();
 
-   std::string const manifests =
 
-     cmJoin(this->GetManifestsAsFastbuildPath(), " ");
 
-   vars.Manifests = manifests.c_str();
 
-   std::string const stdLibString = this->Makefile->GetSafeDefinition(
 
-     cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES"));
 
-   LogMessage(cmStrCat("Target type: ", this->GeneratorTarget->GetType()));
 
-   if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
 
-       this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
 
-       this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
 
-     vars.Objects = FASTBUILD_1_0_INPUT_PLACEHOLDER;
 
-     vars.LinkLibraries = stdLibString.c_str();
 
-   } else {
 
-     vars.Objects = FASTBUILD_1_INPUT_PLACEHOLDER;
 
-   }
 
-   vars.ObjectDir = FASTBUILD_DOLLAR_TAG "TargetOutDir" FASTBUILD_DOLLAR_TAG;
 
-   vars.Target = FASTBUILD_2_INPUT_PLACEHOLDER;
 
-   std::string install_dir;
 
-   std::string target_so_name;
 
-   if (this->GeneratorTarget->HasSOName(Config)) {
 
-     vars.SONameFlag = this->Makefile->GetSONameFlag(
 
-       this->GeneratorTarget->GetLinkerLanguage(Config));
 
-     target_so_name =
 
-       cmGlobalFastbuildGenerator::QuoteIfHasSpaces(targetNames.SharedObject);
 
-     vars.TargetSOName = target_so_name.c_str();
 
-     // Tested in "RunCMake.RuntimePath / RunCMake.INSTALL_NAME_DIR"
 
-     // tests.
 
-     install_dir = this->LocalGenerator->ConvertToOutputFormat(
 
-       this->GeneratorTarget->GetInstallNameDirForBuildTree(Config),
 
-       cmOutputConverter::SHELL);
 
-     vars.TargetInstallNameDir = install_dir.c_str();
 
-   } else {
 
-     vars.TargetSOName = "";
 
-   }
 
-   vars.TargetPDB = FASTBUILD_DOLLAR_TAG "LinkerPDB" FASTBUILD_DOLLAR_TAG;
 
-   // Setup the target version.
 
-   std::string targetVersionMajor;
 
-   std::string targetVersionMinor;
 
-   {
 
-     std::ostringstream majorStream;
 
-     std::ostringstream minorStream;
 
-     int major;
 
-     int minor;
 
-     this->GeneratorTarget->GetTargetVersion(major, minor);
 
-     majorStream << major;
 
-     minorStream << minor;
 
-     targetVersionMajor = majorStream.str();
 
-     targetVersionMinor = minorStream.str();
 
-   }
 
-   vars.TargetVersionMajor = targetVersionMajor.c_str();
 
-   vars.TargetVersionMinor = targetVersionMinor.c_str();
 
-   vars.Defines =
 
-     FASTBUILD_DOLLAR_TAG "CompileDefineFlags" FASTBUILD_DOLLAR_TAG;
 
-   vars.Flags = targetFlags.c_str();
 
-   vars.LinkFlags = linkFlags.c_str();
 
-   vars.LanguageCompileFlags = "";
 
-   std::string const linker = this->GeneratorTarget->GetLinkerTool(Config);
 
-   vars.Linker = linker.c_str();
 
-   std::string const targetSupportPath = this->ConvertToFastbuildPath(
 
-     this->GetGeneratorTarget()->GetCMFSupportDirectory());
 
-   vars.TargetSupportDir = targetSupportPath.c_str();
 
-   LogMessage("linkFlags: " + linkFlags);
 
-   LogMessage("linker: " + linker);
 
-   std::string linkRule = GetLinkCommand();
 
-   ApplyLinkRuleLauncher(linkRule);
 
-   RulePlaceholderExpander->ExpandRuleVariables(
 
-     dynamic_cast<cmLocalFastbuildGenerator*>(this->LocalCommonGenerator),
 
-     linkRule, vars);
 
-   command = std::move(linkRule);
 
-   LogMessage(cmStrCat("Expanded link command: ", command));
 
-   return true;
 
- }
 
- void cmFastbuildNormalTargetGenerator::ApplyCompileRuleLauncher(
 
-   std::string& command)
 
- {
 
-   std::string const val = this->GetLocalGenerator()->GetRuleLauncher(
 
-     this->GetGeneratorTarget(), "RULE_LAUNCH_LINK", Config);
 
-   if (cmNonempty(val)) {
 
-     LogMessage("RULE_LAUNCH_LINK: " + val);
 
-     command = cmStrCat(val, " ", command);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::ApplyLinkRuleLauncher(
 
-   std::string& command)
 
- {
 
-   std::string const val = this->GetLocalGenerator()->GetRuleLauncher(
 
-     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE", Config);
 
-   if (cmNonempty(val)) {
 
-     LogMessage("RULE_LAUNCH_COMPILE: " + val);
 
-     command = cmStrCat(val, " ", command);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::ApplyLWYUToLinkerCommand(
 
-   FastbuildLinkerNode& linkerNode)
 
- {
 
-   cmValue const lwyuCheck =
 
-     this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
 
-   if (this->UseLWYU && lwyuCheck) {
 
-     LogMessage("UseLWYU=true");
 
-     std::string args = " -E __run_co_compile --lwyu=";
 
-     args += this->GetLocalGenerator()->EscapeForShell(*lwyuCheck);
 
-     args += cmStrCat(
 
-       " --source=",
 
-       this->ConvertToFastbuildPath(this->GetGeneratorTarget()->GetFullPath(
 
-         Config, cmStateEnums::RuntimeBinaryArtifact,
 
-         /*realname=*/true)));
 
-     LogMessage("LWUY args: " + args);
 
-     linkerNode.LinkerStampExe = cmSystemTools::GetCMakeCommand();
 
-     linkerNode.LinkerStampExeArgs = std::move(args);
 
-   }
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::ComputeDefines(
 
-   cmSourceFile const& srcFile)
 
- {
 
-   std::string const language = srcFile.GetLanguage();
 
-   std::set<std::string> defines;
 
-   cmGeneratorExpressionInterpreter genexInterpreter(
 
-     this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
 
-   if (auto compile_defs = srcFile.GetProperty(COMPILE_DEFINITIONS)) {
 
-     this->GetLocalGenerator()->AppendDefines(
 
-       defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
 
-   }
 
-   std::string defPropName = "COMPILE_DEFINITIONS_";
 
-   defPropName += cmSystemTools::UpperCase(Config);
 
-   if (auto config_compile_defs = srcFile.GetProperty(defPropName)) {
 
-     this->GetLocalGenerator()->AppendDefines(
 
-       defines,
 
-       genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
 
-   }
 
-   std::string definesString = this->GetDefines(language, Config);
 
-   LogMessage(cmStrCat("TARGET DEFINES = ", definesString));
 
-   this->GetLocalGenerator()->JoinDefines(defines, definesString, language);
 
-   LogMessage(cmStrCat("DEFINES = ", definesString));
 
-   return definesString;
 
- }
 
- void cmFastbuildNormalTargetGenerator::ComputePCH(
 
-   cmSourceFile const& srcFile, FastbuildObjectListNode& node,
 
-   std::set<std::string>& createdPCH)
 
- {
 
-   if (srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
 
-     return;
 
-   }
 
-   // We have already computed PCH for this node.
 
-   if (!node.PCHOptions.empty() || !node.PCHInputFile.empty() ||
 
-       !node.PCHOutputFile.empty()) {
 
-     return;
 
-   }
 
-   std::string const language = srcFile.GetLanguage();
 
-   cmGeneratorExpressionInterpreter genexInterpreter(
 
-     this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
 
-   //.cxx
 
-   std::string const pchSource =
 
-     this->GeneratorTarget->GetPchSource(Config, language);
 
-   //.hxx
 
-   std::string const pchHeader =
 
-     this->GeneratorTarget->GetPchHeader(Config, language);
 
-   //.pch
 
-   std::string const pchFile =
 
-     this->GeneratorTarget->GetPchFile(Config, language);
 
-   if (pchHeader.empty() || pchFile.empty()) {
 
-     return;
 
-   }
 
-   // In "RunCMake.GenEx-TARGET_PROPERTY" test we call set
 
-   // CMAKE_PCH_EXTENSION="", so pchHeader becomes same as pchFile...
 
-   if (pchHeader == pchFile) {
 
-     LogMessage("pchHeader == pchFile > skipping");
 
-     LogMessage("pchHeader: " + pchHeader);
 
-     LogMessage("pchFile: " + pchFile);
 
-     return;
 
-   }
 
-   node.PCHOutputFile =
 
-     this->GetGlobalGenerator()->ConvertToFastbuildPath(pchFile);
 
-   // Tell the ObjectList how to use PCH.
 
-   std::string const pchUseOption =
 
-     this->GeneratorTarget->GetPchUseCompileOptions(Config, language);
 
-   LogMessage(cmStrCat("pchUseOption: ", pchUseOption));
 
-   std::string origCompileOptions = node.CompilerOptions;
 
-   for (auto const& opt :
 
-        cmList{ genexInterpreter.Evaluate(pchUseOption, COMPILE_OPTIONS) }) {
 
-     node.CompilerOptions += " ";
 
-     node.CompilerOptions += opt;
 
-   }
 
-   if (!createdPCH.emplace(node.PCHOutputFile).second) {
 
-     LogMessage(node.PCHOutputFile + " is already created by this target");
 
-     return;
 
-   }
 
-   // Short circuit if the PCH has already been created by another target.
 
-   if (!this->GeneratorTarget->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM")
 
-          .empty()) {
 
-     LogMessage(cmStrCat("PCH: ", node.PCHOutputFile,
 
-                         " already created by another target"));
 
-     return;
 
-   }
 
-   node.PCHInputFile =
 
-     this->GetGlobalGenerator()->ConvertToFastbuildPath(pchSource);
 
-   std::string const pchCreateOptions =
 
-     this->GeneratorTarget->GetPchCreateCompileOptions(Config, language);
 
-   LogMessage(cmStrCat("pchCreateOptions: ", pchCreateOptions));
 
-   char const* sep = "";
 
-   for (auto const& opt : cmList{
 
-          genexInterpreter.Evaluate(pchCreateOptions, COMPILE_OPTIONS) }) {
 
-     node.PCHOptions += sep;
 
-     node.PCHOptions += opt;
 
-     sep = " ";
 
-   }
 
-   // Reuse compiler options for PCH options.
 
-   node.PCHOptions += origCompileOptions;
 
-   if (this->Makefile->GetSafeDefinition("CMAKE_" + language +
 
-                                         "_COMPILER_ID") == "MSVC") {
 
-     cmSystemTools::ReplaceString(node.PCHOptions,
 
-                                  FASTBUILD_2_INPUT_PLACEHOLDER,
 
-                                  FASTBUILD_3_INPUT_PLACEHOLDER);
 
-   }
 
-   LogMessage("PCH Source: " + pchSource);
 
-   LogMessage("node.PCHInputFile: " + node.PCHInputFile);
 
-   LogMessage("node.PCHOutputFile: " + node.PCHOutputFile);
 
-   LogMessage("node.PCHOptions: " + node.PCHOptions);
 
-   LogMessage("node.CompilerOptions: " + node.CompilerOptions);
 
- }
 
- void cmFastbuildNormalTargetGenerator::EnsureDirectoryExists(
 
-   std::string const& path) const
 
- {
 
-   if (cmSystemTools::FileIsFullPath(path.c_str())) {
 
-     cmSystemTools::MakeDirectory(path.c_str());
 
-   } else {
 
-     auto* gg = this->GetGlobalGenerator();
 
-     std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
 
-     // Also ensures there is a trailing slash.
 
-     fullPath += path;
 
-     cmSystemTools::MakeDirectory(fullPath);
 
-   }
 
- }
 
- std::vector<std::string>
 
- cmFastbuildNormalTargetGenerator::GetManifestsAsFastbuildPath() const
 
- {
 
-   std::vector<cmSourceFile const*> manifest_srcs;
 
-   this->GeneratorTarget->GetManifests(manifest_srcs, Config);
 
-   std::vector<std::string> manifests;
 
-   manifests.reserve(manifest_srcs.size());
 
-   for (auto& manifest_src : manifest_srcs) {
 
-     std::string str = this->ConvertToFastbuildPath(
 
-       cmSystemTools::ConvertToOutputPath(manifest_src->GetFullPath()));
 
-     LogMessage("Manifest: " + str);
 
-     manifests.emplace_back(std::move(str));
 
-   }
 
-   return manifests;
 
- }
 
- void cmFastbuildNormalTargetGenerator::GenerateModuleDefinitionInfo(
 
-   FastbuildTarget& target) const
 
- {
 
-   cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
 
-     GeneratorTarget->GetModuleDefinitionInfo(Config);
 
-   if (mdi && mdi->DefFileGenerated) {
 
-     FastbuildExecNode execNode;
 
-     execNode.Name = target.Name + "-def-files";
 
-     execNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
 
-     execNode.ExecArguments =
 
-       cmStrCat("-E __create_def ", FASTBUILD_2_INPUT_PLACEHOLDER, " ",
 
-                FASTBUILD_1_INPUT_PLACEHOLDER);
 
-     std::string const obj_list_file = mdi->DefFile + ".objs";
 
-     auto const nm_executable = GetMakefile()->GetDefinition("CMAKE_NM");
 
-     if (!nm_executable.IsEmpty()) {
 
-       execNode.ExecArguments += " --nm=";
 
-       execNode.ExecArguments += ConvertToFastbuildPath(*nm_executable);
 
-     }
 
-     execNode.ExecOutput = ConvertToFastbuildPath(mdi->DefFile);
 
-     execNode.ExecInput.push_back(ConvertToFastbuildPath(obj_list_file));
 
-     // RunCMake.AutoExportDll
 
-     for (auto const& objList : target.ObjectListNodes) {
 
-       execNode.PreBuildDependencies.emplace(objList.Name);
 
-     }
 
-     // Tested in "RunCMake.AutoExportDll" / "ModuleDefinition" tests.
 
-     for (auto& linkerNode : target.LinkerNode) {
 
-       linkerNode.Libraries2.emplace_back(execNode.Name);
 
-     }
 
-     target.PreLinkExecNodes.Nodes.emplace_back(std::move(execNode));
 
-     // create a list of obj files for the -E __create_def to read
 
-     cmGeneratedFileStream fout(obj_list_file);
 
-     // Since we generate this file once during configuration, we should not
 
-     // remove it when "clean" is built.
 
-     // Tested in "RunCMake.AutoExportDll" / "ModuleDefinition" tests.
 
-     this->GetGlobalGenerator()->AllFilesToKeep.insert(obj_list_file);
 
-     if (mdi->WindowsExportAllSymbols) {
 
-       std::vector<cmSourceFile const*> objectSources;
 
-       GeneratorTarget->GetObjectSources(objectSources, Config);
 
-       std::map<cmSourceFile const*, cmObjectLocations> mapping;
 
-       for (cmSourceFile const* it : objectSources) {
 
-         mapping[it];
 
-       }
 
-       GeneratorTarget->LocalGenerator->ComputeObjectFilenames(mapping,
 
-                                                               GeneratorTarget);
 
-       std::vector<std::string> objs;
 
-       for (cmSourceFile const* it : objectSources) {
 
-         auto const& v = mapping[it];
 
-         LogMessage("Obj source : " + v.LongLoc.GetPath());
 
-         std::string objFile = this->ConvertToFastbuildPath(
 
-           GeneratorTarget->GetObjectDirectory(Config) + v.LongLoc.GetPath());
 
-         objFile = cmSystemTools::ConvertToOutputPath(objFile);
 
-         LogMessage("objFile path: " + objFile);
 
-         objs.push_back(objFile);
 
-       }
 
-       std::vector<cmSourceFile const*> externalObjectSources;
 
-       GeneratorTarget->GetExternalObjects(externalObjectSources, Config);
 
-       for (cmSourceFile const* it : externalObjectSources) {
 
-         objs.push_back(cmSystemTools::ConvertToOutputPath(
 
-           this->ConvertToFastbuildPath(it->GetFullPath())));
 
-       }
 
-       for (std::string const& objFile : objs) {
 
-         if (cmHasLiteralSuffix(objFile, ".obj")) {
 
-           fout << objFile << "\n";
 
-         }
 
-       }
 
-     }
 
-     for (cmSourceFile const* src : mdi->Sources) {
 
-       fout << src->GetFullPath() << "\n";
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddPrebuildDeps(
 
-   FastbuildTarget& target) const
 
- {
 
-   // All ObjectLists should wait for PRE_BUILD.
 
-   for (FastbuildObjectListNode& node : target.ObjectListNodes) {
 
-     if (!target.PreBuildExecNodes.Name.empty()) {
 
-       node.PreBuildDependencies.emplace(target.PreBuildExecNodes.Name);
 
-     }
 
-     if (!target.ExecNodes.Name.empty()) {
 
-       node.PreBuildDependencies.emplace(target.ExecNodes.Name);
 
-     }
 
-   }
 
-   for (auto& linkerNode : target.LinkerNode) {
 
-     // Wait for 'PRE_BUILD' custom commands.
 
-     if (!target.PreBuildExecNodes.Name.empty()) {
 
-       linkerNode.PreBuildDependencies.emplace(target.PreBuildExecNodes.Name);
 
-     }
 
-     // Wait for regular custom commands.
 
-     if (!target.ExecNodes.Name.empty()) {
 
-       linkerNode.PreBuildDependencies.emplace(target.ExecNodes.Name);
 
-     }
 
-     // All targets that we depend on must be prebuilt.
 
-     if (!target.DependenciesAlias.PreBuildDependencies.empty()) {
 
-       linkerNode.PreBuildDependencies.emplace(target.DependenciesAlias.Name);
 
-     }
 
-   }
 
- }
 
- std::set<std::string> cmFastbuildNormalTargetGenerator::GetLanguages()
 
- {
 
-   std::set<std::string> result;
 
-   this->GetGeneratorTarget()->GetLanguages(result, Config);
 
-   for (std::string const& lang : result) {
 
-     this->GetGlobalGenerator()->AddCompiler(lang, this->GetMakefile());
 
-   }
 
-   LogMessage("Languages: " + cmJoin(result, ", "));
 
-   return result;
 
- }
 
- std::unordered_map<std::string, std::string>
 
- cmFastbuildNormalTargetGenerator::GetCompileObjectCommand() const
 
- {
 
-   std::unordered_map<std::string, std::string> result;
 
-   result.reserve(Languages.size());
 
-   for (std::string const& lang : Languages) {
 
-     std::vector<std::string> commands;
 
-     std::string cmakeVar;
 
-     if (lang == "CUDA") {
 
-       if (this->GeneratorTarget->GetPropertyAsBool(
 
-             "CUDA_SEPARABLE_COMPILATION")) {
 
-         cmakeVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
 
-       } else if (this->GeneratorTarget->GetPropertyAsBool(
 
-                    "CUDA_PTX_COMPILATION")) {
 
-         cmakeVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
 
-       } else {
 
-         cmakeVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
 
-       }
 
-     } else {
 
-       cmakeVar = "CMAKE_";
 
-       cmakeVar += lang;
 
-       cmakeVar += "_COMPILE_OBJECT";
 
-     }
 
-     std::string cmakeValue =
 
-       LocalCommonGenerator->GetMakefile()->GetSafeDefinition(cmakeVar);
 
-     LogMessage(cmakeVar.append(" = ").append(cmakeValue));
 
-     result[lang] = std::move(cmakeValue);
 
-   }
 
-   return result;
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::GetLinkCommand() const
 
- {
 
-   std::string const& linkLanguage = GeneratorTarget->GetLinkerLanguage(Config);
 
-   std::string linkCmdVar =
 
-     GeneratorTarget->GetCreateRuleVariable(linkLanguage, Config);
 
-   std::string res = this->Makefile->GetSafeDefinition(linkCmdVar);
 
-   if (res.empty() &&
 
-       this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
 
-     linkCmdVar = linkCmdVar =
 
-       cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE");
 
-     res = this->Makefile->GetSafeDefinition(linkCmdVar);
 
-   }
 
-   LogMessage("Link rule: " + cmStrCat(linkCmdVar, " = ", res));
 
-   return res;
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddCompilerLaunchersForLanguages()
 
- {
 
-   // General rule for all languages.
 
-   std::string const launchCompile = this->GetLocalGenerator()->GetRuleLauncher(
 
-     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE", Config);
 
-   // See if we need to use a compiler launcher like ccache or distcc
 
-   for (std::string const& language : Languages) {
 
-     std::string const compilerLauncher =
 
-       cmCommonTargetGenerator::GetCompilerLauncher(language, Config);
 
-     LogMessage("compilerLauncher: " + compilerLauncher);
 
-     std::vector<std::string> expanded;
 
-     cmExpandList(compilerLauncher, expanded);
 
-     if (!expanded.empty()) {
 
-       std::string const exe = expanded[0];
 
-       expanded.erase(expanded.begin());
 
-       this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX, exe,
 
-                                               language, cmJoin(expanded, " "));
 
-     } else if (!launchCompile.empty()) {
 
-       std::string exe;
 
-       std::string args;
 
-       cmSystemTools::SplitProgramFromArgs(launchCompile, exe, args);
 
-       this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX, exe,
 
-                                               language, args);
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddLinkerLauncher()
 
- {
 
-   std::string const linkerLauncher =
 
-     cmCommonTargetGenerator::GetLinkerLauncher(Config);
 
-   std::vector<std::string> args;
 
- #ifdef _WIN32
 
-   cmSystemTools::ParseWindowsCommandLine(linkerLauncher.c_str(), args);
 
- #else
 
-   cmSystemTools::ParseUnixCommandLine(linkerLauncher.c_str(), args);
 
- #endif
 
-   if (!args.empty()) {
 
-     std::string const exe = std::move(args[0]);
 
-     args.erase(args.begin());
 
-     this->GetGlobalGenerator()->AddLauncher(
 
-       FASTBUILD_LINKER_LAUNCHER_PREFIX, exe,
 
-       this->GeneratorTarget->GetLinkerLanguage(Config), cmJoin(args, " "));
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddCMakeLauncher()
 
- {
 
-   // Add CMake launcher (might be used for static analysis).
 
-   this->GetGlobalGenerator()->AddLauncher(FASTBUILD_LAUNCHER_PREFIX,
 
-                                           cmSystemTools::GetCMakeCommand(),
 
-                                           CMAKE_LANGUAGE, "");
 
- }
 
- void cmFastbuildNormalTargetGenerator::ComputePaths(
 
-   FastbuildTarget& target) const
 
- {
 
-   std::string const objPath = GetGeneratorTarget()->GetSupportDirectory();
 
-   EnsureDirectoryExists(objPath);
 
-   target.Variables["TargetOutDir"] =
 
-     cmSystemTools::ConvertToOutputPath(this->ConvertToFastbuildPath(objPath));
 
-   if (GeneratorTarget->GetType() <= cmStateEnums::MODULE_LIBRARY) {
 
-     std::string const pdbDir = GeneratorTarget->GetPDBDirectory(Config);
 
-     LogMessage("GetPDBDirectory: " + pdbDir);
 
-     EnsureDirectoryExists(pdbDir);
 
-     std::string const linkerPDB =
 
-       cmStrCat(pdbDir, '/', this->GeneratorTarget->GetPDBName(Config));
 
-     if (!linkerPDB.empty()) {
 
-       target.Variables["LinkerPDB"] = cmSystemTools::ConvertToOutputPath(
 
-         this->ConvertToFastbuildPath(linkerPDB));
 
-     }
 
-   }
 
-   if (GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
 
-     std::string const pdbDir = GeneratorTarget->GetCompilePDBDirectory(Config);
 
-     LogMessage("GetCompilePDBDirectory: " + pdbDir);
 
-     EnsureDirectoryExists(pdbDir);
 
-     std::string pdbName = this->GeneratorTarget->GetCompilePDBName(Config);
 
-     LogMessage("GetCompilePDBName: " + pdbDir);
 
-     // If we don't have Compiler's PDB, we must add a trailing slash to satisfy
 
-     // MSVC.
 
-     bool needTrailingSlash = false;
 
-     if (pdbName.empty()) {
 
-       needTrailingSlash = true;
 
-     }
 
-     std::string const compilerPDB = cmStrCat(pdbDir, '\\', pdbName);
 
-     if (!compilerPDB.empty()) {
 
-       target.Variables["CompilerPDB"] = cmSystemTools::ConvertToOutputPath(
 
-         this->ConvertToFastbuildPath(compilerPDB) +
 
-         (needTrailingSlash ? "\\ " : ""));
 
-     }
 
-   }
 
-   std::string impLibFile = ConvertToFastbuildPath(
 
-     GeneratorTarget->GetFullPath(Config, cmStateEnums::ImportLibraryArtifact));
 
-   cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(impLibFile));
 
-   if (!impLibFile.empty()) {
 
-     cmSystemTools::ConvertToOutputSlashes(impLibFile);
 
-     target.Variables["TargetOutputImplib"] = std::move(impLibFile);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::Generate()
 
- {
 
-   this->GeneratorTarget->CheckCxxModuleStatus(Config);
 
-   FastbuildTarget fastbuildTarget;
 
-   fastbuildTarget.Name = GetTargetName();
 
-   fastbuildTarget.BaseName = this->GeneratorTarget->GetName();
 
-   LogMessage("<-------------->");
 
-   LogMessage("Generate target: " + fastbuildTarget.Name);
 
-   LogMessage("Config: " + Config);
 
-   LogMessage("Deps: ");
 
-   for (cmTargetDepend const& dep : TargetDirectDependencies) {
 
-     auto const tname = dep->GetName();
 
-     LogMessage(tname);
 
-     FastbuildTargetDep targetDep{ tname };
 
-     if (dep->GetType() == cmStateEnums::OBJECT_LIBRARY) {
 
-       targetDep.Type = FastbuildTargetDepType::ORDER_ONLY;
 
-     } else {
 
-       targetDep.Type = FastbuildTargetDepType::ALL;
 
-     }
 
-     fastbuildTarget.PreBuildDependencies.emplace(std::move(targetDep));
 
-   }
 
-   ComputePaths(fastbuildTarget);
 
-   AddCompilerLaunchersForLanguages();
 
-   AddLinkerLauncher();
 
-   AddCMakeLauncher();
 
-   for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_BUILD).Nodes) {
 
-     fastbuildTarget.PreBuildExecNodes.PreBuildDependencies.emplace(cc.Name);
 
-     fastbuildTarget.PreBuildDependencies.emplace(cc.Name);
 
-     this->GetGlobalGenerator()->AddTarget(std::move(cc));
 
-   }
 
-   for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_LINK).Nodes) {
 
-     cc.PreBuildDependencies.emplace(fastbuildTarget.Name +
 
-                                     FASTBUILD_DEPS_ARTIFACTS_ALIAS_POSTFIX);
 
-     fastbuildTarget.PreLinkExecNodes.Nodes.emplace_back(std::move(cc));
 
-   }
 
-   for (auto& cc : GenerateCommands(FastbuildBuildStep::REST).Nodes) {
 
-     fastbuildTarget.ExecNodes.PreBuildDependencies.emplace(cc.Name);
 
-     this->GetGlobalGenerator()->AddTarget(std::move(cc));
 
-   }
 
-   for (auto& cc : GenerateCommands(FastbuildBuildStep::POST_BUILD).Nodes) {
 
-     fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
 
-       cc.Name);
 
-     fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(std::move(cc));
 
-   }
 
-   fastbuildTarget.ObjectListNodes = GenerateObjects();
 
-   std::vector<std::string> objectDepends;
 
-   AddObjectDependencies(fastbuildTarget, objectDepends);
 
-   GenerateLink(fastbuildTarget, objectDepends);
 
-   if (fastbuildTarget.LinkerNode.size() > 1) {
 
-     if (!this->GeneratorTarget->IsApple()) {
 
-       cmSystemTools::Error(
 
-         "Can't handle more than 1 arch on non-Apple target");
 
-       return;
 
-     }
 
-     AddLipoCommand(fastbuildTarget);
 
-   }
 
-   fastbuildTarget.CopyNodes = std::move(this->CopyNodes);
 
-   // Generate symlink commands if real output name differs from "expected".
 
-   for (auto& symlink : GetSymlinkExecs()) {
 
-     fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
 
-       symlink.Name);
 
-     fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(std::move(symlink));
 
-   }
 
-   {
 
-     auto appleTextStubCommand = GetAppleTextStubCommand();
 
-     if (!appleTextStubCommand.Name.empty()) {
 
-       fastbuildTarget.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
 
-         appleTextStubCommand.Name);
 
-       fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(
 
-         std::move(appleTextStubCommand));
 
-     }
 
-   }
 
-   AddPrebuildDeps(fastbuildTarget);
 
-   fastbuildTarget.IsGlobal =
 
-     GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET;
 
-   fastbuildTarget.ExcludeFromAll =
 
-     this->GetGlobalGenerator()->IsExcluded(GeneratorTarget);
 
-   if (GeneratorTarget->GetPropertyAsBool("DONT_DISTRIBUTE")) {
 
-     fastbuildTarget.AllowDistribution = false;
 
-   }
 
-   GenerateModuleDefinitionInfo(fastbuildTarget);
 
-   // Needs to be called after we've added all PRE-LINK steps (like creation of
 
-   // .def files on Windows).
 
-   AddLinkerNodeDependnecies(fastbuildTarget);
 
-   // Must be called after "GenerateObjects", since it also adds Prebuild deps
 
-   // to it.
 
-   // Also after "GenerateModuleDefinitionInfo", since uses PreLinkExecNodes.
 
-   fastbuildTarget.GenerateAliases();
 
-   if (!fastbuildTarget.ExecNodes.PreBuildDependencies.empty()) {
 
-     fastbuildTarget.DependenciesAlias.PreBuildDependencies.emplace(
 
-       fastbuildTarget.ExecNodes.Name);
 
-   }
 
-   fastbuildTarget.Hidden = false;
 
-   fastbuildTarget.BasePath = this->GetMakefile()->GetCurrentSourceDirectory();
 
-   this->GetGlobalGenerator()->AddIDEProject(fastbuildTarget, Config);
 
-   AddStampExeIfApplicable(fastbuildTarget);
 
-   AdditionalCleanFiles();
 
-   this->GetGlobalGenerator()->AddTarget(std::move(fastbuildTarget));
 
- }
 
- void cmFastbuildNormalTargetGenerator::ProcessManifests(
 
-   FastbuildLinkerNode& linkerNode) const
 
- {
 
-   if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
 
-     return;
 
-   }
 
-   auto manifests = this->GetManifestsAsFastbuildPath();
 
-   if (manifests.empty()) {
 
-     return;
 
-   }
 
-   // Manifests should always be in .Libraries2, so we re-link when needed.
 
-   // Tested in RunCMake.BuildDepends
 
-   for (auto const& manifest : manifests) {
 
-     linkerNode.Libraries2.emplace_back(manifest);
 
-   }
 
-   if (this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID") != "MSVC") {
 
-     return;
 
-   }
 
-   for (auto const& manifest : manifests) {
 
-     linkerNode.LinkerOptions =
 
-       cmStrCat("/MANIFESTINPUT:", manifest, ' ', linkerNode.LinkerOptions);
 
-   }
 
-   // /MANIFESTINPUT only works with /MANIFEST:EMBED
 
-   linkerNode.LinkerOptions =
 
-     cmStrCat("/MANIFEST:EMBED ", linkerNode.LinkerOptions);
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddStampExeIfApplicable(
 
-   FastbuildTarget& fastbuildTarget) const
 
- {
 
-   LogMessage("AddStampExeIfApplicable(...)");
 
-   if (fastbuildTarget.LinkerNode.empty() ||
 
-       (fastbuildTarget.LinkerNode[0].Type != FastbuildLinkerNode::EXECUTABLE &&
 
-        fastbuildTarget.LinkerNode[0].Type !=
 
-          FastbuildLinkerNode::SHARED_LIBRARY)) {
 
-     return;
 
-   }
 
-   // File which executes all POST_BUILD steps.
 
-   // We use it in .LinkerStampExeArgs in order to run POST_BUILD steps after
 
-   // the compilation.
 
-   if (!fastbuildTarget.PostBuildExecNodes.Nodes.empty()) {
 
-     std::string const AllPostBuildExecsScriptFile =
 
-       cmStrCat(this->Makefile->GetHomeOutputDirectory(), "/CMakeFiles/",
 
-                fastbuildTarget.Name,
 
-                "-all-postbuild-commands" FASTBUILD_SCRIPT_FILE_EXTENSION);
 
-     CollapseAllExecsIntoOneScriptfile(
 
-       AllPostBuildExecsScriptFile, fastbuildTarget.PostBuildExecNodes.Nodes);
 
-     auto& linkerNode = fastbuildTarget.LinkerNode.back();
 
-     // On macOS, a target may have multiple linker nodes (e.g., for different
 
-     // architectures). In that case, add the POST_BUILD step to only one node
 
-     // to avoid running lipo multiple times.
 
-     linkerNode.LinkerStampExe =
 
-       cmGlobalFastbuildGenerator::GetExternalShellExecutable();
 
-     linkerNode.LinkerStampExeArgs = FASTBUILD_SCRIPT_FILE_ARG;
 
-     linkerNode.LinkerStampExeArgs +=
 
-       cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
 
-         AllPostBuildExecsScriptFile);
 
-   } else {
 
-     LogMessage("No POST_BUILD steps for target: " + fastbuildTarget.Name);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::CollapseAllExecsIntoOneScriptfile(
 
-   std::string const& scriptFileName,
 
-   std::vector<FastbuildExecNode> const& execs) const
 
- {
 
-   cmsys::ofstream scriptFile(scriptFileName.c_str());
 
-   if (!scriptFile.is_open()) {
 
-     cmSystemTools::Error("Failed to open: " + scriptFileName);
 
-     return;
 
-   }
 
-   LogMessage("Writing collapsed Execs to " + scriptFileName);
 
-   auto const shell = cmGlobalFastbuildGenerator::GetExternalShellExecutable();
 
-   for (auto const& exec : execs) {
 
-     if (exec.ScriptFile.empty()) {
 
-       scriptFile << cmSystemTools::ConvertToOutputPath(exec.ExecExecutable)
 
-                  << " " << exec.ExecArguments << '\n';
 
-     } else {
 
- #if defined(_WIN32)
 
-       scriptFile << "call "
 
-                  << cmSystemTools::ConvertToWindowsOutputPath(exec.ScriptFile)
 
-                  << '\n';
 
- #else
 
-       scriptFile << cmSystemTools::ConvertToOutputPath(shell) << " "
 
-                  << cmSystemTools::ConvertToOutputPath(exec.ScriptFile)
 
-                  << '\n';
 
- #endif
 
-     }
 
-   }
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::ComputeCodeCheckOptions(
 
-   cmSourceFile const& srcFile)
 
- {
 
-   cmValue const skipCodeCheck = srcFile.GetProperty("SKIP_LINTING");
 
-   std::string staticCheckRule;
 
-   if (!skipCodeCheck.IsOn()) {
 
-     std::string compilerLauncher;
 
-     staticCheckRule = this->GenerateCodeCheckRules(srcFile, compilerLauncher,
 
-                                                    "", Config, nullptr);
 
-     LogMessage(cmStrCat("CodeCheck: ", staticCheckRule));
 
-   }
 
-   return staticCheckRule;
 
- }
 
- void cmFastbuildNormalTargetGenerator::ComputeCompilerAndOptions(
 
-   std::string const& compilerOptions, std::string const& staticCheckOptions,
 
-   std::string const& language, FastbuildObjectListNode& outObjectList)
 
- {
 
-   auto& compilers = this->GetGlobalGenerator()->Compilers;
 
-   auto const compilerIter =
 
-     compilers.find(FASTBUILD_COMPILER_PREFIX + language);
 
-   auto const launcherIter =
 
-     compilers.find(FASTBUILD_LAUNCHER_PREFIX + language);
 
-   if (!staticCheckOptions.empty()) {
 
-     // If we want to run static checks - use CMake as a launcher.
 
-     // Tested in "RunCMake.ClangTidy", "RunCMake.IncludeWhatYouUse",
 
-     // "RunCMake.Cpplint", "RunCMake.Cppcheck", "RunCMake.MultiLint" tests.
 
-     outObjectList.Compiler = "." FASTBUILD_LAUNCHER_PREFIX + CMAKE_LANGUAGE;
 
-     outObjectList.CompilerOptions = staticCheckOptions;
 
-     // Add compile command which will be passed to the static analyzer via
 
-     // dash-dash.
 
-     if (compilerIter != compilers.end()) {
 
-       // Wrap in quotes to account for potential spaces in the path.
 
-       outObjectList.CompilerOptions +=
 
-         cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
 
-           compilerIter->second.Executable);
 
-       outObjectList.CompilerOptions += compilerOptions;
 
-     }
 
-   } else if (launcherIter != compilers.end()) {
 
-     // Tested in "RunCMake.CompilerLauncher" test.
 
-     outObjectList.Compiler = "." + launcherIter->first;
 
-     outObjectList.CompilerOptions = launcherIter->second.Args;
 
-     auto vars = cmFastbuildNormalTargetGenerator::ComputeRuleVariables();
 
-     vars.Language = language.c_str();
 
-     std::string const targetSupportPath = this->ConvertToFastbuildPath(
 
-       this->GetGeneratorTarget()->GetCMFSupportDirectory());
 
-     vars.TargetSupportDir = targetSupportPath.c_str();
 
-     RulePlaceholderExpander->ExpandRuleVariables(
 
-       LocalCommonGenerator, outObjectList.CompilerOptions, vars);
 
-     // Add compiler executable explicitly to the compile options.
 
-     if (compilerIter != compilers.end()) {
 
-       outObjectList.CompilerOptions += " ";
 
-       // Wrap in quotes to account for potential spaces in the path.
 
-       outObjectList.CompilerOptions +=
 
-         cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
 
-           compilerIter->second.Executable);
 
-       outObjectList.CompilerOptions += compilerOptions;
 
-     }
 
-   } else if (compilerIter != compilers.end()) {
 
-     outObjectList.Compiler = "." + compilerIter->first;
 
-     outObjectList.CompilerOptions = compilerOptions;
 
-   }
 
-   LogMessage(cmStrCat(".Compiler = ", outObjectList.Compiler));
 
-   LogMessage(cmStrCat(".CompilerOptions = ", outObjectList.CompilerOptions));
 
- }
 
- cmRulePlaceholderExpander::RuleVariables
 
- cmFastbuildNormalTargetGenerator::ComputeRuleVariables() const
 
- {
 
-   cmRulePlaceholderExpander::RuleVariables compileObjectVars;
 
-   compileObjectVars.CMTargetName = GeneratorTarget->GetName().c_str();
 
-   compileObjectVars.CMTargetType =
 
-     cmState::GetTargetTypeName(GeneratorTarget->GetType()).c_str();
 
-   compileObjectVars.CMTargetLabels =
 
-     this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
 
-   compileObjectVars.Source = FASTBUILD_1_INPUT_PLACEHOLDER;
 
-   compileObjectVars.Object = FASTBUILD_2_INPUT_PLACEHOLDER;
 
-   compileObjectVars.ObjectDir =
 
-     FASTBUILD_DOLLAR_TAG "TargetOutputDir" FASTBUILD_DOLLAR_TAG;
 
-   compileObjectVars.ObjectFileDir = "";
 
-   compileObjectVars.Flags = "";
 
-   compileObjectVars.Includes = "";
 
-   compileObjectVars.Defines = "";
 
-   compileObjectVars.Includes = "";
 
-   compileObjectVars.TargetCompilePDB =
 
-     FASTBUILD_DOLLAR_TAG "CompilerPDB" FASTBUILD_DOLLAR_TAG;
 
-   compileObjectVars.Config = Config.c_str();
 
-   return compileObjectVars;
 
- }
 
- std::vector<std::string> cmFastbuildNormalTargetGenerator::GetSourceProperty(
 
-   cmSourceFile const& srcFile, std::string const& prop) const
 
- {
 
-   std::vector<std::string> res;
 
-   if (cmValue val = srcFile.GetProperty(prop)) {
 
-     cmExpandList(*val, res);
 
-     return GetGlobalGenerator()->ConvertToFastbuildPath(res);
 
-   }
 
-   return res;
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendExtraResources(
 
-   std::set<std::string>& deps) const
 
- {
 
-   // Generate Fastbuild's "Copy" commands to copy resources.
 
-   auto const generateCopyCommands =
 
-     [this](std::vector<cmSourceFile const*>& frameworkDeps) {
 
-       this->OSXBundleGenerator->GenerateMacOSXContentStatements(
 
-         frameworkDeps, this->MacOSXContentGenerator.get(), Config);
 
-     };
 
-   std::vector<cmSourceFile const*> headerSources;
 
-   this->GeneratorTarget->GetHeaderSources(headerSources, Config);
 
-   generateCopyCommands(headerSources);
 
-   std::vector<cmSourceFile const*> extraSources;
 
-   this->GeneratorTarget->GetExtraSources(extraSources, Config);
 
-   generateCopyCommands(extraSources);
 
-   std::vector<cmSourceFile const*> externalObjects;
 
-   this->GeneratorTarget->GetExternalObjects(externalObjects, Config);
 
-   generateCopyCommands(externalObjects);
 
-   for (FastbuildCopyNode const& node : this->CopyNodes) {
 
-     LogMessage("Adding resource: " + node.Name);
 
-     deps.emplace(node.Name);
 
-   }
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::GetCompileOptions(
 
-   cmSourceFile const& srcFile, std::string const& arch)
 
- {
 
-   std::string const language = srcFile.GetLanguage();
 
-   cmRulePlaceholderExpander::RuleVariables compileObjectVars =
 
-     ComputeRuleVariables();
 
-   std::string const compilerFlags = DetectCompilerFlags(srcFile, arch);
 
-   std::string const compilerDefines = ComputeDefines(srcFile);
 
-   compileObjectVars.Flags = compilerFlags.c_str();
 
-   compileObjectVars.Defines = compilerDefines.c_str();
 
-   compileObjectVars.Language = language.c_str();
 
-   std::string rule = CompileObjectCmakeRules.at(language);
 
-   RulePlaceholderExpander->ExpandRuleVariables(LocalCommonGenerator, rule,
 
-                                                compileObjectVars);
 
-   std::string compilerExecutable;
 
-   // Remove the compiler from .CompilerOptions, since it would be set as
 
-   // .Compiler in Fastbuild.
 
-   // See https://www.fastbuild.org/docs/functions/objectlist.html for a
 
-   // reference.
 
-   std::string options;
 
-   if (!cmSystemTools::SplitProgramFromArgs(rule, compilerExecutable,
 
-                                            options)) {
 
-     cmSystemTools::Error(cmStrCat("Failed to split compiler options: ", rule));
 
-   }
 
-   LogMessage("Expanded compile options = " + options);
 
-   LogMessage("Compiler executable = " + compilerExecutable);
 
-   return options;
 
- }
 
- std::vector<std::string> cmFastbuildNormalTargetGenerator::GetArches() const
 
- {
 
-   auto arches = this->GetGeneratorTarget()->GetAppleArchs(Config, {});
 
-   // Don't add any arch-specific logic if arch is only one.
 
-   if (arches.empty() || arches.size() == 1) {
 
-     arches.clear();
 
-     arches.emplace_back();
 
-   }
 
-   return arches;
 
- }
 
- std::vector<FastbuildObjectListNode>
 
- cmFastbuildNormalTargetGenerator::GenerateObjects()
 
- {
 
-   this->GetGlobalGenerator()->AllFoldersToClean.insert(ObjectOutDir);
 
-   std::map<std::string, FastbuildObjectListNode> nodesPermutations;
 
-   cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
 
-   std::vector<cmSourceFile const*> objectSources;
 
-   GeneratorTarget->GetObjectSources(objectSources, Config);
 
-   std::set<std::string> createdPCH;
 
-   for (cmSourceFile const* source : objectSources) {
 
-     cmSourceFile const& srcFile = *source;
 
-     // Do not generate separate node for PCH source file.
 
-     if (this->GeneratorTarget->GetPchSource(Config, srcFile.GetLanguage()) ==
 
-         srcFile.GetFullPath()) {
 
-       continue;
 
-     }
 
-     std::string const language = srcFile.GetLanguage();
 
-     LogMessage(cmStrCat("Source file: ",
 
-                         this->ConvertToFastbuildPath(srcFile.GetFullPath())));
 
-     LogMessage("Language: " + language);
 
-     std::string const staticCheckOptions = ComputeCodeCheckOptions(srcFile);
 
-     for (auto const& arch : this->GetArches()) {
 
-       std::string const compileOptions = GetCompileOptions(srcFile, arch);
 
-       std::string objOutDirWithPossibleSubdir = ObjectOutDir;
 
-       // If object should be placed in some subdir in the output
 
-       // path. Tested in "SourceGroups" test.
 
-       auto const subdir = cmSystemTools::GetFilenamePath(
 
-         this->GeneratorTarget->GetObjectName(source));
 
-       if (!subdir.empty()) {
 
-         objOutDirWithPossibleSubdir += "/";
 
-         objOutDirWithPossibleSubdir += subdir;
 
-       }
 
-       std::string const objectListHash = hash.HashString(cmStrCat(
 
-         compileOptions, staticCheckOptions, objOutDirWithPossibleSubdir,
 
-         // If file does not need PCH - it must be in another ObjectList.
 
-         srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS"),
 
-         srcFile.GetLanguage()));
 
-       LogMessage("ObjectList Hash: " + objectListHash);
 
-       FastbuildObjectListNode& objectListNode =
 
-         nodesPermutations[objectListHash];
 
-       // Absolute path needed in "RunCMake.SymlinkTrees" test.
 
-       objectListNode.CompilerInputFiles.push_back(srcFile.GetFullPath());
 
-       std::vector<std::string> const outputs =
 
-         GetSourceProperty(srcFile, "OBJECT_OUTPUTS");
 
-       objectListNode.ObjectOutputs.insert(outputs.begin(), outputs.end());
 
-       std::vector<std::string> const depends =
 
-         GetSourceProperty(srcFile, "OBJECT_DEPENDS");
 
-       objectListNode.ObjectDepends.insert(depends.begin(), depends.end());
 
-       // We have already computed properties that are computed below.
 
-       // (.CompilerOptions, .PCH*, etc.). Short circuit this iteration.
 
-       if (!objectListNode.CompilerOptions.empty()) {
 
-         continue;
 
-       }
 
-       objectListNode.CompilerOutputPath = objOutDirWithPossibleSubdir;
 
-       LogMessage(cmStrCat("Output path: ", objectListNode.CompilerOutputPath));
 
-       ComputeCompilerAndOptions(compileOptions, staticCheckOptions, language,
 
-                                 objectListNode);
 
-       ComputePCH(*source, objectListNode, createdPCH);
 
-       objectListNode.Name =
 
-         cmStrCat(language, "_ObjectGroup_", GetTargetName());
 
-       // TODO: Ask cmake the output objects and group by extension instead
 
-       // of doing this
 
-       if (language == "RC") {
 
-         objectListNode.CompilerOutputExtension = ".res";
 
-       } else {
 
-         if (!arch.empty()) {
 
-           objectListNode.CompilerOutputExtension = cmStrCat('.', arch);
 
-           objectListNode.arch = arch;
 
-         }
 
-         objectListNode.CompilerOutputExtension +=
 
-           this->GetMakefile()->GetSafeDefinition(
 
-             cmStrCat("CMAKE_", language, "_OUTPUT_EXTENSION"));
 
-       }
 
-     }
 
-   }
 
-   int groupNameCount = 1;
 
-   for (auto& val : nodesPermutations) {
 
-     auto& objectListNode = val.second;
 
-     objectListNode.Name =
 
-       cmStrCat(objectListNode.Name, "-", objectListNode.CompilerOutputPath,
 
-                "-", std::to_string(groupNameCount++));
 
-     LogMessage(cmStrCat("ObjectList name: ", objectListNode.Name));
 
-   }
 
-   std::vector<FastbuildObjectListNode> objects;
 
-   objects.reserve(nodesPermutations.size());
 
-   for (auto& val : nodesPermutations) {
 
-     auto& node = val.second;
 
-     objects.emplace_back(std::move(node));
 
-     if (!objects.back().PCHInputFile.empty()) {
 
-       // Node that produces PCH should be the first one, since other nodes
 
-       // might reuse this PCH.
 
-       std::swap(*objects.begin(), objects.back());
 
-     }
 
-   }
 
-   return objects;
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::ResolveIfAlias(
 
-   std::string const& targetName) const
 
- {
 
-   LogMessage("targetName: " + targetName);
 
-   std::map<std::string, std::string> const aliases =
 
-     this->Makefile->GetAliasTargets();
 
-   auto const iter = aliases.find(targetName);
 
-   if (iter != aliases.end()) {
 
-     LogMessage("Non alias name: " + iter->second);
 
-     return iter->second;
 
-   }
 
-   return targetName;
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendExternalObject(
 
-   FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedDeps) const
 
- {
 
-   // Different aspects of this logic exercised in "ObjectLibrary" and
 
-   // "ExportImport" test. When making changes here - verify that both of those
 
-   // tests are still passing.
 
-   LogMessage("AppendExternalObject(...)");
 
-   std::vector<cmSourceFile const*> extObjects;
 
-   this->GeneratorTarget->GetExternalObjects(extObjects, Config);
 
-   for (cmSourceFile const* src : extObjects) {
 
-     std::string const pathToObj =
 
-       this->ConvertToFastbuildPath(src->GetFullPath());
 
-     LogMessage("EXT OBJ: " + pathToObj);
 
-     std::string const objLibName = ResolveIfAlias(src->GetObjectLibrary());
 
-     LogMessage("GetObjectLibrary: " + objLibName);
 
-     // Tested in "ExternalOBJ" test.
 
-     cmTarget const* target =
 
-       this->GlobalCommonGenerator->FindTarget(objLibName);
 
-     if (objLibName.empty()) {
 
-       linkerNode.LibrarianAdditionalInputs.emplace_back(pathToObj);
 
-     }
 
-     // We know how to generate this target and haven't added this dependency
 
-     // yet.
 
-     else if (target) {
 
-       if (!linkedDeps.emplace(objLibName + FASTBUILD_OBJECTS_ALIAS_POSTFIX)
 
-              .second) {
 
-         LogMessage("Object Target: " + objLibName +
 
-                    FASTBUILD_OBJECTS_ALIAS_POSTFIX " already linked");
 
-         continue;
 
-       }
 
-       linkerNode.LibrarianAdditionalInputs.emplace_back(
 
-         objLibName + FASTBUILD_OBJECTS_ALIAS_POSTFIX);
 
-     } else if (linkedDeps.emplace(pathToObj).second) {
 
-       LogMessage("Adding obj dep : " + pathToObj);
 
-       linkerNode.LibrarianAdditionalInputs.emplace_back(pathToObj);
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendExeToLink(
 
-   FastbuildLinkerNode& linkerNode,
 
-   cmComputeLinkInformation::Item const& item) const
 
- {
 
-   std::string const decorated =
 
-     item.GetFormattedItem(this->ConvertToFastbuildPath(item.Value.Value))
 
-       .Value;
 
-   LogMessage("Linking to executable : " + decorated);
 
-   // Tested in "InterfaceLinkLibrariesDirect" and "Plugin" test.
 
-   linkerNode.LinkerOptions +=
 
-     (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(decorated));
 
- }
 
- std::string cmFastbuildNormalTargetGenerator::GetImportedLoc(
 
-   cmComputeLinkInformation::Item const& item) const
 
- {
 
-   // Link to import library when possible.
 
-   // Tested in "StagingPrefix" test on Windows/MSVC.
 
-   cmStateEnums::ArtifactType const artifact =
 
-     item.Target->HasImportLibrary(Config)
 
-     ? cmStateEnums::ImportLibraryArtifact
 
-     : cmStateEnums::RuntimeBinaryArtifact;
 
-   std::string importedLoc = this->ConvertToFastbuildPath(
 
-     item.Target->GetFullPath(Config, artifact, true));
 
-   LogMessage("ImportedGetLocation: " + importedLoc);
 
-   return importedLoc;
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendTargetDep(
 
-   FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedObjects,
 
-   cmComputeLinkInformation::Item const& item) const
 
- {
 
-   LogMessage("AppendTargetDep(...)");
 
-   cmStateEnums::TargetType const depType = item.Target->GetType();
 
-   LogMessage("Link dep type: " + std::to_string(depType));
 
-   LogMessage("Target name: " + item.Target->GetName());
 
-   auto const resolvedTargetName = ResolveIfAlias(item.Target->GetName());
 
-   LogMessage("Resolved: " + resolvedTargetName);
 
-   if (depType == cmStateEnums::INTERFACE_LIBRARY) {
 
-     return;
 
-   }
 
-   std::string const feature = item.GetFeatureName();
 
-   if (item.Target->IsImported()) {
 
-     if (feature == "FRAMEWORK") {
 
-       // Use just framework's name. The exact path where to look for the
 
-       // framework will be provided from "frameworkPath" in
 
-       // "cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(...)".
 
-       // Tested in "RunCMake.Framework - ImportedFrameworkConsumption".
 
-       std::string const decorated =
 
-         item.GetFormattedItem(item.Value.Value).Value;
 
-       LogMessage("Adding framework dep <" + decorated + "> to command line");
 
-       linkerNode.LinkerOptions += (" " + decorated);
 
-       return;
 
-     }
 
-     if (depType == cmStateEnums::UNKNOWN_LIBRARY) {
 
-       LogMessage("Unknown library -- adding to LibrarianAdditionalInputs or "
 
-                  "Libraries2");
 
-       if (UsingCommandLine) {
 
-         AppendCommandLineDep(linkerNode, item);
 
-       } else {
 
-         AppendLinkDep(linkerNode, GetImportedLoc(item));
 
-       }
 
-       return;
 
-     }
 
-     // Tested in "ExportImport" test.
 
-     if (depType == cmStateEnums::EXECUTABLE) {
 
-       AppendExeToLink(linkerNode, item);
 
-       return;
 
-     }
 
-     // Skip exported objects.
 
-     // Tested in "ExportImport" test.
 
-     if (depType == cmStateEnums::OBJECT_LIBRARY) {
 
-       LogMessage("target : " + item.Target->GetName() +
 
-                  " already linked... Skipping");
 
-       return;
 
-     }
 
-     // Tested in "ExportImport" test.
 
-     cmList const list{ GetImportedLoc(item) };
 
-     for (std::string const& linkDep : list) {
 
-       AppendLinkDep(linkerNode, linkDep);
 
-     }
 
-   } else {
 
-     if (depType == cmStateEnums::SHARED_LIBRARY &&
 
-         this->GeneratorTarget->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED")) {
 
-       // It moves the dep outside of FASTBuild control, so the binary won't
 
-       // be re-built if the shared lib has changed.
 
-       // Tested in "BuildDepends" test.
 
-       LogMessage("LINK_DEPENDS_NO_SHARED is set on the target, adding dep" +
 
-                  item.Value.Value + " as is");
 
-       linkerNode.LinkerOptions +=
 
-         (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(item.Value.Value));
 
-       return;
 
-     }
 
-     // Just add path to binary artifact to command line (except for OBJECT
 
-     // libraries which we will link directly).
 
-     if (UsingCommandLine && depType != cmStateEnums::OBJECT_LIBRARY) {
 
-       AppendCommandLineDep(linkerNode, item);
 
-       return;
 
-     }
 
-     // This dep has a special way of linking to it (e.g.
 
-     // "CMAKE_LINK_LIBRARY_USING_<FEATURE>").
 
-     bool const isFeature = !feature.empty() && feature != "DEFAULT";
 
-     if (isFeature) {
 
-       std::string const decorated =
 
-         item.GetFormattedItem(this->ConvertToFastbuildPath(item.Value.Value))
 
-           .Value;
 
-       LogMessage("Prepending with feature: " + decorated);
 
-       linkerNode.LinkerOptions += (" " + decorated);
 
-     }
 
-     std::string dep = resolvedTargetName +
 
-       (depType == cmStateEnums::OBJECT_LIBRARY
 
-          ? FASTBUILD_OBJECTS_ALIAS_POSTFIX
 
-          : FASTBUILD_LINK_ARTIFACTS_ALIAS_POSTFIX);
 
-     if (!linkerNode.Arch.empty()) {
 
-       dep += cmStrCat('-', linkerNode.Arch);
 
-     }
 
-     // If we have a special way of linking the dep, we can't have it in
 
-     // ".Libraries" (since there might be multiple such deps, but
 
-     // FASTBuild expands ".Libraries" as a continuous array, so we can't
 
-     // inject any properties in between). Tested in
 
-     // "RunCMake.target_link_libraries-LINK_LIBRARY" test.
 
-     if (isFeature) {
 
-       LogMessage("AppendTargetDep: " + dep + " as prebuild");
 
-       linkerNode.PreBuildDependencies.emplace(dep);
 
-       return;
 
-     }
 
-     if (depType != cmStateEnums::OBJECT_LIBRARY ||
 
-         linkedObjects.emplace(dep).second) {
 
-       AppendLinkDep(linkerNode, dep);
 
-     }
 
-     AppendTransitivelyLinkedObjects(*item.Target, linkedObjects);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendPrebuildDeps(
 
-   FastbuildLinkerNode& linkerNode,
 
-   cmComputeLinkInformation::Item const& item) const
 
- {
 
-   if (!item.Target->IsImported()) {
 
-     return;
 
-   }
 
-   // In "RunCMake.FileAPI" imported object library "imported_object_lib" is
 
-   // added w/o import location...
 
-   if (item.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
 
-     return;
 
-   }
 
-   cmList const list{ GetImportedLoc(item) };
 
-   for (std::string const& linkDep : list) {
 
-     // In case we know how to generate this file (needed for proper
 
-     // sorting by deps). Tested in "RunCMake.target_link_libraries-ALIAS"
 
-     // test.
 
-     auto fastbuildTarget =
 
-       this->GetGlobalGenerator()->GetTargetByOutputName(linkDep);
 
-     std::string fastbuildTargetName;
 
-     if (fastbuildTarget) {
 
-       fastbuildTargetName = std::move(fastbuildTarget->Name);
 
-     }
 
-     if (!fastbuildTargetName.empty()) {
 
-       LogMessage("Adding dep to " + fastbuildTargetName);
 
-       linkerNode.PreBuildDependencies.insert(std::move(fastbuildTargetName));
 
-     } else {
 
-       LogMessage("Adding dep " + linkDep + " for sorting");
 
-       linkerNode.PreBuildDependencies.insert(linkDep);
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendTransitivelyLinkedObjects(
 
-   cmGeneratorTarget const& target, std::set<std::string>& linkedObjects) const
 
- {
 
-   std::vector<std::string> objs;
 
-   // Consider that all those object are now linked as well.
 
-   // Tested in "ExportImport" test.
 
-   target.GetTargetObjectNames(Config, objs);
 
-   for (std::string const& obj : objs) {
 
-     std::string const pathToObj = this->ConvertToFastbuildPath(
 
-       cmStrCat(target.GetObjectDirectory(Config), '/', obj));
 
-     linkedObjects.insert(pathToObj);
 
-   }
 
-   // Object libs should not be propagated transitively. It's especially
 
-   // important for LinkObjRHSObject2 test where the absence of the propagation
 
-   // is tested.
 
-   for (auto const& linkedTarget :
 
-        target.Target->GetLinkImplementationEntries()) {
 
-     auto objAlias = linkedTarget.Value + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
 
-     LogMessage("Object target is linked transitively " + objAlias);
 
-     linkedObjects.emplace(std::move(objAlias));
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendCommandLineDep(
 
-   FastbuildLinkerNode& linkerNode,
 
-   cmComputeLinkInformation::Item const& item) const
 
- {
 
-   LogMessage("AppendCommandLineDep(...)");
 
-   // Tested in:
 
-   // "LinkDirectory" (TargetType::EXECUTABLE),
 
-   // "ObjC.simple-build-test" (TargetType::SHARED_LIBRARY),
 
-   // "XCTest" (TargetType::MODULE_LIBRARY) tests.
 
-   std::string formatted;
 
-   if (item.Target && item.Target->IsImported()) {
 
-     formatted = GetImportedLoc(item);
 
-   } else {
 
-     formatted = item.GetFormattedItem(item.Value.Value).Value;
 
-   }
 
-   formatted = this->ConvertToFastbuildPath(formatted);
 
-   LogMessage("Unknown link dep: " + formatted + ", adding to command line");
 
-   // Only add real artifacts to .Libraries2, otherwise Fastbuild will always
 
-   // consider the target out-of-date (since its input doesn't exist).
 
-   if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes &&
 
-       item.GetFeatureName() == "DEFAULT") {
 
-     linkerNode.LinkerOptions +=
 
-       (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(formatted));
 
-     AppendToLibraries2IfApplicable(linkerNode, std::move(formatted));
 
-   } else {
 
-     // It's some link option, not a path.
 
-     linkerNode.LinkerOptions += (" " + formatted);
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendToLibraries2IfApplicable(
 
-   FastbuildLinkerNode& linkerNode, std::string dep) const
 
- {
 
-   // Strings like "-framework Cocoa" in .Libraries2 node will always make the
 
-   // target out-of-date (since it never exists).
 
-   if (this->GeneratorTarget->IsApple() &&
 
-       cmSystemTools::StringStartsWith(dep, "-framework")) {
 
-     LogMessage("Not adding framework: " + dep + " to .Libraries2");
 
-     return;
 
-   }
 
-   auto const target = this->GetGlobalGenerator()->GetTargetByOutputName(dep);
 
-   // Fastbuild doesn't support executables in .Libraries2, though we can use
 
-   // Executables via "-bundle_loader" on Apple.
 
-   if (this->GeneratorTarget->IsApple() && target &&
 
-       !target->LinkerNode.empty() &&
 
-       target->LinkerNode[0].Type == FastbuildLinkerNode::EXECUTABLE) {
 
-     LogMessage("Not adding DLL/Executable(" + linkerNode.Name +
 
-                " to .Libraries2");
 
-     return;
 
-   }
 
-   // Additing to .Libraries2 for tracking.
 
-   LogMessage("Adding " + dep + " .Libraries2");
 
-   linkerNode.Libraries2.emplace_back(std::move(dep));
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendLINK_DEPENDS(
 
-   FastbuildLinkerNode& linkerNode) const
 
- {
 
-   // LINK_DEPENDS and such.
 
-   // Tested in "BuildDepends" test.
 
-   for (std::string const& lang : Languages) {
 
-     for (BT<std::string> const& dep :
 
-          this->GeneratorTarget->GetLinkDepends(Config, lang)) {
 
-       // We can't add "LINK_DEPENDS" to .PreBuildDependencies, since FASTBuild
 
-       // only forces such targets to be built and doesn't force re-linking if
 
-       // they've changed.
 
-       linkerNode.Libraries2.emplace_back(
 
-         this->ConvertToFastbuildPath(dep.Value));
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendLinkDep(
 
-   FastbuildLinkerNode& linkerNode, std::string dep) const
 
- {
 
-   LogMessage("AppendLinkDep: " + dep +
 
-              " to .LibrarianAdditionalInputs/.Libraries");
 
-   linkerNode.LibrarianAdditionalInputs.emplace_back(std::move(dep));
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendDirectObjectLibs(
 
-   FastbuildLinkerNode& linkerNode, std::set<std::string>& linkedObjects)
 
- {
 
-   auto const srcs = this->GeneratorTarget->GetSourceFiles(Config);
 
-   for (auto const& entry : srcs) {
 
-     auto const objLib = entry.Value->GetObjectLibrary();
 
-     auto const objPath = entry.Value->GetFullPath();
 
-     LogMessage("Source obj entry: " + objPath);
 
-     if (!objLib.empty()) {
 
-       auto* const objTarget =
 
-         this->LocalGenerator->FindGeneratorTargetToUse(objLib);
 
-       if (objTarget) {
 
-         LogMessage("Imported: " + std::to_string(objTarget->IsImported()));
 
-         std::string fastbuildTarget;
 
-         // If target is imported - we don't have it in our build file, so can't
 
-         // refer to it by name. Use file path to the object then.
 
-         // Tested in "ExportImport" test.
 
-         if (objTarget->IsImported()) {
 
-           fastbuildTarget = entry.Value->GetFullPath();
 
-         } else {
 
-           // Mark all target objects as linked.
 
-           linkedObjects.emplace(this->ConvertToFastbuildPath(objPath));
 
-           fastbuildTarget =
 
-             objTarget->GetName() + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
 
-         }
 
-         if (linkedObjects.emplace(fastbuildTarget).second) {
 
-           LogMessage("Adding object target: " + fastbuildTarget);
 
-           linkerNode.LibrarianAdditionalInputs.emplace_back(
 
-             std::move(fastbuildTarget));
 
-         }
 
-       }
 
-     }
 
-   }
 
- }
 
- void cmFastbuildNormalTargetGenerator::AppendLinkDeps(
 
-   std::set<FastbuildTargetDep>& preBuildDeps, FastbuildLinkerNode& linkerNode)
 
- {
 
-   std::set<std::string> linkedObjects;
 
-   cmComputeLinkInformation const* linkInfo =
 
-     this->GeneratorTarget->GetLinkInformation(Config);
 
-   if (!linkInfo) {
 
-     return;
 
-   }
 
-   UsingCommandLine = false;
 
-   AppendLINK_DEPENDS(linkerNode);
 
-   // Object libs that are linked directly to target (e.g.
 
-   // add_executable(test_exe archiveObjs)
 
-   AppendDirectObjectLibs(linkerNode, linkedObjects);
 
-   // target_link_libraries.
 
-   cmComputeLinkInformation::ItemVector const items = linkInfo->GetItems();
 
-   LogMessage(cmStrCat("Link items size: ", items.size()));
 
-   for (cmComputeLinkInformation::Item const& item : items) {
 
-     std::string const feature = item.GetFeatureName();
 
-     LogMessage("GetFeatureName: " + feature);
 
-     if (!feature.empty()) {
 
-       LogMessage("GetFormattedItem: " +
 
-                  item.GetFormattedItem(item.Value.Value).Value);
 
-     }
 
-     // We're linked to `$<TARGET_OBJECTS>`.
 
-     // Static libs transitively propagate such deps, see:
 
-     // https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries-via-target-objects
 
-     if (item.ObjectSource &&
 
-         linkerNode.Type != FastbuildLinkerNode::STATIC_LIBRARY) {
 
-       // Tested in "ObjectLibrary" test.
 
-       auto libName = item.ObjectSource->GetObjectLibrary();
 
-       std::string dep = libName + FASTBUILD_OBJECTS_ALIAS_POSTFIX;
 
-       if (linkedObjects.emplace(dep).second) {
 
-         FastbuildTargetDep targetDep{ std::move(libName) };
 
-         targetDep.Type = FastbuildTargetDepType::ORDER_ONLY;
 
-         preBuildDeps.emplace(std::move(targetDep));
 
-         linkerNode.LibrarianAdditionalInputs.emplace_back(std::move(dep));
 
-       }
 
-     } else if (linkerNode.Type == FastbuildLinkerNode::STATIC_LIBRARY) {
 
-       LogMessage("Skipping linking to STATIC_LIBRARY (" + linkerNode.Name +
 
-                  ")");
 
-       continue;
 
-     }
 
-     // We're linked to exact target.
 
-     else if (item.Target) {
 
-       AppendTargetDep(linkerNode, linkedObjects, item);
 
-       AppendPrebuildDeps(linkerNode, item);
 
-     } else {
 
-       AppendCommandLineDep(linkerNode, item);
 
-       UsingCommandLine = true;
 
-     }
 
-   }
 
-   AppendExternalObject(linkerNode, linkedObjects);
 
- }
 
- void cmFastbuildNormalTargetGenerator::AddLipoCommand(FastbuildTarget& target)
 
- {
 
-   static auto const lipo = cmSystemTools::FindProgram("lipo");
 
-   LogMessage("found lipo at " + lipo);
 
-   FastbuildExecNode exec;
 
-   exec.ExecExecutable = lipo;
 
-   exec.ExecOutput = target.RealOutput;
 
-   for (auto const& ArchSpecificTarget : target.LinkerNode) {
 
-     exec.ExecInput.emplace_back(ArchSpecificTarget.LinkerOutput);
 
-   }
 
-   exec.ExecArguments +=
 
-     "-create -output " + target.RealOutput + " " + cmJoin(exec.ExecInput, " ");
 
-   target.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
 
-     exec.ExecOutput);
 
-   target.PostBuildExecNodes.Nodes.emplace_back(std::move(exec));
 
- }
 
- void cmFastbuildNormalTargetGenerator::GenerateLink(
 
-   FastbuildTarget& target, std::vector<std::string> const& objectDepends)
 
- {
 
-   std::string const targetName = this->GetTargetName();
 
-   cmGeneratorTarget::Names const targetNames = DetectOutput();
 
-   LogMessage("targetNames.Real: " + targetNames.Real);
 
-   LogMessage("targetNames.ImportOutput: " + targetNames.ImportOutput);
 
-   LogMessage("targetNames.SharedObject: " + targetNames.SharedObject);
 
-   LogMessage("targetNames.Base: " + targetNames.Base);
 
-   std::vector<std::string> allNodes;
 
-   auto const arches = this->GetArches();
 
-   for (std::size_t i = 0; i < arches.size(); ++i) {
 
-     auto const& arch = arches[i];
 
-     FastbuildLinkerNode linkerNode;
 
-     ProcessManifests(linkerNode);
 
-     // Objects built by the current target.
 
-     for (auto const& objectList : target.ObjectListNodes) {
 
-       if (objectList.arch.empty() || objectList.arch == arch) {
 
-         linkerNode.LibrarianAdditionalInputs.push_back(objectList.Name);
 
-       }
 
-     }
 
-     // Detection of the link command as follows:
 
-     auto const type = this->GeneratorTarget->GetType();
 
-     switch (type) {
 
-       case cmStateEnums::EXECUTABLE: {
 
-         LogMessage("Generating EXECUTABLE");
 
-         linkerNode.Type = FastbuildLinkerNode::EXECUTABLE;
 
-         break;
 
-       }
 
-       case cmStateEnums::MODULE_LIBRARY: {
 
-         LogMessage("Generating MODULE_LIBRARY");
 
-         linkerNode.Type = FastbuildLinkerNode::SHARED_LIBRARY;
 
-         break;
 
-       }
 
-       case cmStateEnums::SHARED_LIBRARY: {
 
-         LogMessage("Generating SHARED_LIBRARY");
 
-         linkerNode.Type = FastbuildLinkerNode::SHARED_LIBRARY;
 
-         break;
 
-       }
 
-       case cmStateEnums::STATIC_LIBRARY: {
 
-         LogMessage("Generating STATIC_LIBRARY");
 
-         linkerNode.Type = FastbuildLinkerNode::STATIC_LIBRARY;
 
-         break;
 
-       }
 
-       case cmStateEnums::OBJECT_LIBRARY: {
 
-         LogMessage("Generating OBJECT_LIBRARY");
 
-         return;
 
-       }
 
-       default: {
 
-         LogMessage("Skipping GenerateLink");
 
-         return;
 
-       }
 
-     }
 
-     std::string const targetOutput =
 
-       ConvertToFastbuildPath(GeneratorTarget->GetFullPath(Config));
 
-     std::string targetOutputReal = ConvertToFastbuildPath(
 
-       GeneratorTarget->GetFullPath(Config, cmStateEnums::RuntimeBinaryArtifact,
 
-                                    /*realname=*/true));
 
-     LogMessage("targetOutput: " + targetOutput);
 
-     LogMessage("targetOutputReal: " + targetOutputReal);
 
-     std::string const output =
 
-       cmSystemTools::GetFilenameName(targetNames.Output);
 
-     std::string const outputReal =
 
-       cmSystemTools::GetFilenameName(targetNames.Real);
 
-     // Generate "Copy" nodes for copying Framework / Bundle resources.
 
-     AppendExtraResources(linkerNode.PreBuildDependencies);
 
-     if (type == cmStateEnums::EXECUTABLE ||
 
-         type == cmStateEnums::SHARED_LIBRARY) {
 
-       // Tested in "RunCMake.BuildDepends" test (we need to rebuild when
 
-       // manifest  changes).
 
-       std::copy(objectDepends.begin(), objectDepends.end(),
 
-                 std::back_inserter(linkerNode.Libraries2));
 
-     }
 
-     if (GeneratorTarget->IsAppBundleOnApple()) {
 
-       // Create the app bundle
 
-       std::string outpath = GeneratorTarget->GetDirectory(Config);
 
-       this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
 
-                                                 Config);
 
-       targetOutputReal = outpath;
 
-       targetOutputReal += "/";
 
-       targetOutputReal += outputReal;
 
-       targetOutputReal = this->ConvertToFastbuildPath(targetOutputReal);
 
-     } else if (GeneratorTarget->IsFrameworkOnApple()) {
 
-       // Create the library framework.
 
-       this->OSXBundleGenerator->CreateFramework(
 
-         targetNames.Output, GeneratorTarget->GetDirectory(Config), Config);
 
-     } else if (GeneratorTarget->IsCFBundleOnApple()) {
 
-       // Create the core foundation bundle.
 
-       this->OSXBundleGenerator->CreateCFBundle(
 
-         targetNames.Output, GeneratorTarget->GetDirectory(Config), Config);
 
-     }
 
-     std::string linkCmd;
 
-     if (!DetectBaseLinkerCommand(linkCmd, arch, targetNames)) {
 
-       LogMessage("No linker command detected");
 
-       return;
 
-     }
 
-     std::string executable;
 
-     std::string linkerOptions;
 
-     std::string linkerType = "auto";
 
-     GetLinkerExecutableAndArgs(linkCmd, executable, linkerOptions);
 
-     linkerNode.Compiler = ".Compiler_dummy";
 
-     linkerNode.CompilerOptions = " ";
 
-     linkerNode.Name = targetName;
 
-     linkerNode.LinkerOutput = targetOutputReal;
 
-     this->GetGlobalGenerator()->AddFileToClean(linkerNode.LinkerOutput);
 
-     target.RealOutput = targetOutputReal;
 
-     if (!arch.empty()) {
 
-       linkerNode.Name += cmStrCat('-', arch);
 
-       linkerNode.LinkerOutput += cmStrCat('.', arch);
 
-       linkerNode.Arch = arch;
 
-     }
 
-     linkerNode.Linker = executable;
 
-     linkerNode.LinkerType = linkerType;
 
-     linkerNode.LinkerOptions += linkerOptions;
 
-     AppendLinkDeps(target.PreBuildDependencies, linkerNode);
 
-     ApplyLWYUToLinkerCommand(linkerNode);
 
-     // On macOS, only the last LinkerNode performs lipo in POST_BUILD.
 
-     // Make it depend on all previous nodes to ensure correct execution order.
 
-     if (i == arches.size() - 1) {
 
-       for (auto& prevNode : allNodes) {
 
-         linkerNode.PreBuildDependencies.emplace(std::move(prevNode));
 
-       }
 
-     } else {
 
-       allNodes.emplace_back(linkerNode.Name);
 
-     }
 
-     if (!target.ObjectListNodes.empty()) {
 
-       // Just reuse any of compiler options mainly for the correct IDE project
 
-       // generation.
 
-       linkerNode.CompilerOptions = target.ObjectListNodes[0].CompilerOptions;
 
-     }
 
-     target.LinkerNode.emplace_back(std::move(linkerNode));
 
-   }
 
- }
 
- std::vector<FastbuildExecNode>
 
- cmFastbuildNormalTargetGenerator::GetSymlinkExecs() const
 
- {
 
-   std::vector<FastbuildExecNode> res;
 
-   cmGeneratorTarget::Names const targetNames = DetectOutput();
 
-   LogMessage("targetNames.Real: " + targetNames.Real);
 
-   LogMessage("targetNames.ImportOutput: " + targetNames.ImportOutput);
 
-   LogMessage("targetNames.SharedObject: " + targetNames.SharedObject);
 
-   LogMessage("targetNames.Base: " + targetNames.Base);
 
-   std::string const targetOutput =
 
-     ConvertToFastbuildPath(GeneratorTarget->GetFullPath(Config));
 
-   std::string const targetOutputReal = ConvertToFastbuildPath(
 
-     GeneratorTarget->GetFullPath(Config, cmStateEnums::RuntimeBinaryArtifact,
 
-                                  /*realname=*/true));
 
-   LogMessage("targetOutput: " + targetOutput);
 
-   LogMessage("targetOutputReal: " + targetOutputReal);
 
-   if (targetOutput != targetOutputReal &&
 
-       !GeneratorTarget->IsFrameworkOnApple()) {
 
-     auto const generateSymlinkCommand = [&](std::string const& from,
 
-                                             std::string const& to) {
 
-       if (from.empty() || to.empty() || from == to) {
 
-         return;
 
-       }
 
-       LogMessage("Symlinking " + from + " -> " + to);
 
-       FastbuildExecNode postBuildExecNode;
 
-       postBuildExecNode.Name = "cmake_symlink_" + to;
 
-       postBuildExecNode.ExecOutput =
 
-         cmJoin({ GeneratorTarget->GetDirectory(Config), to }, "/");
 
-       postBuildExecNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
 
-       postBuildExecNode.ExecArguments =
 
-         "-E cmake_symlink_executable " +
 
-         cmGlobalFastbuildGenerator::QuoteIfHasSpaces(from) + " " +
 
-         cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
 
-           this->ConvertToFastbuildPath(postBuildExecNode.ExecOutput));
 
-       res.emplace_back(std::move(postBuildExecNode));
 
-     };
 
-     generateSymlinkCommand(targetNames.Real, targetNames.Output);
 
-     generateSymlinkCommand(targetNames.Real, targetNames.SharedObject);
 
-     generateSymlinkCommand(targetNames.ImportReal, targetNames.ImportOutput);
 
-   }
 
-   return res;
 
- }
 
 
  |