CMake/Source/cmFindProgramCommand.cxx

258 lines
7.5 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 22:01:08 +03:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2001-01-18 19:20:24 +03:00
#include "cmFindProgramCommand.h"
#include <stdlib.h>
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#endif
struct cmFindProgramHelper
{
cmFindProgramHelper()
{
#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.push_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 full path under consideration.
std::string TestPath;
void AddName(std::string const& name) { this->Names.push_back(name); }
void SetName(std::string const& name)
{
this->Names.clear();
this->AddName(name);
}
bool CheckDirectory(std::string const& path)
{
for (std::vector<std::string>::iterator i = this->Names.begin();
i != this->Names.end(); ++i) {
if (this->CheckDirectoryForName(path, *i)) {
return true;
}
}
return false;
}
bool CheckDirectoryForName(std::string const& path, std::string const& name)
{
for (std::vector<std::string>::iterator ext = this->Extensions.begin();
ext != this->Extensions.end(); ++ext) {
this->TestPath = path;
this->TestPath += name;
if (!ext->empty() && cmSystemTools::StringEndsWith(name, ext->c_str())) {
continue;
}
this->TestPath += *ext;
if (cmSystemTools::FileExists(this->TestPath, true)) {
this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
return true;
}
}
return false;
}
};
cmFindProgramCommand::cmFindProgramCommand()
{
this->NamesPerDirAllowed = true;
}
2001-01-18 19:20:24 +03:00
// cmFindProgramCommand
bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn,
cmExecutionStatus&)
{
2006-03-02 21:30:22 +03:00
this->VariableDocumentation = "Path to a program.";
this->CMakePathName = "PROGRAM";
// call cmFindBase::ParseArguments
if (!this->ParseArguments(argsIn)) {
return false;
}
if (this->AlreadyInCache) {
// If the user specifies the entry on the command line without a
// type we should add the type and docstring but keep the original
// value.
if (this->AlreadyInCacheWithoutMetaInfo) {
this->Makefile->AddCacheDefinition(this->VariableName, "",
this->VariableDocumentation.c_str(),
cmState::FILEPATH);
}
return true;
}
std::string result = FindProgram();
if (result != "") {
2006-03-02 21:30:22 +03:00
// Save the value in the cache
this->Makefile->AddCacheDefinition(this->VariableName, result.c_str(),
2006-03-15 19:02:08 +03:00
this->VariableDocumentation.c_str(),
cmState::FILEPATH);
2006-03-02 21:30:22 +03:00
return true;
}
this->Makefile->AddCacheDefinition(
this->VariableName, (this->VariableName + "-NOTFOUND").c_str(),
this->VariableDocumentation.c_str(), cmState::FILEPATH);
return true;
}
std::string cmFindProgramCommand::FindProgram()
{
std::string program = "";
if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) {
program = 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();
}
2016-09-16 23:45:24 +03:00
return this->FindNormalProgramDirsPerName();
}
std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
{
// Search for all names in each directory.
cmFindProgramHelper helper;
for (std::vector<std::string>::const_iterator ni = this->Names.begin();
ni != this->Names.end(); ++ni) {
helper.AddName(*ni);
}
// Check for the names themselves (e.g. absolute paths).
if (helper.CheckDirectory(std::string())) {
return helper.BestPath;
}
// Search every directory.
for (std::vector<std::string>::const_iterator p = this->SearchPaths.begin();
p != this->SearchPaths.end(); ++p) {
if (helper.CheckDirectory(*p)) {
return helper.BestPath;
}
}
// Couldn't find the program.
return "";
}
std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
{
// Search the entire path for each name.
cmFindProgramHelper helper;
for (std::vector<std::string>::const_iterator ni = this->Names.begin();
ni != this->Names.end(); ++ni) {
// Switch to searching for this name.
helper.SetName(*ni);
// Check for the name by itself (e.g. an absolute path).
if (helper.CheckDirectory(std::string())) {
return helper.BestPath;
}
// Search every directory.
for (std::vector<std::string>::const_iterator p =
this->SearchPaths.begin();
p != this->SearchPaths.end(); ++p) {
if (helper.CheckDirectory(*p)) {
return helper.BestPath;
}
}
}
// Couldn't find the program.
return "";
}
std::string cmFindProgramCommand::FindAppBundle()
{
for (std::vector<std::string>::const_iterator name = this->Names.begin();
name != this->Names.end(); ++name) {
std::string appName = *name + std::string(".app");
std::string appPath =
cmSystemTools::FindDirectory(appName, this->SearchPaths, true);
if (!appPath.empty()) {
std::string executable = GetBundleExecutable(appPath);
if (!executable.empty()) {
return cmSystemTools::CollapseFullPath(executable);
}
}
}
// Couldn't find app bundle
return "";
}
std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
{
std::string executable = "";
2006-04-14 07:24:09 +04:00
(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);
2006-05-10 23:46:45 +04:00
// Make a CFURLRef from the CFString representation of the
// bundles 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 != NULL) {
const int MAX_OSX_PATH_SIZE = 1024;
char buffer[MAX_OSX_PATH_SIZE];
// Convert the CFString to a C string
CFStringGetCString(CFURLGetString(executableURL), buffer,
MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8);
// And finally to a c++ string
executable = bundlePath + "/Contents/MacOS/" + std::string(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;
}