1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFindProgramCommand.cxx,v $
6 Date: $Date: 2008/01/23 15:27:59 $
7 Version: $Revision: 1.42 $
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 // First/last order taken care of in cmFindBase when the paths are setup.
101 if(this->SearchAppBundleFirst
|| this->SearchAppBundleLast
)
103 program
= FindAppBundle(names
);
105 if(program
.empty() && !this->SearchAppBundleOnly
)
107 program
= cmSystemTools::FindProgram(names
, this->SearchPaths
, true);
113 std::string cmFindProgramCommand
114 ::FindAppBundle(std::vector
<std::string
> names
)
116 for(std::vector
<std::string
>::const_iterator name
= names
.begin();
117 name
!= names
.end() ; ++name
)
120 std::string appName
= *name
+ std::string(".app");
121 std::string appPath
= cmSystemTools::FindDirectory(appName
.c_str(),
125 if ( !appPath
.empty() )
127 std::string executable
= GetBundleExecutable(appPath
);
128 if (!executable
.empty())
130 return cmSystemTools::CollapseFullPath(executable
.c_str());
135 // Couldn't find app bundle
139 std::string
cmFindProgramCommand::GetBundleExecutable(std::string bundlePath
)
141 std::string executable
= "";
143 #if defined(__APPLE__)
144 // Started with an example on developer.apple.com about finding bundles
145 // and modified from that.
147 // Get a CFString of the app bundle path
148 // XXX - Is it safe to assume everything is in UTF8?
149 CFStringRef bundlePathCFS
=
150 CFStringCreateWithCString(kCFAllocatorDefault
,
151 bundlePath
.c_str(), kCFStringEncodingUTF8
);
153 // Make a CFURLRef from the CFString representation of the
155 CFURLRef bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
157 kCFURLPOSIXPathStyle
,
160 // Make a bundle instance using the URLRef.
161 CFBundleRef appBundle
= CFBundleCreate( kCFAllocatorDefault
, bundleURL
);
163 // returned executableURL is relative to <appbundle>/Contents/MacOS/
164 CFURLRef executableURL
= CFBundleCopyExecutableURL(appBundle
);
166 if (executableURL
!= NULL
)
168 const int MAX_OSX_PATH_SIZE
= 1024;
169 char buffer
[MAX_OSX_PATH_SIZE
];
171 // Convert the CFString to a C string
172 CFStringGetCString( CFURLGetString(executableURL
), buffer
,
173 MAX_OSX_PATH_SIZE
, kCFStringEncodingUTF8
);
175 // And finally to a c++ string
176 executable
= bundlePath
+ "/Contents/MacOS/" + std::string(buffer
);
179 // Any CF objects returned from functions with "create" or
180 // "copy" in their names must be released by us!
181 CFRelease( bundlePathCFS
);
182 CFRelease( bundleURL
);
183 CFRelease( appBundle
);
184 CFRelease( executableURL
);