/* 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(cmStrCat("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 =
    cmStrCat(FASTBUILD_SCRIPT_FILE_ARG,
             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, ccg.GetCC().GetCMP0212Status())) {
      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(
        cmStrCat("dep: ", dep, ", target: ", targetInfo.Target->GetName()));
      auto const& target = targetInfo.Target;
      auto const processCCs = [this, &currentCCName, &targetDep,
                               dep](std::vector<cmCustomCommand> const& ccs,
                                    FastbuildBuildStep step) {
        for (auto const& cc : ccs) {
          for (auto const& output : cc.GetOutputs()) {
            LogMessage(cmStrCat("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(cmStrCat("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(cmStrCat("dep: ", dep, ", no source, byproduct: ",
                          targetInfo.SourceIsByproduct));
      // Tested in "OutDir" test.
      if (!cmSystemTools::FileIsFullPath(orig)) {
        targetDep.emplace(std::move(orig));
      }
      continue;
    }
    if (!targetInfo.Source->GetCustomCommand()) {
      LogMessage(cmStrCat("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 = cmStrCat("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 =
    cmStrCat(std::move(exec.ExecArguments),
             "-E cmake_fastbuild_check_depends ", depender.ExecOutput);
  for (auto const& dep : depender.OutputsAlias.PreBuildDependencies) {
    exec.ExecArguments =
      cmStrCat(std::move(exec.ExecArguments), ' ', dep.Name);
  }
  for (auto const& dep : depender.ByproductsAlias.PreBuildDependencies) {
    exec.ExecArguments =
      cmStrCat(std::move(exec.ExecArguments), ' ', dep.Name);
  }
  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 dependencies 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(cmStrCat("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(
          cmStrCat("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(cmStrCat("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::AddLinkerNodeDependencies(
  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)));
    }
  }
}
