summaryrefslogtreecommitdiff
path: root/Source/cmExportCommand.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2009-09-01 14:04:53 -0400
committerBrad King <brad.king@kitware.com>2009-09-01 14:04:53 -0400
commit16ce84b06712a8f859a352804013805f8f8435c4 (patch)
treeca5e381f344d1e2acf466c473c70e5427100d058 /Source/cmExportCommand.cxx
parented0650f6ae10911092adc25373b9c61724192124 (diff)
downloadcmake-16ce84b06712a8f859a352804013805f8f8435c4.tar.gz
Teach export(PACKAGE) to fill the package registry
We define the export(PACKAGE) command mode to store the location of the build tree in the user package registry. This will help find_package locate the package in the build tree. It simplies user workflow for manually building a series of dependent projects.
Diffstat (limited to 'Source/cmExportCommand.cxx')
-rw-r--r--Source/cmExportCommand.cxx149
1 files changed, 149 insertions, 0 deletions
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 8dfb623b3c..945cfee4fc 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -20,6 +20,8 @@
#include "cmGeneratedFileStream.h"
#include "cmake.h"
+#include <cmsys/RegularExpression.hxx>
+
#include "cmExportBuildFileGenerator.h"
cmExportCommand::cmExportCommand()
@@ -47,6 +49,11 @@ bool cmExportCommand
return false;
}
+ if(args[0] == "PACKAGE")
+ {
+ return this->HandlePackage(args);
+ }
+
std::vector<std::string> unknownArgs;
this->Helper.Parse(&args, &unknownArgs);
@@ -184,3 +191,145 @@ bool cmExportCommand
return true;
}
+
+//----------------------------------------------------------------------------
+bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
+{
+ // Parse PACKAGE mode arguments.
+ enum Doing { DoingNone, DoingPackage };
+ Doing doing = DoingPackage;
+ std::string package;
+ for(unsigned int i=1; i < args.size(); ++i)
+ {
+ if(doing == DoingPackage)
+ {
+ package = args[i];
+ doing = DoingNone;
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "PACKAGE given unknown argumsnt: " << args[i];
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
+
+ // Verify the package name.
+ if(package.empty())
+ {
+ this->SetError("PACKAGE must be given a package name.");
+ return false;
+ }
+ const char* packageExpr = "^[A-Za-z0-9_.-]+$";
+ cmsys::RegularExpression packageRegex(packageExpr);
+ if(!packageRegex.find(package.c_str()))
+ {
+ cmOStringStream e;
+ e << "PACKAGE given invalid package name \"" << package << "\". "
+ << "Package names must match \"" << packageExpr << "\".";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // We store the current build directory in the registry as a value
+ // named by a hash of its own content. This is deterministic and is
+ // unique with high probability.
+ const char* outDir = this->Makefile->GetCurrentOutputDirectory();
+ std::string hash = cmSystemTools::ComputeStringMD5(outDir);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->StorePackageRegistryWin(package, outDir, hash.c_str());
+#else
+ this->StorePackageRegistryDir(package, outDir, hash.c_str());
+#endif
+
+ return true;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+# undef GetCurrentDirectory
+//----------------------------------------------------------------------------
+void cmExportCommand::ReportRegistryError(std::string const& msg,
+ std::string const& key,
+ long err)
+{
+ cmOStringStream e;
+ e << msg << "\n"
+ << " HKEY_CURRENT_USER\\" << key << "\n";
+ char winmsg[1024];
+ if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ winmsg, 1024, 0) > 0)
+ {
+ e << "Windows reported:\n"
+ << " " << winmsg;
+ }
+ this->Makefile->IssueMessage(cmake::WARNING, e.str());
+}
+
+//----------------------------------------------------------------------------
+void cmExportCommand::StorePackageRegistryWin(std::string const& package,
+ const char* content,
+ const char* hash)
+{
+ std::string key = "Software\\Kitware\\CMake\\Packages\\";
+ key += package;
+ HKEY hKey;
+ LONG err = RegCreateKeyEx(HKEY_CURRENT_USER,
+ key.c_str(), 0, 0, REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE, 0, &hKey, 0);
+ if(err != ERROR_SUCCESS)
+ {
+ this->ReportRegistryError(
+ "Cannot create/open registry key", key, err);
+ return;
+ }
+ err = RegSetValueEx(hKey, hash, 0, REG_SZ, (BYTE const*)content,
+ static_cast<DWORD>(strlen(content)+1));
+ RegCloseKey(hKey);
+ if(err != ERROR_SUCCESS)
+ {
+ cmOStringStream msg;
+ msg << "Cannot set registry value \"" << hash << "\" under key";
+ this->ReportRegistryError(msg.str(), key, err);
+ return;
+ }
+}
+#else
+//----------------------------------------------------------------------------
+void cmExportCommand::StorePackageRegistryDir(std::string const& package,
+ const char* content,
+ const char* hash)
+{
+ const char* home = cmSystemTools::GetEnv("HOME");
+ if(!home)
+ {
+ return;
+ }
+ std::string fname = home;
+ cmSystemTools::ConvertToUnixSlashes(fname);
+ fname += "/.cmake/packages/";
+ fname += package;
+ cmSystemTools::MakeDirectory(fname.c_str());
+ fname += "/";
+ fname += hash;
+ if(!cmSystemTools::FileExists(fname.c_str()))
+ {
+ cmGeneratedFileStream entry(fname.c_str(), true);
+ if(entry)
+ {
+ entry << content << "\n";
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "Cannot create package registry file:\n"
+ << " " << fname << "\n"
+ << cmSystemTools::GetLastSystemError() << "\n";
+ this->Makefile->IssueMessage(cmake::WARNING, e.str());
+ }
+ }
+}
+#endif