1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFindProgramCommand.cxx,v $
6 Date: $Date: 2008-06-09 15:58:29 $
7 Version: $Revision: 1.43 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmFindProgramCommand.h"
18 #include "cmCacheManager.h"
21 #if defined(__APPLE__)
22 #include <CoreFoundation/CoreFoundation.h>
25 cmFindProgramCommand::cmFindProgramCommand()
27 cmSystemTools::ReplaceString(this->GenericDocumentation
,
28 "FIND_XXX", "find_program");
29 cmSystemTools::ReplaceString(this->GenericDocumentation
,
30 "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
31 cmSystemTools::ReplaceString(this->GenericDocumentation
,
33 "CMAKE_APPBUNDLE_PATH");
34 cmSystemTools::ReplaceString(this->GenericDocumentation
,
35 "CMAKE_SYSTEM_XXX_MAC_PATH",
36 "CMAKE_SYSTEM_APPBUNDLE_PATH");
37 cmSystemTools::ReplaceString(this->GenericDocumentation
,
39 cmSystemTools::ReplaceString(this->GenericDocumentation
,
40 "CMAKE_SYSTEM_XXX_PATH",
41 "CMAKE_SYSTEM_PROGRAM_PATH");
42 cmSystemTools::ReplaceString(this->GenericDocumentation
,
43 "SEARCH_XXX_DESC", "program");
44 cmSystemTools::ReplaceString(this->GenericDocumentation
,
45 "SEARCH_XXX", "program");
46 cmSystemTools::ReplaceString(this->GenericDocumentation
,
47 "XXX_SUBDIR", "[s]bin");
48 cmSystemTools::ReplaceString(this->GenericDocumentation
,
49 "CMAKE_FIND_ROOT_PATH_MODE_XXX",
50 "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM");
53 // cmFindProgramCommand
54 bool cmFindProgramCommand
55 ::InitialPass(std::vector
<std::string
> const& argsIn
, cmExecutionStatus
&)
57 this->VariableDocumentation
= "Path to a program.";
58 this->CMakePathName
= "PROGRAM";
59 // call cmFindBase::ParseArguments
60 if(!this->ParseArguments(argsIn
))
64 if(this->AlreadyInCache
)
66 // If the user specifies the entry on the command line without a
67 // type we should add the type and docstring but keep the original
69 if(this->AlreadyInCacheWithoutMetaInfo
)
71 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(), "",
72 this->VariableDocumentation
.c_str(),
73 cmCacheManager::FILEPATH
);
78 std::string result
= FindProgram(this->Names
);
81 // Save the value in the cache
82 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(),
84 this->VariableDocumentation
.c_str(),
85 cmCacheManager::FILEPATH
);
89 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(),
90 (this->VariableName
+ "-NOTFOUND").c_str(),
91 this->VariableDocumentation
.c_str(),
92 cmCacheManager::FILEPATH
);
96 std::string
cmFindProgramCommand::FindProgram(std::vector
<std::string
> names
)
98 std::string program
= "";
100 if(this->SearchAppBundleFirst
|| this->SearchAppBundleOnly
)
102 program
= FindAppBundle(names
);
104 if(program
.empty() && !this->SearchAppBundleOnly
)
106 program
= cmSystemTools::FindProgram(names
, this->SearchPaths
, true);
109 if(program
.empty() && this->SearchAppBundleLast
)
111 program
= this->FindAppBundle(names
);
116 std::string cmFindProgramCommand
117 ::FindAppBundle(std::vector
<std::string
> names
)
119 for(std::vector
<std::string
>::const_iterator name
= names
.begin();
120 name
!= names
.end() ; ++name
)
123 std::string appName
= *name
+ std::string(".app");
124 std::string appPath
= cmSystemTools::FindDirectory(appName
.c_str(),
128 if ( !appPath
.empty() )
130 std::string executable
= GetBundleExecutable(appPath
);
131 if (!executable
.empty())
133 return cmSystemTools::CollapseFullPath(executable
.c_str());
138 // Couldn't find app bundle
142 std::string
cmFindProgramCommand::GetBundleExecutable(std::string bundlePath
)
144 std::string executable
= "";
146 #if defined(__APPLE__)
147 // Started with an example on developer.apple.com about finding bundles
148 // and modified from that.
150 // Get a CFString of the app bundle path
151 // XXX - Is it safe to assume everything is in UTF8?
152 CFStringRef bundlePathCFS
=
153 CFStringCreateWithCString(kCFAllocatorDefault
,
154 bundlePath
.c_str(), kCFStringEncodingUTF8
);
156 // Make a CFURLRef from the CFString representation of the
158 CFURLRef bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
160 kCFURLPOSIXPathStyle
,
163 // Make a bundle instance using the URLRef.
164 CFBundleRef appBundle
= CFBundleCreate( kCFAllocatorDefault
, bundleURL
);
166 // returned executableURL is relative to <appbundle>/Contents/MacOS/
167 CFURLRef executableURL
= CFBundleCopyExecutableURL(appBundle
);
169 if (executableURL
!= NULL
)
171 const int MAX_OSX_PATH_SIZE
= 1024;
172 char buffer
[MAX_OSX_PATH_SIZE
];
174 // Convert the CFString to a C string
175 CFStringGetCString( CFURLGetString(executableURL
), buffer
,
176 MAX_OSX_PATH_SIZE
, kCFStringEncodingUTF8
);
178 // And finally to a c++ string
179 executable
= bundlePath
+ "/Contents/MacOS/" + std::string(buffer
);
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
);
187 CFRelease( executableURL
);