diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index f53977ca1..1cb2994bf 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -41,6 +41,7 @@ #include "cmExportLibraryDependencies.cxx" #include "cmFindFileCommand.cxx" #include "cmFindLibraryCommand.cxx" +#include "cmFindPackageCommand.cxx" #include "cmFindPathCommand.cxx" #include "cmFindProgramCommand.cxx" #include "cmForEachCommand.cxx" @@ -126,6 +127,7 @@ void GetPredefinedCommands(std::list& commands) commands.push_back(new cmExportLibraryDependenciesCommand); commands.push_back(new cmFindFileCommand); commands.push_back(new cmFindLibraryCommand); + commands.push_back(new cmFindPackageCommand); commands.push_back(new cmFindPathCommand); commands.push_back(new cmFindProgramCommand); commands.push_back(new cmForEachCommand); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx new file mode 100644 index 000000000..c61cde241 --- /dev/null +++ b/Source/cmFindPackageCommand.cxx @@ -0,0 +1,231 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "cmFindPackageCommand.h" + +//---------------------------------------------------------------------------- +bool cmFindPackageCommand::InitialPass(std::vector const& args) +{ + if(args.size() < 1) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + this->Name = args[0]; + this->UpperName = cmSystemTools::UpperCase(this->Name); + + // See if there is a Find.cmake module. + bool foundModule = false; + if(!this->FindModule(foundModule)) + { + return false; + } + if(foundModule) + { + return true; + } + // No find module. Assume the project has a CMake config file. Use + // a _DIR cache variable to locate it. + this->Variable = this->UpperName; + this->Variable += "_DIR"; + this->Config = this->Name; + this->Config += "Config.cmake"; + const char* def = m_Makefile->GetDefinition(this->Variable.c_str()); + if(cmSystemTools::IsOff(def)) + { + if(!this->FindConfig()) + { + return false; + } + } + + // If the config file was found, load it. + bool result = true; + bool found = false; + def = m_Makefile->GetDefinition(this->Variable.c_str()); + if(!cmSystemTools::IsOff(def)) + { + std::string f = def; + f += "/"; + f += this->Config; + if(cmSystemTools::FileExists(f.c_str())) + { + if(this->ReadListFile(f.c_str())) + { + found = true; + } + else + { + result = false; + } + } + else + { + cmOStringStream e; + e << this->Variable << " is set to \"" << def << "\", which is " + << "not a directory containing " << this->Config; + cmSystemTools::Error(e.str().c_str()); + result = true; + } + } + else + { + cmOStringStream e; + e << this->Variable << " is not set. It must be set to the directory " + << "containing " << this->Config << " so in order to use " + << this->Name << "."; + cmSystemTools::Error(e.str().c_str()); + result = true; + } + + std::string foundVar = this->UpperName; + foundVar += "_FOUND"; + m_Makefile->AddDefinition(foundVar.c_str(), found? "1":"0"); + return result; +} + +//---------------------------------------------------------------------------- +bool cmFindPackageCommand::FindModule(bool& found) +{ + // If there is a find module, use it. + std::string module = m_Makefile->GetDefinition("CMAKE_ROOT"); + module += "/Modules/Find"; + module += this->Name; + module += ".cmake"; + found = false; + // TODO: CMAKE_PACKAGE_PATH for looking for Find.cmake + // modules? + if(cmSystemTools::FileExists(module.c_str())) + { + found = true; + return this->ReadListFile(module.c_str()); + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmFindPackageCommand::FindConfig() +{ + std::string help = "The directory containing "; + help += this->Config; + help += "."; + + // Construct the list of relative paths to each prefix to be + // searched. + std::string rel = "/lib/"; + rel += cmSystemTools::LowerCase(this->Name); + this->Relatives.push_back(rel); + rel = "/lib/"; + rel += this->Name; + this->Relatives.push_back(rel); + + // It is likely that CMake will have recently built the project. + for(int i=1; i <= 10; ++i) + { + cmOStringStream r; + r << "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild" + << i << "]"; + std::string entry = r.str(); + cmSystemTools::ExpandRegistryValues(entry); + cmSystemTools::ConvertToUnixSlashes(entry); + if(cmSystemTools::FileIsDirectory(entry.c_str())) + { + this->Builds.push_back(entry); + } + } + + // The project may be installed. Use the system search path to + // construct a list of possible install prefixes. + std::vector systemPath; + cmSystemTools::GetPath(systemPath); + for(std::vector::iterator i = systemPath.begin(); + i != systemPath.end(); ++i) + { + *i += "/.."; + if(cmSystemTools::FileIsDirectory(i->c_str())) + { + this->Prefixes.push_back(cmSystemTools::CollapseFullPath(i->c_str())); + } + } +#if !defined(WIN32) || defined(__CYGWIN__) + this->Prefixes.push_back("/usr/local"); + this->Prefixes.push_back("/usr"); +#endif + + // Look for the project's configuration file. + std::string init = this->SearchForConfig(); + + // Store the entry in the cache so it can be set by the user. + m_Makefile->AddCacheDefinition(this->Variable.c_str(), + init.c_str(), + help.c_str(), + cmCacheManager::PATH); + return true; +} + +//---------------------------------------------------------------------------- +std::string cmFindPackageCommand::SearchForConfig() const +{ + // Search the build directories. + for(std::vector::const_iterator b = this->Builds.begin(); + b != this->Builds.end(); ++b) + { + std::string f = *b; + f += "/"; + f += this->Config; + if(cmSystemTools::FileExists(f.c_str())) + { + return *b; + } + } + + // Search paths relative to each installation prefix. + for(std::vector::const_iterator p = this->Prefixes.begin(); + p != this->Prefixes.end(); ++p) + { + std::string prefix = *p; + for(std::vector::const_iterator r = this->Relatives.begin(); + r != this->Relatives.end(); ++r) + { + std::string dir = prefix; + dir += *r; + std::string f = dir; + f += "/"; + f += this->Config; + if(cmSystemTools::FileExists(f.c_str())) + { + return dir; + } + } + } + + return "NOTFOUND"; +} + +//---------------------------------------------------------------------------- +bool cmFindPackageCommand::ReadListFile(const char* f) +{ + if(m_Makefile->ReadListFile(m_Makefile->GetCurrentListFile(), f)) + { + return true; + } + std::string e = "Error reading CMake code from \""; + e += f; + e += "\"."; + this->SetError(e.c_str()); + return false; +} diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h new file mode 100644 index 000000000..93f054a66 --- /dev/null +++ b/Source/cmFindPackageCommand.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef cmFindPackageCommand_h +#define cmFindPackageCommand_h + +#include "cmStandardIncludes.h" +#include "cmCommand.h" + +/** \class cmFindPackageCommand + * \brief Load settings from an external project. + * + * cmFindPackageCommand + */ +class cmFindPackageCommand : public cmCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmFindPackageCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector const& args); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() { return "FIND_PACKAGE";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() + { + return "Load settings for an external project."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() + { + return + "FIND_PACKAGE( [major.minor])\n" + "Finds and loads settings from an external project. _FOUND will\n" + "be set to indicate whether the package was found. Settings that\n" + "can be used when _FOUND is true are package-specific."; + } + + cmTypeMacro(cmFindPackageCommand, cmCommand); +private: + bool FindModule(bool& found); + bool FindConfig(); + std::string SearchForConfig() const; + bool ReadListFile(const char* f); + + cmStdString Name; + cmStdString UpperName; + cmStdString Variable; + cmStdString Config; + std::vector Builds; + std::vector Prefixes; + std::vector Relatives; +}; + + +#endif