1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmExportCommand.h"
13 #include "cmGlobalGenerator.h"
14 #include "cmLocalGenerator.h"
15 #include "cmGeneratedFileStream.h"
18 #include <cmsys/RegularExpression.hxx>
20 #include "cmExportBuildFileGenerator.h"
22 #if defined(__HAIKU__)
23 #include <StorageKit.h>
26 cmExportCommand::cmExportCommand()
29 ,Targets(&Helper, "TARGETS")
30 ,Append(&Helper, "APPEND", &ArgumentGroup)
31 ,Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
32 ,Filename(&Helper, "FILE", &ArgumentGroup)
35 this->Targets.Follows(0);
36 // and after that the other options in any order
37 this->ArgumentGroup.Follows(&this->Targets);
43 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
47 this->SetError("called with too few arguments");
51 if(args[0] == "PACKAGE")
53 return this->HandlePackage(args);
56 std::vector<std::string> unknownArgs;
57 this->Helper.Parse(&args, &unknownArgs);
59 if (!unknownArgs.empty())
61 this->SetError("Unknown arguments.");
65 if (this->Targets.WasFound() == false)
67 this->SetError("TARGETS option missing.");
71 if(!this->Filename.WasFound())
73 this->SetError("FILE <filename> option missing.");
77 // Make sure the file has a .cmake extension.
78 if(cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString())
82 e << "FILE option given filename \"" << this->Filename.GetString()
83 << "\" which does not have an extension of \".cmake\".\n";
84 this->SetError(e.str().c_str());
88 // Get the file to write.
89 std::string fname = this->Filename.GetString();
90 if(cmSystemTools::FileIsFullPath(fname.c_str()))
92 if(!this->Makefile->CanIWriteThisFile(fname.c_str()))
95 e << "FILE option given filename \"" << fname
96 << "\" which is in the source tree.\n";
97 this->SetError(e.str().c_str());
103 // Interpret relative paths with respect to the current build dir.
104 fname = this->Makefile->GetCurrentOutputDirectory();
106 fname += this->Filename.GetString();
109 // Collect the targets to be exported.
110 std::vector<cmTarget*> targets;
111 for(std::vector<std::string>::const_iterator
112 currentTarget = this->Targets.GetVector().begin();
113 currentTarget != this->Targets.GetVector().end();
116 if(cmTarget* target =
117 this->Makefile->GetLocalGenerator()->
118 GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
120 if((target->GetType() == cmTarget::EXECUTABLE) ||
121 (target->GetType() == cmTarget::STATIC_LIBRARY) ||
122 (target->GetType() == cmTarget::SHARED_LIBRARY) ||
123 (target->GetType() == cmTarget::MODULE_LIBRARY))
125 targets.push_back(target);
127 else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
130 e << "given OBJECT library \"" << *currentTarget
131 << "\" which may not be exported.";
132 this->SetError(e.str().c_str());
138 e << "given target \"" << *currentTarget
139 << "\" which is not an executable or library.";
140 this->SetError(e.str().c_str());
147 e << "given target \"" << *currentTarget
148 << "\" which is not built by this project.";
149 this->SetError(e.str().c_str());
154 // Setup export file generation.
155 cmExportBuildFileGenerator ebfg;
156 ebfg.SetExportFile(fname.c_str());
157 ebfg.SetNamespace(this->Namespace.GetCString());
158 ebfg.SetAppendMode(this->Append.IsEnabled());
159 ebfg.SetExports(&targets);
160 ebfg.SetCommand(this);
162 // Compute the set of configurations exported.
163 std::vector<std::string> configurationTypes;
164 this->Makefile->GetConfigurations(configurationTypes);
165 if(!configurationTypes.empty())
167 for(std::vector<std::string>::const_iterator
168 ci = configurationTypes.begin();
169 ci != configurationTypes.end(); ++ci)
171 ebfg.AddConfiguration(ci->c_str());
176 ebfg.AddConfiguration("");
179 // Generate the import file.
180 if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty())
182 this->SetError("could not write export file.");
186 // Report generated error message if any.
187 if(!this->ErrorMessage.empty())
189 this->SetError(this->ErrorMessage.c_str());
196 //----------------------------------------------------------------------------
197 bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
199 // Parse PACKAGE mode arguments.
200 enum Doing { DoingNone, DoingPackage };
201 Doing doing = DoingPackage;
203 for(unsigned int i=1; i < args.size(); ++i)
205 if(doing == DoingPackage)
213 e << "PACKAGE given unknown argumsnt: " << args[i];
214 this->SetError(e.str().c_str());
219 // Verify the package name.
222 this->SetError("PACKAGE must be given a package name.");
225 const char* packageExpr = "^[A-Za-z0-9_.-]+$";
226 cmsys::RegularExpression packageRegex(packageExpr);
227 if(!packageRegex.find(package.c_str()))
230 e << "PACKAGE given invalid package name \"" << package << "\". "
231 << "Package names must match \"" << packageExpr << "\".";
232 this->SetError(e.str().c_str());
236 // We store the current build directory in the registry as a value
237 // named by a hash of its own content. This is deterministic and is
238 // unique with high probability.
239 const char* outDir = this->Makefile->GetCurrentOutputDirectory();
240 std::string hash = cmSystemTools::ComputeStringMD5(outDir);
241 #if defined(_WIN32) && !defined(__CYGWIN__)
242 this->StorePackageRegistryWin(package, outDir, hash.c_str());
244 this->StorePackageRegistryDir(package, outDir, hash.c_str());
250 #if defined(_WIN32) && !defined(__CYGWIN__)
251 # include <windows.h>
252 # undef GetCurrentDirectory
253 //----------------------------------------------------------------------------
254 void cmExportCommand::ReportRegistryError(std::string const& msg,
255 std::string const& key,
260 << " HKEY_CURRENT_USER\\" << key << "\n";
262 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
263 FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
264 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
265 winmsg, 1024, 0) > 0)
267 e << "Windows reported:\n"
270 this->Makefile->IssueMessage(cmake::WARNING, e.str());
273 //----------------------------------------------------------------------------
274 void cmExportCommand::StorePackageRegistryWin(std::string const& package,
278 std::string key = "Software\\Kitware\\CMake\\Packages\\";
281 LONG err = RegCreateKeyEx(HKEY_CURRENT_USER,
282 key.c_str(), 0, 0, REG_OPTION_NON_VOLATILE,
283 KEY_SET_VALUE, 0, &hKey, 0);
284 if(err != ERROR_SUCCESS)
286 this->ReportRegistryError(
287 "Cannot create/open registry key", key, err);
290 err = RegSetValueEx(hKey, hash, 0, REG_SZ, (BYTE const*)content,
291 static_cast<DWORD>(strlen(content)+1));
293 if(err != ERROR_SUCCESS)
296 msg << "Cannot set registry value \"" << hash << "\" under key";
297 this->ReportRegistryError(msg.str(), key, err);
302 //----------------------------------------------------------------------------
303 void cmExportCommand::StorePackageRegistryDir(std::string const& package,
307 #if defined(__HAIKU__)
309 if (find_directory(B_USER_SETTINGS_DIRECTORY, &dir) != B_OK)
313 dir.Append("cmake/packages");
314 dir.Append(package.c_str());
315 std::string fname = dir.Path();
317 const char* home = cmSystemTools::GetEnv("HOME");
322 std::string fname = home;
323 cmSystemTools::ConvertToUnixSlashes(fname);
324 fname += "/.cmake/packages/";
327 cmSystemTools::MakeDirectory(fname.c_str());
330 if(!cmSystemTools::FileExists(fname.c_str()))
332 cmGeneratedFileStream entry(fname.c_str(), true);
335 entry << content << "\n";
340 e << "Cannot create package registry file:\n"
341 << " " << fname << "\n"
342 << cmSystemTools::GetLastSystemError() << "\n";
343 this->Makefile->IssueMessage(cmake::WARNING, e.str());