Browse Source

Merge topic 'UsingCMakeLikePkgConfig2'

59238dc Fix --find-package mode on Cygwin, where enable_language(RC) is called
98472e4 Require the current cmake version in --find-package mode
a6ccf3c Use $(CXXFLAGS) and $(LDFLAGS) in the --find-package test Makefile
4386918 Fix line length
7d69310 Only enable the test when using GNU make
3011149 Make the test harder by always having a space in the include dirs
ab57ff6 Make the --find-package test harder
626fc71 Much improved test, should now be executed on all UNIXes
ec6982d Disable any STATUS output in --find-package mode
e552ae7 Dont check for -isysroot and -mmacosx-version on OSX in --find-package mode
e589589 Rename helper macros print_compile_flags() to set_compile_flags_var()
aecfc1f Fix test on OpenBSD with BSD make
6bb4ca3 The makefile for the test was kindof wrong
fd15b5e Only run the test if we are using a makefile generator under UNIX
9fc87c6 Add a test for the new --find-package mode
d3ae0ff Improve documentation for --find-package mode
bf07375 Add a cmake.m4 for using cmake in autoconf projects instead of pkgconfig
b0e3578 Use the file-utility to test for 64bit if there is no /usr/lib64
53edfb2 Better support for lib64 and Debian multiarch
b8fdaa1 Fix copyright notice in new CMakeFindPackageMode.cmake
7690edf Replace cmake::GetScriptMode() with GetWorkingMode()
e4f603b Implement find-package mode of cmake
a91d662 Add find-package mode, which does nothing yet
b976e70 Make clLocalGenerator::GetTargetFlags() public
David Cole 14 years ago
parent
commit
28cba226b3

+ 187 - 0
Modules/CMakeFindPackageMode.cmake

@@ -0,0 +1,187 @@
+# This file is executed by cmake when invoked with --find-package.
+# It expects that the following variables are set using -D:
+#   NAME = name of the package
+#   COMPILER_ID = the CMake compiler ID for which the result is, i.e. GNU/Intel/Clang/MSVC, etc.
+#   LANGUAGE = language for which the result will be used, i.e. C/CXX/Fortan/ASM
+#   MODE = EXIST : only check for existance of the given package
+#          COMPILE : print the flags needed for compiling an object file which uses the given package
+#          LINK : print the flags needed for linking when using the given package
+#   QUIET = if TRUE, don't print anything
+
+#=============================================================================
+# Copyright 2006-2011 Alexander Neundorf, <[email protected]>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+if(NOT NAME)
+  message(FATAL_ERROR "Name of the package to be searched not specified. Set the CMake variable NAME, e.g. -DNAME=JPEG .")
+endif()
+
+if(NOT COMPILER_ID)
+  message(FATAL_ERROR "COMPILER_ID argument not specified. In doubt, use GNU.")
+endif()
+
+if(NOT LANGUAGE)
+  message(FATAL_ERROR "LANGUAGE argument not specified. Use C, CXX or Fortran.")
+endif()
+
+if(NOT MODE)
+  message(FATAL_ERROR "MODE argument not specified. Use either EXIST, COMPILE or LINK.")
+endif()
+
+# require the current version. If we don't do this, Platforms/CYGWIN.cmake complains because
+# it doesn't know whether it should set WIN32 or not:
+cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} )
+
+macro(ENABLE_LANGUAGE)
+  # disable the enable_language() command, otherwise --find-package breaks on Windows.
+  # On Windows, enable_language(RC) is called in the platform files unconditionally.
+  # But in --find-package mode, we don't want (and can't) enable any language.
+endmacro()
+
+include(CMakeDetermineSystem)
+
+# short-cut some tests on Darwin, see Darwin-GNU.cmake:
+if("${CMAKE_SYSTEM_NAME}" MATCHES Darwin  AND  "${COMPILER_ID}" MATCHES GNU)
+  set(${CMAKE_${LANGUAGE}_HAS_ISYSROOT} 0 )
+  set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "")
+endif()
+
+# Also load the system specific file, which sets up e.g. the search paths.
+# This makes the FIND_XXX() calls work much better
+include(CMakeSystemSpecificInformation)
+
+if(UNIX)
+
+  # try to guess whether we have a 64bit system, if it has not been set
+  # from the outside
+  if(NOT CMAKE_SIZEOF_VOID_P)
+    set(CMAKE_SIZEOF_VOID_P 4)
+    if(EXISTS /usr/lib64)
+      set(CMAKE_SIZEOF_VOID_P 8)
+    else()
+      # use the file utility to check whether itself is 64 bit:
+      find_program(FILE_EXECUTABLE file)
+      if(FILE_EXECUTABLE)
+        execute_process(COMMAND "${FILE_EXECUTABLE}" "${FILE_EXECUTABLE}" OUTPUT_VARIABLE fileOutput ERROR_QUIET)
+        if("${fileOutput}" MATCHES "64-bit")
+          set(CMAKE_SIZEOF_VOID_P 8)
+        endif()
+      endif()
+    endif()
+  endif()
+
+  # guess Debian multiarch if it has not been set:
+  if(EXISTS /etc/debian_version)
+    if(NOT CMAKE_${LANGUAGE}_LANGUAGE_ARCHITECTURE )
+      file(GLOB filesInLib RELATIVE /lib /lib/*-linux-gnu* )
+      foreach(file ${filesInLib})
+        if("${file}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}")
+          set(CMAKE_${LANGUAGE}_LANGUAGE_ARCHITECTURE ${file})
+          break()
+        endif()
+      endforeach()
+    endif()
+  endif()
+
+endif()
+
+set(CMAKE_${LANGUAGE}_COMPILER "dummy")
+set(CMAKE_${LANGUAGE}_COMPILER_ID "${COMPILER_ID}")
+include(CMake${LANGUAGE}Information)
+
+
+function(set_compile_flags_var _packageName)
+  string(TOUPPER "${_packageName}" PACKAGE_NAME)
+  # Check the following variables:
+  # FOO_INCLUDE_DIRS
+  # Foo_INCLUDE_DIRS
+  # FOO_INCLUDES
+  # Foo_INCLUDES
+  # FOO_INCLUDE_DIR
+  # Foo_INCLUDE_DIR
+  set(includes)
+  if(DEFINED ${_packageName}_INCLUDE_DIRS)
+    set(includes ${_packageName}_INCLUDE_DIRS)
+  elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIRS)
+    set(includes ${PACKAGE_NAME}_INCLUDE_DIRS)
+  elseif(DEFINED ${_packageName}_INCLUDES)
+    set(includes ${_packageName}_INCLUDES)
+  elseif(DEFINED ${PACKAGE_NAME}_INCLUDES)
+    set(includes ${PACKAGE_NAME}_INCLUDES)
+  elseif(DEFINED ${_packageName}_INCLUDE_DIR)
+    set(includes ${_packageName}_INCLUDE_DIR)
+  elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIR)
+    set(includes ${PACKAGE_NAME}_INCLUDE_DIR)
+  endif()
+
+  set(PACKAGE_INCLUDE_DIRS "${${includes}}" PARENT_SCOPE)
+
+  # Check the following variables:
+  # FOO_DEFINITIONS
+  # Foo_DEFINITIONS
+  set(definitions)
+  if(DEFINED ${_packageName}_DEFINITIONS)
+    set(definitions ${_packageName}_DEFINITIONS)
+  elseif(DEFINED ${PACKAGE_NAME}_DEFINITIONS)
+    set(definitions ${PACKAGE_NAME}_DEFINITIONS)
+  endif()
+
+  set(PACKAGE_DEFINITIONS  "${${definitions}}" )
+
+endfunction()
+
+
+function(set_link_flags_var _packageName)
+  string(TOUPPER "${_packageName}" PACKAGE_NAME)
+  # Check the following variables:
+  # FOO_LIBRARIES
+  # Foo_LIBRARIES
+  # FOO_LIBS
+  # Foo_LIBS
+  set(libs)
+  if(DEFINED ${_packageName}_LIBRARIES)
+    set(libs ${_packageName}_LIBRARIES)
+  elseif(DEFINED ${PACKAGE_NAME}_LIBRARIES)
+    set(libs ${PACKAGE_NAME}_LIBRARIES)
+  elseif(DEFINED ${_packageName}_LIBS)
+    set(libs ${_packageName}_LIBS)
+  elseif(DEFINED ${PACKAGE_NAME}_LIBS)
+    set(libs ${PACKAGE_NAME}_LIBS)
+  endif()
+
+  set(PACKAGE_LIBRARIES "${${libs}}" PARENT_SCOPE )
+
+endfunction()
+
+
+find_package("${NAME}" QUIET)
+
+set(PACKAGE_FOUND FALSE)
+
+string(TOUPPER "${NAME}" UPPERCASE_NAME)
+
+if(${NAME}_FOUND  OR  ${UPPERCASE_NAME}_FOUND)
+  set(PACKAGE_FOUND TRUE)
+
+  if("${MODE}" STREQUAL "EXIST")
+    # do nothing
+  elseif("${MODE}" STREQUAL "COMPILE")
+    set_compile_flags_var(${NAME})
+  elseif("${MODE}" STREQUAL "LINK")
+    set_link_flags_var(${NAME})
+  else("${MODE}" STREQUAL "LINK")
+    message(FATAL_ERROR "Invalid mode argument ${MODE} given.")
+  endif()
+
+endif()
+
+set(PACKAGE_QUIET ${SILENT} )

+ 1 - 1
Source/cmGlobalGenerator.cxx

@@ -783,7 +783,7 @@ void cmGlobalGenerator::Configure()
   // so create the map from project name to vector of local generators
   this->FillProjectMap();
 
-  if ( !this->CMakeInstance->GetScriptMode() )
+  if ( this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE)
     {
     const char* msg = "Configuring done";
     if(cmSystemTools::GetErrorOccuredFlag())

+ 1 - 1
Source/cmLocalGenerator.h

@@ -307,7 +307,6 @@ public:
                                              std::string const& dir_max,
                                              bool* hasSourceExtension = 0);
 
-protected:
   /** Fill out these strings for the given target.  Libraries to link,
    *  flags, and linkflags. */
   void GetTargetFlags(std::string& linkLibs, 
@@ -315,6 +314,7 @@ protected:
                       std::string& linkFlags,
                       cmTarget&target);
   
+protected:
   ///! put all the libraries for a target on into the given stream
   virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink);
   

+ 14 - 5
Source/cmMakefile.cxx

@@ -384,7 +384,9 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
 
     // Decide whether to invoke the command.
     if(pcmd->GetEnabled() && !cmSystemTools::GetFatalErrorOccured()  &&
-       (!this->GetCMakeInstance()->GetScriptMode() || pcmd->IsScriptable()))
+       (this->GetCMakeInstance()->GetWorkingMode() != cmake::SCRIPT_MODE
+       || pcmd->IsScriptable()))
+
       {
       // if trace is one, print out invoke information
       if(this->GetCMakeInstance()->GetTrace())
@@ -411,7 +413,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
           this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError());
           }
         result = false;
-        if ( this->GetCMakeInstance()->GetScriptMode() )
+        if ( this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE)
           {
           cmSystemTools::SetFatalErrorOccured();
           }
@@ -422,7 +424,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
         this->UsedCommands.push_back(pcmd.release());
         }
       }
-    else if ( this->GetCMakeInstance()->GetScriptMode()
+    else if ( this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE
               && !pcmd->IsScriptable() )
       {
       std::string error = "Command ";
@@ -3025,8 +3027,15 @@ cmCacheManager *cmMakefile::GetCacheManager() const
 
 void cmMakefile::DisplayStatus(const char* message, float s)
 {
-  this->GetLocalGenerator()->GetGlobalGenerator()
-    ->GetCMakeInstance()->UpdateProgress(message, s);
+  cmake* cm = this->GetLocalGenerator()->GetGlobalGenerator()
+                                                          ->GetCMakeInstance();
+  if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE)
+    {
+    // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
+    // directly be fed to the compiler, which will be confused.
+    return;
+    }
+  cm->UpdateProgress(message, s);
 }
 
 std::string cmMakefile::GetModulesFile(const char* filename)

+ 128 - 7
Source/cmake.cxx

@@ -183,7 +183,7 @@ cmake::cmake()
   this->GlobalGenerator = 0;
   this->ProgressCallback = 0;
   this->ProgressCallbackClientData = 0;
-  this->ScriptMode = false;
+  this->CurrentWorkingMode = NORMAL_MODE;
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
   this->VariableWatch = new cmVariableWatch;
@@ -356,6 +356,7 @@ void cmake::RemoveUnscriptableCommands()
 // Parse the args
 bool cmake::SetCacheArgs(const std::vector<std::string>& args)
 {
+  bool findPackageMode = false;
   for(unsigned int i=1; i < args.size(); ++i)
     {
     std::string arg = args[i];
@@ -483,7 +484,17 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
         }
       this->ReadListFile(args, path.c_str());
       }
+    else if (arg.find("--find-package",0) == 0)
+      {
+      findPackageMode = true;
+      }
     }
+
+  if (findPackageMode)
+    {
+    return this->FindPackage(args);
+    }
+
   return true;
 }
 
@@ -514,7 +525,7 @@ void cmake::ReadListFile(const std::vector<std::string>& args,
       (cmSystemTools::GetCurrentWorkingDirectory().c_str());
     lg->GetMakefile()->SetStartDirectory
       (cmSystemTools::GetCurrentWorkingDirectory().c_str());
-    if (this->GetScriptMode())
+    if (this->GetWorkingMode() != NORMAL_MODE)
       {
       std::string file(cmSystemTools::CollapseFullPath(path));
       cmSystemTools::ConvertToUnixSlashes(file);
@@ -535,6 +546,111 @@ void cmake::ReadListFile(const std::vector<std::string>& args,
     }
 }
 
+
+bool cmake::FindPackage(const std::vector<std::string>& args)
+{
+  // if a generator was not yet created, temporarily create one
+  cmGlobalGenerator *gg = new cmGlobalGenerator;
+  gg->SetCMakeInstance(this);
+  this->SetGlobalGenerator(gg);
+
+  // read in the list file to fill the cache
+  std::auto_ptr<cmLocalGenerator> lg(gg->CreateLocalGenerator());
+  cmMakefile* mf = lg->GetMakefile();
+  mf->SetHomeOutputDirectory
+    (cmSystemTools::GetCurrentWorkingDirectory().c_str());
+  mf->SetStartOutputDirectory
+    (cmSystemTools::GetCurrentWorkingDirectory().c_str());
+  mf->SetHomeDirectory
+    (cmSystemTools::GetCurrentWorkingDirectory().c_str());
+  mf->SetStartDirectory
+    (cmSystemTools::GetCurrentWorkingDirectory().c_str());
+
+  mf->SetArgcArgv(args);
+
+  std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
+  mf->ReadListFile(0, systemFile.c_str());
+
+  std::string language = mf->GetSafeDefinition("LANGUAGE");
+  std::string mode = mf->GetSafeDefinition("MODE");
+  std::string packageName = mf->GetSafeDefinition("NAME");
+  bool packageFound = mf->IsOn("PACKAGE_FOUND");
+  bool quiet = mf->IsOn("PACKAGE_QUIET");
+
+  if (!packageFound)
+    {
+    if (!quiet)
+      {
+      printf("%s not found.\n", packageName.c_str());
+      }
+    }
+  else if (mode == "EXIST")
+    {
+    if (!quiet)
+      {
+      printf("%s found.\n", packageName.c_str());
+      }
+    }
+  else if (mode == "COMPILE")
+    {
+    std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
+    std::vector<std::string> includeDirs;
+    cmSystemTools::ExpandListArgument(includes, includeDirs);
+    for(std::vector<std::string>::const_iterator dirIt=includeDirs.begin();
+            dirIt != includeDirs.end();
+            ++dirIt)
+      {
+      mf->AddIncludeDirectory(dirIt->c_str(), false);
+      }
+
+    std::string includeFlags = lg->GetIncludeFlags(language.c_str(), false);
+    std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
+    printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
+    }
+  else if (mode == "LINK")
+    {
+    const char* targetName = "dummy";
+    std::vector<std::string> srcs;
+    cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
+    tgt->SetProperty("LINKER_LANGUAGE", language.c_str());
+
+    std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
+    std::vector<std::string> libList;
+    cmSystemTools::ExpandListArgument(libs, libList);
+    for(std::vector<std::string>::const_iterator libIt=libList.begin();
+            libIt != libList.end();
+            ++libIt)
+      {
+      mf->AddLinkLibraryForTarget(targetName, libIt->c_str(),
+                                  cmTarget::GENERAL);
+      }
+
+
+    std::string linkLibs;
+    std::string flags;
+    std::string linkFlags;
+    lg->GetTargetFlags(linkLibs, flags, linkFlags, *tgt);
+
+    printf("%s\n", linkLibs.c_str() );
+
+/*    if ( use_win32 )
+      {
+      tgt->SetProperty("WIN32_EXECUTABLE", "ON");
+      }
+    if ( use_macbundle)
+      {
+      tgt->SetProperty("MACOSX_BUNDLE", "ON");
+      }*/
+    }
+
+  // free generic one if generated
+//  this->SetGlobalGenerator(0); // setting 0-pointer is not possible
+//  delete gg; // this crashes inside the cmake instance
+
+  return packageFound;
+}
+
+
 // Parse the args
 void cmake::SetArgs(const std::vector<std::string>& args,
                     bool directoriesSetBefore)
@@ -607,6 +723,11 @@ void cmake::SetArgs(const std::vector<std::string>& args,
       // skip for now
       i++;
       }
+    else if(arg.find("--find-package",0) == 0)
+      {
+      // skip for now
+      i++;
+      }
     else if(arg.find("-Wno-dev",0) == 0)
       {
       // skip for now
@@ -2035,7 +2156,7 @@ int cmake::ActualConfigure()
   this->CleanupCommandsAndMacros();
 
   int res = 0;
-  if ( !this->ScriptMode )
+  if ( this->GetWorkingMode() == NORMAL_MODE )
     {
     res = this->DoPreConfigureChecks();
     }
@@ -2223,7 +2344,7 @@ int cmake::ActualConfigure()
     this->CacheManager->RemoveCacheEntry("CMAKE_EXTRA_GENERATOR");
     }
   // only save the cache if there were no fatal errors
-  if ( !this->ScriptMode )
+  if ( this->GetWorkingMode() == NORMAL_MODE )
     {
     this->CacheManager->SaveCache(this->GetHomeOutputDirectory());
     }
@@ -2289,7 +2410,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
   // set the cmake command
   this->CMakeCommand = args[0];
 
-  if ( !this->ScriptMode )
+  if ( this->GetWorkingMode() == NORMAL_MODE )
     {
     // load the cache
     if(this->LoadCache() < 0)
@@ -2310,7 +2431,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
     }
 
   // In script mode we terminate after running the script.
-  if(this->ScriptMode)
+  if(this->GetWorkingMode() != NORMAL_MODE)
     {
     if(cmSystemTools::GetErrorOccuredFlag())
       {
@@ -2356,7 +2477,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
   this->SetStartDirectory(this->GetHomeDirectory());
   this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
   int ret = this->Configure();
-  if (ret || this->ScriptMode)
+  if (ret || this->GetWorkingMode() != NORMAL_MODE)
     {
 #if defined(CMAKE_HAVE_VS_GENERATORS)
     if(!this->VSSolutionFile.empty() && this->GlobalGenerator)

+ 23 - 8
Source/cmake.h

@@ -64,6 +64,25 @@ class cmake
     WARNING,
     LOG
   };
+
+
+  /** Describes the working modes of cmake.
+   * NORMAL_MODE: cmake runs to create project files
+   * SCRIPT_MODE: in script mode there is no generator and no cache. Also,
+   *              language are not enabled, so add_executable and things do
+   *              not do anything. Started by using -P
+   * FIND_PACKAGE_MODE: cmake runs in pkg-config like mode, i.e. it just
+   *              searches for a package and prints the results to stdout.
+   *              This is similar to SCRIPT_MODE, but commands like
+   *              add_library() work too, since they may be used e.g. in
+   *              exported target files. Started via --find-package
+   */
+  enum WorkingMode
+  {
+    NORMAL_MODE,
+    SCRIPT_MODE,
+    FIND_PACKAGE_MODE
+  };
   typedef std::map<cmStdString, cmCommand*> RegisteredCommandsMap;
 
   ///! construct an instance of cmake
@@ -274,13 +293,8 @@ class cmake
   ///! Do all the checks before running configure
   int DoPreConfigureChecks();
 
-  /**
-   * Set and get the script mode option. In script mode there is no
-   * generator and no cache. Also, language are not enabled, so
-   * add_executable and things do not do anything.
-   */
-  void SetScriptMode(bool mode) { this->ScriptMode = mode; }
-  bool GetScriptMode() { return this->ScriptMode; }
+  void SetWorkingMode(WorkingMode mode) { this->CurrentWorkingMode = mode; }
+  WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
 
   ///! Debug the try compile stuff by not delelting the files
   bool GetDebugTryCompile(){return this->DebugTryCompile;}
@@ -409,6 +423,7 @@ protected:
 
   ///! read in a cmake list file to initialize the cache
   void ReadListFile(const std::vector<std::string>& args, const char *path);
+  bool FindPackage(const std::vector<std::string>& args);
 
   ///! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
   ///  If it is set, truncate it to 50kb
@@ -462,7 +477,7 @@ private:
   void* ProgressCallbackClientData;
   bool Verbose;
   bool InTryCompile;
-  bool ScriptMode;
+  WorkingMode CurrentWorkingMode;
   bool DebugOutput;
   bool Trace;
   bool WarnUninitialized;

+ 14 - 3
Source/cmakemain.cxx

@@ -103,6 +103,11 @@ static const char * cmDocumentationOptions[][3] =
    "No configure or generate step is performed and the cache is not"
    " modified. If variables are defined using -D, this must be done "
    "before the -P argument."},
+  {"--find-package", "Run in pkg-config like mode.",
+   "Search a package using find_package() and print the resulting flags "
+   "to stdout. This can be used to use cmake instead of pkg-config to find "
+   "installed libraries in plain Makefile-based projects or in "
+   "autoconf-based projects (via share/aclocal/cmake.m4)."},
   {"--graphviz=[file]", "Generate graphviz of dependencies.",
    "Generate a graphviz input file that will contain all the library and "
    "executable dependencies in the project."},
@@ -434,7 +439,7 @@ int do_cmake(int ac, char** av)
   bool list_all_cached = false;
   bool list_help = false;
   bool view_only = false;
-  bool script_mode = false;
+  cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
   std::vector<std::string> args;
   for(int i =0; i < ac; ++i)
     {
@@ -482,12 +487,18 @@ int do_cmake(int ac, char** av)
         }
       else
         {
-        script_mode = true;
+        workingMode = cmake::SCRIPT_MODE;
         args.push_back(av[i]);
         i++;
         args.push_back(av[i]);
         }
       }
+    else if (!command && strncmp(av[i], "--find-package",
+                                 strlen("--find-package")) == 0)
+      {
+      workingMode = cmake::FIND_PACKAGE_MODE;
+      args.push_back(av[i]);
+      }
     else 
       {
       args.push_back(av[i]);
@@ -512,7 +523,7 @@ int do_cmake(int ac, char** av)
   cmake cm;  
   cmSystemTools::SetErrorCallback(cmakemainErrorCallback, (void *)&cm);
   cm.SetProgressCallback(cmakemainProgressCallback, (void *)&cm);
-  cm.SetScriptMode(script_mode);
+  cm.SetWorkingMode(workingMode);
 
   int res = cm.Run(args, view_only);
   if ( list_cached || list_all_cached )

+ 2 - 0
Tests/CMakeLists.txt

@@ -48,6 +48,8 @@ IF(BUILD_TESTING)
 
   ADD_SUBDIRECTORY(CMakeLib)
 
+  ADD_SUBDIRECTORY(FindPackageModeMakefileTest)
+
   # Collect a list of all test build directories.
   SET(TEST_BUILD_DIRS)
 

+ 30 - 0
Tests/FindPackageModeMakefileTest/CMakeLists.txt

@@ -0,0 +1,30 @@
+
+
+if(UNIX  AND  "${CMAKE_GENERATOR}" MATCHES "Makefile")
+
+  # Test whether the make is GNU make, and only add the test in this case,
+  # since the configured makefile in this test uses $(shell ...), which
+  # is AFAIK a GNU make extension. Alex
+  execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} -v
+                  OUTPUT_VARIABLE makeVersionOutput
+                  TIMEOUT 10)
+  string(TOUPPER "${makeVersionOutput}" MAKE_VERSION_OUTPUT)
+  if("${MAKE_VERSION_OUTPUT}" MATCHES ".*GNU MAKE.*")
+
+    # build a library which we can search during the test
+    add_library(foo STATIC foo.cpp)
+
+    # configure a FindFoo.cmake so it knows where the library can be found
+    configure_file(FindFoo.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindFoo.cmake @ONLY)
+
+    # now set up the test:
+    get_target_property(cmakeExecutable cmake LOCATION)
+
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Makefile.in ${CMAKE_CURRENT_BINARY_DIR}/ConfMakefile @ONLY)
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/main.cpp COPYONLY)
+
+    add_test(FindPackageModeMakefileTest ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_BINARY_DIR}/ConfMakefile )
+
+  endif()
+
+endif()

+ 9 - 0
Tests/FindPackageModeMakefileTest/FindFoo.cmake.in

@@ -0,0 +1,9 @@
+
+find_library(FOO_LIBRARY NAMES foo HINTS "@CMAKE_CURRENT_BINARY_DIR@" )
+find_path(FOO_INCLUDE_DIR NAMES foo.h HINTS "@CMAKE_CURRENT_SOURCE_DIR@" )
+
+set(FOO_LIBRARIES ${FOO_LIBRARY})
+set(FOO_INCLUDE_DIRS "${FOO_INCLUDE_DIR}"  "/some/path/with a space/include" )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Foo  DEFAULT_MSG  FOO_LIBRARY FOO_INCLUDE_DIR )

+ 10 - 0
Tests/FindPackageModeMakefileTest/Makefile.in

@@ -0,0 +1,10 @@
+all: clean pngtest
+
+main.o: main.cpp
+	"@CMAKE_CXX_COMPILER@" $(CXXFLAGS) -c $(shell "@cmakeExecutable@" --find-package -DCMAKE_MODULE_PATH="@CMAKE_CURRENT_BINARY_DIR@" -DNAME=Foo -DLANGUAGE=CXX -DCOMPILER_ID=@CMAKE_CXX_COMPILER_ID@ -DMODE=COMPILE) main.cpp
+
+pngtest: main.o
+	"@CMAKE_CXX_COMPILER@" $(LDFLAGS) -o pngtest main.o $(shell "@cmakeExecutable@" --find-package -DCMAKE_MODULE_PATH="@CMAKE_CURRENT_BINARY_DIR@" -DNAME=Foo -DLANGUAGE=CXX -DCOMPILER_ID=@CMAKE_CXX_COMPILER_ID@ -DMODE=LINK)
+
+clean:
+	rm -f *.o pngtest

+ 4 - 0
Tests/FindPackageModeMakefileTest/foo.cpp

@@ -0,0 +1,4 @@
+int foo()
+{
+  return 1477;
+}

+ 6 - 0
Tests/FindPackageModeMakefileTest/foo.h

@@ -0,0 +1,6 @@
+#ifndef FOO_H
+#define FOO_H
+
+int foo();
+
+#endif

+ 8 - 0
Tests/FindPackageModeMakefileTest/main.cpp

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <foo.h>
+
+int main()
+{
+ printf("foo is: %d\n", foo());
+ return 0;
+}

+ 1 - 0
Utilities/CMakeLists.txt

@@ -126,6 +126,7 @@ ADD_CUSTOM_COMMAND(
 
 INSTALL_FILES(${CMAKE_MAN_DIR}/man1 FILES ${MAN_FILES})
 INSTALL_FILES(${CMAKE_DOC_DIR} FILES ${HTML_FILES} ${TEXT_FILES})
+INSTALL_FILES(share/aclocal FILES cmake.m4)
 
 # Drive documentation generation.
 ADD_CUSTOM_TARGET(documentation ALL DEPENDS ${DOC_FILES} ${CMake_BINARY_DIR}/Docs/cmake.txt )

+ 53 - 0
Utilities/cmake.m4

@@ -0,0 +1,53 @@
+dnl ============================================================================
+dnl   CMake - Cross Platform Makefile Generator
+dnl   Copyright 2011 Matthias Kretz, [email protected]
+dnl
+dnl   Distributed under the OSI-approved BSD License (the "License");
+dnl   see accompanying file Copyright.txt for details.
+dnl
+dnl   This software is distributed WITHOUT ANY WARRANTY; without even the
+dnl   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl   See the License for more information.
+dnl ============================================================================
+
+AC_DEFUN([CMAKE_FIND_BINARY],
+[AC_ARG_VAR([CMAKE_BINARY], [path to the cmake binary])dnl
+
+if test "x$ac_cv_env_CMAKE_BINARY_set" != "xset"; then
+    AC_PATH_TOOL([CMAKE_BINARY], [cmake])dnl
+fi
+])dnl
+
+# $1: package name
+# $2: language (e.g. C/CXX/Fortran)
+# $3: The compiler ID, defaults to GNU.
+#     Possible values are: GNU, Intel, Clang, SunPro, HP, XL, VisualAge, PGI,
+#     PathScale, Cray, SCO, MIPSpro, MSVC
+# $4: optional extra arguments to cmake, e.g. "-DCMAKE_SIZEOF_VOID_P=8"
+# $5: optional path to cmake binary
+AC_DEFUN([CMAKE_FIND_PACKAGE], [
+AC_REQUIRE([CMAKE_FIND_BINARY])dnl
+
+AC_ARG_VAR([$1][_][$2][FLAGS], [$2 compiler flags for $1. This overrides the cmake output])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1. This overrides the cmake output])dnl
+
+failed=false
+AC_MSG_CHECKING([for $1])
+if test -n "$1[]_$2[]FLAGS"; then
+    $1[]_$2[]FLAGS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=COMPILE $4` || failed=true
+fi
+if test -n "$1[]_LIBS"; then
+    $1[]_LIBS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=LINK $4` || failed=true
+fi
+
+if $failed; then
+    unset $1[]_$2[]FLAGS
+    unset $1[]_LIBS
+
+    AC_MSG_RESULT([no])
+    $6
+else
+    AC_MSG_RESULT([yes])
+    $5
+fi[]dnl
+])