cmFindProgramCommand.cxx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmFindProgramCommand.h"
  14. #include "cmCacheManager.h"
  15. #include <stdlib.h>
  16. #if defined(__APPLE__)
  17. #include <CoreFoundation/CoreFoundation.h>
  18. #endif
  19. cmFindProgramCommand::cmFindProgramCommand()
  20. {
  21. cmSystemTools::ReplaceString(this->GenericDocumentation,
  22. "FIND_XXX", "find_program");
  23. cmSystemTools::ReplaceString(this->GenericDocumentation,
  24. "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
  25. cmSystemTools::ReplaceString(this->GenericDocumentation,
  26. "CMAKE_XXX_MAC_PATH",
  27. "CMAKE_APPBUNDLE_PATH");
  28. cmSystemTools::ReplaceString(this->GenericDocumentation,
  29. "CMAKE_SYSTEM_XXX_MAC_PATH",
  30. "CMAKE_SYSTEM_APPBUNDLE_PATH");
  31. cmSystemTools::ReplaceString(this->GenericDocumentation,
  32. "XXX_SYSTEM", "");
  33. cmSystemTools::ReplaceString(this->GenericDocumentation,
  34. "CMAKE_SYSTEM_XXX_PATH",
  35. "CMAKE_SYSTEM_PROGRAM_PATH");
  36. cmSystemTools::ReplaceString(this->GenericDocumentation,
  37. "SEARCH_XXX_DESC", "program");
  38. cmSystemTools::ReplaceString(this->GenericDocumentation,
  39. "SEARCH_XXX", "program");
  40. cmSystemTools::ReplaceString(this->GenericDocumentation,
  41. "XXX_SUBDIR", "[s]bin");
  42. cmSystemTools::ReplaceString(this->GenericDocumentation,
  43. "CMAKE_FIND_ROOT_PATH_MODE_XXX",
  44. "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM");
  45. }
  46. // cmFindProgramCommand
  47. bool cmFindProgramCommand
  48. ::InitialPass(std::vector<std::string> const& argsIn, cmExecutionStatus &)
  49. {
  50. this->VariableDocumentation = "Path to a program.";
  51. this->CMakePathName = "PROGRAM";
  52. // call cmFindBase::ParseArguments
  53. if(!this->ParseArguments(argsIn))
  54. {
  55. return false;
  56. }
  57. if(this->AlreadyInCache)
  58. {
  59. // If the user specifies the entry on the command line without a
  60. // type we should add the type and docstring but keep the original
  61. // value.
  62. if(this->AlreadyInCacheWithoutMetaInfo)
  63. {
  64. this->Makefile->AddCacheDefinition(this->VariableName.c_str(), "",
  65. this->VariableDocumentation.c_str(),
  66. cmCacheManager::FILEPATH);
  67. }
  68. return true;
  69. }
  70. std::string result = FindProgram(this->Names);
  71. if(result != "")
  72. {
  73. // Save the value in the cache
  74. this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
  75. result.c_str(),
  76. this->VariableDocumentation.c_str(),
  77. cmCacheManager::FILEPATH);
  78. return true;
  79. }
  80. this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
  81. (this->VariableName + "-NOTFOUND").c_str(),
  82. this->VariableDocumentation.c_str(),
  83. cmCacheManager::FILEPATH);
  84. return true;
  85. }
  86. std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
  87. {
  88. std::string program = "";
  89. if(this->SearchAppBundleFirst || this->SearchAppBundleOnly)
  90. {
  91. program = FindAppBundle(names);
  92. }
  93. if(program.empty() && !this->SearchAppBundleOnly)
  94. {
  95. program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
  96. }
  97. if(program.empty() && this->SearchAppBundleLast)
  98. {
  99. program = this->FindAppBundle(names);
  100. }
  101. return program;
  102. }
  103. std::string cmFindProgramCommand
  104. ::FindAppBundle(std::vector<std::string> names)
  105. {
  106. for(std::vector<std::string>::const_iterator name = names.begin();
  107. name != names.end() ; ++name)
  108. {
  109. std::string appName = *name + std::string(".app");
  110. std::string appPath = cmSystemTools::FindDirectory(appName.c_str(),
  111. this->SearchPaths,
  112. true);
  113. if ( !appPath.empty() )
  114. {
  115. std::string executable = GetBundleExecutable(appPath);
  116. if (!executable.empty())
  117. {
  118. return cmSystemTools::CollapseFullPath(executable.c_str());
  119. }
  120. }
  121. }
  122. // Couldn't find app bundle
  123. return "";
  124. }
  125. std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
  126. {
  127. std::string executable = "";
  128. (void)bundlePath;
  129. #if defined(__APPLE__)
  130. // Started with an example on developer.apple.com about finding bundles
  131. // and modified from that.
  132. // Get a CFString of the app bundle path
  133. // XXX - Is it safe to assume everything is in UTF8?
  134. CFStringRef bundlePathCFS =
  135. CFStringCreateWithCString(kCFAllocatorDefault ,
  136. bundlePath.c_str(), kCFStringEncodingUTF8 );
  137. // Make a CFURLRef from the CFString representation of the
  138. // bundle’s path.
  139. CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
  140. bundlePathCFS,
  141. kCFURLPOSIXPathStyle,
  142. true );
  143. // Make a bundle instance using the URLRef.
  144. CFBundleRef appBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
  145. // returned executableURL is relative to <appbundle>/Contents/MacOS/
  146. CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
  147. if (executableURL != NULL)
  148. {
  149. const int MAX_OSX_PATH_SIZE = 1024;
  150. char buffer[MAX_OSX_PATH_SIZE];
  151. // Convert the CFString to a C string
  152. CFStringGetCString( CFURLGetString(executableURL), buffer,
  153. MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8 );
  154. // And finally to a c++ string
  155. executable = bundlePath + "/Contents/MacOS/" + std::string(buffer);
  156. }
  157. // Any CF objects returned from functions with "create" or
  158. // "copy" in their names must be released by us!
  159. CFRelease( bundlePathCFS );
  160. CFRelease( bundleURL );
  161. CFRelease( appBundle );
  162. CFRelease( executableURL );
  163. #endif
  164. return executable;
  165. }