cmFindProgramCommand.cxx 6.6 KB

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