Browse Source

ENH: add patch for finding applications on OSX

Bill Hoffman 19 years ago
parent
commit
cae4e6b37a

+ 8 - 0
Modules/Platform/Darwin.cmake

@@ -73,6 +73,14 @@ SET(CMAKE_SYSTEM_FRAMEWORK_PATH
   /Network/Library/Frameworks
   /Network/Library/Frameworks
   /System/Library/Frameworks)
   /System/Library/Frameworks)
 
 
+# default to searching for application bundles first
+SET(CMAKE_FIND_APPBUNDLE FIRST)
+# set up the default search directories for application bundles
+SET(CMAKE_SYSTEM_APPBUNDLE_PATH
+  ~/Applications
+  /Applications
+  /Developer/Applications)
+
 INCLUDE(Platform/UnixPaths)
 INCLUDE(Platform/UnixPaths)
 SET(CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH} /sw/include)
 SET(CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH} /sw/include)
 SET(CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} /sw/lib)
 SET(CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} /sw/lib)

+ 6 - 0
Source/CMakeLists.txt

@@ -220,6 +220,12 @@ IF(UNIX)
   TARGET_LINK_LIBRARIES(CMakeLib ${CMAKE_DL_LIBS})
   TARGET_LINK_LIBRARIES(CMakeLib ${CMAKE_DL_LIBS})
 ENDIF(UNIX)
 ENDIF(UNIX)
 
 
+# On Apple we need Carbon
+IF(APPLE)
+  FIND_LIBRARY(CARBON Carbon)
+  TARGET_LINK_LIBRARIES(CMakeLib ${CARBON})
+ENDIF(APPLE)
+
 # On some platforms we need the rpcrt4 library for the VS 7 generators.
 # On some platforms we need the rpcrt4 library for the VS 7 generators.
 IF(CMAKE_BUILD_ON_VISUAL_STUDIO OR MINGW)
 IF(CMAKE_BUILD_ON_VISUAL_STUDIO OR MINGW)
   TARGET_LINK_LIBRARIES(CMakeLib rpcrt4)
   TARGET_LINK_LIBRARIES(CMakeLib rpcrt4)

+ 106 - 4
Source/cmFindBase.cxx

@@ -27,11 +27,15 @@ cmFindBase::cmFindBase()
   // default is to search frameworks first on apple
   // default is to search frameworks first on apple
 #if defined(__APPLE__)
 #if defined(__APPLE__)
   this->SearchFrameworkFirst = true;
   this->SearchFrameworkFirst = true;
+  this->SearchAppBundleFirst = true;
 #else
 #else
   this->SearchFrameworkFirst = false;
   this->SearchFrameworkFirst = false;
+  this->SearchAppBundleFirst = false;
 #endif
 #endif
   this->SearchFrameworkOnly = false;
   this->SearchFrameworkOnly = false;
   this->SearchFrameworkLast = false;
   this->SearchFrameworkLast = false;
+  this->SearchAppBundleOnly = false;
+  this->SearchAppBundleLast = false;
   this->GenericDocumentation = 
   this->GenericDocumentation = 
     "   FIND_XXX(<VAR> name1 path1 path2 ...)\n"
     "   FIND_XXX(<VAR> name1 path1 path2 ...)\n"
     "This is the short-hand signature for the command that "
     "This is the short-hand signature for the command that "
@@ -71,6 +75,7 @@ cmFindBase::cmFindBase()
     "can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
     "can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
     ""
     ""
     "   CMAKE_FRAMEWORK_PATH\n"
     "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_APPBUNDLE_PATH\n"
     "   CMAKE_XXX_PATH\n"
     "   CMAKE_XXX_PATH\n"
     "2. Search cmake variables with the same names as "
     "2. Search cmake variables with the same names as "
     "the cmake specific environment variables.  These "
     "the cmake specific environment variables.  These "
@@ -79,6 +84,7 @@ cmFindBase::cmFindBase()
     "is passed.\n"
     "is passed.\n"
     ""
     ""
     "   CMAKE_FRAMEWORK_PATH\n"
     "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_APPBUNDLE_PATH\n"
     "   CMAKE_XXX_PATH\n"
     "   CMAKE_XXX_PATH\n"
     "3. Search the standard system environment variables. "
     "3. Search the standard system environment variables. "
     "This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is an argument.\n"
     "This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is an argument.\n"
@@ -88,6 +94,7 @@ cmFindBase::cmFindBase()
     "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
     "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
     "is passed.\n"
     "is passed.\n"
     "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
     "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
+    "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
     "   CMAKE_SYSTEM_XXX_PATH\n"
     "   CMAKE_SYSTEM_XXX_PATH\n"
     "5. Search the paths specified after PATHS or in the short-hand version "
     "5. Search the paths specified after PATHS or in the short-hand version "
     "of the command.\n"
     "of the command.\n"
@@ -99,6 +106,14 @@ cmFindBase::cmFindBase()
     "              libraries or headers.\n"
     "              libraries or headers.\n"
     "   \"ONLY\"   - Only try to find frameworks.\n"
     "   \"ONLY\"   - Only try to find frameworks.\n"
     "   \"NEVER\". - Never try to find frameworks.\n"
     "   \"NEVER\". - Never try to find frameworks.\n"
+    "On Darwin or systems supporting OSX Application Bundles, the cmake variable"
+    "    CMAKE_FIND_APPBUNDLE can be set to empty or one of the following:\n"
+    "   \"FIRST\"  - Try to find application bundles before standard\n"
+    "              programs. This is the default on Darwin.\n"
+    "   \"LAST\"   - Try to find application bundles after standard\n"
+    "              programs.\n"
+    "   \"ONLY\"   - Only try to find application bundles.\n"
+    "   \"NEVER\". - Never try to find application bundles.\n"
     "The reason the paths listed in the call to the command are searched "
     "The reason the paths listed in the call to the command are searched "
     "last is that most users of CMake would expect things to be found "
     "last is that most users of CMake would expect things to be found "
     "first in the locations specified by their environment. Projects may "
     "first in the locations specified by their environment. Projects may "
@@ -142,6 +157,32 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
     this->SearchFrameworkOnly = false;
     this->SearchFrameworkOnly = false;
     }
     }
 
 
+  std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
+  if(fab == "NEVER")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = false;
+    }
+  else if (fab == "ONLY")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = true;
+    }
+  else if (fab == "FIRST")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = true;
+    this->SearchAppBundleOnly = false;
+    }
+  else if (fab == "LAST")
+    {
+    this->SearchAppBundleLast = true;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = false;
+    }
+
   // CMake versions below 2.3 did not search all these extra
   // CMake versions below 2.3 did not search all these extra
   // locations.  Preserve compatibility unless a modern argument is
   // locations.  Preserve compatibility unless a modern argument is
   // passed.
   // passed.
@@ -355,28 +396,36 @@ void cmFindBase::ExpandPaths(std::vector<std::string> userPaths)
       {
       {
       this->AddFrameWorkPaths();
       this->AddFrameWorkPaths();
       }
       }
-    if(!this->NoCMakeEnvironmentPath && !this->SearchFrameworkOnly)
+    if(this->SearchAppBundleFirst)
+      {
+      this->AddAppBundlePaths();
+      }
+    if(!this->NoCMakeEnvironmentPath && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly))
       {
       {
       // Add CMAKE_*_PATH environment variables
       // Add CMAKE_*_PATH environment variables
       this->AddEnvironmentVairables();
       this->AddEnvironmentVairables();
       }
       }
-    if(!this->NoCMakePath && !this->SearchFrameworkOnly)
+    if(!this->NoCMakePath && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly))
       {
       {
       // Add CMake varibles of the same name as the previous environment
       // Add CMake varibles of the same name as the previous environment
       // varibles CMAKE_*_PATH to be used most of the time with -D
       // varibles CMAKE_*_PATH to be used most of the time with -D
       // command line options
       // command line options
       this->AddCMakeVairables();
       this->AddCMakeVairables();
       }
       }
-    if(!this->NoSystemEnvironmentPath && !this->SearchFrameworkOnly)
+    if(!this->NoSystemEnvironmentPath && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly))
       {
       {
       // add System environment PATH and (LIB or INCLUDE)
       // add System environment PATH and (LIB or INCLUDE)
       this->AddSystemEnvironmentVairables();
       this->AddSystemEnvironmentVairables();
       }
       }
-    if(!this->NoCMakeSystemPath && !this->SearchFrameworkOnly)
+    if(!this->NoCMakeSystemPath && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly))
       {
       {
       // Add CMAKE_SYSTEM_*_PATH variables which are defined in platform files
       // Add CMAKE_SYSTEM_*_PATH variables which are defined in platform files
       this->AddCMakeSystemVariables();
       this->AddCMakeSystemVariables();
       }
       }
+    if(this->SearchAppBundleLast)
+      {
+      this->AddAppBundlePaths();
+      }
     if(this->SearchFrameworkLast)
     if(this->SearchFrameworkLast)
       {
       {
       this->AddFrameWorkPaths();
       this->AddFrameWorkPaths();
@@ -398,6 +447,10 @@ void cmFindBase::AddEnvironmentVairables()
   var += this->CMakePathName;
   var += this->CMakePathName;
   var += "_PATH";
   var += "_PATH";
   cmSystemTools::GetPath(this->SearchPaths, var.c_str());
   cmSystemTools::GetPath(this->SearchPaths, var.c_str());
+  if(this->SearchAppBundleLast)
+    {
+    cmSystemTools::GetPath(this->SearchPaths, "CMAKE_APPBUNDLE_PATH");
+    }
   if(this->SearchFrameworkLast)
   if(this->SearchFrameworkLast)
     {
     {
     cmSystemTools::GetPath(this->SearchPaths, "CMAKE_FRAMEWORK_PATH");
     cmSystemTools::GetPath(this->SearchPaths, "CMAKE_FRAMEWORK_PATH");
@@ -436,6 +489,37 @@ void cmFindBase::AddFrameWorkPaths()
      }
      }
 }
 }
 
 
+void cmFindBase::AddAppBundlePaths()
+{
+  if(this->NoDefaultPath)
+    {
+    return;
+    }
+  // first environment variables
+  if(!this->NoCMakeEnvironmentPath)
+    {
+    cmSystemTools::GetPath(this->SearchPaths, "CMAKE_APPBUNDLE_PATH");
+    }
+  // add cmake variables
+  if(!this->NoCMakePath)
+    {
+    if(const char* path = 
+       this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, this->SearchPaths);
+      }
+    }
+  // AddCMakeSystemVariables
+   if(!this->NoCMakeSystemPath)
+     {
+     if(const char* path = 
+        this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH"))
+       {
+       cmSystemTools::ExpandListArgument(path, this->SearchPaths);
+       }
+     }
+}
+
 void cmFindBase::AddCMakeVairables()
 void cmFindBase::AddCMakeVairables()
 { 
 { 
   std::string var = "CMAKE_";
   std::string var = "CMAKE_";
@@ -445,6 +529,14 @@ void cmFindBase::AddCMakeVairables()
     {
     {
     cmSystemTools::ExpandListArgument(path, this->SearchPaths);
     cmSystemTools::ExpandListArgument(path, this->SearchPaths);
     } 
     } 
+  if(this->SearchAppBundleLast)
+    {
+    if(const char* path = 
+       this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, this->SearchPaths);
+      }
+    }
   if(this->SearchFrameworkLast)
   if(this->SearchFrameworkLast)
     {
     {
     if(const char* path = 
     if(const char* path = 
@@ -475,6 +567,13 @@ void cmFindBase::AddCMakeSystemVariables()
     {
     {
     cmSystemTools::ExpandListArgument(path, this->SearchPaths);
     cmSystemTools::ExpandListArgument(path, this->SearchPaths);
     }  
     }  
+  if(this->SearchAppBundleLast)
+    {
+    if(const char* path = this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, this->SearchPaths);
+      }
+    }
   if(this->SearchFrameworkLast)
   if(this->SearchFrameworkLast)
     {
     {
     if(const char* path = this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH"))
     if(const char* path = this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH"))
@@ -528,6 +627,9 @@ void cmFindBase::PrintFindStuff()
   std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
   std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
   std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
   std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
   std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
   std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
+  std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n";
+  std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n";
+  std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n";
   std::cerr << "VariableName " << this->VariableName << "\n";
   std::cerr << "VariableName " << this->VariableName << "\n";
   std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n";
   std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n";
   std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";
   std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";

+ 5 - 0
Source/cmFindBase.h

@@ -43,6 +43,7 @@ protected:
   void PrintFindStuff();
   void PrintFindStuff();
   void ExpandPaths(std::vector<std::string> userPaths);
   void ExpandPaths(std::vector<std::string> userPaths);
   void AddFrameWorkPaths();
   void AddFrameWorkPaths();
+  void AddAppBundlePaths();
   void AddEnvironmentVairables();
   void AddEnvironmentVairables();
   void AddCMakeVairables();
   void AddCMakeVairables();
   void AddSystemEnvironmentVairables();
   void AddSystemEnvironmentVairables();
@@ -76,6 +77,10 @@ protected:
   bool SearchFrameworkOnly;
   bool SearchFrameworkOnly;
   bool SearchFrameworkLast;
   bool SearchFrameworkLast;
   
   
+  bool SearchAppBundleFirst;
+  bool SearchAppBundleOnly;
+  bool SearchAppBundleLast;
+  
 };
 };
 
 
 
 

+ 94 - 2
Source/cmFindProgramCommand.cxx

@@ -17,6 +17,10 @@
 #include "cmFindProgramCommand.h"
 #include "cmFindProgramCommand.h"
 #include "cmCacheManager.h"
 #include "cmCacheManager.h"
 #include <stdlib.h>
 #include <stdlib.h>
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
   
   
 cmFindProgramCommand::cmFindProgramCommand()
 cmFindProgramCommand::cmFindProgramCommand()
 {
 {
@@ -48,8 +52,8 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
     {
     {
     return true;
     return true;
     }
     }
-  std::string result = cmSystemTools::FindProgram(this->Names,
-                                                  this->SearchPaths, true);
+
+  std::string result = FindProgram(this->Names);
   if(result != "")
   if(result != "")
     {
     {
     // Save the value in the cache
     // Save the value in the cache
@@ -67,3 +71,91 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
   return true;
   return true;
 }
 }
 
 
+std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
+{
+  std::string program = "";
+
+  // First/last order taken care of in cmFindBase when the paths are setup.
+  if(this->SearchAppBundleFirst || this->SearchAppBundleLast)
+    {
+    program = FindAppBundle(names);
+    }
+  if(program.empty() && !this->SearchAppBundleOnly)
+    {
+    program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
+    }
+
+  return program;
+}
+
+std::string cmFindProgramCommand::FindAppBundle(std::vector<std::string> names)
+{
+  for(std::vector<std::string>::const_iterator name = names.begin();
+      name != names.end() ; ++name)
+    {
+    
+    std::string appName = *name + std::string(".app");
+    std::string appPath = cmSystemTools::FindDirectory(appName.c_str(), this->SearchPaths, true);
+
+    if ( !appPath.empty() )
+      {
+      std::string executable = GetBundleExecutable(appPath);
+      if (!executable.empty()) 
+        {
+        return cmSystemTools::CollapseFullPath(executable.c_str());
+        }
+      } 
+    } 
+
+  // Couldn't find app bundle
+  return "";
+}
+
+std::string cmFindProgramCommand::GetBundleExecutable(std::string bundlePath)
+{
+  std::string executable = "";
+
+#if defined(__APPLE__)
+  // Started with an example on developer.apple.com about finding bundles 
+  // and modified from that.
+  
+  // Get a CFString of the app bundle path
+  // XXX - Is it safe to assume everything is in UTF8?
+  CFStringRef bundlePathCFS = CFStringCreateWithCString(kCFAllocatorDefault , 
+                                                        bundlePath.c_str(), kCFStringEncodingUTF8 );
+  
+  // Make a CFURLRef from the CFString representation of the bundle’s path.
+  CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 
+                                                     bundlePathCFS,
+                                                     kCFURLPOSIXPathStyle,
+                                                     true );
+  
+  // Make a bundle instance using the URLRef.
+  CFBundleRef appBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
+  
+  // returned executableURL is relative to <appbundle>/Contents/MacOS/
+  CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
+  
+  if (executableURL != NULL)
+    {
+    const int MAX_OSX_PATH_SIZE = 1024;
+    char buffer[MAX_OSX_PATH_SIZE];
+    
+    // Convert the CFString to a C string
+    CFStringGetCString( CFURLGetString(executableURL), buffer, MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8 );
+    
+    // And finally to a c++ string
+    executable = bundlePath + "/Contents/MacOS/" + std::string(buffer);
+    }
+
+  // Any CF objects returned from functions with "create" or 
+  // "copy" in their names must be released by us!
+  CFRelease( bundlePathCFS );
+  CFRelease( bundleURL );
+  CFRelease( appBundle );
+  CFRelease( executableURL );
+#endif
+
+  return executable;
+}
+

+ 8 - 0
Source/cmFindProgramCommand.h

@@ -64,6 +64,14 @@ public:
     }
     }
   
   
   cmTypeMacro(cmFindProgramCommand, cmFindBase);
   cmTypeMacro(cmFindProgramCommand, cmFindBase);
+
+protected:
+  std::string FindProgram(std::vector<std::string> names);
+
+private:
+  std::string FindAppBundle(std::vector<std::string> names);
+  std::string GetBundleExecutable(std::string bundlePath);
+
 };
 };
 
 
 
 

+ 48 - 7
Source/kwsys/SystemTools.cxx

@@ -1877,13 +1877,17 @@ size_t SystemTools::GetMaximumFilePathLength()
  * found.  Otherwise, the empty string is returned.
  * found.  Otherwise, the empty string is returned.
  */
  */
 kwsys_stl::string SystemTools
 kwsys_stl::string SystemTools
-::FindFile(const char* name,
-           const kwsys_stl::vector<kwsys_stl::string>& userPaths)
+::FindName(const char* name,
+           const kwsys_stl::vector<kwsys_stl::string>& userPaths,
+           bool no_system_path)
 {
 {
   // Add the system search path to our path first
   // Add the system search path to our path first
   kwsys_stl::vector<kwsys_stl::string> path;
   kwsys_stl::vector<kwsys_stl::string> path;
-  SystemTools::GetPath(path, "CMAKE_FILE_PATH");
-  SystemTools::GetPath(path);
+  if (!no_system_path) 
+    {
+    SystemTools::GetPath(path, "CMAKE_FILE_PATH");
+    SystemTools::GetPath(path);
+    }
   // now add the additional paths
   // now add the additional paths
   for(kwsys_stl::vector<kwsys_stl::string>::const_iterator i = userPaths.begin();
   for(kwsys_stl::vector<kwsys_stl::string>::const_iterator i = userPaths.begin();
         i != userPaths.end(); ++i)
         i != userPaths.end(); ++i)
@@ -1898,16 +1902,53 @@ kwsys_stl::string SystemTools
     tryPath = *p;
     tryPath = *p;
     tryPath += "/";
     tryPath += "/";
     tryPath += name;
     tryPath += name;
-    if(SystemTools::FileExists(tryPath.c_str()) &&
-      !SystemTools::FileIsDirectory(tryPath.c_str()))
+    if(SystemTools::FileExists(tryPath.c_str()))
       {
       {
-      return SystemTools::CollapseFullPath(tryPath.c_str());
+      return tryPath;
       }
       }
     }
     }
   // Couldn't find the file.
   // Couldn't find the file.
   return "";
   return "";
 }
 }
 
 
+/**
+ * Find the file the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the file if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+kwsys_stl::string SystemTools
+::FindFile(const char* name,
+           const kwsys_stl::vector<kwsys_stl::string>& userPaths,
+           bool no_system_path)
+{
+  kwsys_stl::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  if(tryPath != "" && !SystemTools::FileIsDirectory(tryPath.c_str()))
+    {
+    return SystemTools::CollapseFullPath(tryPath.c_str());
+    }
+  // Couldn't find the file.
+  return "";
+}
+
+/**
+ * Find the directory the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the directory if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+kwsys_stl::string SystemTools
+::FindDirectory(const char* name,
+                const kwsys_stl::vector<kwsys_stl::string>& userPaths,
+                bool no_system_path)
+{
+  kwsys_stl::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  if(tryPath != "" && SystemTools::FileIsDirectory(tryPath.c_str()))
+    {
+    return SystemTools::CollapseFullPath(tryPath.c_str());
+    }
+  // Couldn't find the file.
+  return "";
+}
+
 /**
 /**
  * Find the executable with the given name.  Searches the given path and then
  * Find the executable with the given name.  Searches the given path and then
  * the system search path.  Returns the full path to the executable if it is
  * the system search path.  Returns the full path to the executable if it is

+ 22 - 1
Source/kwsys/SystemTools.hxx.in

@@ -495,7 +495,17 @@ public:
   static kwsys_stl::string FindFile(
   static kwsys_stl::string FindFile(
     const char* name,
     const char* name,
     const kwsys_stl::vector<kwsys_stl::string>& path = 
     const kwsys_stl::vector<kwsys_stl::string>& path = 
-    kwsys_stl::vector<kwsys_stl::string>());
+    kwsys_stl::vector<kwsys_stl::string>(),
+    bool no_system_path = false);
+
+  /**
+   * Find a directory in the system PATH, with optional extra paths
+   */
+  static kwsys_stl::string FindDirectory(
+    const char* name,
+    const kwsys_stl::vector<kwsys_stl::string>& path = 
+    kwsys_stl::vector<kwsys_stl::string>(),
+    bool no_system_path = false);
 
 
   /**
   /**
    * Find an executable in the system PATH, with optional extra paths
    * Find an executable in the system PATH, with optional extra paths
@@ -762,6 +772,17 @@ private:
     return &SystemToolsManagerInstance;
     return &SystemToolsManagerInstance;
     }
     }
 
 
+  /**
+   * Find a filename (file or directory) in the system PATH, with
+   * optional extra paths.
+   */
+  static kwsys_stl::string FindName(
+    const char* name,
+    const kwsys_stl::vector<kwsys_stl::string>& path = 
+    kwsys_stl::vector<kwsys_stl::string>(),
+    bool no_system_path = false);
+
+
   /**
   /**
    * Path translation table from dir to refdir
    * Path translation table from dir to refdir
    * Each time 'dir' will be found it will be replace by 'refdir'
    * Each time 'dir' will be found it will be replace by 'refdir'

+ 17 - 3
bootstrap

@@ -35,6 +35,13 @@ else
   cmake_system_mingw=false
   cmake_system_mingw=false
 fi
 fi
 
 
+# Determine whether this is OS X
+if echo "${cmake_system}" | grep Darwin >/dev/null 2>&1; then
+  cmake_system_darwin=true
+else
+  cmake_system_darwin=false
+fi
+
 # Choose the generator to use for bootstrapping.
 # Choose the generator to use for bootstrapping.
 if ${cmake_system_mingw}; then
 if ${cmake_system_mingw}; then
   # Bootstrapping from an MSYS prompt.
   # Bootstrapping from an MSYS prompt.
@@ -509,6 +516,13 @@ rm -f "${cmake_bootstrap_dir}/cmConfigure.h.tmp"
 cmake_c_flags=${CFLAGS}
 cmake_c_flags=${CFLAGS}
 cmake_cxx_flags=${CXXFLAGS}
 cmake_cxx_flags=${CXXFLAGS}
 
 
+# Add Carbon framework on Darwin
+if ${cmake_system_darwin}; then
+  cmake_ld_flags="${LDFLAGS} -framework Carbon"  
+else
+  cmake_ld_flags=${LDFLAGS}
+fi
+
 # Test C compiler
 # Test C compiler
 cmake_c_compiler=
 cmake_c_compiler=
 
 
@@ -1162,7 +1176,7 @@ cmake_c_flags="${cmake_c_flags}-I`cmake_escape \"${cmake_source_dir}/Source\"` \
 cmake_cxx_flags="${cmake_cxx_flags}-I`cmake_escape \"${cmake_source_dir}/Source\"` \
 cmake_cxx_flags="${cmake_cxx_flags}-I`cmake_escape \"${cmake_source_dir}/Source\"` \
   -I`cmake_escape \"${cmake_bootstrap_dir}\"`"
   -I`cmake_escape \"${cmake_bootstrap_dir}\"`"
 echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile"
 echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile"
-echo "	${cmake_cxx_compiler} ${LDFLAGS} ${cmake_cxx_flags} ${objs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile"
+echo "	${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile"
 for a in ${CMAKE_CXX_SOURCES}; do
 for a in ${CMAKE_CXX_SOURCES}; do
   src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"`
   src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"`
   echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
@@ -1190,9 +1204,9 @@ if ${cmake_system_mingw}; then
   cmd=`cmake_escape "${cmake_bootstrap_dir}/cmsysEncodeExecutable.exe"`
   cmd=`cmake_escape "${cmake_bootstrap_dir}/cmsysEncodeExecutable.exe"`
   a="cmsysProcessFwd9xEnc"
   a="cmsysProcessFwd9xEnc"
   echo "${cmd} : EncodeExecutable.o" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${cmd} : EncodeExecutable.o" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_c_compiler} ${LDFLAGS} ${cmake_c_flags} EncodeExecutable.o -o ${cmd}" >> "${cmake_bootstrap_dir}/Makefile"
+  echo "	${cmake_c_compiler} ${cmake_ld_flags} ${cmake_c_flags} EncodeExecutable.o -o ${cmd}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${in} : ProcessFwd9x.o" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${in} : ProcessFwd9x.o" >> "${cmake_bootstrap_dir}/Makefile"
-  echo "	${cmake_c_compiler} ${LDFLAGS} ${cmake_c_flags} ProcessFwd9x.o -o ${in}" >> "${cmake_bootstrap_dir}/Makefile"
+  echo "	${cmake_c_compiler} ${cmake_ld_flags} ${cmake_c_flags} ProcessFwd9x.o -o ${in}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${src} : ${cmd} ${in}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${src} : ${cmd} ${in}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "	${cmd} ${in} ${src} cmsys ProcessFwd9x" >> "${cmake_bootstrap_dir}/Makefile"
   echo "	${cmd} ${in} ${src} cmsys ProcessFwd9x" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"
   echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile"