mirror of
https://github.com/Kitware/CMake.git
synced 2025-06-20 11:47:23 +08:00

Set progress callback on cmake instance used by CPack. The progress callback is used to output STATUS messages which are otherwise missing when issued from e.g. CPack External staging scripts. Fixes: #18567
462 lines
17 KiB
C++
462 lines
17 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
|
|
#include "cmsys/CommandLineArguments.hxx"
|
|
#include "cmsys/Encoding.hxx"
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <memory> // IWYU pragma: keep
|
|
#include <sstream>
|
|
#include <stddef.h>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
|
|
# include "cmsys/ConsoleBuf.hxx"
|
|
#endif
|
|
|
|
#include "cmCPackGenerator.h"
|
|
#include "cmCPackGeneratorFactory.h"
|
|
#include "cmCPackLog.h"
|
|
#include "cmDocumentation.h"
|
|
#include "cmDocumentationEntry.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmStateSnapshot.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmake.h"
|
|
|
|
static const char* cmDocumentationName[][2] = {
|
|
{ nullptr, " cpack - Packaging driver provided by CMake." },
|
|
{ nullptr, nullptr }
|
|
};
|
|
|
|
static const char* cmDocumentationUsage[][2] = {
|
|
// clang-format off
|
|
{ nullptr, " cpack [options]" },
|
|
{ nullptr, nullptr }
|
|
// clang-format on
|
|
};
|
|
|
|
static const char* cmDocumentationOptions[][2] = {
|
|
{ "-G <generators>", "Override/define CPACK_GENERATOR" },
|
|
{ "-C <Configuration>", "Specify the project configuration" },
|
|
{ "-D <var>=<value>", "Set a CPack variable." },
|
|
{ "--config <configFile>", "Specify the config file." },
|
|
{ "--verbose,-V", "Enable verbose output" },
|
|
{ "--trace", "Put underlying cmake scripts in trace mode." },
|
|
{ "--trace-expand", "Put underlying cmake scripts in expanded trace mode." },
|
|
{ "--debug", "Enable debug output (for CPack developers)" },
|
|
{ "-P <packageName>", "Override/define CPACK_PACKAGE_NAME" },
|
|
{ "-R <packageVersion>", "Override/define CPACK_PACKAGE_VERSION" },
|
|
{ "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" },
|
|
{ "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" },
|
|
{ nullptr, nullptr }
|
|
};
|
|
|
|
int cpackUnknownArgument(const char* /*unused*/, void* /*unused*/)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
struct cpackDefinitions
|
|
{
|
|
typedef std::map<std::string, std::string> MapType;
|
|
MapType Map;
|
|
cmCPackLog* Log;
|
|
};
|
|
|
|
int cpackDefinitionArgument(const char* argument, const char* cValue,
|
|
void* call_data)
|
|
{
|
|
(void)argument;
|
|
cpackDefinitions* def = static_cast<cpackDefinitions*>(call_data);
|
|
std::string value = cValue;
|
|
size_t pos = value.find_first_of('=');
|
|
if (pos == std::string::npos) {
|
|
cmCPack_Log(def->Log, cmCPackLog::LOG_ERROR,
|
|
"Please specify CPack definitions as: KEY=VALUE" << std::endl);
|
|
return 0;
|
|
}
|
|
std::string key = value.substr(0, pos);
|
|
value = value.c_str() + pos + 1;
|
|
def->Map[key] = value;
|
|
cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
|
|
"Set CPack variable: " << key << " to \"" << value << "\""
|
|
<< std::endl);
|
|
return 1;
|
|
}
|
|
|
|
static void cpackProgressCallback(const char* message, float progress,
|
|
void* clientdata)
|
|
{
|
|
(void)progress;
|
|
(void)clientdata;
|
|
|
|
std::cout << "-- " << message << std::endl;
|
|
}
|
|
|
|
// this is CPack.
|
|
int main(int argc, char const* const* argv)
|
|
{
|
|
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
|
|
// Replace streambuf so we can output Unicode to console
|
|
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
|
|
consoleOut.SetUTF8Pipes();
|
|
cmsys::ConsoleBuf::Manager consoleErr(std::cerr, true);
|
|
consoleErr.SetUTF8Pipes();
|
|
#endif
|
|
cmsys::Encoding::CommandLineArguments args =
|
|
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
|
|
argc = args.argc();
|
|
argv = args.argv();
|
|
|
|
cmSystemTools::EnableMSVCDebugHook();
|
|
cmSystemTools::InitializeLibUV();
|
|
cmSystemTools::FindCMakeResources(argv[0]);
|
|
cmCPackLog log;
|
|
|
|
log.SetErrorPrefix("CPack Error: ");
|
|
log.SetWarningPrefix("CPack Warning: ");
|
|
log.SetOutputPrefix("CPack: ");
|
|
log.SetVerbosePrefix("CPack Verbose: ");
|
|
|
|
if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Current working directory cannot be established."
|
|
<< std::endl);
|
|
return 1;
|
|
}
|
|
|
|
std::string generator;
|
|
bool help = false;
|
|
bool helpVersion = false;
|
|
bool verbose = false;
|
|
bool trace = false;
|
|
bool traceExpand = false;
|
|
bool debug = false;
|
|
std::string helpFull;
|
|
std::string helpMAN;
|
|
std::string helpHTML;
|
|
|
|
std::string cpackProjectName;
|
|
std::string cpackProjectDirectory;
|
|
std::string cpackBuildConfig;
|
|
std::string cpackProjectVersion;
|
|
std::string cpackProjectPatch;
|
|
std::string cpackProjectVendor;
|
|
std::string cpackConfigFile;
|
|
|
|
cpackDefinitions definitions;
|
|
definitions.Log = &log;
|
|
|
|
cpackConfigFile.clear();
|
|
|
|
cmsys::CommandLineArguments arg;
|
|
arg.Initialize(argc, argv);
|
|
typedef cmsys::CommandLineArguments argT;
|
|
// Help arguments
|
|
arg.AddArgument("--help", argT::NO_ARGUMENT, &help, "CPack help");
|
|
arg.AddArgument("--help-full", argT::SPACE_ARGUMENT, &helpFull,
|
|
"CPack help");
|
|
arg.AddArgument("--help-html", argT::SPACE_ARGUMENT, &helpHTML,
|
|
"CPack help");
|
|
arg.AddArgument("--help-man", argT::SPACE_ARGUMENT, &helpMAN, "CPack help");
|
|
arg.AddArgument("--version", argT::NO_ARGUMENT, &helpVersion, "CPack help");
|
|
|
|
arg.AddArgument("-V", argT::NO_ARGUMENT, &verbose, "CPack verbose");
|
|
arg.AddArgument("--verbose", argT::NO_ARGUMENT, &verbose, "-V");
|
|
arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V");
|
|
arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile,
|
|
"CPack configuration file");
|
|
arg.AddArgument("--trace", argT::NO_ARGUMENT, &trace,
|
|
"Put underlying cmake scripts in trace mode.");
|
|
arg.AddArgument("--trace-expand", argT::NO_ARGUMENT, &traceExpand,
|
|
"Put underlying cmake scripts in expanded trace mode.");
|
|
arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig,
|
|
"CPack build configuration");
|
|
arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator");
|
|
arg.AddArgument("-P", argT::SPACE_ARGUMENT, &cpackProjectName,
|
|
"CPack project name");
|
|
arg.AddArgument("-R", argT::SPACE_ARGUMENT, &cpackProjectVersion,
|
|
"CPack project version");
|
|
arg.AddArgument("-B", argT::SPACE_ARGUMENT, &cpackProjectDirectory,
|
|
"CPack project directory");
|
|
arg.AddArgument("--patch", argT::SPACE_ARGUMENT, &cpackProjectPatch,
|
|
"CPack project patch");
|
|
arg.AddArgument("--vendor", argT::SPACE_ARGUMENT, &cpackProjectVendor,
|
|
"CPack project vendor");
|
|
arg.AddCallback("-D", argT::SPACE_ARGUMENT, cpackDefinitionArgument,
|
|
&definitions, "CPack Definitions");
|
|
arg.SetUnknownArgumentCallback(cpackUnknownArgument);
|
|
|
|
// Parse command line
|
|
int parsed = arg.Parse();
|
|
|
|
// Setup logging
|
|
if (verbose) {
|
|
log.SetVerbose(verbose);
|
|
cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
|
|
}
|
|
if (debug) {
|
|
log.SetDebug(debug);
|
|
cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
|
|
}
|
|
|
|
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
|
|
"Read CPack config file: " << cpackConfigFile << std::endl);
|
|
|
|
cmake cminst(cmake::RoleScript);
|
|
cminst.SetHomeDirectory("");
|
|
cminst.SetHomeOutputDirectory("");
|
|
cminst.SetProgressCallback(cpackProgressCallback, nullptr);
|
|
cminst.GetCurrentSnapshot().SetDefaultDefinitions();
|
|
cmGlobalGenerator cmgg(&cminst);
|
|
cmMakefile globalMF(&cmgg, cminst.GetCurrentSnapshot());
|
|
#if defined(__CYGWIN__)
|
|
globalMF.AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
|
|
#endif
|
|
|
|
if (trace) {
|
|
cminst.SetTrace(true);
|
|
}
|
|
if (traceExpand) {
|
|
cminst.SetTrace(true);
|
|
cminst.SetTraceExpand(true);
|
|
}
|
|
|
|
bool cpackConfigFileSpecified = true;
|
|
if (cpackConfigFile.empty()) {
|
|
cpackConfigFile = cmSystemTools::GetCurrentWorkingDirectory();
|
|
cpackConfigFile += "/CPackConfig.cmake";
|
|
cpackConfigFileSpecified = false;
|
|
}
|
|
|
|
cmCPackGeneratorFactory generators;
|
|
generators.SetLogger(&log);
|
|
cmCPackGenerator* cpackGenerator = nullptr;
|
|
|
|
cmDocumentation doc;
|
|
doc.addCPackStandardDocSections();
|
|
/* Were we invoked to display doc or to do some work ?
|
|
* Unlike cmake launching cpack with zero argument
|
|
* should launch cpack using "cpackConfigFile" if it exists
|
|
* in the current directory.
|
|
*/
|
|
help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
|
|
|
|
// This part is used for cpack documentation lookup as well.
|
|
cminst.AddCMakePaths();
|
|
|
|
if (parsed && !help) {
|
|
// find out which system cpack is running on, so it can setup the search
|
|
// paths, so FIND_XXX() commands can be used in scripts
|
|
std::string systemFile =
|
|
globalMF.GetModulesFile("CMakeDetermineSystem.cmake");
|
|
if (!globalMF.ReadListFile(systemFile.c_str())) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Error reading CMakeDetermineSystem.cmake" << std::endl);
|
|
return 1;
|
|
}
|
|
|
|
systemFile =
|
|
globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake");
|
|
if (!globalMF.ReadListFile(systemFile.c_str())) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Error reading CMakeSystemSpecificInformation.cmake"
|
|
<< std::endl);
|
|
return 1;
|
|
}
|
|
|
|
if (!cpackBuildConfig.empty()) {
|
|
globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str());
|
|
}
|
|
|
|
if (cmSystemTools::FileExists(cpackConfigFile)) {
|
|
cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
|
|
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
|
|
"Read CPack configuration file: " << cpackConfigFile
|
|
<< std::endl);
|
|
if (!globalMF.ReadListFile(cpackConfigFile.c_str())) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Problem reading CPack config file: \""
|
|
<< cpackConfigFile << "\"" << std::endl);
|
|
return 1;
|
|
}
|
|
} else if (cpackConfigFileSpecified) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Cannot find CPack config file: \"" << cpackConfigFile
|
|
<< "\"" << std::endl);
|
|
return 1;
|
|
}
|
|
|
|
if (!generator.empty()) {
|
|
globalMF.AddDefinition("CPACK_GENERATOR", generator.c_str());
|
|
}
|
|
if (!cpackProjectName.empty()) {
|
|
globalMF.AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName.c_str());
|
|
}
|
|
if (!cpackProjectVersion.empty()) {
|
|
globalMF.AddDefinition("CPACK_PACKAGE_VERSION",
|
|
cpackProjectVersion.c_str());
|
|
}
|
|
if (!cpackProjectVendor.empty()) {
|
|
globalMF.AddDefinition("CPACK_PACKAGE_VENDOR",
|
|
cpackProjectVendor.c_str());
|
|
}
|
|
// if this is not empty it has been set on the command line
|
|
// go for it. Command line override values set in config file.
|
|
if (!cpackProjectDirectory.empty()) {
|
|
globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
|
|
cpackProjectDirectory.c_str());
|
|
}
|
|
// The value has not been set on the command line
|
|
else {
|
|
// get a default value (current working directory)
|
|
cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory();
|
|
// use default value iff no value has been provided by the config file
|
|
if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) {
|
|
globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
|
|
cpackProjectDirectory.c_str());
|
|
}
|
|
}
|
|
for (auto const& cd : definitions.Map) {
|
|
globalMF.AddDefinition(cd.first, cd.second.c_str());
|
|
}
|
|
|
|
const char* cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
|
|
if (cpackModulesPath) {
|
|
globalMF.AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath);
|
|
}
|
|
const char* genList = globalMF.GetDefinition("CPACK_GENERATOR");
|
|
if (!genList) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"CPack generator not specified" << std::endl);
|
|
} else {
|
|
std::vector<std::string> generatorsVector;
|
|
cmSystemTools::ExpandListArgument(genList, generatorsVector);
|
|
for (std::string const& gen : generatorsVector) {
|
|
cmMakefile::ScopePushPop raii(&globalMF);
|
|
cmMakefile* mf = &globalMF;
|
|
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
|
|
"Specified generator: " << gen << std::endl);
|
|
if (parsed && !mf->GetDefinition("CPACK_PACKAGE_NAME")) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"CPack project name not specified" << std::endl);
|
|
parsed = 0;
|
|
}
|
|
if (parsed &&
|
|
!(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
|
|
(mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"CPack project version not specified"
|
|
<< std::endl
|
|
<< "Specify CPACK_PACKAGE_VERSION, or "
|
|
"CPACK_PACKAGE_VERSION_MAJOR, "
|
|
"CPACK_PACKAGE_VERSION_MINOR, and "
|
|
"CPACK_PACKAGE_VERSION_PATCH."
|
|
<< std::endl);
|
|
parsed = 0;
|
|
}
|
|
if (parsed) {
|
|
cpackGenerator = generators.NewGenerator(gen);
|
|
if (cpackGenerator) {
|
|
cpackGenerator->SetTrace(trace);
|
|
cpackGenerator->SetTraceExpand(traceExpand);
|
|
} else {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Cannot initialize CPack generator: " << gen
|
|
<< std::endl);
|
|
parsed = 0;
|
|
}
|
|
|
|
if (parsed && !cpackGenerator->Initialize(gen, mf)) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Cannot initialize the generator " << gen
|
|
<< std::endl);
|
|
parsed = 0;
|
|
}
|
|
|
|
if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
|
|
!mf->GetDefinition("CPACK_INSTALL_SCRIPT") &&
|
|
!mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
|
|
!mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
|
|
cmCPack_Log(
|
|
&log, cmCPackLog::LOG_ERROR,
|
|
"Please specify build tree of the project that uses CMake "
|
|
"using CPACK_INSTALL_CMAKE_PROJECTS, specify "
|
|
"CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or "
|
|
"CPACK_INSTALLED_DIRECTORIES."
|
|
<< std::endl);
|
|
parsed = 0;
|
|
}
|
|
if (parsed) {
|
|
const char* projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
|
|
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
|
|
"Use generator: " << cpackGenerator->GetNameOfClass()
|
|
<< std::endl);
|
|
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
|
|
"For project: " << projName << std::endl);
|
|
|
|
const char* projVersion =
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION");
|
|
if (!projVersion) {
|
|
const char* projVersionMajor =
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
|
|
const char* projVersionMinor =
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
|
|
const char* projVersionPatch =
|
|
mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
|
|
std::ostringstream ostr;
|
|
ostr << projVersionMajor << "." << projVersionMinor << "."
|
|
<< projVersionPatch;
|
|
mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str().c_str());
|
|
}
|
|
|
|
int res = cpackGenerator->DoPackage();
|
|
if (!res) {
|
|
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
|
|
"Error when generating package: " << projName
|
|
<< std::endl);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* In this case we are building the documentation object
|
|
* instance in order to create appropriate structure
|
|
* in order to satisfy the appropriate --help-xxx request
|
|
*/
|
|
if (help) {
|
|
// Construct and print requested documentation.
|
|
|
|
doc.SetName("cpack");
|
|
doc.SetSection("Name", cmDocumentationName);
|
|
doc.SetSection("Usage", cmDocumentationUsage);
|
|
doc.PrependSection("Options", cmDocumentationOptions);
|
|
|
|
std::vector<cmDocumentationEntry> v;
|
|
for (auto const& g : generators.GetGeneratorsList()) {
|
|
cmDocumentationEntry e;
|
|
e.Name = g.first;
|
|
e.Brief = g.second;
|
|
v.push_back(std::move(e));
|
|
}
|
|
doc.SetSection("Generators", v);
|
|
|
|
return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
|
|
}
|
|
|
|
if (cmSystemTools::GetErrorOccuredFlag()) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|