| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 | 
							- /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 
-    file Copyright.txt or https://cmake.org/licensing for details.  */
 
- #include "cmFindProgramCommand.h"
 
- #include <algorithm>
 
- #include <string>
 
- #include <utility>
 
- #include "cmMakefile.h"
 
- #include "cmMessageType.h"
 
- #include "cmPolicies.h"
 
- #include "cmStateTypes.h"
 
- #include "cmStringAlgorithms.h"
 
- #include "cmSystemTools.h"
 
- class cmExecutionStatus;
 
- #if defined(__APPLE__)
 
- #  include <CoreFoundation/CoreFoundation.h>
 
- #endif
 
- struct cmFindProgramHelper
 
- {
 
-   cmFindProgramHelper(std::string debugName, cmMakefile* makefile,
 
-                       cmFindBase const* base)
 
-     : DebugSearches(std::move(debugName), base)
 
-     , Makefile(makefile)
 
-     , PolicyCMP0109(makefile->GetPolicyStatus(cmPolicies::CMP0109))
 
-   {
 
- #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
 
-     // Consider platform-specific extensions.
 
-     this->Extensions.push_back(".com");
 
-     this->Extensions.push_back(".exe");
 
- #endif
 
-     // Consider original name with no extensions.
 
-     this->Extensions.emplace_back();
 
-   }
 
-   // List of valid extensions.
 
-   std::vector<std::string> Extensions;
 
-   // Keep track of the best program file found so far.
 
-   std::string BestPath;
 
-   // Current names under consideration.
 
-   std::vector<std::string> Names;
 
-   // Current name with extension under consideration.
 
-   std::string TestNameExt;
 
-   // Current full path under consideration.
 
-   std::string TestPath;
 
-   // Debug state
 
-   cmFindBaseDebugState DebugSearches;
 
-   cmMakefile* Makefile;
 
-   cmPolicies::PolicyStatus PolicyCMP0109;
 
-   void AddName(std::string const& name) { this->Names.push_back(name); }
 
-   void SetName(std::string const& name)
 
-   {
 
-     this->Names.clear();
 
-     this->AddName(name);
 
-   }
 
-   bool CheckCompoundNames()
 
-   {
 
-     return std::any_of(this->Names.begin(), this->Names.end(),
 
-                        [this](std::string const& n) -> bool {
 
-                          // Only perform search relative to current directory
 
-                          // if the file name contains a directory separator.
 
-                          return n.find('/') != std::string::npos &&
 
-                            this->CheckDirectoryForName("", n);
 
-                        });
 
-   }
 
-   bool CheckDirectory(std::string const& path)
 
-   {
 
-     return std::any_of(this->Names.begin(), this->Names.end(),
 
-                        [this, &path](std::string const& n) -> bool {
 
-                          // Only perform search relative to current directory
 
-                          // if the file name contains a directory separator.
 
-                          return this->CheckDirectoryForName(path, n);
 
-                        });
 
-   }
 
-   bool CheckDirectoryForName(std::string const& path, std::string const& name)
 
-   {
 
-     return std::any_of(this->Extensions.begin(), this->Extensions.end(),
 
-                        [this, &path, &name](std::string const& ext) -> bool {
 
-                          if (!ext.empty() && cmHasSuffix(name, ext)) {
 
-                            return false;
 
-                          }
 
-                          this->TestNameExt = cmStrCat(name, ext);
 
-                          this->TestPath = cmSystemTools::CollapseFullPath(
 
-                            this->TestNameExt, path);
 
-                          bool exists = this->FileIsExecutable(this->TestPath);
 
-                          exists ? this->DebugSearches.FoundAt(this->TestPath)
 
-                                 : this->DebugSearches.FailedAt(this->TestPath);
 
-                          if (exists) {
 
-                            this->BestPath = this->TestPath;
 
-                            return true;
 
-                          }
 
-                          return false;
 
-                        });
 
-   }
 
-   bool FileIsExecutable(std::string const& file) const
 
-   {
 
- #ifdef _WIN32
 
-     if (!this->FileIsExecutableCMP0109(file)) {
 
-       return false;
 
-     }
 
-     // Pretend the Windows "python" app installer alias does not exist.
 
-     if (cmSystemTools::LowerCase(file).find("/windowsapps/python") !=
 
-         std::string::npos) {
 
-       std::string dest;
 
-       if (cmSystemTools::ReadSymlink(file, dest) &&
 
-           cmHasLiteralSuffix(dest, "\\AppInstallerPythonRedirector.exe")) {
 
-         return false;
 
-       }
 
-     }
 
-     return true;
 
- #else
 
-     return this->FileIsExecutableCMP0109(file);
 
- #endif
 
-   }
 
-   bool FileIsExecutableCMP0109(std::string const& file) const
 
-   {
 
-     switch (this->PolicyCMP0109) {
 
-       case cmPolicies::OLD:
 
-         return cmSystemTools::FileExists(file, true);
 
-       case cmPolicies::NEW:
 
-       case cmPolicies::REQUIRED_ALWAYS:
 
-       case cmPolicies::REQUIRED_IF_USED:
 
-         return cmSystemTools::FileIsExecutable(file);
 
-       default:
 
-         break;
 
-     }
 
-     bool const isExeOld = cmSystemTools::FileExists(file, true);
 
-     bool const isExeNew = cmSystemTools::FileIsExecutable(file);
 
-     if (isExeNew == isExeOld) {
 
-       return isExeNew;
 
-     }
 
-     if (isExeNew) {
 
-       this->Makefile->IssueMessage(
 
-         MessageType::AUTHOR_WARNING,
 
-         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
 
-                  "\n"
 
-                  "The file\n"
 
-                  "  ",
 
-                  file,
 
-                  "\n"
 
-                  "is executable but not readable.  "
 
-                  "CMake is ignoring it for compatibility."));
 
-     } else {
 
-       this->Makefile->IssueMessage(
 
-         MessageType::AUTHOR_WARNING,
 
-         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
 
-                  "\n"
 
-                  "The file\n"
 
-                  "  ",
 
-                  file,
 
-                  "\n"
 
-                  "is readable but not executable.  "
 
-                  "CMake is using it for compatibility."));
 
-     }
 
-     return isExeOld;
 
-   }
 
- };
 
- cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status)
 
-   : cmFindBase("find_program", status)
 
- {
 
-   this->NamesPerDirAllowed = true;
 
-   this->VariableDocumentation = "Path to a program.";
 
-   this->VariableType = cmStateEnums::FILEPATH;
 
- }
 
- // cmFindProgramCommand
 
- bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
 
- {
 
-   this->CMakePathName = "PROGRAM";
 
-   // call cmFindBase::ParseArguments
 
-   if (!this->ParseArguments(argsIn)) {
 
-     return false;
 
-   }
 
-   this->DebugMode = this->ComputeIfDebugModeWanted(this->VariableName);
 
-   if (this->AlreadyDefined) {
 
-     this->NormalizeFindResult();
 
-     return true;
 
-   }
 
-   std::string const result = this->FindProgram();
 
-   this->StoreFindResult(result);
 
-   return true;
 
- }
 
- std::string cmFindProgramCommand::FindProgram()
 
- {
 
-   std::string program;
 
-   if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) {
 
-     program = this->FindAppBundle();
 
-   }
 
-   if (program.empty() && !this->SearchAppBundleOnly) {
 
-     program = this->FindNormalProgram();
 
-   }
 
-   if (program.empty() && this->SearchAppBundleLast) {
 
-     program = this->FindAppBundle();
 
-   }
 
-   return program;
 
- }
 
- std::string cmFindProgramCommand::FindNormalProgram()
 
- {
 
-   if (this->NamesPerDir) {
 
-     return this->FindNormalProgramNamesPerDir();
 
-   }
 
-   return this->FindNormalProgramDirsPerName();
 
- }
 
- std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
 
- {
 
-   // Search for all names in each directory.
 
-   cmFindProgramHelper helper(this->FindCommandName, this->Makefile, this);
 
-   for (std::string const& n : this->Names) {
 
-     helper.AddName(n);
 
-   }
 
-   // Check for the names themselves if they contain a directory separator.
 
-   if (helper.CheckCompoundNames()) {
 
-     return helper.BestPath;
 
-   }
 
-   // Search every directory.
 
-   for (std::string const& sp : this->SearchPaths) {
 
-     if (helper.CheckDirectory(sp)) {
 
-       return helper.BestPath;
 
-     }
 
-   }
 
-   // Couldn't find the program.
 
-   return "";
 
- }
 
- std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
 
- {
 
-   // Search the entire path for each name.
 
-   cmFindProgramHelper helper(this->FindCommandName, this->Makefile, this);
 
-   for (std::string const& n : this->Names) {
 
-     // Switch to searching for this name.
 
-     helper.SetName(n);
 
-     // Check for the names themselves if they contain a directory separator.
 
-     if (helper.CheckCompoundNames()) {
 
-       return helper.BestPath;
 
-     }
 
-     // Search every directory.
 
-     for (std::string const& sp : this->SearchPaths) {
 
-       if (helper.CheckDirectory(sp)) {
 
-         return helper.BestPath;
 
-       }
 
-     }
 
-   }
 
-   // Couldn't find the program.
 
-   return "";
 
- }
 
- std::string cmFindProgramCommand::FindAppBundle()
 
- {
 
-   for (std::string const& name : this->Names) {
 
-     std::string appName = name + std::string(".app");
 
-     std::string appPath =
 
-       cmSystemTools::FindDirectory(appName, this->SearchPaths, true);
 
-     if (!appPath.empty()) {
 
-       std::string executable = this->GetBundleExecutable(appPath);
 
-       if (!executable.empty()) {
 
-         return cmSystemTools::CollapseFullPath(executable);
 
-       }
 
-     }
 
-   }
 
-   // Couldn't find app bundle
 
-   return "";
 
- }
 
- std::string cmFindProgramCommand::GetBundleExecutable(
 
-   std::string const& bundlePath)
 
- {
 
-   std::string executable;
 
-   (void)bundlePath;
 
- #if defined(__APPLE__)
 
-   // Started with an example on developer.apple.com about finding bundles
 
-   // and modified from that.
 
-   // Get a CFString of the app bundle path
 
-   // XXX - Is it safe to assume everything is in UTF8?
 
-   CFStringRef bundlePathCFS = CFStringCreateWithCString(
 
-     kCFAllocatorDefault, bundlePath.c_str(), kCFStringEncodingUTF8);
 
-   // Make a CFURLRef from the CFString representation of the
 
-   // bundle’s path.
 
-   CFURLRef bundleURL = CFURLCreateWithFileSystemPath(
 
-     kCFAllocatorDefault, bundlePathCFS, kCFURLPOSIXPathStyle, true);
 
-   // Make a bundle instance using the URLRef.
 
-   CFBundleRef appBundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
 
-   // returned executableURL is relative to <appbundle>/Contents/MacOS/
 
-   CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
 
-   if (executableURL != nullptr) {
 
-     const int MAX_OSX_PATH_SIZE = 1024;
 
-     UInt8 buffer[MAX_OSX_PATH_SIZE];
 
-     if (CFURLGetFileSystemRepresentation(executableURL, false, buffer,
 
-                                          MAX_OSX_PATH_SIZE)) {
 
-       executable = bundlePath + "/Contents/MacOS/" +
 
-         std::string(reinterpret_cast<char*>(buffer));
 
-     }
 
-     // Only release CFURLRef if it's not null
 
-     CFRelease(executableURL);
 
-   }
 
-   // Any CF objects returned from functions with "create" or
 
-   // "copy" in their names must be released by us!
 
-   CFRelease(bundlePathCFS);
 
-   CFRelease(bundleURL);
 
-   CFRelease(appBundle);
 
- #endif
 
-   return executable;
 
- }
 
- bool cmFindProgram(std::vector<std::string> const& args,
 
-                    cmExecutionStatus& status)
 
- {
 
-   return cmFindProgramCommand(status).InitialPass(args);
 
- }
 
 
  |