1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExportCommand.cxx,v $
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"
23 #include <cmsys/RegularExpression.hxx>
25 #include "cmExportBuildFileGenerator.h"
27 cmExportCommand::cmExportCommand()
30 ,Targets(&Helper
, "TARGETS")
31 ,Append(&Helper
, "APPEND", &ArgumentGroup
)
32 ,Namespace(&Helper
, "NAMESPACE", &ArgumentGroup
)
33 ,Filename(&Helper
, "FILE", &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(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
);
131 e
<< "given target \"" << *currentTarget
132 << "\" which is not an executable or library.";
133 this->SetError(e
.str().c_str());
140 e
<< "given target \"" << *currentTarget
141 << "\" which is not built by this project.";
142 this->SetError(e
.str().c_str());
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
);
175 ebfg
.AddConfiguration("");
178 // Generate the import file.
179 if(!ebfg
.GenerateImportFile() && this->ErrorMessage
.empty())
181 this->SetError("could not write export file.");
185 // Report generated error message if any.
186 if(!this->ErrorMessage
.empty())
188 this->SetError(this->ErrorMessage
.c_str());
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
;
202 for(unsigned int i
=1; i
< args
.size(); ++i
)
204 if(doing
== DoingPackage
)
212 e
<< "PACKAGE given unknown argumsnt: " << args
[i
];
213 this->SetError(e
.str().c_str());
218 // Verify the package name.
221 this->SetError("PACKAGE must be given a package name.");
224 const char* packageExpr
= "^[A-Za-z0-9_.-]+$";
225 cmsys::RegularExpression
packageRegex(packageExpr
);
226 if(!packageRegex
.find(package
.c_str()))
229 e
<< "PACKAGE given invalid package name \"" << package
<< "\". "
230 << "Package names must match \"" << packageExpr
<< "\".";
231 this->SetError(e
.str().c_str());
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());
243 this->StorePackageRegistryDir(package
, outDir
, hash
.c_str());
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
,
259 << " HKEY_CURRENT_USER\\" << key
<< "\n";
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"
269 this->Makefile
->IssueMessage(cmake::WARNING
, e
.str());
272 //----------------------------------------------------------------------------
273 void cmExportCommand::StorePackageRegistryWin(std::string
const& package
,
277 std::string key
= "Software\\Kitware\\CMake\\Packages\\";
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
);
289 err
= RegSetValueEx(hKey
, hash
, 0, REG_SZ
, (BYTE
const*)content
,
290 static_cast<DWORD
>(strlen(content
)+1));
292 if(err
!= ERROR_SUCCESS
)
295 msg
<< "Cannot set registry value \"" << hash
<< "\" under key";
296 this->ReportRegistryError(msg
.str(), key
, err
);
301 //----------------------------------------------------------------------------
302 void cmExportCommand::StorePackageRegistryDir(std::string
const& package
,
306 const char* home
= cmSystemTools::GetEnv("HOME");
311 std::string fname
= home
;
312 cmSystemTools::ConvertToUnixSlashes(fname
);
313 fname
+= "/.cmake/packages/";
315 cmSystemTools::MakeDirectory(fname
.c_str());
318 if(!cmSystemTools::FileExists(fname
.c_str()))
320 cmGeneratedFileStream
entry(fname
.c_str(), true);
323 entry
<< content
<< "\n";
328 e
<< "Cannot create package registry file:\n"
329 << " " << fname
<< "\n"
330 << cmSystemTools::GetLastSystemError() << "\n";
331 this->Makefile
->IssueMessage(cmake::WARNING
, e
.str());