diff options
Diffstat (limited to 'Source/CPack/cpack.cxx')
-rw-r--r-- | Source/CPack/cpack.cxx | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx new file mode 100644 index 0000000..da9575b --- /dev/null +++ b/Source/CPack/cpack.cxx @@ -0,0 +1,472 @@ +/* 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 "cmDocumentationFormatter.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.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 std::string& message, float /*unused*/) +{ + 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, cmState::CPack); + cminst.SetHomeDirectory(""); + cminst.SetHomeOutputDirectory(""); + cminst.SetProgressCallback(cpackProgressCallback); + 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)) { + cmCPack_Log(&log, cmCPackLog::LOG_ERROR, + "Error reading CMakeDetermineSystem.cmake" << std::endl); + return 1; + } + + systemFile = + globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake"); + if (!globalMF.ReadListFile(systemFile)) { + 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)) { + 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, + "Could not create CPack generator: " << gen + << std::endl); + // Print out all the valid generators + cmDocumentation generatorDocs; + 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)); + } + generatorDocs.SetSection("Generators", v); + std::cerr << "\n"; + generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators, + std::cerr); + 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; +} |