1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
14 #include <cmext/algorithm>
16 #include "cmsys/Encoding.hxx"
18 #include "cmCPackGenerator.h"
19 #include "cmCPackGeneratorFactory.h"
20 #include "cmCPackLog.h"
21 #include "cmCommandLineArgument.h"
22 #include "cmConsoleBuf.h"
23 #include "cmDocumentation.h"
24 #include "cmDocumentationEntry.h"
25 #include "cmDocumentationFormatter.h"
26 #include "cmGlobalGenerator.h"
27 #include "cmMakefile.h"
29 #include "cmStateSnapshot.h"
30 #include "cmStringAlgorithms.h"
31 #include "cmSystemTools.h"
36 const char* cmDocumentationName[][2] = {
37 { nullptr, " cpack - Packaging driver provided by CMake." },
41 const char* cmDocumentationUsage[][2] = {
43 { nullptr, " cpack [options]" },
48 const char* cmDocumentationOptions[][2] = {
49 { "-G <generators>", "Override/define CPACK_GENERATOR" },
50 { "-C <Configuration>", "Specify the project configuration" },
51 { "-D <var>=<value>", "Set a CPack variable." },
52 { "--config <configFile>", "Specify the config file." },
53 { "--verbose,-V", "Enable verbose output" },
54 { "--trace", "Put underlying cmake scripts in trace mode." },
55 { "--trace-expand", "Put underlying cmake scripts in expanded trace mode." },
56 { "--debug", "Enable debug output (for CPack developers)" },
57 { "-P <packageName>", "Override/define CPACK_PACKAGE_NAME" },
58 { "-R <packageVersion>", "Override/define CPACK_PACKAGE_VERSION" },
59 { "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" },
60 { "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" },
64 void cpackProgressCallback(const std::string& message, float /*unused*/)
66 std::cout << "-- " << message << std::endl;
71 int main(int argc, char const* const* argv)
73 cmSystemTools::EnsureStdPipes();
75 // Replace streambuf so we can output Unicode to console
76 cmConsoleBuf consoleBuf;
77 consoleBuf.SetUTF8Pipes();
79 cmsys::Encoding::CommandLineArguments args =
80 cmsys::Encoding::CommandLineArguments::Main(argc, argv);
84 std::vector<std::string> inputArgs;
85 inputArgs.reserve(argc - 1);
86 cm::append(inputArgs, argv + 1, argv + argc);
88 cmSystemTools::InitializeLibUV();
89 cmSystemTools::FindCMakeResources(argv[0]);
92 log.SetErrorPrefix("CPack Error: ");
93 log.SetWarningPrefix("CPack Warning: ");
94 log.SetOutputPrefix("CPack: ");
95 log.SetVerbosePrefix("CPack Verbose: ");
97 if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
98 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
99 "Current working directory cannot be established."
104 std::string generator;
106 bool helpVersion = false;
107 std::string helpFull;
109 std::string helpHTML;
111 std::string cpackProjectName;
112 std::string cpackProjectDirectory;
113 std::string cpackBuildConfig;
114 std::string cpackProjectVersion;
115 std::string cpackProjectPatch;
116 std::string cpackProjectVendor;
117 std::string cpackConfigFile;
119 std::map<std::string, std::string> definitions;
121 auto const verboseLambda = [&log](const std::string&, cmake*,
122 cmMakefile*) -> bool {
123 log.SetVerbose(true);
124 cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
128 auto const debugLambda = [&log](const std::string&, cmake*,
129 cmMakefile*) -> bool {
131 cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
135 auto const traceLambda = [](const std::string&, cmake* state,
136 cmMakefile*) -> bool {
137 state->SetTrace(true);
141 auto const traceExpandLambda = [](const std::string&, cmake* state,
142 cmMakefile*) -> bool {
143 state->SetTrace(true);
144 state->SetTraceExpand(true);
148 using CommandArgument =
149 cmCommandLineArgument<bool(std::string const&, cmake*, cmMakefile*)>;
151 std::vector<CommandArgument> arguments = {
152 CommandArgument{ "--help", CommandArgument::Values::Zero,
153 CommandArgument::setToTrue(help) },
154 CommandArgument{ "--help-full", CommandArgument::Values::Zero,
155 CommandArgument::setToValue(helpFull) },
156 CommandArgument{ "--help-html", CommandArgument::Values::Zero,
157 CommandArgument::setToValue(helpHTML) },
158 CommandArgument{ "--help-man", CommandArgument::Values::Zero,
159 CommandArgument::setToValue(helpMAN) },
160 CommandArgument{ "--version", CommandArgument::Values::Zero,
161 CommandArgument::setToTrue(helpVersion) },
162 CommandArgument{ "-V", CommandArgument::Values::Zero, verboseLambda },
163 CommandArgument{ "--verbose", CommandArgument::Values::Zero,
165 CommandArgument{ "--debug", CommandArgument::Values::Zero, debugLambda },
166 CommandArgument{ "--config", CommandArgument::Values::One,
167 CommandArgument::setToValue(cpackConfigFile) },
168 CommandArgument{ "--trace", CommandArgument::Values::Zero, traceLambda },
169 CommandArgument{ "--trace-expand", CommandArgument::Values::Zero,
171 CommandArgument{ "-C", CommandArgument::Values::One,
172 CommandArgument::setToValue(cpackBuildConfig) },
173 CommandArgument{ "-G", CommandArgument::Values::One,
174 CommandArgument::setToValue(generator) },
175 CommandArgument{ "-P", CommandArgument::Values::One,
176 CommandArgument::setToValue(cpackProjectName) },
177 CommandArgument{ "-R", CommandArgument::Values::One,
178 CommandArgument::setToValue(cpackProjectVersion) },
179 CommandArgument{ "-B", CommandArgument::Values::One,
180 CommandArgument::setToValue(cpackProjectDirectory) },
181 CommandArgument{ "--patch", CommandArgument::Values::One,
182 CommandArgument::setToValue(cpackProjectPatch) },
183 CommandArgument{ "--vendor", CommandArgument::Values::One,
184 CommandArgument::setToValue(cpackProjectVendor) },
186 "-D", CommandArgument::Values::One,
187 [&log, &definitions](const std::string& arg, cmake*,
188 cmMakefile*) -> bool {
189 std::string value = arg;
190 size_t pos = value.find_first_of('=');
191 if (pos == std::string::npos) {
192 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
193 "Please specify CPack definitions as: KEY=VALUE"
197 std::string key = value.substr(0, pos);
198 value.erase(0, pos + 1);
199 definitions[key] = value;
200 cmCPack_Log(&log, cmCPackLog::LOG_DEBUG,
201 "Set CPack variable: " << key << " to \"" << value << "\""
207 cmake cminst(cmake::RoleScript, cmState::CPack);
208 cminst.SetHomeDirectory("");
209 cminst.SetHomeOutputDirectory("");
210 cminst.SetProgressCallback(cpackProgressCallback);
211 cminst.GetCurrentSnapshot().SetDefaultDefinitions();
212 cmGlobalGenerator cmgg(&cminst);
213 cmMakefile globalMF(&cmgg, cminst.GetCurrentSnapshot());
214 #if defined(__CYGWIN__)
215 globalMF.AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
219 for (std::size_t i = 0; i < inputArgs.size(); i++) {
220 auto const& arg = inputArgs[i];
221 for (auto const& m : arguments) {
222 if (m.matches(arg)) {
223 if (!m.parse(arg, i, inputArgs, &cminst, &globalMF)) {
231 cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
232 "Read CPack config file: " << cpackConfigFile << std::endl);
234 bool cpackConfigFileSpecified = true;
235 if (cpackConfigFile.empty()) {
236 cpackConfigFile = cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(),
237 "/CPackConfig.cmake");
238 cpackConfigFileSpecified = false;
241 cmCPackGeneratorFactory generators;
242 generators.SetLogger(&log);
245 doc.addCPackStandardDocSections();
246 /* Were we invoked to display doc or to do some work ?
247 * Unlike cmake launching cpack with zero argument
248 * should launch cpack using "cpackConfigFile" if it exists
249 * in the current directory.
251 help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
253 // This part is used for cpack documentation lookup as well.
254 cminst.AddCMakePaths();
256 if (parsed && !help) {
257 // find out which system cpack is running on, so it can setup the search
258 // paths, so FIND_XXX() commands can be used in scripts
259 std::string systemFile =
260 globalMF.GetModulesFile("CMakeDetermineSystem.cmake");
261 if (!globalMF.ReadListFile(systemFile)) {
262 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
263 "Error reading CMakeDetermineSystem.cmake" << std::endl);
268 globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake");
269 if (!globalMF.ReadListFile(systemFile)) {
270 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
271 "Error reading CMakeSystemSpecificInformation.cmake"
276 if (!cpackBuildConfig.empty()) {
277 globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig);
280 if (cmSystemTools::FileExists(cpackConfigFile)) {
281 cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
282 cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
283 "Read CPack configuration file: " << cpackConfigFile
285 if (!globalMF.ReadListFile(cpackConfigFile)) {
286 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
287 "Problem reading CPack config file: \""
288 << cpackConfigFile << "\"" << std::endl);
291 } else if (cpackConfigFileSpecified) {
292 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
293 "Cannot find CPack config file: \"" << cpackConfigFile
294 << "\"" << std::endl);
298 if (!generator.empty()) {
299 globalMF.AddDefinition("CPACK_GENERATOR", generator);
301 if (!cpackProjectName.empty()) {
302 globalMF.AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName);
304 if (!cpackProjectVersion.empty()) {
305 globalMF.AddDefinition("CPACK_PACKAGE_VERSION", cpackProjectVersion);
307 if (!cpackProjectVendor.empty()) {
308 globalMF.AddDefinition("CPACK_PACKAGE_VENDOR", cpackProjectVendor);
310 // if this is not empty it has been set on the command line
311 // go for it. Command line override values set in config file.
312 if (!cpackProjectDirectory.empty()) {
313 globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
315 // The value has not been set on the command line
317 // get a default value (current working directory)
318 cpackProjectDirectory = cmSystemTools::GetCurrentWorkingDirectory();
319 // use default value if no value has been provided by the config file
320 if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) {
321 globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
322 cpackProjectDirectory);
325 for (auto const& cd : definitions) {
326 globalMF.AddDefinition(cd.first, cd.second);
329 // Force CPACK_PACKAGE_DIRECTORY as absolute path
330 cpackProjectDirectory =
331 globalMF.GetSafeDefinition("CPACK_PACKAGE_DIRECTORY");
332 cpackProjectDirectory =
333 cmSystemTools::CollapseFullPath(cpackProjectDirectory);
334 globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
336 cmValue cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
337 if (cpackModulesPath) {
338 globalMF.AddDefinition("CMAKE_MODULE_PATH", *cpackModulesPath);
340 cmValue genList = globalMF.GetDefinition("CPACK_GENERATOR");
342 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
343 "CPack generator not specified" << std::endl);
345 std::vector<std::string> generatorsVector = cmExpandedList(*genList);
346 for (std::string const& gen : generatorsVector) {
347 cmMakefile::ScopePushPop raii(&globalMF);
348 cmMakefile* mf = &globalMF;
349 cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
350 "Specified generator: " << gen << std::endl);
351 if (!mf->GetDefinition("CPACK_PACKAGE_NAME")) {
352 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
353 "CPack project name not specified" << std::endl);
357 !(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
358 (mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
359 mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
360 mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
361 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
362 "CPack project version not specified"
364 << "Specify CPACK_PACKAGE_VERSION, or "
365 "CPACK_PACKAGE_VERSION_MAJOR, "
366 "CPACK_PACKAGE_VERSION_MINOR, and "
367 "CPACK_PACKAGE_VERSION_PATCH."
372 std::unique_ptr<cmCPackGenerator> cpackGenerator =
373 generators.NewGenerator(gen);
374 if (cpackGenerator) {
375 cpackGenerator->SetTrace(cminst.GetTrace());
376 cpackGenerator->SetTraceExpand(cminst.GetTraceExpand());
378 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
379 "Could not create CPack generator: " << gen
381 // Print out all the valid generators
382 cmDocumentation generatorDocs;
383 std::vector<cmDocumentationEntry> v;
384 for (auto const& g : generators.GetGeneratorsList()) {
385 cmDocumentationEntry e;
388 v.push_back(std::move(e));
390 generatorDocs.SetSection("Generators", v);
392 generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators,
397 if (parsed && !cpackGenerator->Initialize(gen, mf)) {
398 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
399 "Cannot initialize the generator " << gen
404 if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
405 !mf->GetDefinition("CPACK_INSTALL_SCRIPT") &&
406 !mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
407 !mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
409 &log, cmCPackLog::LOG_ERROR,
410 "Please specify build tree of the project that uses CMake "
411 "using CPACK_INSTALL_CMAKE_PROJECTS, specify "
412 "CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or "
413 "CPACK_INSTALLED_DIRECTORIES."
418 cmValue projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
419 cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
420 "Use generator: " << cpackGenerator->GetNameOfClass()
422 cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
423 "For project: " << *projName << std::endl);
425 cmValue projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION");
427 cmValue projVersionMajor =
428 mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
429 cmValue projVersionMinor =
430 mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
431 cmValue projVersionPatch =
432 mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
433 std::ostringstream ostr;
434 ostr << *projVersionMajor << "." << *projVersionMinor << "."
435 << *projVersionPatch;
436 mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str());
439 int res = cpackGenerator->DoPackage();
441 cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
442 "Error when generating package: " << *projName
452 /* In this case we are building the documentation object
453 * instance in order to create appropriate structure
454 * in order to satisfy the appropriate --help-xxx request
457 // Construct and print requested documentation.
459 doc.SetName("cpack");
460 doc.SetSection("Name", cmDocumentationName);
461 doc.SetSection("Usage", cmDocumentationUsage);
462 doc.PrependSection("Options", cmDocumentationOptions);
464 std::vector<cmDocumentationEntry> v;
465 for (auto const& g : generators.GetGeneratorsList()) {
466 cmDocumentationEntry e;
469 v.push_back(std::move(e));
471 doc.SetSection("Generators", v);
473 return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
476 if (cmSystemTools::GetErrorOccurredFlag()) {