/* 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, &currentCCName, &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::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)));
    }
  }
}
