Rescan dependencies also if CMakeDirectoryInformation.cmake has changed.
[cmake.git] / Source / cmExportCommand.cxx
blobe98b5118b26cb6a561aab9716d0fe20924a5244d
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExportCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-01 18:04:53 $
7 Version: $Revision: 1.12 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmExportCommand.h"
18 #include "cmGlobalGenerator.h"
19 #include "cmLocalGenerator.h"
20 #include "cmGeneratedFileStream.h"
21 #include "cmake.h"
23 #include <cmsys/RegularExpression.hxx>
25 #include "cmExportBuildFileGenerator.h"
27 cmExportCommand::cmExportCommand()
28 :cmCommand()
29 ,ArgumentGroup()
30 ,Targets(&Helper, "TARGETS")
31 ,Append(&Helper, "APPEND", &ArgumentGroup)
32 ,Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
33 ,Filename(&Helper, "FILE", &ArgumentGroup)
35 // at first TARGETS
36 this->Targets.Follows(0);
37 // and after that the other options in any order
38 this->ArgumentGroup.Follows(&this->Targets);
42 // cmExportCommand
43 bool cmExportCommand
44 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
46 if(args.size() < 2 )
48 this->SetError("called with too few arguments");
49 return false;
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.");
63 return false;
66 if (this->Targets.WasFound() == false)
68 this->SetError("TARGETS option missing.");
69 return false;
72 if(!this->Filename.WasFound())
74 this->SetError("FILE <filename> option missing.");
75 return false;
78 // Make sure the file has a .cmake extension.
79 if(cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString())
80 != ".cmake")
82 cmOStringStream e;
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());
86 return false;
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()))
95 cmOStringStream e;
96 e << "FILE option given filename \"" << fname
97 << "\" which is in the source tree.\n";
98 this->SetError(e.str().c_str());
99 return false;
102 else
104 // Interpret relative paths with respect to the current build dir.
105 fname = this->Makefile->GetCurrentOutputDirectory();
106 fname += "/";
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();
115 ++currentTarget)
117 if(cmTarget* target =
118 this->Makefile->GetLocalGenerator()->
119 GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
121 if((target->GetType() == cmTarget::EXECUTABLE) ||
122 (target->GetType() == cmTarget::STATIC_LIBRARY) ||
123 (target->GetType() == cmTarget::SHARED_LIBRARY) ||
124 (target->GetType() == cmTarget::MODULE_LIBRARY))
126 targets.push_back(target);
128 else
130 cmOStringStream e;
131 e << "given target \"" << *currentTarget
132 << "\" which is not an executable or library.";
133 this->SetError(e.str().c_str());
134 return false;
137 else
139 cmOStringStream e;
140 e << "given target \"" << *currentTarget
141 << "\" which is not built by this project.";
142 this->SetError(e.str().c_str());
143 return false;
147 // Setup export file generation.
148 cmExportBuildFileGenerator ebfg;
149 ebfg.SetExportFile(fname.c_str());
150 ebfg.SetNamespace(this->Namespace.GetCString());
151 ebfg.SetAppendMode(this->Append.IsEnabled());
152 ebfg.SetExports(&targets);
153 ebfg.SetCommand(this);
155 // Compute the set of configurations exported.
156 if(const char* types =
157 this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
159 std::vector<std::string> configurationTypes;
160 cmSystemTools::ExpandListArgument(types, configurationTypes);
161 for(std::vector<std::string>::const_iterator
162 ci = configurationTypes.begin();
163 ci != configurationTypes.end(); ++ci)
165 ebfg.AddConfiguration(ci->c_str());
168 else if(const char* config =
169 this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"))
171 ebfg.AddConfiguration(config);
173 else
175 ebfg.AddConfiguration("");
178 // Generate the import file.
179 if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty())
181 this->SetError("could not write export file.");
182 return false;
185 // Report generated error message if any.
186 if(!this->ErrorMessage.empty())
188 this->SetError(this->ErrorMessage.c_str());
189 return false;
192 return true;
195 //----------------------------------------------------------------------------
196 bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
198 // Parse PACKAGE mode arguments.
199 enum Doing { DoingNone, DoingPackage };
200 Doing doing = DoingPackage;
201 std::string package;
202 for(unsigned int i=1; i < args.size(); ++i)
204 if(doing == DoingPackage)
206 package = args[i];
207 doing = DoingNone;
209 else
211 cmOStringStream e;
212 e << "PACKAGE given unknown argumsnt: " << args[i];
213 this->SetError(e.str().c_str());
214 return false;
218 // Verify the package name.
219 if(package.empty())
221 this->SetError("PACKAGE must be given a package name.");
222 return false;
224 const char* packageExpr = "^[A-Za-z0-9_.-]+$";
225 cmsys::RegularExpression packageRegex(packageExpr);
226 if(!packageRegex.find(package.c_str()))
228 cmOStringStream e;
229 e << "PACKAGE given invalid package name \"" << package << "\". "
230 << "Package names must match \"" << packageExpr << "\".";
231 this->SetError(e.str().c_str());
232 return false;
235 // We store the current build directory in the registry as a value
236 // named by a hash of its own content. This is deterministic and is
237 // unique with high probability.
238 const char* outDir = this->Makefile->GetCurrentOutputDirectory();
239 std::string hash = cmSystemTools::ComputeStringMD5(outDir);
240 #if defined(_WIN32) && !defined(__CYGWIN__)
241 this->StorePackageRegistryWin(package, outDir, hash.c_str());
242 #else
243 this->StorePackageRegistryDir(package, outDir, hash.c_str());
244 #endif
246 return true;
249 #if defined(_WIN32) && !defined(__CYGWIN__)
250 # include <windows.h>
251 # undef GetCurrentDirectory
252 //----------------------------------------------------------------------------
253 void cmExportCommand::ReportRegistryError(std::string const& msg,
254 std::string const& key,
255 long err)
257 cmOStringStream e;
258 e << msg << "\n"
259 << " HKEY_CURRENT_USER\\" << key << "\n";
260 char winmsg[1024];
261 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
262 FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
263 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
264 winmsg, 1024, 0) > 0)
266 e << "Windows reported:\n"
267 << " " << winmsg;
269 this->Makefile->IssueMessage(cmake::WARNING, e.str());
272 //----------------------------------------------------------------------------
273 void cmExportCommand::StorePackageRegistryWin(std::string const& package,
274 const char* content,
275 const char* hash)
277 std::string key = "Software\\Kitware\\CMake\\Packages\\";
278 key += package;
279 HKEY hKey;
280 LONG err = RegCreateKeyEx(HKEY_CURRENT_USER,
281 key.c_str(), 0, 0, REG_OPTION_NON_VOLATILE,
282 KEY_SET_VALUE, 0, &hKey, 0);
283 if(err != ERROR_SUCCESS)
285 this->ReportRegistryError(
286 "Cannot create/open registry key", key, err);
287 return;
289 err = RegSetValueEx(hKey, hash, 0, REG_SZ, (BYTE const*)content,
290 static_cast<DWORD>(strlen(content)+1));
291 RegCloseKey(hKey);
292 if(err != ERROR_SUCCESS)
294 cmOStringStream msg;
295 msg << "Cannot set registry value \"" << hash << "\" under key";
296 this->ReportRegistryError(msg.str(), key, err);
297 return;
300 #else
301 //----------------------------------------------------------------------------
302 void cmExportCommand::StorePackageRegistryDir(std::string const& package,
303 const char* content,
304 const char* hash)
306 const char* home = cmSystemTools::GetEnv("HOME");
307 if(!home)
309 return;
311 std::string fname = home;
312 cmSystemTools::ConvertToUnixSlashes(fname);
313 fname += "/.cmake/packages/";
314 fname += package;
315 cmSystemTools::MakeDirectory(fname.c_str());
316 fname += "/";
317 fname += hash;
318 if(!cmSystemTools::FileExists(fname.c_str()))
320 cmGeneratedFileStream entry(fname.c_str(), true);
321 if(entry)
323 entry << content << "\n";
325 else
327 cmOStringStream e;
328 e << "Cannot create package registry file:\n"
329 << " " << fname << "\n"
330 << cmSystemTools::GetLastSystemError() << "\n";
331 this->Makefile->IssueMessage(cmake::WARNING, e.str());
335 #endif