1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmFindProgramCommand.h"
13 #include "cmCacheManager.h"
16 #if defined(__APPLE__)
17 #include <CoreFoundation/CoreFoundation.h>
20 void cmFindProgramCommand::GenerateDocumentation()
22 this->cmFindBase::GenerateDocumentation();
23 cmSystemTools::ReplaceString(this->GenericDocumentation,
24 "FIND_XXX", "find_program");
25 cmSystemTools::ReplaceString(this->GenericDocumentation,
26 "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
27 cmSystemTools::ReplaceString(this->GenericDocumentation,
29 "CMAKE_APPBUNDLE_PATH");
30 cmSystemTools::ReplaceString(this->GenericDocumentation,
31 "CMAKE_SYSTEM_XXX_MAC_PATH",
32 "CMAKE_SYSTEM_APPBUNDLE_PATH");
33 cmSystemTools::ReplaceString(this->GenericDocumentation,
35 cmSystemTools::ReplaceString(this->GenericDocumentation,
36 "CMAKE_SYSTEM_XXX_PATH",
37 "CMAKE_SYSTEM_PROGRAM_PATH");
38 cmSystemTools::ReplaceString(this->GenericDocumentation,
39 "SEARCH_XXX_DESC", "program");
40 cmSystemTools::ReplaceString(this->GenericDocumentation,
41 "SEARCH_XXX", "program");
42 cmSystemTools::ReplaceString(this->GenericDocumentation,
43 "XXX_SUBDIR", "[s]bin");
44 cmSystemTools::ReplaceString(this->GenericDocumentation,
45 "XXX_EXTRA_PREFIX_ENTRY", "");
46 cmSystemTools::ReplaceString(this->GenericDocumentation,
47 "CMAKE_FIND_ROOT_PATH_MODE_XXX",
48 "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM");
51 // cmFindProgramCommand
52 bool cmFindProgramCommand
53 ::InitialPass(std::vector<std::string> const& argsIn, cmExecutionStatus &)
55 this->VariableDocumentation = "Path to a program.";
56 this->CMakePathName = "PROGRAM";
57 // call cmFindBase::ParseArguments
58 if(!this->ParseArguments(argsIn))
62 if(this->AlreadyInCache)
64 // If the user specifies the entry on the command line without a
65 // type we should add the type and docstring but keep the original
67 if(this->AlreadyInCacheWithoutMetaInfo)
69 this->Makefile->AddCacheDefinition(this->VariableName.c_str(), "",
70 this->VariableDocumentation.c_str(),
71 cmCacheManager::FILEPATH);
76 std::string result = FindProgram(this->Names);
79 // Save the value in the cache
80 this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
82 this->VariableDocumentation.c_str(),
83 cmCacheManager::FILEPATH);
87 this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
88 (this->VariableName + "-NOTFOUND").c_str(),
89 this->VariableDocumentation.c_str(),
90 cmCacheManager::FILEPATH);
94 std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
96 std::string program = "";
98 if(this->SearchAppBundleFirst || this->SearchAppBundleOnly)
100 program = FindAppBundle(names);
102 if(program.empty() && !this->SearchAppBundleOnly)
104 program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
107 if(program.empty() && this->SearchAppBundleLast)
109 program = this->FindAppBundle(names);
114 std::string cmFindProgramCommand
115 ::FindAppBundle(std::vector<std::string> names)
117 for(std::vector<std::string>::const_iterator name = names.begin();
118 name != names.end() ; ++name)
121 std::string appName = *name + std::string(".app");
122 std::string appPath = cmSystemTools::FindDirectory(appName.c_str(),
126 if ( !appPath.empty() )
128 std::string executable = GetBundleExecutable(appPath);
129 if (!executable.empty())
131 return cmSystemTools::CollapseFullPath(executable.c_str());
136 // Couldn't find app bundle
140 std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
142 std::string executable = "";
144 #if defined(__APPLE__)
145 // Started with an example on developer.apple.com about finding bundles
146 // and modified from that.
148 // Get a CFString of the app bundle path
149 // XXX - Is it safe to assume everything is in UTF8?
150 CFStringRef bundlePathCFS =
151 CFStringCreateWithCString(kCFAllocatorDefault ,
152 bundlePath.c_str(), kCFStringEncodingUTF8 );
154 // Make a CFURLRef from the CFString representation of the
156 CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
158 kCFURLPOSIXPathStyle,
161 // Make a bundle instance using the URLRef.
162 CFBundleRef appBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
164 // returned executableURL is relative to <appbundle>/Contents/MacOS/
165 CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
167 if (executableURL != NULL)
169 const int MAX_OSX_PATH_SIZE = 1024;
170 char buffer[MAX_OSX_PATH_SIZE];
172 // Convert the CFString to a C string
173 CFStringGetCString( CFURLGetString(executableURL), buffer,
174 MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8 );
176 // And finally to a c++ string
177 executable = bundlePath + "/Contents/MacOS/" + std::string(buffer);
178 // Only release CFURLRef if it's not null
179 CFRelease( executableURL );
182 // Any CF objects returned from functions with "create" or
183 // "copy" in their names must be released by us!
184 CFRelease( bundlePathCFS );
185 CFRelease( bundleURL );
186 CFRelease( appBundle );