/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSearchPath.h" #include #include #include #include "cmFindCommon.h" #include "cmMakefile.h" #include "cmProperty.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmSearchPath::cmSearchPath(cmFindCommon* findCmd) : FC(findCmd) { } cmSearchPath::~cmSearchPath() = default; void cmSearchPath::ExtractWithout(const std::set& ignore, std::vector& outPaths, bool clear) const { if (clear) { outPaths.clear(); } for (std::string const& path : this->Paths) { if (ignore.count(path) == 0) { outPaths.push_back(path); } } } void cmSearchPath::AddPath(const std::string& path) { this->AddPathInternal(path); } void cmSearchPath::AddUserPath(const std::string& path) { assert(this->FC != nullptr); std::vector outPaths; // We should view the registry as the target application would view // it. cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32; cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64; if (this->FC->Makefile->PlatformIs64Bit()) { view = cmSystemTools::KeyWOW64_64; other_view = cmSystemTools::KeyWOW64_32; } // Expand using the view of the target application. std::string expanded = path; cmSystemTools::ExpandRegistryValues(expanded, view); cmSystemTools::GlobDirs(expanded, outPaths); // Executables can be either 32-bit or 64-bit, so expand using the // alternative view. if (expanded != path && this->FC->CMakePathName == "PROGRAM") { expanded = path; cmSystemTools::ExpandRegistryValues(expanded, other_view); cmSystemTools::GlobDirs(expanded, outPaths); } // Process them all from the current directory for (std::string const& p : outPaths) { this->AddPathInternal( p, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); } } void cmSearchPath::AddCMakePath(const std::string& variable) { assert(this->FC != nullptr); // Get a path from a CMake variable. if (cmProp value = this->FC->Makefile->GetDefinition(variable)) { std::vector expanded = cmExpandedList(*value); for (std::string const& p : expanded) { this->AddPathInternal( p, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); } } } void cmSearchPath::AddEnvPath(const std::string& variable) { std::vector expanded; cmSystemTools::GetPath(expanded, variable.c_str()); for (std::string const& p : expanded) { this->AddPathInternal(p); } } void cmSearchPath::AddCMakePrefixPath(const std::string& variable) { assert(this->FC != nullptr); // Get a path from a CMake variable. if (cmProp value = this->FC->Makefile->GetDefinition(variable)) { std::vector expanded = cmExpandedList(*value); this->AddPrefixPaths( expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); } } static std::string cmSearchPathStripBin(std::string const& s) { // If the path is a PREFIX/bin case then add its parent instead. if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) { return cmSystemTools::GetFilenamePath(s); } return s; } void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin) { std::vector expanded; cmSystemTools::GetPath(expanded, variable.c_str()); if (stripBin) { std::transform(expanded.begin(), expanded.end(), expanded.begin(), cmSearchPathStripBin); } this->AddPrefixPaths(expanded); } void cmSearchPath::AddSuffixes(const std::vector& suffixes) { std::vector inPaths; inPaths.swap(this->Paths); this->Paths.reserve(inPaths.size() * (suffixes.size() + 1)); for (std::string& inPath : inPaths) { cmSystemTools::ConvertToUnixSlashes(inPath); // if *i is only / then do not add a // // this will get incorrectly considered a network // path on windows and cause huge delays. std::string p = inPath; if (!p.empty() && p.back() != '/') { p += "/"; } // Combine with all the suffixes for (std::string const& suffix : suffixes) { this->Paths.push_back(p + suffix); } // And now the original w/o any suffix this->Paths.push_back(std::move(inPath)); } } void cmSearchPath::AddPrefixPaths(const std::vector& paths, const char* base) { assert(this->FC != nullptr); // default for programs std::string subdir = "bin"; if (this->FC->CMakePathName == "INCLUDE") { subdir = "include"; } else if (this->FC->CMakePathName == "LIBRARY") { subdir = "lib"; } else if (this->FC->CMakePathName == "FRAMEWORK") { subdir.clear(); // ? what to do for frameworks ? } for (std::string const& path : paths) { std::string dir = path; if (!subdir.empty() && !dir.empty() && dir.back() != '/') { dir += "/"; } if (subdir == "include" || subdir == "lib") { cmProp arch = this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE"); if (cmNonempty(arch)) { if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") && this->FC->Makefile->IsDefinitionSet( "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) { this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), base); } else { this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), base); } } } std::string add = dir + subdir; if (add != "/") { this->AddPathInternal(add, base); } if (subdir == "bin") { this->AddPathInternal(dir + "sbin", base); } if (!subdir.empty() && path != "/") { this->AddPathInternal(path, base); } } } void cmSearchPath::AddPathInternal(const std::string& path, const char* base) { assert(this->FC != nullptr); std::string collapsed = cmSystemTools::CollapseFullPath(path, base); if (collapsed.empty()) { return; } // Insert the path if has not already been emitted. if (this->FC->SearchPathsEmitted.insert(collapsed).second) { this->Paths.push_back(std::move(collapsed)); } } 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmIncludeDirectoryCommand.h"

#include <algorithm>
#include <set>

#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"

class cmExecutionStatus;

// cmIncludeDirectoryCommand
bool cmIncludeDirectoryCommand::InitialPass(
  std::vector<std::string> const& args, cmExecutionStatus&)
{
  if (args.empty()) {
    return true;
  }

  std::vector<std::string>::const_iterator i = args.begin();

  bool before = this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_BEFORE");
  bool system = false;

  if ((*i) == "BEFORE") {
    before = true;
    ++i;
  } else if ((*i) == "AFTER") {
    before = false;
    ++i;
  }

  std::vector<std::string> beforeIncludes;
  std::vector<std::string> afterIncludes;
  std::set<std::string> systemIncludes;

  for (; i != args.end(); ++i) {
    if (*i == "SYSTEM") {
      system = true;
      continue;
    }
    if (i->empty()) {
      this->SetError("given empty-string as include directory.");
      return false;
    }

    std::vector<std::string> includes;

    this->GetIncludes(*i, includes);

    if (before) {
      beforeIncludes.insert(beforeIncludes.end(), includes.begin(),
                            includes.end());
    } else {
      afterIncludes.insert(afterIncludes.end(), includes.begin(),
                           includes.end());
    }
    if (system) {
      systemIncludes.insert(includes.begin(), includes.end());
    }
  }
  std::reverse(beforeIncludes.begin(), beforeIncludes.end());

  this->Makefile->AddIncludeDirectories(afterIncludes);
  this->Makefile->AddIncludeDirectories(beforeIncludes, before);
  this->Makefile->AddSystemIncludeDirectories(systemIncludes);

  return true;
}

// do a lot of cleanup on the arguments because this is one place where folks
// sometimes take the output of a program and pass it directly into this
// command not thinking that a single argument could be filled with spaces
// and newlines etc like below:
//
// "   /foo/bar
//    /boo/hoo /dingle/berry "
//
// ideally that should be three separate arguments but when sucking the
// output from a program and passing it into a command the cleanup doesn't
// always happen
//
void cmIncludeDirectoryCommand::GetIncludes(const std::string& arg,
                                            std::vector<std::string>& incs)
{
  // break apart any line feed arguments
  std::string::size_type pos = 0;
  std::string::size_type lastPos = 0;
  while ((pos = arg.find('\n', lastPos)) != std::string::npos) {
    if (pos) {
      std::string inc = arg.substr(lastPos, pos);
      this->NormalizeInclude(inc);
      if (!inc.empty()) {
        incs.push_back(std::move(inc));
      }
    }
    lastPos = pos + 1;
  }
  std::string inc = arg.substr(lastPos);
  this->NormalizeInclude(inc);
  if (!inc.empty()) {
    incs.push_back(std::move(inc));
  }
}

void cmIncludeDirectoryCommand::NormalizeInclude(std::string& inc)
{
  std::string::size_type b = inc.find_first_not_of(" \r");
  std::string::size_type e = inc.find_last_not_of(" \r");
  if ((b != std::string::npos) && (e != std::string::npos)) {
    inc.assign(inc, b, 1 + e - b); // copy the remaining substring
  } else {
    inc.clear();
    return;
  }

  if (!cmSystemTools::IsOff(inc)) {
    cmSystemTools::ConvertToUnixSlashes(inc);

    if (!cmSystemTools::FileIsFullPath(inc)) {
      if (!cmGeneratorExpression::StartsWithGeneratorExpression(inc)) {
        std::string tmp = this->Makefile->GetCurrentSourceDirectory();
        tmp += "/";
        tmp += inc;
        inc = tmp;
      }
    }
  }
}