Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmFindProgramCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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"
14 #include <stdlib.h>
15
16 #if defined(__APPLE__)
17 #include <CoreFoundation/CoreFoundation.h>
18 #endif
19
20 void cmFindProgramCommand::GenerateDocumentation()
21 {
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,
28                                "CMAKE_XXX_MAC_PATH",
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,
34                                "XXX_SYSTEM", "");
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");
49 }
50
51 // cmFindProgramCommand
52 bool cmFindProgramCommand
53 ::InitialPass(std::vector<std::string> const& argsIn, cmExecutionStatus &)
54 {
55   this->VariableDocumentation = "Path to a program.";
56   this->CMakePathName = "PROGRAM";
57   // call cmFindBase::ParseArguments
58   if(!this->ParseArguments(argsIn))
59     {
60     return false;
61     }
62   if(this->AlreadyInCache)
63     {
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
66     // value.
67     if(this->AlreadyInCacheWithoutMetaInfo)
68       {
69       this->Makefile->AddCacheDefinition(this->VariableName.c_str(), "",
70                                          this->VariableDocumentation.c_str(),
71                                          cmCacheManager::FILEPATH);
72       }
73     return true;
74     }
75
76   std::string result = FindProgram(this->Names);
77   if(result != "")
78     {
79     // Save the value in the cache
80     this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
81                                        result.c_str(),
82                                        this->VariableDocumentation.c_str(),
83                                        cmCacheManager::FILEPATH);
84
85     return true;
86     }
87   this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
88                                  (this->VariableName + "-NOTFOUND").c_str(),
89                                  this->VariableDocumentation.c_str(),
90                                  cmCacheManager::FILEPATH);
91   return true;
92 }
93
94 std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
95 {
96   std::string program = "";
97
98   if(this->SearchAppBundleFirst || this->SearchAppBundleOnly)
99     {
100     program = FindAppBundle(names);
101     }
102   if(program.empty() && !this->SearchAppBundleOnly)
103     {
104     program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
105     }
106
107   if(program.empty() && this->SearchAppBundleLast)
108     {
109     program = this->FindAppBundle(names);
110     }
111   return program;
112 }
113
114 std::string cmFindProgramCommand
115 ::FindAppBundle(std::vector<std::string> names)
116 {
117   for(std::vector<std::string>::const_iterator name = names.begin();
118       name != names.end() ; ++name)
119     {
120
121     std::string appName = *name + std::string(".app");
122     std::string appPath = cmSystemTools::FindDirectory(appName.c_str(),
123                                                        this->SearchPaths,
124                                                        true);
125
126     if ( !appPath.empty() )
127       {
128       std::string executable = GetBundleExecutable(appPath);
129       if (!executable.empty())
130         {
131         return cmSystemTools::CollapseFullPath(executable.c_str());
132         }
133       }
134     }
135
136   // Couldn't find app bundle
137   return "";
138 }
139
140 std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
141 {
142   std::string executable = "";
143   (void)bundlePath;
144 #if defined(__APPLE__)
145   // Started with an example on developer.apple.com about finding bundles
146   // and modified from that.
147
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 );
153
154   // Make a CFURLRef from the CFString representation of the
155   // bundle’s path.
156   CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
157                                                      bundlePathCFS,
158                                                      kCFURLPOSIXPathStyle,
159                                                      true );
160
161   // Make a bundle instance using the URLRef.
162   CFBundleRef appBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
163
164   // returned executableURL is relative to <appbundle>/Contents/MacOS/
165   CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
166
167   if (executableURL != NULL)
168     {
169     const int MAX_OSX_PATH_SIZE = 1024;
170     char buffer[MAX_OSX_PATH_SIZE];
171
172     // Convert the CFString to a C string
173     CFStringGetCString( CFURLGetString(executableURL), buffer,
174                         MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8 );
175
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 );
180     }
181
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 #endif
188
189   return executable;
190 }
191