/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */
#include "cmExportInstallFileGenerator.h"

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <memory>
#include <set>
#include <sstream>
#include <utility>

#include "cmExportSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmList.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetExport.h"
#include "cmValue.h"
#include "cmake.h"

cmExportInstallFileGenerator::cmExportInstallFileGenerator(
  cmInstallExportGenerator* iegen)
  : IEGen(iegen)
{
}

void cmExportInstallFileGenerator::ReplaceInstallPrefix(
  std::string& input) const
{
  cmGeneratorExpression::ReplaceInstallPrefix(input, this->GetInstallPrefix());
}

void cmExportInstallFileGenerator::PopulateImportProperties(
  std::string const& config, std::string const& suffix,
  cmTargetExport const* targetExport, ImportPropertyMap& properties,
  std::set<std::string>& importedLocations)
{
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->ArchiveGenerator, properties,
                                  importedLocations);
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->LibraryGenerator, properties,
                                  importedLocations);
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->RuntimeGenerator, properties,
                                  importedLocations);
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->ObjectsGenerator, properties,
                                  importedLocations);
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->FrameworkGenerator, properties,
                                  importedLocations);
  this->SetImportLocationProperty(config, suffix,
                                  targetExport->BundleGenerator, properties,
                                  importedLocations);

  // If any file location was set for the target add it to the
  // import file.
  if (!properties.empty()) {
    // Get the rest of the target details.
    cmGeneratorTarget const* const gtgt = targetExport->Target;
    this->SetImportDetailProperties(config, suffix, gtgt, properties);

    // TODO: PUBLIC_HEADER_LOCATION
    // This should wait until the build feature propagation stuff is done.
    // Then this can be a propagated include directory.
    // this->GenerateImportProperty(config, te->HeaderGenerator, properties);
  }
}

std::string cmExportInstallFileGenerator::GetImportXcFrameworkLocation(
  std::string const& config, cmTargetExport const* targetExport) const
{
  std::string importedXcFrameworkLocation = targetExport->XcFrameworkLocation;
  if (!importedXcFrameworkLocation.empty()) {
    importedXcFrameworkLocation = cmGeneratorExpression::Preprocess(
      importedXcFrameworkLocation,
      cmGeneratorExpression::PreprocessContext::InstallInterface,
      this->GetImportPrefixWithSlash());
    importedXcFrameworkLocation = cmGeneratorExpression::Evaluate(
      importedXcFrameworkLocation, targetExport->Target->GetLocalGenerator(),
      config, targetExport->Target, nullptr, targetExport->Target);
    if (!importedXcFrameworkLocation.empty() &&
        !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) &&
        !cmHasPrefix(importedXcFrameworkLocation,
                     this->GetImportPrefixWithSlash())) {
      return cmStrCat(this->GetImportPrefixWithSlash(),
                      importedXcFrameworkLocation);
    }
  }

  return importedXcFrameworkLocation;
}

bool cmExportInstallFileGenerator::GenerateImportFileConfig(
  std::string const& config)
{
  // Skip configurations not enabled for this export.
  if (!this->IEGen->InstallsForConfig(config)) {
    return true;
  }

  // Construct the name of the file to generate.
  std::string fileName = cmStrCat(this->FileDir, '/', this->FileBase,
                                  this->GetConfigFileNameSeparator());
  if (!config.empty()) {
    fileName += cmSystemTools::LowerCase(config);
  } else {
    fileName += "noconfig";
  }
  fileName += this->FileExt;

  // Open the output file to generate it.
  cmGeneratedFileStream exportFileStream(fileName, true);
  if (!exportFileStream) {
    std::string se = cmSystemTools::GetLastSystemError();
    std::ostringstream e;
    e << "cannot write to file \"" << fileName << "\": " << se;
    cmSystemTools::Error(e.str());
    return false;
  }
  exportFileStream.SetCopyIfDifferent(true);
  std::ostream& os = exportFileStream;

  // Generate the per-config target information.
  this->GenerateImportConfig(os, config);

  // Record this per-config import file.
  this->ConfigImportFiles[config] = fileName;

  return true;
}

void cmExportInstallFileGenerator::SetImportLocationProperty(
  std::string const& config, std::string const& suffix,
  cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
  std::set<std::string>& importedLocations)
{
  // Skip rules that do not match this configuration.
  if (!(itgen && itgen->InstallsForConfig(config))) {
    return;
  }

  // Get the target to be installed.
  cmGeneratorTarget* target = itgen->GetTarget();

  // Construct the installed location of the target.
  std::string dest = itgen->GetDestination(config);
  std::string value;
  if (!cmSystemTools::FileIsFullPath(dest)) {
    // The target is installed relative to the installation prefix.
    value = std::string{ this->GetImportPrefixWithSlash() };
  }
  value += dest;
  value += "/";

  if (itgen->IsImportLibrary()) {
    // Construct the property name.
    std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);

    // Append the installed file name.
    value += cmInstallTargetGenerator::GetInstallFilename(
      target, config, cmInstallTargetGenerator::NameImplibReal);

    // Store the property.
    properties[prop] = value;
    importedLocations.insert(prop);
  } else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
    // Construct the property name.
    std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);

    // Compute all the object files inside this target and setup
    // IMPORTED_OBJECTS as a list of object files
    std::vector<std::string> objects;
    itgen->GetInstallObjectNames(config, objects);
    for (std::string& obj : objects) {
      obj = cmStrCat(value, obj);
    }

    // Store the property.
    properties[prop] = cmList::to_string(objects);
    importedLocations.insert(prop);
  } else {
    if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {
      // store as well IMPLIB value
      auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix);
      auto importValue =
        cmStrCat(value,
                 cmInstallTargetGenerator::GetInstallFilename(
                   target, config, cmInstallTargetGenerator::NameImplibReal));

      // Store the property.
      properties[importProp] = importValue;
      importedLocations.insert(importProp);
    }

    // Construct the property name.
    std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);

    // Append the installed file name.
    if (target->IsAppBundleOnApple()) {
      value += cmInstallTargetGenerator::GetInstallFilename(target, config);
      value += ".app/";
      if (!target->Makefile->PlatformIsAppleEmbedded()) {
        value += "Contents/MacOS/";
      }
      value += cmInstallTargetGenerator::GetInstallFilename(target, config);
    } else {
      value += cmInstallTargetGenerator::GetInstallFilename(
        target, config, cmInstallTargetGenerator::NameReal);
    }

    // Store the property.
    properties[prop] = value;
    importedLocations.insert(prop);
  }
}

cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType(
  cmTargetExport const* targetExport) const
{
  cmStateEnums::TargetType targetType = targetExport->Target->GetType();
  // An OBJECT library installed with no OBJECTS DESTINATION
  // is transformed to an INTERFACE library.
  if (targetType == cmStateEnums::OBJECT_LIBRARY &&
      !targetExport->ObjectsGenerator) {
    targetType = cmStateEnums::INTERFACE_LIBRARY;
  }
  return targetType;
}

std::string const& cmExportInstallFileGenerator::GetExportName() const
{
  return this->GetExportSet()->GetName();
}

void cmExportInstallFileGenerator::HandleMissingTarget(
  std::string& link_libs, cmGeneratorTarget const* depender,
  cmGeneratorTarget* dependee)
{
  auto const& exportInfo = this->FindExportInfo(dependee);

  if (exportInfo.Namespaces.size() == 1 && exportInfo.Sets.size() == 1) {
    std::string missingTarget = *exportInfo.Namespaces.begin();

    missingTarget += dependee->GetExportName();
    link_libs += missingTarget;
    this->MissingTargets.emplace_back(std::move(missingTarget));
  } else {
    // All exported targets should be known here and should be unique.
    // This is probably user-error.
    this->ComplainAboutMissingTarget(depender, dependee, exportInfo);
  }
}

cmExportFileGenerator::ExportInfo cmExportInstallFileGenerator::FindExportInfo(
  cmGeneratorTarget const* target) const
{
  std::vector<std::string> exportFiles;
  std::set<std::string> exportSets;
  std::set<std::string> namespaces;

  auto const& name = target->GetName();
  auto& allExportSets =
    target->GetLocalGenerator()->GetGlobalGenerator()->GetExportSets();

  for (auto const& exp : allExportSets) {
    auto const& exportSet = exp.second;
    auto const& targets = exportSet.GetTargetExports();

    if (std::any_of(targets.begin(), targets.end(),
                    [&name](std::unique_ptr<cmTargetExport> const& te) {
                      return te->TargetName == name;
                    })) {
      std::vector<cmInstallExportGenerator const*> const* installs =
        exportSet.GetInstallations();
      if (!installs->empty()) {
        exportSets.insert(exp.first);
        for (cmInstallExportGenerator const* install : *installs) {
          exportFiles.push_back(install->GetDestinationFile());
          namespaces.insert(install->GetNamespace());
        }
      }
    }
  }
  return { exportFiles, exportSets, namespaces };
}

void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
  ExportInfo const& exportInfo) const
{
  std::ostringstream e;
  e << "install(" << this->IEGen->InstallSubcommand() << " \""
    << this->GetExportName() << "\" ...) "
    << "includes target \"" << depender->GetName()
    << "\" which requires target \"" << dependee->GetName() << "\" ";
  if (exportInfo.Sets.empty()) {
    e << "that is not in any export set.";
  } else {
    if (exportInfo.Sets.size() == 1) {
      e << "that is not in this export set, but in another export set which "
           "is "
           "exported multiple times with different namespaces: ";
    } else {
      e << "that is not in this export set, but in multiple other export "
           "sets: ";
    }
    e << cmJoin(exportInfo.Files, ", ") << ".\n"
      << "An exported target cannot depend upon another target which is "
         "exported in more than one export set or with more than one "
         "namespace. "
         "Consider consolidating the exports of the \""
      << dependee->GetName() << "\" target to a single export.";
  }
  this->ReportError(e.str());
}

void cmExportInstallFileGenerator::ComplainAboutDuplicateTarget(
  std::string const& targetName) const
{
  std::ostringstream e;
  e << "install(" << this->IEGen->InstallSubcommand() << " \""
    << this->GetExportName() << "\" ...) "
    << "includes target \"" << targetName
    << "\" more than once in the export set.";
  this->ReportError(e.str());
}

void cmExportInstallFileGenerator::IssueMessage(
  MessageType type, std::string const& message) const
{
  this->IEGen->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
    type, message,
    this->IEGen->GetLocalGenerator()->GetMakefile()->GetBacktrace());
}

std::string cmExportInstallFileGenerator::InstallNameDir(
  cmGeneratorTarget const* target, std::string const& config)
{
  std::string install_name_dir;

  cmMakefile* mf = target->Target->GetMakefile();
  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
    auto const& prefix = this->GetInstallPrefix();
    install_name_dir = target->GetInstallNameDirForInstallTree(config, prefix);
  }

  return install_name_dir;
}

std::string cmExportInstallFileGenerator::GetCxxModuleFile() const
{
  return this->GetCxxModuleFile(this->GetExportSet()->GetName());
}

bool cmExportInstallFileGenerator::CollectExports(
  std::function<void(cmTargetExport const*)> const& visitor)
{
  auto pred = [&](std::unique_ptr<cmTargetExport> const& te) -> bool {
    if (te->NamelinkOnly) {
      return true;
    }
    if (this->ExportedTargets.insert(te->Target).second) {
      visitor(te.get());
      return true;
    }

    this->ComplainAboutDuplicateTarget(te->Target->GetName());
    return false;
  };

  auto const& targets = this->GetExportSet()->GetTargetExports();
  return std::all_of(targets.begin(), targets.end(), pred);
}

bool cmExportInstallFileGenerator::PopulateInterfaceProperties(
  cmTargetExport const* targetExport, ImportPropertyMap& properties)
{
  cmGeneratorTarget const* const gt = targetExport->Target;

  std::string includesDestinationDirs;
  this->PopulateSystemIncludeDirectoriesInterface(
    gt, cmGeneratorExpression::InstallInterface, properties);
  this->PopulateIncludeDirectoriesInterface(
    gt, cmGeneratorExpression::InstallInterface, properties, *targetExport,
    includesDestinationDirs);
  this->PopulateLinkDirectoriesInterface(
    gt, cmGeneratorExpression::InstallInterface, properties);
  this->PopulateLinkDependsInterface(
    gt, cmGeneratorExpression::InstallInterface, properties);
  this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
                                 properties);

  return this->PopulateInterfaceProperties(
    gt, includesDestinationDirs, cmGeneratorExpression::InstallInterface,
    properties);
}

namespace {
bool isSubDirectory(std::string const& a, std::string const& b)
{
  return (cmSystemTools::ComparePath(a, b) ||
          cmSystemTools::IsSubDirectory(a, b));
}
}

bool cmExportInstallFileGenerator::CheckInterfaceDirs(
  std::string const& prepro, cmGeneratorTarget const* target,
  std::string const& prop) const
{
  std::string const& installDir =
    target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
  std::string const& topSourceDir =
    target->GetLocalGenerator()->GetSourceDirectory();
  std::string const& topBinaryDir =
    target->GetLocalGenerator()->GetBinaryDirectory();

  std::vector<std::string> parts;
  cmGeneratorExpression::Split(prepro, parts);

  bool const inSourceBuild = topSourceDir == topBinaryDir;

  bool hadFatalError = false;

  for (std::string const& li : parts) {
    size_t genexPos = cmGeneratorExpression::Find(li);
    if (genexPos == 0) {
      continue;
    }
    if (cmHasPrefix(li, this->GetImportPrefixWithSlash())) {
      continue;
    }
    std::ostringstream e;
    if (genexPos != std::string::npos) {
      hadFatalError = true;
    }
    if (!cmSystemTools::FileIsFullPath(li)) {
      /* clang-format off */
      e << "Target \"" << target->GetName() << "\" " << prop <<
           " property contains relative path:\n"
           "  \"" << li << "\"";
      /* clang-format on */
      target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
                                                e.str());
    }
    bool inBinary = isSubDirectory(li, topBinaryDir);
    bool inSource = isSubDirectory(li, topSourceDir);
    if (isSubDirectory(li, installDir)) {
      // The include directory is inside the install tree.  If the
      // install tree is inside the source tree or build tree then do not
      // fall through to the checks below that the include directory is not
      // also inside the source tree or build tree.
      if ((!inBinary || isSubDirectory(installDir, topBinaryDir)) &&
          (!inSource || isSubDirectory(installDir, topSourceDir))) {
        continue;
      }
    }
    if (inBinary) {
      /* clang-format off */
      e << "Target \"" << target->GetName() << "\" " << prop <<
           " property contains path:\n"
           "  \"" << li << "\"\nwhich is prefixed in the build directory.";
      /* clang-format on */
      target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
                                                e.str());
    }
    if (!inSourceBuild) {
      if (inSource) {
        e << "Target \"" << target->GetName() << "\" " << prop
          << " property contains path:\n"
             "  \""
          << li << "\"\nwhich is prefixed in the source directory.";
        target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
                                                  e.str());
      }
    }
  }
  return !hadFatalError;
}

void cmExportInstallFileGenerator::PopulateSourcesInterface(
  cmGeneratorTarget const* gt,
  cmGeneratorExpression::PreprocessContext preprocessRule,
  ImportPropertyMap& properties)
{
  assert(preprocessRule == cmGeneratorExpression::InstallInterface);

  char const* const propName = "INTERFACE_SOURCES";
  cmValue input = gt->GetProperty(propName);

  if (!input) {
    return;
  }

  if (input->empty()) {
    properties[propName].clear();
    return;
  }

  std::string prepro = cmGeneratorExpression::Preprocess(
    *input, preprocessRule, this->GetImportPrefixWithSlash());
  if (!prepro.empty()) {
    this->ResolveTargetsInGeneratorExpressions(prepro, gt);

    if (!this->CheckInterfaceDirs(prepro, gt, propName)) {
      return;
    }
    properties[propName] = prepro;
  }
}

void cmExportInstallFileGenerator::PopulateSystemIncludeDirectoriesInterface(
  cmGeneratorTarget const* target,
  cmGeneratorExpression::PreprocessContext preprocessRule,
  ImportPropertyMap& properties)
{
  assert(preprocessRule == cmGeneratorExpression::InstallInterface);

  char const* const propName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES";
  cmValue input = target->GetProperty(propName);

  if (!input) {
    return;
  }
  if (input->empty()) {
    // Set to empty
    properties[propName].clear();
    return;
  }

  std::string includes = (input ? *input : "");
  std::string prepro = cmGeneratorExpression::Preprocess(
    includes, preprocessRule, this->GetImportPrefixWithSlash());
  if (!prepro.empty()) {
    this->ResolveTargetsInGeneratorExpressions(prepro, target);

    if (!this->CheckInterfaceDirs(prepro, target, propName)) {
      return;
    }
    properties[propName] = prepro;
  }
}

void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface(
  cmGeneratorTarget const* target,
  cmGeneratorExpression::PreprocessContext preprocessRule,
  ImportPropertyMap& properties, cmTargetExport const& te,
  std::string& includesDestinationDirs)
{
  assert(preprocessRule == cmGeneratorExpression::InstallInterface);

  includesDestinationDirs.clear();

  char const* const propName = "INTERFACE_INCLUDE_DIRECTORIES";
  cmValue input = target->GetProperty(propName);

  cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());

  std::string dirs = cmGeneratorExpression::Preprocess(
    cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)),
    preprocessRule, this->GetImportPrefixWithSlash());
  this->ReplaceInstallPrefix(dirs);
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
  std::string exportDirs =
    cge->Evaluate(target->GetLocalGenerator(), "", target);

  if (cge->GetHadContextSensitiveCondition()) {
    cmLocalGenerator* lg = target->GetLocalGenerator();
    std::ostringstream e;
    e << "Target \"" << target->GetName()
      << "\" is installed with "
         "INCLUDES DESTINATION set to a context sensitive path.  Paths which "
         "depend on the configuration, policy values or the link interface "
         "are "
         "not supported.  Consider using target_include_directories instead.";
    lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
    return;
  }

  if (!input && exportDirs.empty()) {
    return;
  }
  if ((input && input->empty()) && exportDirs.empty()) {
    // Set to empty
    properties[propName].clear();
    return;
  }

  this->AddImportPrefix(exportDirs);
  includesDestinationDirs = exportDirs;

  std::string includes = (input ? *input : "");
  char const* const sep = input ? ";" : "";
  includes += sep + exportDirs;
  std::string prepro = cmGeneratorExpression::Preprocess(
    includes, preprocessRule, this->GetImportPrefixWithSlash());
  if (!prepro.empty()) {
    this->ResolveTargetsInGeneratorExpressions(prepro, target);

    if (!this->CheckInterfaceDirs(prepro, target, propName)) {
      return;
    }
    properties[propName] = prepro;
  }
}

void cmExportInstallFileGenerator::PopulateLinkDependsInterface(
  cmGeneratorTarget const* gt,
  cmGeneratorExpression::PreprocessContext preprocessRule,
  ImportPropertyMap& properties)
{
  assert(preprocessRule == cmGeneratorExpression::InstallInterface);

  char const* const propName = "INTERFACE_LINK_DEPENDS";
  cmValue input = gt->GetProperty(propName);

  if (!input) {
    return;
  }

  if (input->empty()) {
    properties[propName].clear();
    return;
  }

  std::string prepro = cmGeneratorExpression::Preprocess(
    *input, preprocessRule, this->GetImportPrefixWithSlash());
  if (!prepro.empty()) {
    this->ResolveTargetsInGeneratorExpressions(prepro, gt);

    if (!this->CheckInterfaceDirs(prepro, gt, propName)) {
      return;
    }
    properties[propName] = prepro;
  }
}

void cmExportInstallFileGenerator::PopulateLinkDirectoriesInterface(
  cmGeneratorTarget const* gt,
  cmGeneratorExpression::PreprocessContext preprocessRule,
  ImportPropertyMap& properties)
{
  assert(preprocessRule == cmGeneratorExpression::InstallInterface);

  char const* const propName = "INTERFACE_LINK_DIRECTORIES";
  cmValue input = gt->GetProperty(propName);

  if (!input) {
    return;
  }

  if (input->empty()) {
    properties[propName].clear();
    return;
  }

  std::string prepro = cmGeneratorExpression::Preprocess(
    *input, preprocessRule, this->GetImportPrefixWithSlash());
  if (!prepro.empty()) {
    this->ResolveTargetsInGeneratorExpressions(prepro, gt);

    if (!this->CheckInterfaceDirs(prepro, gt, propName)) {
      return;
    }
    properties[propName] = prepro;
  }
}
