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)
33 ,ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup)
36 this->Targets.Follows(0);
37 // and after that the other options in any order
38 this->ArgumentGroup.Follows(&this->Targets);
44 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
48 this->SetError("called with too few arguments");
52 if(args[0] == "PACKAGE")
54 return this->HandlePackage(args);
57 std::vector<std::string> unknownArgs;
58 this->Helper.Parse(&args, &unknownArgs);
60 if (!unknownArgs.empty())
62 this->SetError("Unknown arguments.");
66 if (this->Targets.WasFound() == false)
68 this->SetError("TARGETS option missing.");
72 if(!this->Filename.WasFound())
74 this->SetError("FILE <filename> option missing.");
78 // Make sure the file has a .cmake extension.
79 if(cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString())
83 e << "FILE option given filename \"" << this->Filename.GetString()
84 << "\" which does not have an extension of \".cmake\".\n";
85 this->SetError(e.str().c_str());
89 // Get the file to write.
90 std::string fname = this->Filename.GetString();
91 if(cmSystemTools::FileIsFullPath(fname.c_str()))
93 if(!this->Makefile->CanIWriteThisFile(fname.c_str()))
96 e << "FILE option given filename \"" << fname
97 << "\" which is in the source tree.\n";
98 this->SetError(e.str().c_str());
104 // Interpret relative paths with respect to the current build dir.
105 fname = this->Makefile->GetCurrentOutputDirectory();
107 fname += this->Filename.GetString();
110 // Collect the targets to be exported.
111 std::vector<cmTarget*> targets;
112 for(std::vector<std::string>::const_iterator
113 currentTarget = this->Targets.GetVector().begin();
114 currentTarget != this->Targets.GetVector().end();
117 if (this->Makefile->IsAlias(currentTarget->c_str()))
120 e << "given ALIAS target \"" << *currentTarget
121 << "\" which may not be exported.";
122 this->SetError(e.str().c_str());
126 if(cmTarget* target =
127 this->Makefile->GetLocalGenerator()->
128 GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
130 if((target->GetType() == cmTarget::EXECUTABLE) ||
131 (target->GetType() == cmTarget::STATIC_LIBRARY) ||
132 (target->GetType() == cmTarget::SHARED_LIBRARY) ||
133 (target->GetType() == cmTarget::MODULE_LIBRARY))
135 targets.push_back(target);
137 else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
140 e << "given OBJECT library \"" << *currentTarget
141 << "\" which may not be exported.";
142 this->SetError(e.str().c_str());
148 e << "given target \"" << *currentTarget
149 << "\" which is not an executable or library.";
150 this->SetError(e.str().c_str());
157 e << "given target \"" << *currentTarget
158 << "\" which is not built by this project.";
159 this->SetError(e.str().c_str());
164 // Setup export file generation.
165 cmExportBuildFileGenerator ebfg;
166 ebfg.SetExportFile(fname.c_str());
167 ebfg.SetNamespace(this->Namespace.GetCString());
168 ebfg.SetAppendMode(this->Append.IsEnabled());
169 ebfg.SetExports(&targets);
170 ebfg.SetCommand(this);
171 ebfg.SetExportOld(this->ExportOld.IsEnabled());
173 // Compute the set of configurations exported.
174 std::vector<std::string> configurationTypes;
175 this->Makefile->GetConfigurations(configurationTypes);
176 if(!configurationTypes.empty())
178 for(std::vector<std::string>::const_iterator
179 ci = configurationTypes.begin();
180 ci != configurationTypes.end(); ++ci)
182 ebfg.AddConfiguration(ci->c_str());
187 ebfg.AddConfiguration("");
190 // Generate the import file.
191 if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty())
193 this->SetError("could not write export file.");
197 // Report generated error message if any.
198 if(!this->ErrorMessage.empty())
200 this->SetError(this->ErrorMessage.c_str());
207 //----------------------------------------------------------------------------
208 bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
210 // Parse PACKAGE mode arguments.
211 enum Doing { DoingNone, DoingPackage };
212 Doing doing = DoingPackage;
214 for(unsigned int i=1; i < args.size(); ++i)
216 if(doing == DoingPackage)
224 e << "PACKAGE given unknown argument: " << args[i];
225 this->SetError(e.str().c_str());
230 // Verify the package name.
233 this->SetError("PACKAGE must be given a package name.");
236 const char* packageExpr = "^[A-Za-z0-9_.-]+$";
237 cmsys::RegularExpression packageRegex(packageExpr);
238 if(!packageRegex.find(package.c_str()))
241 e << "PACKAGE given invalid package name \"" << package << "\". "
242 << "Package names must match \"" << packageExpr << "\".";
243 this->SetError(e.str().c_str());
247 // We store the current build directory in the registry as a value
248 // named by a hash of its own content. This is deterministic and is
249 // unique with high probability.
250 const char* outDir = this->Makefile->GetCurrentOutputDirectory();
251 std::string hash = cmSystemTools::ComputeStringMD5(outDir);
252 #if defined(_WIN32) && !defined(__CYGWIN__)
253 this->StorePackageRegistryWin(package, outDir, hash.c_str());
255 this->StorePackageRegistryDir(package, outDir, hash.c_str());
261 #if defined(_WIN32) && !defined(__CYGWIN__)
262 # include <windows.h>
263 # undef GetCurrentDirectory
264 //----------------------------------------------------------------------------
265 void cmExportCommand::ReportRegistryError(std::string const& msg,
266 std::string const& key,
271 << " HKEY_CURRENT_USER\\" << key << "\n";
273 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
274 FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
275 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
276 winmsg, 1024, 0) > 0)
278 e << "Windows reported:\n"
281 this->Makefile->IssueMessage(cmake::WARNING, e.str());
284 //----------------------------------------------------------------------------
285 void cmExportCommand::StorePackageRegistryWin(std::string const& package,
289 std::string key = "Software\\Kitware\\CMake\\Packages\\";
292 LONG err = RegCreateKeyEx(HKEY_CURRENT_USER,
293 key.c_str(), 0, 0, REG_OPTION_NON_VOLATILE,
294 KEY_SET_VALUE, 0, &hKey, 0);
295 if(err != ERROR_SUCCESS)
297 this->ReportRegistryError(
298 "Cannot create/open registry key", key, err);
301 err = RegSetValueEx(hKey, hash, 0, REG_SZ, (BYTE const*)content,
302 static_cast<DWORD>(strlen(content)+1));
304 if(err != ERROR_SUCCESS)
307 msg << "Cannot set registry value \"" << hash << "\" under key";
308 this->ReportRegistryError(msg.str(), key, err);
313 //----------------------------------------------------------------------------
314 void cmExportCommand::StorePackageRegistryDir(std::string const& package,
318 #if defined(__HAIKU__)
320 if (find_directory(B_USER_SETTINGS_DIRECTORY, &dir) != B_OK)
324 dir.Append("cmake/packages");
325 dir.Append(package.c_str());
326 std::string fname = dir.Path();
328 const char* home = cmSystemTools::GetEnv("HOME");
333 std::string fname = home;
334 cmSystemTools::ConvertToUnixSlashes(fname);
335 fname += "/.cmake/packages/";
338 cmSystemTools::MakeDirectory(fname.c_str());
341 if(!cmSystemTools::FileExists(fname.c_str()))
343 cmGeneratedFileStream entry(fname.c_str(), true);
346 entry << content << "\n";
351 e << "Cannot create package registry file:\n"
352 << " " << fname << "\n"
353 << cmSystemTools::GetLastSystemError() << "\n";
354 this->Makefile->IssueMessage(cmake::WARNING, e.str());