You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
6.3 KiB

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