瀏覽代碼

ENH: check in new find stuff

Bill Hoffman 19 年之前
父節點
當前提交
a5825cd11a

+ 1 - 0
Modules/Platform/CYGWIN.cmake

@@ -27,3 +27,4 @@ SET(CMAKE_C_CREATE_SHARED_LIBRARY
   "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> <OBJECTS> <LINK_LIBRARIES>")
 SET(CMAKE_CXX_CREATE_SHARED_LIBRARY
   "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> <OBJECTS> <LINK_LIBRARIES>")
+INCLUDE(Platform/UnixPaths)

+ 3 - 0
Modules/Platform/Darwin.cmake

@@ -46,3 +46,6 @@ SET(CMAKE_SYSTEM_FRAMEWORK_PATH
   /Network/Library/Frameworks
   /System/Library/Frameworks)
 
+INCLUDE(Platform/UnixPaths)
+SET(CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH} /sw/include)
+SET(CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} /sw/lib)

+ 1 - 0
Modules/Platform/Linux.cmake

@@ -7,3 +7,4 @@ SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
 SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
 SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
 SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
+INCLUDE(Platform/UnixPaths)

+ 1 - 0
Modules/Platform/SunOS.cmake

@@ -60,3 +60,4 @@ ELSE(CMAKE_COMPILER_IS_GNUCXX)
       "<CMAKE_RANLIB> <TARGET> ")
   ENDIF(CMAKE_CXX_COMPILER)
 ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+INCLUDE(Platform/UnixPaths)

+ 5 - 0
Modules/Platform/UnixPaths.cmake

@@ -0,0 +1,5 @@
+SET(CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH} /usr/include  
+  /usr/local/include /usr/local /usr/X11R6/include /usr/include/X11)
+SET(CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} /lib /use/lib /usr/local/lib 
+  /usr/lib/w32api /usr/X11R6/lib /opt/local/lib /opt/csw/lib /opt/lib )
+SET(CMAKE_SYSTEM_PROGRAM_PATH ${CMAKE_SYSTEM_PROGRAM_PATH} /bin /usr/bin /usr/local/bin /sbin)

+ 1 - 0
Modules/Platform/Windows-cl.cmake

@@ -231,3 +231,4 @@ IF(NOT EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeCXXPlatform.cmake")
                ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeCXXPlatform.cmake IMMEDIATE)
 ENDIF(NOT EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeCXXPlatform.cmake")
 
+INCLUDE(Platform/WindowsPaths)

+ 3 - 0
Modules/Platform/WindowsPaths.cmake

@@ -0,0 +1,3 @@
+SET(CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH}  "$ENV{ProgramFiles}")
+SET(CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} "$ENV{ProgramFiles}")
+SET(CMAKE_SYSTEM_PROGRAM_PATH ${CMAKE_SYSTEM_PROGRAM_PATH} "$ENV{ProgramFiles}")

+ 1 - 0
Source/cmBootstrapCommands.cxx

@@ -37,6 +37,7 @@
 #include "cmEndForEachCommand.cxx"
 #include "cmEndIfCommand.cxx"
 #include "cmExecProgramCommand.cxx"
+#include "cmFindBase.cxx"
 #include "cmFileCommand.cxx"
 #include "cmFindFileCommand.cxx"
 #include "cmFindLibraryCommand.cxx"

+ 61 - 4
Source/cmFindBase.cxx

@@ -31,8 +31,68 @@ cmFindBase::cmFindBase()
 #endif
   this->SearchFrameworkOnly = false;
   this->SearchFrameworkLast = false;
+  this->GenericDocumentation = 
+    "   FIND_XXX(<VAR> name1 path1 path2 ...)\n"
+    "This is the short-hand signature for the command that"
+    "is sufficient in many cases.  It is the same "
+    "as FIND_XXX(<VAR> NAMES name1 PATHS path2 path2 ...)\n"
+    "   FIND_XXX(\n"
+    "             <VAR> \n"
+    "             NAMES name1 [name2 ...]\n"
+    "             PATHS path1 [path2 ...]\n"
+    "             [PATH_SUFFIXES suffix1 [suffix2 ...]]\n"
+    "             [DOC \"cache documentation string\"]\n"
+    "             [NO_CMAKE_ENVIRONMENT_PATH]\n"
+    "             [NO_CMAKE_PATH]\n"
+    "             [NO_SYSTEM_PATH]\n"
+    "             [NO_CMAKE_SYSTEM_PATH]\n"
+    "            )\n"
+    ""
+    "This command is used to find a SEARCH_XXX_DESC. "
+    "A cache entry named by <VAR> is created to store the result "
+    "of this command.  If nothing is found, the result will be "
+    "<VAR>-NOTFOUND.  The name of the SEARCH_XXX that "
+    "is searched for is specified by the names listed "
+    "after the NAMES argument.   Additional search locations "
+    "can be specified after the PATHS arguement.  The arguement "
+    "after DOC will be used for the documentation string in "
+    "the cache.  PATH_SUFFIXES can be used to give sub directories "
+    "that will be appeneded to the search paths.\n"
+    "The search process is as follows:\n"
+    "1. Search cmake specific environment varibles.  This "
+    "can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
+    ""
+    "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_XXX_PATH\n"
+    "2. Search cmake variables with the same names as "
+    "the cmake specific environment variables.  These "
+    "are intended to be used on the command line with a "
+    "-DVAR=value.  This can be skipped if NO_CMAKE_PATH "
+    "is passed.\n"
+    ""
+    "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_XXX_PATH\n"
+    "3. Search the standard system environment variables. "
+    "This can be skipped if NO_SYSTEM_PATH is an argument.\n"
+    "   PATH\n"
+    "   XXX_SYSTEM\n"  // replace with "", LIB, or INCLUDE
+    "4. Search cmake variables defined in the Platform files "
+    "for the current system. This can be skipped if NO_CMAKE_SYSTEM_PATH "
+    "is passed.\n"
+    "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
+    "   CMAKE_SYSTEM_XXX_PATH\n"
+    "5. Search the paths specified after PATHS or in the short-hand version "
+    "of the command.\n"
+    "On Darwin or systems supporting OSX Frameworks, the cmake variable"
+    "    CMAKE_FIND_FRAMEWORK can be set to empty or one of the following:\n"
+    "   \"FIRST\"  - Try to find frameworks before standard\n"
+    "              libraries or headers. This is the default on Darwin.\n"
+    "   \"LAST\"   - Try to find frameworks after standard\n"
+    "              librareis or headers.\n"
+    "   \"ONLY\"   - Only try to find frameworks.\n"
+    "   \"NEVER\". - Never try to find frameworks.\n";
 }
-
+  
 bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
 {
   if(argsIn.size() < 2 )
@@ -162,7 +222,6 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
   // FIND_*(VAR name path1 path2 ...)
   if(!newStyle)
     {
-    std::cerr << "oldstyle\n";
     this->Names.push_back(args[1]);
     for(unsigned int j = 2; j < args.size(); ++j)
       {
@@ -355,7 +414,6 @@ void cmFindBase::PrintFindStuff()
 
 bool cmFindBase::CheckForVariableInCache()
 {
-  std::cerr << "CheckForVariableInCache " << this->VariableName << "\n";
   const char* cacheValue
     = m_Makefile->GetDefinition(this->VariableName.c_str());
   if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
@@ -364,7 +422,6 @@ bool cmFindBase::CheckForVariableInCache()
     }
   if(cacheValue)
     {
-    std::cerr << "Cachevalue " << cacheValue << "\n";
     cmCacheManager::CacheIterator it = 
       m_Makefile->GetCacheManager()->GetCacheIterator(this->VariableName.c_str());
     if(!it.IsAtEnd())

+ 5 - 0
Source/cmFindBase.h

@@ -35,6 +35,10 @@ public:
    */
   virtual bool ParseArguments(std::vector<std::string> const& args);
   cmTypeMacro(cmFindBase, cmCommand);
+  
+  virtual const char* GetFullDocumentation()
+    {return this->GenericDocumentation.c_str();}
+
 protected:
   void PrintFindStuff();
   void ExpandPaths(std::vector<std::string> userPaths);
@@ -48,6 +52,7 @@ protected:
   // if it has documentation in the cache
   bool CheckForVariableInCache();
   
+  cmStdString GenericDocumentation;
   // use by command during find
   cmStdString VariableDocumentation;
   cmStdString VariableName;

+ 9 - 77
Source/cmFindFileCommand.cxx

@@ -15,83 +15,15 @@
 
 =========================================================================*/
 #include "cmFindFileCommand.h"
-#include "cmCacheManager.h"
-#include "cmGlob.h"
-#include <stdlib.h>
-  
+#include "cmSystemTools.h"
 
-// cmFindFileCommand
-bool cmFindFileCommand::InitialPass(std::vector<std::string> const& argsIn)
+cmFindFileCommand::cmFindFileCommand()
 {
-  if(argsIn.size() < 2)
-    {
-    this->SetError("called with incorrect number of arguments");
-    return false;
-    }
-  std::string helpString = "Where can the ";
-  helpString += argsIn[1] + " file be found";
-  size_t size = argsIn.size();
-  std::vector<std::string> args;
-  for(unsigned int j = 0; j < size; ++j)
-    {
-    if(argsIn[j] != "DOC")
-      {
-      args.push_back(argsIn[j]);
-      }
-    else
-      {
-      if(j+1 < size)
-        {
-        helpString = argsIn[j+1];
-        }
-      break;
-      }
-    }
-
-  std::vector<std::string>::const_iterator i = args.begin();
-  // Use the first argument as the name of something to be defined
-  const char* define = (*i).c_str();
-  i++; // move iterator to next arg
-  // Now check and see if the value has been stored in the cache
-  // already, if so use that value and don't look for the program
-  const char* cacheValue
-    = m_Makefile->GetDefinition(define);
-  if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
-    {
-    return true;
-    }
-
-  // The location is not in the cache.  Create a search path.
-  std::vector<std::string> path;
-  std::vector<std::string> callPaths;
-  for (unsigned int j = 2; j < args.size(); j++)
-    {
-    // Glob the entry in case of wildcards.
-    cmSystemTools::GlobDirs(args[j].c_str(), callPaths);
-    }
-  m_Makefile->GetLibrarySearchPath(callPaths, path);
-
-  // Use the search path to find the file.
-  for(unsigned int k=0; k < path.size(); k++)
-    {
-    std::string tryPath = path[k];
-    tryPath += "/";
-    tryPath += *i;
-    if(cmSystemTools::FileExists(tryPath.c_str()))
-      {
-      // Save the value in the cache
-      m_Makefile->AddCacheDefinition(define,
-                                     tryPath.c_str(),
-                                     helpString.c_str(),
-                                     cmCacheManager::FILEPATH);
-      return true;
-      }
-    }
-  std::string s = args[0] + "-NOTFOUND";
-  m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                 s.c_str(),
-                                 helpString.c_str(),
-                                 cmCacheManager::FILEPATH);
-  return true;
+  this->IncludeFileInPath = true;
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "FIND_PATH", "FIND_FILE");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "directory containing the named file", "full path to named file");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                                "file in a directory", "full path to a file");
 }
-

+ 4 - 35
Source/cmFindFileCommand.h

@@ -17,7 +17,7 @@
 #ifndef cmFindFileCommand_h
 #define cmFindFileCommand_h
 
-#include "cmCommand.h"
+#include "cmFindPathCommand.h"
 
 /** \class cmFindFileCommand
  * \brief Define a command to search for an executable program.
@@ -27,9 +27,10 @@
  * in the current path (e.g., PATH environment variable) for
  * an executable that matches one of the supplied names.
  */
-class cmFindFileCommand : public cmCommand
+class cmFindFileCommand : public cmFindPathCommand
 {
 public:
+  cmFindFileCommand();
   /**
    * This is a virtual constructor for the command.
    */
@@ -37,21 +38,6 @@ public:
     {
     return new cmFindFileCommand;
     }
-
-  /**
-   * This is called when the command is first encountered in
-   * the CMakeLists.txt file.
-   */
-  virtual bool InitialPass(std::vector<std::string> const& args);
-
-  /**
-   * This determines if the command is invoked when in script mode.
-   */
-  virtual bool IsScriptable() { return true; }
-
-  /**
-   * The name of the command as specified in CMakeList.txt.
-   */
   virtual const char* GetName() { return "FIND_FILE";}
 
   /**
@@ -62,24 +48,7 @@ public:
     return "Find the full path to a file.";
     }
   
-  /**
-   * More documentation.
-   */
-  virtual const char* GetFullDocumentation()
-    {
-    return
-      "  FIND_FILE(<VAR> fileName path1 [path2 ...]\n"
-      "            [DOC \"docstring\"])\n"
-      "Find the full path to a file named by fileName.  Paths "
-      "are searched in the order specified.  A cache entry named by "
-      "<VAR> is created to store the result.  If the file is not "
-      "found, the result will be <VAR>-NOTFOUND.  If DOC is specified "
-      "then the next argument is treated as a documentation string for "
-      "the cache entry <VAR>.  Note that since executables can have "
-      "different extensions on different platforms, FIND_PROGRAM "
-      "should be used instead of FIND_FILE when looking for them.";
-    }
-  cmTypeMacro(cmFindFileCommand, cmCommand);
+  cmTypeMacro(cmFindFileCommand, cmFindPathCommand);
 };
 
 

+ 155 - 102
Source/cmFindLibraryCommand.cxx

@@ -17,129 +17,182 @@
 #include "cmFindLibraryCommand.h"
 #include "cmCacheManager.h"
 
+cmFindLibraryCommand::cmFindLibraryCommand()
+{ 
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "FIND_XXX", "FIND_LIBRARY");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_PATH", "CMAKE_LIBRARY_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "XXX_SYSTEM", "LIB");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_PATH", "CMAKE_SYSTEM_LIBRARY_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX_DESC", "library");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX", "library");
+  this->GenericDocumentation += 
+    "\n"
+    "If the library found is a framework, then VAR will be set to the "
+    "the full path to the framework <fullPath>/A.framework. "
+    "When a full path to a framework is used as a library, "
+    "CMake will use a -framework A, and a -F<fullPath> to "
+    "link the framework to the target. ";
+}
+
 // cmFindLibraryCommand
 bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  if(argsIn.size() < 2)
+  this->VariableDocumentation = "Path to a library.";
+  this->CMakePathName = "LIBRARY";
+  if(!this->ParseArguments(argsIn))
     {
-    this->SetError("called with incorrect number of arguments");
     return false;
-    } 
-  std::string helpString;
-  size_t size = argsIn.size();
-  std::vector<std::string> args;
-  for(unsigned int j = 0; j < size; ++j)
+    }
+  if(this->AlreadyInCache)
     {
-    if(argsIn[j] != "DOC")
-      {
-      args.push_back(argsIn[j]);
-      }
-    else
-      {
-      if(j+1 < size)
-        {
-        helpString = argsIn[j+1];
-        }
-      break;
-      }
+    return true;
     }
+  // add special 64 bit paths if this is a 64 bit compile.
+  this->AddLib64Paths();
+  std::string library;
+  for(std::vector<std::string>::iterator i = this->Names.begin();
+      i != this->Names.end() ; ++i)
+    {
+    library = this->FindLibrary(i->c_str());
+    if(library != "")
+      {  
+      m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                     library.c_str(),
+                                     this->VariableDocumentation.c_str(),
+                                     cmCacheManager::FILEPATH);
+      return true;
+      } 
+    }
+  std::string notfound = this->VariableName + "-NOTFOUND";
+  m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                 notfound.c_str(),
+                                 this->VariableDocumentation.c_str(),
+                                 cmCacheManager::FILEPATH);
+  return true;
+}
+
 
-  std::vector<std::string> path;
-  std::vector<std::string> names;
-  bool foundName = false;
-  bool foundPath = false;
-  bool doingNames = true;
-  for (unsigned int j = 1; j < args.size(); ++j)
+void cmFindLibraryCommand::AddLib64Paths()
+{  
+  if(!m_Makefile->GetLocalGenerator()->GetGlobalGenerator()->GetLanguageEnabled("C"))
+    {
+    return;
+    }
+  std::string voidsize = m_Makefile->GetRequiredDefinition("CMAKE_SIZEOF_VOID_P");
+  int size = atoi(voidsize.c_str());
+  std::vector<std::string> path64;
+  if(size != 8)
     {
-    if(args[j] == "NAMES")
+    return;
+    }
+  bool found64 = false;
+  for(std::vector<std::string>::iterator i = this->SearchPaths.begin(); 
+      i != this->SearchPaths.end(); ++i)
+    {
+    std::string s = *i;
+    std::string s2 = *i;
+    cmSystemTools::ReplaceString(s, "lib/", "lib64/");
+    // try to replace lib with lib64 and see if it is there,
+    // then prepend it to the path
+    if((s != *i) && cmSystemTools::FileIsDirectory(s.c_str()))
       {
-      doingNames = true;
-      foundName = true;
-      }
-    else if (args[j] == "PATHS")
+      path64.push_back(s);
+      found64 = true;
+      }  
+    // now just add a 64 to the path name and if it is there,
+    // add it to the path
+    s2 += "64";
+    if(cmSystemTools::FileIsDirectory(s2.c_str()))
       {
-      doingNames = false;
-      foundPath = true;
-      }
-    else
-      { 
-      if(doingNames)
-        {
-        names.push_back(args[j]);
-        }
-      else
-        {
-        cmSystemTools::ExpandRegistryValues(args[j]);
-        // Glob the entry in case of wildcards.
-        cmSystemTools::GlobDirs(args[j].c_str(), path);
-        }
+      found64 = true;
+      path64.push_back(s2);
+      } 
+    // now add the original unchanged path
+    if(cmSystemTools::FileIsDirectory(i->c_str()))
+      {
+      path64.push_back(*i);
       }
     }
-  // old style name path1 path2 path3
-  if(!foundPath && !foundName)
+  // now replace the SearchPaths with the 64 bit converted path
+  // if any 64 bit paths were discovered
+  if(found64)
     {
-    names.clear();
-    path.clear();
-    names.push_back(args[1]);
-    // add any user specified paths
-    for (unsigned int j = 2; j < args.size(); j++)
-      {
-      // expand variables
-      std::string exp = args[j];
-      cmSystemTools::ExpandRegistryValues(exp);
-      
-      // Glob the entry in case of wildcards.
-      cmSystemTools::GlobDirs(exp.c_str(), path);
-      }
+    this->SearchPaths = path64;
     }
-  if(helpString.size() == 0)
+}
+
+std::string cmFindLibraryCommand::FindLibrary(const char* name)
+{
+  bool supportFrameworks = false;
+  bool onlyFrameworks = false;
+  std::string ff = m_Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
+  if(ff == "FIRST" || ff == "LAST")
     {
-    helpString = "Where can ";
-    if (names.size() == 0)
-      {
-      helpString += "the (unknown) library be found";
-      }
-    else if (names.size() == 1)
+    supportFrameworks = true;
+    }
+  if(ff == "ONLY")
+    {
+    onlyFrameworks = true;
+    supportFrameworks = true;
+    }
+  
+  const char* prefixes_list =
+    m_Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
+  const char* suffixes_list =
+    m_Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_SUFFIXES");
+  std::vector<std::string> prefixes;
+  std::vector<std::string> suffixes;
+  cmSystemTools::ExpandListArgument(prefixes_list, prefixes, true);
+  cmSystemTools::ExpandListArgument(suffixes_list, suffixes, true);
+  std::string tryPath;
+  for(std::vector<std::string>::const_iterator p = this->SearchPaths.begin();
+      p != this->SearchPaths.end(); ++p)
+    {
+    if(supportFrameworks)
       {
-      helpString += "the " + names[0] + " library be found";
+      tryPath = *p;
+      tryPath += "/";
+      tryPath += name;
+      tryPath += ".framework";
+      if(cmSystemTools::FileExists(tryPath.c_str())
+         && cmSystemTools::FileIsDirectory(tryPath.c_str()))
+        {
+        tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
+        cmSystemTools::ConvertToUnixSlashes(tryPath);
+        return tryPath;
+        }
       }
-    else
+    if(!onlyFrameworks)
       {
-      helpString += "one of the " + names[0];
-      for (unsigned int j = 1; j < names.size() - 1; ++j)
+      // Try various library naming conventions.
+      for(std::vector<std::string>::iterator prefix = prefixes.begin();
+          prefix != prefixes.end(); ++prefix)
         {
-        helpString += ", " + names[j];
+        for(std::vector<std::string>::iterator suffix = suffixes.begin();
+            suffix != suffixes.end(); ++suffix)
+          {
+          tryPath = *p;
+          tryPath += "/";
+          tryPath += *prefix;
+          tryPath += name;
+          tryPath += *suffix;
+          if(cmSystemTools::FileExists(tryPath.c_str())
+             && !cmSystemTools::FileIsDirectory(tryPath.c_str()))
+            {
+            tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
+            cmSystemTools::ConvertToUnixSlashes(tryPath);
+            return tryPath;
+            }
+          }
         }
-      helpString += " or " + names[names.size() - 1] + " libraries be found";
       }
     }
-  
-  const char* cacheValue
-    = m_Makefile->GetDefinition(args[0].c_str());
-  if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
-    { 
-    return true;
-    }
-
-  std::string library;
-  for(std::vector<std::string>::iterator i = names.begin();
-      i != names.end() ; ++i)
-    {
-    library = m_Makefile->FindLibrary(i->c_str(), path);
-    if(library != "")
-      {  
-      m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                     library.c_str(),
-                                     helpString.c_str(),
-                                     cmCacheManager::FILEPATH);
-      return true;
-      } 
-    }
-  std::string s = args[0] + "-NOTFOUND";
-  m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                 s.c_str(),
-                                 helpString.c_str(),
-                                 cmCacheManager::FILEPATH);
-  return true;
+  // Couldn't find the library.
+  return "";
 }
-

+ 7 - 29
Source/cmFindLibraryCommand.h

@@ -17,7 +17,7 @@
 #ifndef cmFindLibraryCommand_h
 #define cmFindLibraryCommand_h
 
-#include "cmCommand.h"
+#include "cmFindBase.h"
 
 
 /** \class cmFindLibraryCommand
@@ -27,9 +27,10 @@
  * that specifies a library. The command searches for a given
  * file in a list of directories.
  */
-class cmFindLibraryCommand : public cmCommand
+class cmFindLibraryCommand : public cmFindBase
 {
 public:
+  cmFindLibraryCommand();
   /**
    * This is a virtual constructor for the command.
    */
@@ -61,34 +62,11 @@ public:
     {
     return "Find a library.";
     }
+  cmTypeMacro(cmFindLibraryCommand, cmFindBase);
   
-  /**
-   * More documentation.
-   */
-  virtual const char* GetFullDocumentation()
-    {
-    return
-      "  FIND_LIBRARY(<VAR> NAMES name1 [name2 ...]\n"
-      "               [PATHS path1 path2 ...]\n"
-      "               [DOC \"docstring\"])\n"
-      "Find a library named by one of the names given after the NAMES "
-      "argument.  A cache entry named by <VAR> is created "
-      "to store the result.  If the library is not found, the result "
-      "will be <VAR>-NOTFOUND.  If DOC is specified then the next "
-      "argument is treated as a documentation string for the cache "
-      "entry <VAR>.\n"
-      "  FIND_LIBRARY(VAR libraryName [path1 path2 ...])\n"
-      "Find a library with the given name by searching in the specified "
-      "paths.  This is a short-hand signature for the command that is "
-      "sufficient in many cases.  "
-      "The search proceeds first in paths listed in the CMAKE_LIBRARY_PATH "
-      "CMake variable (which is generally set by the user on the command line), "
-      "then in paths listed in the CMAKE_LIBRARY_PATH environment variable, "
-      "then in paths given to the PATHS option of the command, "
-      "and finally in paths listed in the PATH environment variable.";
-    }
-  
-  cmTypeMacro(cmFindLibraryCommand, cmCommand);
+protected:
+  void AddLib64Paths();\
+  std::string FindLibrary(const char* name);
 };
 
 

+ 107 - 106
Source/cmFindPathCommand.cxx

@@ -17,123 +17,123 @@
 #include "cmFindPathCommand.h"
 #include "cmCacheManager.h"
 
+
+cmFindPathCommand::cmFindPathCommand()
+{
+  this->IncludeFileInPath = false;
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "FIND_XXX", "FIND_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_PATH", "CMAKE_INCLUDE_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "XXX_SYSTEM", "INCLUDE");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_PATH", "CMAKE_SYSTEM_INCLUDE_PATH"); 
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX_DESC", "directory containing the named file");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX", "file in a directory");
+  this->ExtraDocAdded = false;
+}
+
+const char* cmFindPathCommand::GetFullDocumentation()
+{
+  if(!this->ExtraDocAdded && !this->IncludeFileInPath)
+    {
+    this->GenericDocumentation += 
+      "\n"
+      "When searching for frameworks, if the file is specified as "
+      "A/b.h, then the framework search will look for A.framework/Headers/b.h. "
+      "If that is found the path will be set to the path to the framework. "
+      "CMake will convert this to the correct -F option to include the file. ";
+    this->ExtraDocAdded = true;
+    }
+  return this->GenericDocumentation.c_str();
+}
+
 // cmFindPathCommand
 bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  if(argsIn.size() < 2)
+  this->VariableDocumentation = "Path to a file.";
+  this->CMakePathName = "INCLUDE";
+  if(!this->ParseArguments(argsIn))
     {
-    this->SetError("called with incorrect number of arguments");
     return false;
     }
-
-  // Now check and see if the value has been stored in the cache
-  // already, if so use that value and don't look for the program
-  std::string helpString = "What is the path where the file ";
-  helpString += argsIn[1] + " can be found";
-  std::vector<std::string> args;
-  size_t size = argsIn.size();
-  for(unsigned int j = 0; j < size; ++j)
+  if(this->AlreadyInCache)
     {
-    if(argsIn[j] != "DOC")
-      {
-      args.push_back(argsIn[j]);
-      }
-    else
-      {
-      if(j+1 < size)
-        {
-        helpString = argsIn[j+1];
-        }
-      break;
-      }
-    }
-
-  const char* cacheValue
-    = m_Makefile->GetDefinition(args[0].c_str());
-  if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
-    { 
     return true;
     }
-  if(cacheValue)
-    {
-    cmCacheManager::CacheIterator it = 
-      m_Makefile->GetCacheManager()->GetCacheIterator(args[0].c_str());
-    if(!it.IsAtEnd())
-      {
-      const char* hs = it.GetProperty("HELPSTRING");
-      helpString = hs?hs:"(none)";
-      }
-    }
-
-  // Construct a search path.
-  std::vector<std::string> path;
-  std::vector<std::string> callPaths;
-  for (unsigned int j = 2; j < args.size(); j++)
+  std::string ff = m_Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
+  bool supportFrameworks = true;
+  if( ff.size() == 0 || ff == "NEVER" )
     {
-    // expand variables
-    std::string exp = args[j];
-    cmSystemTools::ExpandRegistryValues(exp);
-
-    // Glob the entry in case of wildcards.
-    cmSystemTools::GlobDirs(exp.c_str(), callPaths);
+    supportFrameworks = false;
     }
-  m_Makefile->GetIncludeSearchPath(callPaths, path);
-
+  std::string framework;
   // Use the search path to find the file.
   unsigned int k;
-  for(k=0; k < path.size(); k++)
+  std::string result;
+  for(k=0; k < this->SearchPaths.size(); k++)
     {
-    std::string tryPath = path[k];
-    tryPath += "/";
-    tryPath += args[1];
-    if(cmSystemTools::FileExists(tryPath.c_str()))
+    for(unsigned int j =0; j < this->Names.size(); ++j)
       {
-      path[k] = cmSystemTools::CollapseFullPath(path[k].c_str()); 
-      if(path[k].size() && path[k][path[k].size()-1] == '/')
+      // if frameworks are supported try to find the header in a framework
+      std::string tryPath;
+      if(supportFrameworks)
+        {
+        tryPath = this->FindHeaderInFramework(this->Names[j],
+                                              this->SearchPaths[k]);
+        if(tryPath.size())
+          {
+          result = tryPath;
+          }
+        }
+      if(result.size() == 0)
         {
-        path[k] = path[k].substr(0, path[k].size()-1);
+        tryPath = this->SearchPaths[k];
+        tryPath += "/";
+        tryPath += this->Names[j];
+        if(cmSystemTools::FileExists(tryPath.c_str()))
+          {
+          if(this->IncludeFileInPath)
+            {
+            result = tryPath;
+            }
+          else
+            {
+            result = this->SearchPaths[k];
+            }
+          }
+        }
+      if(result.size() != 0)
+        {
+        m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                       result.c_str(),
+                                       this->VariableDocumentation.c_str(),
+                                       (this->IncludeFileInPath) ? 
+                                       cmCacheManager::FILEPATH :cmCacheManager::PATH);
+        return true;
         }
-      m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                     path[k].c_str(),
-                                     helpString.c_str(),
-                                     cmCacheManager::PATH);
-      return true;
       }
     }
-#if defined (__APPLE__)
-  cmStdString fpath = this->FindHeaderInFrameworks(path, args[0].c_str(), args[1].c_str());
-  if(fpath.size())
-    {
-    m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                   fpath.c_str(),
-                                   helpString.c_str(),
-                                   cmCacheManager::FILEPATH);
-    return true;
-    }
-#endif  
-
-  m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                 (args[0] + "-NOTFOUND").c_str(),
-                                 helpString.c_str(),
-                                 cmCacheManager::PATH);
+  m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                 (this->VariableName + "-NOTFOUND").c_str(),
+                                 this->VariableDocumentation.c_str(),
+                                 (this->IncludeFileInPath) ? 
+                                 cmCacheManager::FILEPATH :cmCacheManager::PATH);
   return true;
 }
 
-cmStdString cmFindPathCommand::FindHeaderInFrameworks(
-  std::vector<std::string> path,
-  const char* defineVar,
-  const char* file)
+std::string cmFindPathCommand::FindHeaderInFramework(std::string& file,
+                                                     std::string& dir)
 {
-  (void)defineVar;
-
-#ifndef __APPLE__
-  (void)path;
-  (void)file;
-  return cmStdString("");
-#else
   cmStdString fileName = file;
   cmStdString frameWorkName;
   cmStdString::size_type pos = fileName.find("/");
+  // if there is a / in the name try to find the header as a framework
+  // For example bar/foo.h would look for:
+  // bar.framework/Headers/foo.h
   if(pos != fileName.npos)
     {
     // remove the name from the slash;
@@ -145,18 +145,10 @@ cmStdString cmFindPathCommand::FindHeaderInFrameworks(
       {
       fileName = file;
       frameWorkName = "";
-      }
-    }
-  path.push_back("~/Library/Frameworks");
-  path.push_back("/Library/Frameworks");
-  path.push_back("/Network/Library/Frameworks");
-  path.push_back("/System/Library/Frameworks");
-  for(  std::vector<std::string>::iterator i = path.begin();
-        i != path.end(); ++i)
-    {
+      } 
     if(frameWorkName.size())
       {
-      std::string fpath = *i;
+      std::string fpath = dir;
       fpath += "/";
       fpath += frameWorkName;
       fpath += ".framework";
@@ -164,11 +156,17 @@ cmStdString cmFindPathCommand::FindHeaderInFrameworks(
       intPath += "/Headers/";
       intPath += fileName;
       if(cmSystemTools::FileExists(intPath.c_str()))
-        {
+        { 
+        if(this->IncludeFileInPath)
+          {
+          return intPath;
+          }
         return fpath;
         }
       }
-    cmStdString glob = *i;
+    // if it is not found yet or not a framework header, then do a glob search
+    // for all files in dir/*/Headers/
+    cmStdString glob = dir;
     glob += "/*/Headers/";
     glob += file;
     cmGlob globIt;
@@ -177,11 +175,14 @@ cmStdString cmFindPathCommand::FindHeaderInFrameworks(
     if(files.size())
       {
       cmStdString fheader = cmSystemTools::CollapseFullPath(files[0].c_str());
+      if(this->IncludeFileInPath)
+        {
+        return fheader;
+        }
       fheader = cmSystemTools::GetFilenamePath(fheader);
       return fheader;
       }
     }
-  return cmStdString("");
-#endif
-
+  return "";
 }
+

+ 9 - 26
Source/cmFindPathCommand.h

@@ -17,7 +17,7 @@
 #ifndef cmFindPathCommand_h
 #define cmFindPathCommand_h
 
-#include "cmCommand.h"
+#include "cmFindBase.h"
 
 
 /** \class cmFindPathCommand
@@ -27,9 +27,10 @@
  * that specifies a library. The command searches for a given
  * file in a list of directories.
  */
-class cmFindPathCommand : public cmCommand
+class cmFindPathCommand : public cmFindBase
 {
 public:
+  cmFindPathCommand();
   /**
    * This is a virtual constructor for the command.
    */
@@ -61,31 +62,13 @@ public:
     {
     return "Find the directory containing a file.";
     }
-  
-  /**
-   * More documentation.
-   */
-  virtual const char* GetFullDocumentation()
-    {
-    return
-      "  FIND_PATH(<VAR> fileName path1 [path2 ...]\n"
-      "            [DOC \"docstring\"])\n"
-      "Find the directory containing a file named by fileName.  "
-      "A cache entry named by "
-      "<VAR> is created to store the result.  If the file is not "
-      "found, the result will be <VAR>-NOTFOUND.  If DOC is specified "
-      "then the next argument is treated as a documentation string for "
-      "the cache entry <VAR>.  "
-      "The search proceeds first in paths listed in the CMAKE_INCLUDE_PATH "
-      "CMake variable (which is generally set by the user on the command line), "
-      "then in paths listed in the CMAKE_INCLUDE_PATH environment variable, "
-      "then in paths given to the command, and finally in paths listed in the "
-      "PATH environment variable.";
-    }
-  cmStdString FindHeaderInFrameworks( std::vector<std::string> path,
-                                      const char* var, const char* file);
 
-  cmTypeMacro(cmFindPathCommand, cmCommand);
+  std::string FindHeaderInFramework( std::string& file,
+                                     std::string& dir);
+  virtual const char* GetFullDocumentation();
+  cmTypeMacro(cmFindPathCommand, cmFindBase);
+  bool IncludeFileInPath;
+  bool ExtraDocAdded;
 };
 
 

+ 33 - 112
Source/cmFindProgramCommand.cxx

@@ -18,130 +18,51 @@
 #include "cmCacheManager.h"
 #include <stdlib.h>
   
+cmFindProgramCommand::cmFindProgramCommand()
+{
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "FIND_XXX", "FIND_PROGRAM");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "XXX_SYSTEM", "");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_PATH", "CMAKE_SYSTEM_PROGRAM_PATH"); 
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX_DESC", "program");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "SEARCH_XXX", "program");
+}
 
 // cmFindProgramCommand
 bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  if(argsIn.size() < 2 )
+  this->VariableDocumentation = "Path to a program.";
+  this->CMakePathName = "PROGRAM";
+  // call cmFindBase::ParseArguments
+  if(!this->ParseArguments(argsIn))
     {
-    this->SetError("called with incorrect number of arguments");
     return false;
     }
-  std::string doc = "Path to a program.";
-  size_t size = argsIn.size();
-  std::vector<std::string> args;
-  for(unsigned int j = 0; j < size; ++j)
-    {
-    if(argsIn[j] != "DOC")
-      {
-      args.push_back(argsIn[j]);
-      }
-    else
-      {
-      if(j+1 < size)
-        {
-        doc = argsIn[j+1];
-        }
-      break;
-      }
-    }
-
-  std::vector<std::string>::iterator i = args.begin();
-  // Use the first argument as the name of something to be defined
-  const char* define = (*i).c_str();
-  i++; // move iterator to next arg
-  // Now check and see if the value has been stored in the cache
-  // already, if so use that value and don't look for the program
-  const char* cacheValue
-    = m_Makefile->GetDefinition(define);
-  if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
+  if(this->AlreadyInCache)
     {
     return true;
     }
-  if(cacheValue)
-    {
-    cmCacheManager::CacheIterator it = 
-      m_Makefile->GetCacheManager()->GetCacheIterator(args[0].c_str());
-    if(!it.IsAtEnd())
-      {
-      const char* hs = it.GetProperty("HELPSTRING");
-      doc = hs?hs:"(none)";
-      }
-    }
-  std::vector<std::string> path;
-  std::vector<std::string> names;
-  bool foundName = false;
-  bool foundPath = false;
-  bool doingNames = true;
-  bool no_system_path = false;
-  for (unsigned int j = 1; j < args.size(); ++j)
-    {
-    if(args[j] == "NAMES")
-      {
-      doingNames = true;
-      foundName = true;
-      }
-    else if (args[j] == "PATHS")
-      {
-      doingNames = false;
-      foundPath = true;
-      }
-    else if (args[j] == "NO_SYSTEM_PATH")
-      {
-      no_system_path = true;
-      }
-    else
-      { 
-      if(doingNames)
-        {
-        names.push_back(args[j]);
-        }
-      else
-        {
-        cmSystemTools::ExpandRegistryValues(args[j]);
-        // Glob the entry in case of wildcards.
-        cmSystemTools::GlobDirs(args[j].c_str(), path);
-        }
-      }
-    }
-  // if it is not in the cache, then search the system path
-  // add any user specified paths 
-  if(!foundPath && !foundName)
+  std::string result = cmSystemTools::FindProgram(this->Names,
+                                                  this->SearchPaths);
+  if(result != "")
     {
-    path.clear();
-    names.clear();
-    names.push_back(args[1]);
-    for (unsigned int j = 2; j < args.size(); j++)
-      {
-      // expand variables
-      std::string exp = args[j];
-      cmSystemTools::ExpandRegistryValues(exp);
-      
-      // Glob the entry in case of wildcards.
-      cmSystemTools::GlobDirs(exp.c_str(), path);
-      }
-    }
-  for(std::vector<std::string>::iterator it = names.begin();
-      it != names.end() ; ++it)
-    {
-    // Try to find the program.
-    std::string result = cmSystemTools::FindProgram(it->c_str(), 
-                                                    path, 
-                                                    no_system_path);
-    if(result != "")
-      {
-      // Save the value in the cache
-      m_Makefile->AddCacheDefinition(define,
-                                     result.c_str(),
-                                     doc.c_str(),
-                                     cmCacheManager::FILEPATH);
-      
-      return true;
-      }
+    // Save the value in the cache
+    m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                   result.c_str(),
+                                   this->VariableDocumentation.c_str(),
+                                   cmCacheManager::FILEPATH);
+    
+    return true;
     }
-  m_Makefile->AddCacheDefinition(args[0].c_str(),
-                                 (args[0] + "-NOTFOUND").c_str(),
-                                 doc.c_str(),
+  m_Makefile->AddCacheDefinition(this->VariableName.c_str(),
+                                 (this->VariableName + "-NOTFOUND").c_str(),
+                                 this->VariableDocumentation.c_str(),
                                  cmCacheManager::FILEPATH);
   return true;
 }

+ 4 - 28
Source/cmFindProgramCommand.h

@@ -17,7 +17,7 @@
 #ifndef cmFindProgramCommand_h
 #define cmFindProgramCommand_h
 
-#include "cmCommand.h"
+#include "cmFindBase.h"
 
 /** \class cmFindProgramCommand
  * \brief Define a command to search for an executable program.
@@ -27,9 +27,10 @@
  * in the current path (e.g., PATH environment variable) for
  * an executable that matches one of the supplied names.
  */
-class cmFindProgramCommand : public cmCommand
+class cmFindProgramCommand : public cmFindBase
 {
 public:
+  cmFindProgramCommand();
   /**
    * This is a virtual constructor for the command.
    */
@@ -62,32 +63,7 @@ public:
     return "Find an executable program.";
     }
   
-  /**
-   * More documentation.
-   */
-  virtual const char* GetFullDocumentation()
-    {
-    return
-      "  FIND_PROGRAM(<VAR> NAMES name1 [name2 ...]\n"
-      "               [PATHS path1 path2 ...]\n"
-      "               [NO_SYSTEM_PATH]\n"
-      "               [DOC \"docstring\"])\n"
-      "Find an executable named by one of the names given after the NAMES "
-      "argument.  Paths specified after the PATHS argument are searched "
-      "in the order specified.  If the NO_SYSTEM_PATH argument is not "
-      "specified, the search continues with the system search path "
-      "specified by the PATH environment variable.  A cache entry named "
-      "by <VAR> is created to store the result.  If the program is not "
-      "found, the result will be <VAR>-NOTFOUND.  If DOC is specified "
-      "then the next argument is treated as a documentation string for "
-      "the cache entry <VAR>.\n"
-      "  FIND_PROGRAM(VAR executableName [path1 path2 ...])\n"
-      "Find a program with the given name by searching in the specified "
-      "paths.  This is a short-hand signature for the command that is "
-      "sufficient in many cases.";
-    }
-  
-  cmTypeMacro(cmFindProgramCommand, cmCommand);
+  cmTypeMacro(cmFindProgramCommand, cmFindBase);
 };
 
 

+ 1 - 0
Source/kwsys/Registry.cxx

@@ -267,6 +267,7 @@ bool Registry::DeleteValue(const char *subkey, const char *key)
     if ( !this->Open(this->GetTopLevel(), subkey, 
         Registry::READWRITE) )
       {
+      std::cerr << "Failed to open\n";
       return res;
       }
     open = true;

+ 44 - 16
Source/kwsys/SystemTools.cxx

@@ -1923,21 +1923,35 @@ kwsys_stl::string SystemTools::FindProgram(
     {
     return "";
     }
+  std::string ext = SystemTools::GetExecutableExtension();
+  if(ext.size())
+    {
+    unsigned int len = strlen(name);
+    if(len > ext.size())
+      {
+      if(strcmp(name+(len-ext.size()), ext.c_str()) == 0)
+        {
+        ext = ""; // name already has Executable extension
+        }
+      }
+    }
   // See if the executable exists as written.
   if(SystemTools::FileExists(name) &&
       !SystemTools::FileIsDirectory(name))
     {
     return SystemTools::CollapseFullPath(name);
     }
-  kwsys_stl::string tryPath = name;
-  tryPath += SystemTools::GetExecutableExtension();
-  if(SystemTools::FileExists(tryPath.c_str()) &&
-     !SystemTools::FileIsDirectory(tryPath.c_str()))
+  if(ext.size())
     {
-    return SystemTools::CollapseFullPath(tryPath.c_str());
+    kwsys_stl::string tryPath = name;
+    tryPath += ext;
+    if(SystemTools::FileExists(tryPath.c_str()) &&
+       !SystemTools::FileIsDirectory(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
     }
   kwsys_stl::vector<kwsys_stl::string> path;
-  SystemTools::GetPath(path, "CMAKE_PROGRAM_PATH");
   // Add the system search path to our path.
   if (!no_system_path)
     {
@@ -1954,9 +1968,10 @@ kwsys_stl::string SystemTools::FindProgram(
       p != path.end(); ++p)
     {
 #ifdef _WIN32
+    // Remove double quotes from the path on windows
     SystemTools::ReplaceString(*p, "\"", "");
 #endif
-    tryPath = *p;
+    kwsys_stl::string tryPath = *p;
     tryPath += "/";
     tryPath += name;
     if(SystemTools::FileExists(tryPath.c_str()) &&
@@ -1965,22 +1980,35 @@ kwsys_stl::string SystemTools::FindProgram(
       return SystemTools::CollapseFullPath(tryPath.c_str());
       }
 #ifdef _WIN32
-    tryPath += ".com";
-    if(SystemTools::FileExists(tryPath.c_str()) &&
-       !SystemTools::FileIsDirectory(tryPath.c_str()))
+    // on windows try .com before .exe
+    if(ext.size() == 0)
       {
-      return SystemTools::CollapseFullPath(tryPath.c_str());
+      SystemTools::ReplaceString(tryPath, ".exe", ".com");
+      SystemTools::ReplaceString(tryPath, ".EXE", ".com");
+      }
+    else
+      {
+      tryPath += ".com";
       }
-    tryPath = *p;
-    tryPath += "/";
-    tryPath += name;
-#endif
-    tryPath += SystemTools::GetExecutableExtension();
     if(SystemTools::FileExists(tryPath.c_str()) &&
        !SystemTools::FileIsDirectory(tryPath.c_str()))
       {
       return SystemTools::CollapseFullPath(tryPath.c_str());
       }
+#endif
+    // now try to add ext if it is different than name
+    if(ext.size())
+      {
+      tryPath = *p;
+      tryPath += "/";
+      tryPath += name;
+      tryPath += ext;
+      if(SystemTools::FileExists(tryPath.c_str()) &&
+         !SystemTools::FileIsDirectory(tryPath.c_str()))
+        {
+        return SystemTools::CollapseFullPath(tryPath.c_str());
+        }
+      }
     }
 
   // Couldn't find the program.