| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file LICENSE.rst or https://cmake.org/licensing for details. */
- #include "cmFastbuildTargetGenerator.h"
- #include <algorithm>
- #include <cstddef>
- #include <unordered_map>
- #include <unordered_set>
- #include <cm/memory>
- #include <cm/optional>
- #include "cmCryptoHash.h"
- #include "cmCustomCommand.h"
- #include "cmCustomCommandGenerator.h"
- #include "cmCustomCommandLines.h"
- #include "cmFastbuildNormalTargetGenerator.h"
- #include "cmFastbuildUtilityTargetGenerator.h"
- #include "cmGeneratorExpression.h"
- #include "cmGeneratorTarget.h"
- #include "cmGlobalCommonGenerator.h"
- #include "cmGlobalFastbuildGenerator.h"
- #include "cmList.h"
- #include "cmListFileCache.h"
- #include "cmLocalCommonGenerator.h"
- #include "cmLocalFastbuildGenerator.h"
- #include "cmLocalGenerator.h"
- #include "cmMakefile.h"
- #include "cmOSXBundleGenerator.h"
- #include "cmOutputConverter.h"
- #include "cmRulePlaceholderExpander.h"
- #include "cmSourceFile.h"
- #include "cmState.h"
- #include "cmStateTypes.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmTarget.h"
- #include "cmValue.h"
- #define FASTBUILD_DOLLAR_TAG "FASTBUILD_DOLLAR_TAG"
- constexpr auto FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT =
- "CMAKE_FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT";
- constexpr auto FASTBUILD_DISABLE_OUTPUT_PRECHECK_EXEC =
- "CMAKE_FASTBUILD_DISABLE_OUTPUT_PRECHECK_EXEC";
- cmFastbuildTargetGenerator* cmFastbuildTargetGenerator::New(
- cmGeneratorTarget* target, std::string config)
- {
- switch (target->GetType()) {
- case cmStateEnums::EXECUTABLE:
- case cmStateEnums::SHARED_LIBRARY:
- case cmStateEnums::STATIC_LIBRARY:
- case cmStateEnums::MODULE_LIBRARY:
- case cmStateEnums::OBJECT_LIBRARY:
- return new cmFastbuildNormalTargetGenerator(target, std::move(config));
- case cmStateEnums::UTILITY:
- case cmStateEnums::GLOBAL_TARGET:
- case cmStateEnums::INTERFACE_LIBRARY:
- return new cmFastbuildUtilityTargetGenerator(target, std::move(config));
- default:
- return nullptr;
- }
- }
- cmFastbuildTargetGenerator::cmFastbuildTargetGenerator(
- cmGeneratorTarget* target, std::string configParam)
- : cmCommonTargetGenerator(target)
- , LocalGenerator(
- static_cast<cmLocalFastbuildGenerator*>(target->GetLocalGenerator()))
- , TargetDirectDependencies(
- this->GlobalCommonGenerator->GetTargetDirectDepends(GeneratorTarget))
- , Config(std::move(configParam))
- {
- this->MacOSXContentGenerator =
- cm::make_unique<MacOSXContentGeneratorType>(this, Config);
- }
- void cmFastbuildTargetGenerator::LogMessage(std::string const& m) const
- {
- this->GetGlobalGenerator()->LogMessage(m);
- }
- std::string cmFastbuildTargetGenerator::GetUtilityAliasFromBuildStep(
- FastbuildBuildStep step) const
- {
- if (step == FastbuildBuildStep::PRE_BUILD) {
- return GetTargetName() + FASTBUILD_PRE_BUILD_ALIAS_POSTFIX;
- }
- if (step == FastbuildBuildStep::PRE_LINK) {
- return GetTargetName() + FASTBUILD_PRE_LINK_ALIAS_POSTFIX;
- }
- if (step == FastbuildBuildStep::POST_BUILD) {
- return GetTargetName() + FASTBUILD_POST_BUILD_ALIAS_POSTFIX;
- }
- return GetTargetName() + FASTBUILD_CUSTOM_COMMAND_ALIAS_POSTFIX;
- }
- void cmFastbuildTargetGenerator::MacOSXContentGeneratorType::operator()(
- cmSourceFile const& source, char const* pkgloc,
- std::string const& configName)
- {
- // Skip OS X content when not building a Framework or Bundle.
- if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
- return;
- }
- // Get the input file location.
- std::string input = source.GetFullPath();
- input = this->Generator->GetGlobalGenerator()->ConvertToFastbuildPath(input);
- // Get the output file location.
- std::string output =
- this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(
- pkgloc, configName);
- output += "/";
- output += cmSystemTools::GetFilenameName(input);
- output =
- this->Generator->GetGlobalGenerator()->ConvertToFastbuildPath(output);
- FastbuildCopyNode node;
- node.Name = "Copy_" + output;
- node.Source = std::move(input);
- if (cmSystemTools::FileIsDirectory(node.Source)) {
- node.CopyDir = true;
- }
- node.Dest = std::move(output);
- // Just in case if "from" is generated by some custom command.
- // Tested in "BundleTest" test.
- node.PreBuildDependencies =
- this->Generator->GetTargetName() + FASTBUILD_CUSTOM_COMMAND_ALIAS_POSTFIX;
- this->Generator->CopyNodes.emplace_back(std::move(node));
- }
- std::string cmFastbuildTargetGenerator::GetCustomCommandTargetName(
- cmCustomCommand const& cc, FastbuildBuildStep step) const
- {
- std::string const extra = this->Makefile->GetCurrentBinaryDirectory();
- std::string targetName = "cc";
- std::string extras = extra;
- // Compute hash based on commands & args & output.
- for (cmCustomCommandLine const& commandLine : cc.GetCommandLines()) {
- extras += cmJoin(commandLine, "");
- }
- for (std::string const& output : cc.GetOutputs()) {
- extras += output;
- }
- extras += std::to_string(static_cast<int>(step));
- cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
- targetName += "-" + hash.HashString(extras).substr(0, 14);
- return targetName;
- }
- void cmFastbuildTargetGenerator::WriteScriptProlog(cmsys::ofstream& file) const
- {
- #ifdef _WIN32
- file << "@echo off\n";
- #else
- file << "set -e\n\n";
- #endif
- }
- void cmFastbuildTargetGenerator::WriteScriptEpilog(cmsys::ofstream& file) const
- {
- (void)file;
- #ifdef _WIN32
- file << "goto :EOF\n\n"
- ":ABORT\n"
- "set ERROR_CODE=%ERRORLEVEL%\n"
- "echo Batch file failed at line %FAIL_LINE% "
- "with errorcode %ERRORLEVEL%\n"
- "exit /b %ERROR_CODE%";
- #endif
- }
- std::string cmFastbuildTargetGenerator::GetScriptWorkingDir(
- cmCustomCommandGenerator const& ccg) const
- {
- std::string workingDirectory = ccg.GetWorkingDirectory();
- if (workingDirectory.empty()) {
- return this->LocalCommonGenerator->GetCurrentBinaryDirectory();
- }
- return workingDirectory;
- }
- std::string cmFastbuildTargetGenerator::GetScriptFilename(
- std::string const& utilityTargetName) const
- {
- std::string scriptFileName = Makefile->GetCurrentBinaryDirectory();
- scriptFileName += "/CMakeFiles/";
- scriptFileName += utilityTargetName;
- scriptFileName += FASTBUILD_SCRIPT_FILE_EXTENSION;
- return scriptFileName;
- }
- void cmFastbuildTargetGenerator::AddCommentPrinting(
- std::vector<std::string>& cmdLines,
- cmCustomCommandGenerator const& ccg) const
- {
- std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
- auto const comment = ccg.GetComment();
- if (comment) {
- // Comment printing should be first. Tested in
- // RunCMake.ExternalProject:EnvVars-build test.
- cmdLines.insert(
- cmdLines.begin(),
- cmakeCommand.append(" -E echo ")
- .append(LocalGenerator->EscapeForShell(cmGeneratorExpression::Evaluate(
- *comment, this->LocalGenerator, Config))));
- }
- }
- std::string cmFastbuildTargetGenerator::GetCdCommand(
- cmCustomCommandGenerator const& ccg) const
- {
- return cmStrCat(FASTBUILD_SCRIPT_CD,
- this->LocalGenerator->ConvertToOutputFormat(
- GetScriptWorkingDir(ccg), cmOutputConverter::SHELL));
- }
- void cmFastbuildTargetGenerator::WriteCmdsToFile(
- cmsys::ofstream& file, std::vector<std::string> const& cmds) const
- {
- #ifdef _WIN32
- int line = 1;
- for (auto cmd : cmds) {
- // On Windows batch, '%' is a special character that needs to be
- // doubled to be escaped
- cmSystemTools::ReplaceString(cmd, "%", "%%");
- file << cmd << " || (set FAIL_LINE=" << ++line << "& goto :ABORT)" << '\n';
- #else
- for (auto const& cmd : cmds) {
- file << cmd << '\n';
- #endif
- }
- }
- void cmFastbuildTargetGenerator::AddOutput(cmCustomCommandGenerator const& ccg,
- FastbuildExecNode& exec)
- {
- std::string dummyOutput = cmSystemTools::JoinPath(
- { LocalCommonGenerator->GetMakefile()->GetHomeOutputDirectory(),
- "/_fbuild_dummy" });
- this->GetGlobalGenerator()->AllFoldersToClean.insert(dummyOutput);
- dummyOutput.append("/").append(exec.Name).append(
- FASTBUILD_DUMMY_OUTPUT_EXTENSION);
- std::vector<std::string> const& outputs = ccg.GetOutputs();
- std::vector<std::string> const& byproducts = ccg.GetByproducts();
- exec.OutputsAlias.Name = exec.Name + FASTBUILD_OUTPUTS_ALIAS_POSTFIX;
- // If CC doesn't have any output - we should always run it.
- // Tested in "RunCMake.CMakePresetsBuild" test.
- bool hasAnyNonSymbolicOutput = false;
- bool const trackByproducts =
- this->Makefile->IsDefinitionSet(FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT);
- auto const isSymbolic = [this](std::string const& file) {
- cmSourceFile* sf = this->Makefile->GetSource(file);
- if (sf && sf->GetPropertyAsBool("SYMBOLIC")) {
- LogMessage("Skipping symbolic file: " + file);
- return true;
- }
- return false;
- };
- for (std::string const& output : outputs) {
- // Tested in "RunCMake.BuildDepends".
- if (isSymbolic(output)) {
- continue;
- }
- hasAnyNonSymbolicOutput = true;
- std::string const outputPath = this->ConvertToFastbuildPath(output);
- LogMessage("CC's output: " + outputPath);
- exec.OutputsAlias.PreBuildDependencies.emplace(outputPath);
- // Ensure output path exists. For some reason, "CMake -E touch" fails with
- // "cmake -E touch: failed to update "...
- cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(outputPath));
- this->GetGlobalGenerator()->AddFileToClean(outputPath);
- }
- exec.ByproductsAlias.Name = exec.Name + FASTBUILD_BYPRODUCTS_ALIAS_POSTFIX;
- for (std::string const& byproduct : byproducts) {
- if (trackByproducts) {
- hasAnyNonSymbolicOutput = true;
- }
- std::string const byproductPath = this->ConvertToFastbuildPath(byproduct);
- exec.ByproductsAlias.PreBuildDependencies.emplace(byproductPath);
- this->GetGlobalGenerator()->AddFileToClean(byproductPath);
- }
- auto const addDummyOutput = [&] {
- // So that the dummy file is always created.
- exec.ExecUseStdOutAsOutput = true;
- exec.ExecOutput = this->ConvertToFastbuildPath(dummyOutput);
- for (auto const& output : exec.OutputsAlias.PreBuildDependencies) {
- OutputsToReplace[output.Name] = exec.ExecOutput;
- LogMessage("Adding replace from " + output.Name + " to " +
- exec.ExecOutput);
- }
- };
- // We don't have any output that is expected to appear on disk -> run always.
- // Tested in "RunCMake.ExternalProject":BUILD_ALWAYS
- if (!hasAnyNonSymbolicOutput) {
- exec.ExecAlways = true;
- addDummyOutput();
- return;
- }
- if (!exec.OutputsAlias.PreBuildDependencies.empty()) {
- exec.ExecOutput = this->ConvertToFastbuildPath(
- exec.OutputsAlias.PreBuildDependencies.begin()->Name);
- } else {
- exec.ExecOutput = this->ConvertToFastbuildPath(
- exec.ByproductsAlias.PreBuildDependencies.begin()->Name);
- }
- // Optionally add the "deps-check" Exec if we have more than 1 OUTPUT, but
- // allow user to opt out.
- if (exec.OutputsAlias.PreBuildDependencies.size() > 1 &&
- !this->Makefile->IsDefinitionSet(
- FASTBUILD_DISABLE_OUTPUT_PRECHECK_EXEC)) {
- exec.NeedsDepsCheckExec = true;
- }
- }
- void cmFastbuildTargetGenerator::AddExecArguments(
- FastbuildExecNode& exec, std::string const& scriptFilename) const
- {
- exec.ExecArguments = FASTBUILD_SCRIPT_FILE_ARG;
- exec.ExecArguments +=
- cmGlobalFastbuildGenerator::QuoteIfHasSpaces(scriptFilename);
- exec.ScriptFile = scriptFilename;
- exec.ExecExecutable =
- cmGlobalFastbuildGenerator::GetExternalShellExecutable();
- }
- void cmFastbuildTargetGenerator::GetDepends(
- cmCustomCommandGenerator const& ccg, std::string const& currentCCName,
- std::vector<std::string>& fileLevelDeps,
- std::set<FastbuildTargetDep>& targetDep) const
- {
- for (auto dep : ccg.GetDepends()) {
- LogMessage("Dep: " + dep);
- auto orig = dep;
- if (this->LocalCommonGenerator->GetRealDependency(dep, Config, dep)) {
- LogMessage("Real dep: " + dep);
- if (!dep.empty()) {
- LogMessage("Custom command real dep: " + dep);
- for (auto const& item : cmList{ cmGeneratorExpression::Evaluate(
- this->ConvertToFastbuildPath(dep), this->LocalGenerator,
- Config) }) {
- fileLevelDeps.emplace_back(item);
- }
- }
- }
- dep = this->ConvertToFastbuildPath(dep);
- LogMessage("Real dep converted: " + dep);
- auto const targetInfo = this->LocalGenerator->GetSourcesWithOutput(dep);
- if (targetInfo.Target) {
- LogMessage("dep: " + dep + ", target: " + targetInfo.Target->GetName());
- auto const& target = targetInfo.Target;
- auto const processCCs = [this, ¤tCCName, &targetDep,
- dep](std::vector<cmCustomCommand> const& ccs,
- FastbuildBuildStep step) {
- for (auto const& cc : ccs) {
- for (auto const& output : cc.GetOutputs()) {
- LogMessage("dep: " + dep + ", post output: " +
- this->ConvertToFastbuildPath(output));
- if (this->ConvertToFastbuildPath(output) == dep) {
- auto ccName = this->GetCustomCommandTargetName(cc, step);
- if (ccName != currentCCName) {
- LogMessage("Additional CC dep from target: " + ccName);
- targetDep.emplace(std::move(ccName));
- }
- }
- }
- for (auto const& byproduct : cc.GetByproducts()) {
- LogMessage("dep: " + dep + ", post byproduct: " +
- this->ConvertToFastbuildPath(byproduct));
- if (this->ConvertToFastbuildPath(byproduct) == dep) {
- auto ccName = this->GetCustomCommandTargetName(cc, step);
- if (ccName != currentCCName) {
- LogMessage("Additional CC dep from target: " + ccName);
- targetDep.emplace(std::move(ccName));
- }
- }
- }
- }
- };
- processCCs(target->GetPreBuildCommands(), FastbuildBuildStep::PRE_BUILD);
- processCCs(target->GetPreLinkCommands(), FastbuildBuildStep::PRE_LINK);
- processCCs(target->GetPostBuildCommands(),
- FastbuildBuildStep::POST_BUILD);
- continue;
- }
- if (!targetInfo.Source) {
- LogMessage("dep: " + dep + ", no source, byproduct: " +
- std::to_string(targetInfo.SourceIsByproduct));
- // Tested in "OutDir" test.
- if (!cmSystemTools::FileIsFullPath(orig)) {
- targetDep.emplace(std::move(orig));
- }
- continue;
- }
- if (!targetInfo.Source->GetCustomCommand()) {
- LogMessage("dep: " + dep + ", no GetCustomCommand");
- continue;
- }
- if (targetInfo.Source && targetInfo.Source->GetCustomCommand()) {
- auto ccName = this->GetCustomCommandTargetName(
- *targetInfo.Source->GetCustomCommand(), FastbuildBuildStep::REST);
- if (ccName != currentCCName) {
- LogMessage("Additional CC dep: " + ccName);
- targetDep.emplace(std::move(ccName));
- }
- }
- }
- }
- void cmFastbuildTargetGenerator::ReplaceProblematicMakeVars(
- std::string& command) const
- {
- // TODO: fix problematic global targets. For now, search and replace the
- // makefile vars.
- cmSystemTools::ReplaceString(
- command, "$(CMAKE_SOURCE_DIR)",
- this->LocalGenerator->ConvertToOutputFormat(
- this->LocalGenerator->GetSourceDirectory(), cmOutputConverter::SHELL));
- cmSystemTools::ReplaceString(
- command, "$(CMAKE_BINARY_DIR)",
- this->LocalGenerator->ConvertToOutputFormat(
- this->LocalGenerator->GetBinaryDirectory(), cmOutputConverter::SHELL));
- cmSystemTools::ReplaceString(command, "$(ARGS)", "");
- }
- FastbuildExecNode cmFastbuildTargetGenerator::GetAppleTextStubCommand() const
- {
- FastbuildExecNode res;
- if (!this->GeneratorTarget->IsApple() ||
- !this->GeneratorTarget->HasImportLibrary(Config)) {
- return res;
- }
- auto const names = DetectOutput();
- std::string const outpathImp =
- this->ConvertToFastbuildPath(this->GeneratorTarget->GetDirectory(
- Config, cmStateEnums::ImportLibraryArtifact));
- std::string const binPath =
- this->ConvertToFastbuildPath(this->GeneratorTarget->GetDirectory(
- Config, cmStateEnums::RuntimeBinaryArtifact));
- cmSystemTools::MakeDirectory(outpathImp);
- std::string rule = this->LocalGenerator->GetMakefile()->GetSafeDefinition(
- "CMAKE_CREATE_TEXT_STUBS");
- LogMessage("CMAKE_CREATE_TEXT_STUBS:" + rule);
- auto rulePlaceholderExpander =
- this->GetLocalGenerator()->CreateRulePlaceholderExpander();
- cmRulePlaceholderExpander::RuleVariables vars;
- res.ExecOutput = cmStrCat(outpathImp, '/', names.ImportReal);
- res.ExecInput = { cmStrCat(binPath, '/', names.SharedObject) };
- vars.Target = res.ExecInput[0].c_str();
- rulePlaceholderExpander->SetTargetImpLib(res.ExecOutput);
- rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), rule,
- vars);
- LogMessage("CMAKE_CREATE_TEXT_STUBS expanded:" + rule);
- std::string executable;
- std::string args;
- if (!cmSystemTools::SplitProgramFromArgs(rule, executable, args)) {
- cmSystemTools::Error("Failed to split program from args: " + rule);
- return res;
- }
- res.Name = "create_" + names.ImportOutput + "_text_stub";
- res.ExecExecutable = std::move(executable);
- res.ExecArguments = std::move(args);
- res.ExecWorkingDir = this->LocalCommonGenerator->GetCurrentBinaryDirectory();
- // Wait for the build.
- res.PreBuildDependencies.emplace(this->GetTargetName());
- return res;
- }
- FastbuildExecNode cmFastbuildTargetGenerator::GetDepsCheckExec(
- FastbuildExecNode const& depender)
- {
- FastbuildExecNode exec;
- exec.Name = depender.Name + "-check-depends";
- exec.ExecAlways = true;
- exec.ExecUseStdOutAsOutput = true;
- exec.ExecOutput = depender.ExecOutput + ".deps-checker";
- exec.ExecExecutable = cmSystemTools::GetCMakeCommand();
- exec.ExecArguments += "-E cmake_fastbuild_check_depends ";
- exec.ExecArguments += depender.ExecOutput + " ";
- char const* sep = "";
- for (auto const& dep : depender.OutputsAlias.PreBuildDependencies) {
- exec.ExecArguments += sep;
- exec.ExecArguments += dep.Name;
- sep = " ";
- }
- for (auto const& dep : depender.ByproductsAlias.PreBuildDependencies) {
- exec.ExecArguments += sep;
- exec.ExecArguments += dep.Name;
- sep = " ";
- }
- return exec;
- }
- FastbuildExecNodes cmFastbuildTargetGenerator::GenerateCommands(
- FastbuildBuildStep buildStep)
- {
- FastbuildExecNodes execs;
- execs.Alias.Name = GetUtilityAliasFromBuildStep(buildStep);
- std::vector<cmCustomCommand> commands;
- if (buildStep == FastbuildBuildStep::PRE_BUILD) {
- commands = GeneratorTarget->GetPreBuildCommands();
- LogMessage("STEP: PRE_BUILD");
- } else if (buildStep == FastbuildBuildStep::PRE_LINK) {
- commands = GeneratorTarget->GetPreLinkCommands();
- LogMessage("STEP: PRE_LINK");
- } else if (buildStep == FastbuildBuildStep::POST_BUILD) {
- commands = GeneratorTarget->GetPostBuildCommands();
- LogMessage("STEP: POST_BUILD");
- } else {
- LogMessage("STEP: ALL CUSTOM COMMANDS");
- std::vector<cmSourceFile const*> customCommands;
- GeneratorTarget->GetCustomCommands(customCommands, Config);
- for (cmSourceFile const* source : customCommands) {
- cmCustomCommand const* cmd = source->GetCustomCommand();
- if (!cmd->GetCommandLines().empty()) {
- commands.emplace_back(*cmd);
- }
- }
- }
- LogMessage(cmStrCat("Number of custom commands: ", commands.size()));
- for (cmCustomCommand const& customCommand : commands) {
- cmCustomCommandGenerator ccg(customCommand, Config, LocalCommonGenerator);
- std::string launcher = this->MakeCustomLauncher(ccg);
- std::string const execName =
- GetCustomCommandTargetName(customCommand, buildStep);
- std::vector<std::string> cmdLines;
- if (ccg.GetNumberOfCommands() > 0) {
- cmdLines.push_back(GetCdCommand(ccg));
- }
- // Since we are not using FASTBuild Exec nodes natively, we need to
- // have shell specific escape.
- this->LocalGenerator->GetState()->SetFastbuildMake(false);
- // To avoid replacing $ with $$ in the command line.
- this->LocalGenerator->SetLinkScriptShell(true);
- for (unsigned j = 0; j != ccg.GetNumberOfCommands(); ++j) {
- std::string const command = ccg.GetCommand(j);
- // Tested in "CustomCommand" ("empty_command") test.
- if (!command.empty()) {
- cmdLines.emplace_back(launcher +
- this->LocalGenerator->ConvertToOutputFormat(
- command, cmOutputConverter::SHELL));
- std::string& cmd = cmdLines.back();
- ccg.AppendArguments(j, cmd);
- ReplaceProblematicMakeVars(cmd);
- LogMessage("cmCustomCommandLine: " + cmd);
- }
- }
- if (cmdLines.empty()) {
- return {};
- }
- this->LocalGenerator->GetState()->SetFastbuildMake(true);
- FastbuildExecNode execNode;
- execNode.Name = execName;
- // Add depncencies to "ExecInput" so that FASTBuild will re-run the Exec
- // when needed, but also add to "PreBuildDependencies" for correct sorting.
- // Tested in "ObjectLibrary / complexOneConfig" tests.
- GetDepends(ccg, execName, execNode.ExecInput,
- execNode.PreBuildDependencies);
- for (auto const& util : ccg.GetUtilities()) {
- auto const& utilTargetName = util.Value.first;
- LogMessage("Util: " + utilTargetName +
- ", cross: " + std::to_string(util.Value.second));
- auto* const target = this->Makefile->FindTargetToUse(utilTargetName);
- if (target && target->IsImported()) {
- std::string importedLoc =
- this->ConvertToFastbuildPath(target->ImportedGetFullPath(
- Config, cmStateEnums::ArtifactType::RuntimeBinaryArtifact));
- if (importedLoc.empty()) {
- importedLoc =
- this->ConvertToFastbuildPath(target->ImportedGetFullPath(
- Config, cmStateEnums::ArtifactType::ImportLibraryArtifact));
- }
- LogMessage("adding file level dep on imported target: " + importedLoc);
- execNode.ExecInput.emplace_back(std::move(importedLoc));
- continue;
- }
- // This CC uses some executable produced by another target. Add explicit
- // dep. Tested in "CustomCommand" test.
- if (util.Value.second) {
- if (utilTargetName != customCommand.GetTarget()) {
- LogMessage("Adding util dep: " + utilTargetName);
- execNode.PreBuildDependencies.emplace(utilTargetName);
- }
- }
- }
- execs.Alias.PreBuildDependencies.emplace(execNode.Name);
- LogMessage(cmStrCat("cmdLines size ", cmdLines.size()));
- if (!cmdLines.empty()) {
- std::string const scriptFileName = GetScriptFilename(execName);
- cmsys::ofstream scriptFile(scriptFileName.c_str());
- AddOutput(ccg, execNode);
- AddExecArguments(execNode, scriptFileName);
- AddCommentPrinting(cmdLines, ccg);
- WriteScriptProlog(scriptFile);
- WriteCmdsToFile(scriptFile, cmdLines);
- WriteScriptEpilog(scriptFile);
- }
- if (buildStep == FastbuildBuildStep::POST_BUILD) {
- // Execute POST_BUILD in order in which they are declared.
- // Tested in "complex" test.
- for (auto& exec : execs.Nodes) {
- execNode.PreBuildDependencies.emplace(exec.Name);
- }
- }
- for (auto const& out : execNode.OutputsAlias.PreBuildDependencies) {
- LogMessage("Adding replace from " + out.Name + " to " + execName);
- OutputToExecName[out.Name] = execName;
- }
- execs.Nodes.emplace_back(std::move(execNode));
- }
- for (auto& exec : execs.Nodes) {
- for (auto& inputFile : exec.ExecInput) {
- auto const iter = OutputsToReplace.find(inputFile);
- if (iter != OutputsToReplace.end()) {
- LogMessage("Replacing input: " + inputFile + " with " + iter->second);
- inputFile = iter->second;
- }
- auto const depIter = std::find_if(
- exec.PreBuildDependencies.begin(), exec.PreBuildDependencies.end(),
- [this](FastbuildTargetDep const& dep) {
- return !OutputToExecName[dep.Name].empty();
- });
- if (depIter != exec.PreBuildDependencies.end()) {
- LogMessage("Replacing dep " + depIter->Name + " with " +
- OutputToExecName[depIter->Name]);
- exec.PreBuildDependencies.emplace(OutputToExecName[depIter->Name]);
- exec.PreBuildDependencies.erase(depIter);
- }
- }
- if (exec.NeedsDepsCheckExec) {
- auto depsCheckExec = GetDepsCheckExec(exec);
- LogMessage("Adding deps check Exec: " + depsCheckExec.Name);
- exec.PreBuildDependencies.emplace(depsCheckExec.Name);
- this->GetGlobalGenerator()->AddTarget(std::move(depsCheckExec));
- }
- }
- return execs;
- }
- std::string cmFastbuildTargetGenerator::MakeCustomLauncher(
- cmCustomCommandGenerator const& ccg)
- {
- // Copied from cmLocalNinjaGenerator::MakeCustomLauncher.
- cmValue property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM");
- if (!cmNonempty(property_value)) {
- return std::string();
- }
- // Expand rule variables referenced in the given launcher command.
- cmRulePlaceholderExpander::RuleVariables vars;
- std::string output;
- std::vector<std::string> const& outputs = ccg.GetOutputs();
- for (size_t i = 0; i < outputs.size(); ++i) {
- output =
- cmStrCat(output,
- this->LocalGenerator->ConvertToOutputFormat(
- ccg.GetWorkingDirectory().empty()
- ? this->LocalGenerator->MaybeRelativeToCurBinDir(outputs[i])
- : outputs[i],
- cmOutputConverter::SHELL));
- if (i != outputs.size() - 1) {
- output = cmStrCat(output, ',');
- }
- }
- vars.Output = output.c_str();
- vars.Role = ccg.GetCC().GetRole().c_str();
- vars.CMTargetName = ccg.GetCC().GetTarget().c_str();
- vars.Config = ccg.GetOutputConfig().c_str();
- auto rulePlaceholderExpander =
- this->LocalGenerator->CreateRulePlaceholderExpander();
- std::string launcher = *property_value;
- rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, launcher,
- vars);
- if (!launcher.empty()) {
- launcher += " ";
- }
- LogMessage("CC Launcher: " + launcher);
- return launcher;
- }
- std::string cmFastbuildTargetGenerator::GetTargetName() const
- {
- if (this->GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET) {
- return this->GetGlobalGenerator()->GetTargetName(GeneratorTarget);
- }
- return this->GeneratorTarget->GetName();
- }
- cmGeneratorTarget::Names cmFastbuildTargetGenerator::DetectOutput() const
- {
- if (GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
- return GeneratorTarget->GetExecutableNames(Config);
- }
- return GeneratorTarget->GetLibraryNames(Config);
- }
- void cmFastbuildTargetGenerator::AddObjectDependencies(
- FastbuildTarget& fastbuildTarget,
- std::vector<std::string>& allObjectDepends) const
- {
- auto const FindObjListWhichOutputs = [&fastbuildTarget](
- std::string const& output) {
- for (FastbuildObjectListNode const& objList :
- fastbuildTarget.ObjectListNodes) {
- if (objList.ObjectOutputs.find(output) != objList.ObjectOutputs.end()) {
- return objList.Name;
- }
- }
- return std::string{};
- };
- for (FastbuildObjectListNode& objList : fastbuildTarget.ObjectListNodes) {
- for (auto const& objDep : objList.ObjectDepends) {
- // Check if there is another object list which outputs (OBJECT_OUTPUTS)
- // something that this object list needs (OBJECT_DEPENDS).
- auto anotherObjList = FindObjListWhichOutputs(objDep);
- if (!anotherObjList.empty()) {
- LogMessage("Adding explicit <OBJECT_DEPENDS> dep: " + anotherObjList);
- allObjectDepends.emplace_back(anotherObjList);
- objList.PreBuildDependencies.emplace(std::move(anotherObjList));
- } else {
- LogMessage("Adding <OBJECT_DEPENDS> dep: " + objDep);
- allObjectDepends.emplace_back(objDep);
- objList.PreBuildDependencies.emplace(objDep);
- }
- }
- }
- cmGlobalFastbuildGenerator::TopologicalSort(fastbuildTarget.ObjectListNodes);
- }
- void cmFastbuildTargetGenerator::AddLinkerNodeDependnecies(
- FastbuildTarget& fastbuildTarget)
- {
- for (auto& linkerNode : fastbuildTarget.LinkerNode) {
- if (!fastbuildTarget.PreLinkExecNodes.Nodes.empty()) {
- linkerNode.PreBuildDependencies.emplace(
- fastbuildTarget.Name + FASTBUILD_PRE_LINK_ALIAS_POSTFIX);
- }
- }
- }
- std::string cmFastbuildTargetGenerator::GetClangTidyReplacementsFilePath(
- std::string const& directory, cmSourceFile const& source,
- std::string const& /*config*/) const
- {
- std::string objectDir =
- this->ConvertToFastbuildPath(this->GeneratorTarget->GetSupportDirectory());
- std::string const& objectName =
- this->GeneratorTarget->GetObjectName(&source);
- std::string path =
- cmStrCat(directory, '/', objectDir, '/', objectName, ".yaml");
- LogMessage("ClangTidy replacements file: " + path);
- return path;
- }
- void cmFastbuildTargetGenerator::AddIncludeFlags(std::string& languageFlags,
- std::string const& language,
- std::string const&)
- {
- std::vector<std::string> includes;
- this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
- language, Config);
- // Add include directory flags.
- std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
- includes, this->GeneratorTarget, language, Config, false);
- this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
- }
- std::string cmFastbuildTargetGenerator::GetName()
- {
- return GeneratorTarget->GetName();
- }
- std::string cmFastbuildTargetGenerator::ConvertToFastbuildPath(
- std::string const& path) const
- {
- return GetGlobalGenerator()->ConvertToFastbuildPath(path);
- }
- cmGlobalFastbuildGenerator* cmFastbuildTargetGenerator::GetGlobalGenerator()
- const
- {
- return this->LocalGenerator->GetGlobalFastbuildGenerator();
- }
- void cmFastbuildTargetGenerator::AdditionalCleanFiles()
- {
- if (cmValue prop_value =
- this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
- auto* lg = this->LocalGenerator;
- cmList cleanFiles(cmGeneratorExpression::Evaluate(*prop_value, lg, Config,
- this->GeneratorTarget));
- std::string const& binaryDir = lg->GetCurrentBinaryDirectory();
- auto* gg = lg->GetGlobalFastbuildGenerator();
- for (auto const& cleanFile : cleanFiles) {
- // Support relative paths
- gg->AddFileToClean(gg->ConvertToFastbuildPath(
- cmSystemTools::CollapseFullPath(cleanFile, binaryDir)));
- }
- }
- }
|