cmFindProgramCommand.cxx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. "XXX_SYSTEM", "");
  27. cmSystemTools::ReplaceString(this->GenericDocumentation,
  28. "CMAKE_SYSTEM_XXX_PATH", "CMAKE_SYSTEM_PROGRAM_PATH");
  29. cmSystemTools::ReplaceString(this->GenericDocumentation,
  30. "SEARCH_XXX_DESC", "program");
  31. cmSystemTools::ReplaceString(this->GenericDocumentation,
  32. "SEARCH_XXX", "program");
  33. }
  34. // cmFindProgramCommand
  35. bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
  36. {
  37. this->VariableDocumentation = "Path to a program.";
  38. this->CMakePathName = "PROGRAM";
  39. // call cmFindBase::ParseArguments
  40. if(!this->ParseArguments(argsIn))
  41. {
  42. return false;
  43. }
  44. if(this->AlreadyInCache)
  45. {
  46. return true;
  47. }
  48. std::string result = FindProgram(this->Names);
  49. if(result != "")
  50. {
  51. // Save the value in the cache
  52. this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
  53. result.c_str(),
  54. this->VariableDocumentation.c_str(),
  55. cmCacheManager::FILEPATH);
  56. return true;
  57. }
  58. this->Makefile->AddCacheDefinition(this->VariableName.c_str(),
  59. (this->VariableName + "-NOTFOUND").c_str(),
  60. this->VariableDocumentation.c_str(),
  61. cmCacheManager::FILEPATH);
  62. return true;
  63. }
  64. std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
  65. {
  66. std::string program = "";
  67. // First/last order taken care of in cmFindBase when the paths are setup.
  68. if(this->SearchAppBundleFirst || this->SearchAppBundleLast)
  69. {
  70. program = FindAppBundle(names);
  71. }
  72. if(program.empty() && !this->SearchAppBundleOnly)
  73. {
  74. program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
  75. }
  76. return program;
  77. }
  78. std::string cmFindProgramCommand::FindAppBundle(std::vector<std::string> names)
  79. {
  80. for(std::vector<std::string>::const_iterator name = names.begin();
  81. name != names.end() ; ++name)
  82. {
  83. std::string appName = *name + std::string(".app");
  84. std::string appPath = cmSystemTools::FindDirectory(appName.c_str(), this->SearchPaths, true);
  85. if ( !appPath.empty() )
  86. {
  87. std::string executable = GetBundleExecutable(appPath);
  88. if (!executable.empty())
  89. {
  90. return cmSystemTools::CollapseFullPath(executable.c_str());
  91. }
  92. }
  93. }
  94. // Couldn't find app bundle
  95. return "";
  96. }
  97. std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
  98. {
  99. std::string executable = "";
  100. #if defined(__APPLE__)
  101. // Started with an example on developer.apple.com about finding bundles
  102. // and modified from that.
  103. // Get a CFString of the app bundle path
  104. // XXX - Is it safe to assume everything is in UTF8?
  105. CFStringRef bundlePathCFS = CFStringCreateWithCString(kCFAllocatorDefault ,
  106. bundlePath.c_str(), kCFStringEncodingUTF8 );
  107. // Make a CFURLRef from the CFString representation of the bundle’s path.
  108. CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
  109. bundlePathCFS,
  110. kCFURLPOSIXPathStyle,
  111. true );
  112. // Make a bundle instance using the URLRef.
  113. CFBundleRef appBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
  114. // returned executableURL is relative to <appbundle>/Contents/MacOS/
  115. CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
  116. if (executableURL != NULL)
  117. {
  118. const int MAX_OSX_PATH_SIZE = 1024;
  119. char buffer[MAX_OSX_PATH_SIZE];
  120. // Convert the CFString to a C string
  121. CFStringGetCString( CFURLGetString(executableURL), buffer, MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8 );
  122. // And finally to a c++ string
  123. executable = bundlePath + "/Contents/MacOS/" + std::string(buffer);
  124. }
  125. // Any CF objects returned from functions with "create" or
  126. // "copy" in their names must be released by us!
  127. CFRelease( bundlePathCFS );
  128. CFRelease( bundleURL );
  129. CFRelease( appBundle );
  130. CFRelease( executableURL );
  131. #endif
  132. return executable;
  133. }