1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFindProgramCommand.cxx,v $
6 <<<<<<< cmFindProgramCommand.cxx
7 Date: $Date: 2008/01/23 15:27:59 $
8 Version: $Revision: 1.42 $
10 Date: $Date: 2008-06-09 15:58:29 $
11 Version: $Revision: 1.43 $
14 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
15 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
17 This software is distributed WITHOUT ANY WARRANTY; without even
18 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 PURPOSE. See the above copyright notices for more information.
21 =========================================================================*/
22 #include "cmFindProgramCommand.h"
23 #include "cmCacheManager.h"
26 #if defined(__APPLE__)
27 #include <CoreFoundation/CoreFoundation.h>
30 cmFindProgramCommand::cmFindProgramCommand()
32 cmSystemTools::ReplaceString(this->GenericDocumentation
,
33 "FIND_XXX", "find_program");
34 cmSystemTools::ReplaceString(this->GenericDocumentation
,
35 "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
36 cmSystemTools::ReplaceString(this->GenericDocumentation
,
38 "CMAKE_APPBUNDLE_PATH");
39 cmSystemTools::ReplaceString(this->GenericDocumentation
,
40 "CMAKE_SYSTEM_XXX_MAC_PATH",
41 "CMAKE_SYSTEM_APPBUNDLE_PATH");
42 cmSystemTools::ReplaceString(this->GenericDocumentation
,
44 cmSystemTools::ReplaceString(this->GenericDocumentation
,
45 "CMAKE_SYSTEM_XXX_PATH",
46 "CMAKE_SYSTEM_PROGRAM_PATH");
47 cmSystemTools::ReplaceString(this->GenericDocumentation
,
48 "SEARCH_XXX_DESC", "program");
49 cmSystemTools::ReplaceString(this->GenericDocumentation
,
50 "SEARCH_XXX", "program");
51 cmSystemTools::ReplaceString(this->GenericDocumentation
,
52 "XXX_SUBDIR", "[s]bin");
53 cmSystemTools::ReplaceString(this->GenericDocumentation
,
54 "CMAKE_FIND_ROOT_PATH_MODE_XXX",
55 "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM");
58 // cmFindProgramCommand
59 bool cmFindProgramCommand
60 ::InitialPass(std::vector
<std::string
> const& argsIn
, cmExecutionStatus
&)
62 this->VariableDocumentation
= "Path to a program.";
63 this->CMakePathName
= "PROGRAM";
64 // call cmFindBase::ParseArguments
65 if(!this->ParseArguments(argsIn
))
69 if(this->AlreadyInCache
)
71 // If the user specifies the entry on the command line without a
72 // type we should add the type and docstring but keep the original
74 if(this->AlreadyInCacheWithoutMetaInfo
)
76 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(), "",
77 this->VariableDocumentation
.c_str(),
78 cmCacheManager::FILEPATH
);
83 std::string result
= FindProgram(this->Names
);
86 // Save the value in the cache
87 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(),
89 this->VariableDocumentation
.c_str(),
90 cmCacheManager::FILEPATH
);
94 this->Makefile
->AddCacheDefinition(this->VariableName
.c_str(),
95 (this->VariableName
+ "-NOTFOUND").c_str(),
96 this->VariableDocumentation
.c_str(),
97 cmCacheManager::FILEPATH
);
101 std::string
cmFindProgramCommand::FindProgram(std::vector
<std::string
> names
)
103 std::string program
= "";
105 if(this->SearchAppBundleFirst
|| this->SearchAppBundleOnly
)
107 program
= FindAppBundle(names
);
109 if(program
.empty() && !this->SearchAppBundleOnly
)
111 program
= cmSystemTools::FindProgram(names
, this->SearchPaths
, true);
114 if(program
.empty() && this->SearchAppBundleLast
)
116 program
= this->FindAppBundle(names
);
121 std::string cmFindProgramCommand
122 ::FindAppBundle(std::vector
<std::string
> names
)
124 for(std::vector
<std::string
>::const_iterator name
= names
.begin();
125 name
!= names
.end() ; ++name
)
128 std::string appName
= *name
+ std::string(".app");
129 std::string appPath
= cmSystemTools::FindDirectory(appName
.c_str(),
133 if ( !appPath
.empty() )
135 std::string executable
= GetBundleExecutable(appPath
);
136 if (!executable
.empty())
138 return cmSystemTools::CollapseFullPath(executable
.c_str());
143 // Couldn't find app bundle
147 std::string
cmFindProgramCommand::GetBundleExecutable(std::string bundlePath
)
149 std::string executable
= "";
151 #if defined(__APPLE__)
152 // Started with an example on developer.apple.com about finding bundles
153 // and modified from that.
155 // Get a CFString of the app bundle path
156 // XXX - Is it safe to assume everything is in UTF8?
157 CFStringRef bundlePathCFS
=
158 CFStringCreateWithCString(kCFAllocatorDefault
,
159 bundlePath
.c_str(), kCFStringEncodingUTF8
);
161 // Make a CFURLRef from the CFString representation of the
163 CFURLRef bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
165 kCFURLPOSIXPathStyle
,
168 // Make a bundle instance using the URLRef.
169 CFBundleRef appBundle
= CFBundleCreate( kCFAllocatorDefault
, bundleURL
);
171 // returned executableURL is relative to <appbundle>/Contents/MacOS/
172 CFURLRef executableURL
= CFBundleCopyExecutableURL(appBundle
);
174 if (executableURL
!= NULL
)
176 const int MAX_OSX_PATH_SIZE
= 1024;
177 char buffer
[MAX_OSX_PATH_SIZE
];
179 // Convert the CFString to a C string
180 CFStringGetCString( CFURLGetString(executableURL
), buffer
,
181 MAX_OSX_PATH_SIZE
, kCFStringEncodingUTF8
);
183 // And finally to a c++ string
184 executable
= bundlePath
+ "/Contents/MacOS/" + std::string(buffer
);
187 // Any CF objects returned from functions with "create" or
188 // "copy" in their names must be released by us!
189 CFRelease( bundlePathCFS
);
190 CFRelease( bundleURL
);
191 CFRelease( appBundle
);
192 CFRelease( executableURL
);