From e4f603b698a13857e79a5f6df18a7461b20d4bd4 Mon Sep 17 00:00:00 2001
From: Alex Neundorf <neundorf@kde.org>
Date: Sat, 2 Jul 2011 23:14:28 +0200
Subject: Implement find-package mode of cmake

In find-package mode, cmake executes Modules/CMakeFindPackage.cmake,
which calls find_package(), and this is then evaluated in cmake.cxx,
which prints an appropriate message to stdout, so it can be used
e.g. in a normal Makefile:

$ /opt/cmake-HEAD/bin/cmake --find-package -DNAME=JPEG
 -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=EXIST
JPEG found.
$ /opt/cmake-HEAD/bin/cmake --find-package -DNAME=JPEG
 -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=COMPILE

$ /opt/cmake-HEAD/bin/cmake --find-package -DNAME=JPEG
 -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=LINK
-rdynamic -ljpeg

Alex
---
 Modules/CMakeFindPackageMode.cmake | 125 +++++++++++++++++++++++++++++++++++++
 Source/cmake.cxx                   | 100 ++++++++++++++++++++++++++++-
 2 files changed, 223 insertions(+), 2 deletions(-)
 create mode 100644 Modules/CMakeFindPackageMode.cmake

diff --git a/Modules/CMakeFindPackageMode.cmake b/Modules/CMakeFindPackageMode.cmake
new file mode 100644
index 0000000..5842c7a
--- /dev/null
+++ b/Modules/CMakeFindPackageMode.cmake
@@ -0,0 +1,125 @@
+# COMPILER_ID = GNU/Intel/etc.
+# LANGUAGE = C/CXX/Fortan/ASM
+# MODE = EXIST/COMPILE/LINK
+# NAME = name of the package
+# QUIET = if TRUE, don't print anything
+
+if(NOT NAME)
+  message(FATAL_ERROR "NAME argument not specified.")
+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()
+
+
+include(CMakeDetermineSystem)
+
+# 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)
+
+# this is ugly, and not enough for the multilib-stuff I guess
+if(UNIX AND EXISTS /usr/lib64)
+  set(CMAKE_SIZEOF_VOID_P 8)
+endif()
+
+set(CMAKE_${LANGUAGE}_COMPILER "dummy")
+set(CMAKE_${LANGUAGE}_COMPILER_ID "${COMPILER_ID}")
+include(CMake${LANGUAGE}Information)
+
+
+function(print_compile_flags _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(print_link_flags _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")
+    print_compile_flags(${NAME})
+  elseif("${MODE}" STREQUAL "LINK")
+    print_link_flags(${NAME})
+  else("${MODE}" STREQUAL "LINK")
+    message(FATAL_ERROR "Invalid mode argument ${MODE} given.")
+  endif()
+
+endif()
+
+set(PACKAGE_QUIET ${SILENT} )
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 3d42c7f..5b6286e 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -547,8 +547,104 @@ void cmake::ReadListFile(const std::vector<std::string>& args,
 
 bool cmake::FindPackage(const std::vector<std::string>& args)
 {
-  // create empty function for now, will be filled later
-  return true;
+  // 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;
 }
 
 
-- 
cgit v0.12