/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying1file LICENSE.rst or https://cmake.org/licensing for details. */2#pragma once34#include "cmConfigure.h" // IWYU pragma: keep56#include <map>7#include <sstream>8#include <string>9#include <vector>1011#include <cm/optional>12#include <cm/string_view>1314#include "cm_sys_stat.h"1516#include "cmCPackComponentGroup.h"17#include "cmSystemTools.h"18#include "cmValue.h"1920class cmCPackLog;21class cmCryptoHash;22class cmGlobalGenerator;23class cmInstalledFile;24class cmMakefile;2526/** \class cmCPackGenerator27* \brief A superclass of all CPack Generators28*29*/30class cmCPackGenerator31{32public:33virtual char const* GetNameOfClass() = 0;34/**35* If verbose then more information is printed out36*/37void SetVerbose(bool val)38{39this->GeneratorVerbose =40val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;41}4243/**44* Put underlying cmake scripts in trace mode.45*/46void SetTrace(bool val) { this->Trace = val; }4748/**49* Put underlying cmake scripts in expanded trace mode.50*/51void SetTraceExpand(bool val) { this->TraceExpand = val; }5253/**54* Returns true if the generator may work on this system.55* Rational:56* Some CPack generator may run on some host and may not on others57* (with the same system) because some tools are missing. If the tool58* is missing then CPack won't activate (in the CPackGeneratorFactory)59* this particular generator.60*/61static bool CanGenerate() { return true; }6263/**64* Do the actual whole package processing.65* Subclass may redefine it but its usually enough66* to redefine @ref PackageFiles, because in fact67* this method do call:68* - PrepareName69* - clean-up temp dirs70* - InstallProject (with the appropriate method)71* - prepare list of files and/or components to be package72* - PackageFiles73* - Copy produced packages at the expected place74* @return 0 if error.75*/76virtual int DoPackage();7778/**79* Initialize generator80*/81int Initialize(std::string const& name, cmMakefile* mf);8283/**84* Construct generator85*/86cmCPackGenerator();87virtual ~cmCPackGenerator();8889//! Set and get the options90void SetOption(std::string const& op, char const* value);91void SetOption(std::string const& op, std::string const& value)92{93this->SetOption(op, cmValue(value));94}95void SetOption(std::string const& op, cmValue value);96void SetOptionIfNotSet(std::string const& op, char const* value);97void SetOptionIfNotSet(std::string const& op, std::string const& value)98{99this->SetOptionIfNotSet(op, cmValue(value));100}101void SetOptionIfNotSet(std::string const& op, cmValue value);102cmValue GetOption(std::string const& op) const;103std::vector<std::string> GetOptions() const;104bool IsSet(std::string const& name) const;105cmValue GetOptionIfSet(std::string const& name) const;106bool IsOn(std::string const& name) const;107bool IsSetToOff(std::string const& op) const;108bool IsSetToEmpty(std::string const& op) const;109110//! Set the logger111void SetLogger(cmCPackLog* log) { this->Logger = log; }112113//! Display verbose information via logger114void DisplayVerboseOutput(std::string const& msg, float progress);115116bool ReadListFile(char const* moduleName);117118protected:119/**120* Prepare common used names by inspecting121* several CPACK_xxx var values.122*/123int PrepareNames();124125/**126* Install the project using appropriate method.127*/128int InstallProject();129130int CleanTemporaryDirectory();131132cmInstalledFile const* GetInstalledFile(std::string const& name) const;133134virtual char const* GetOutputExtension() { return ".cpack"; }135virtual char const* GetOutputPostfix() { return nullptr; }136137/**138* Prepare requested grouping kind from CPACK_xxx vars139* CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE140* CPACK_COMPONENTS_IGNORE_GROUPS141* or142* CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP143* @return 1 on success 0 on failure.144*/145virtual int PrepareGroupingKind();146147/**148* Ensures that the given name only contains characters that can cleanly be149* used as directory or file name and returns this sanitized name. Possibly,150* this name might be replaced by its hash.151* @param[in] name the name for a directory or file that shall be sanitized.152* @param[in] isFullName true if the result is used as the full name for a153* directory or file. (Defaults to true.)154* @return the sanitized name.155*/156virtual std::string GetSanitizedDirOrFileName(std::string const& name,157bool isFullName = true) const;158159/**160* Some CPack generators may prefer to have161* CPack install all components belonging to the same162* [component] group to be install in the same directory.163* The default behavior is to install each component in164* a separate directory.165* @param[in] componentName the name of the component to be installed166* @return the name suffix the generator wants for the specified component167* default is "componentName"168*/169virtual std::string GetComponentInstallSuffix(170std::string const& componentName);171172/**173* The value that GetComponentInstallSuffix returns, but sanitized.174* @param[in] componentName the name of the component to be installed175* @return the name suffix the generator wants for the specified component176* (but sanitized, so that it can be used on the file-system).177* default is "componentName".178*/179virtual std::string GetComponentInstallDirNameSuffix(180std::string const& componentName);181182/**183* CPack specific generator may mangle CPACK_PACKAGE_FILE_NAME184* with CPACK_COMPONENT_xxxx_<NAME>_DISPLAY_NAME if185* CPACK_<GEN>_USE_DISPLAY_NAME_IN_FILENAME is ON.186* @param[in] initialPackageFileName the initial package name to be mangled187* @param[in] groupOrComponentName the name of the group/component188* @param[in] isGroupName true if previous name refers to a group,189* false otherwise190*/191virtual std::string GetComponentPackageFileName(192std::string const& initialPackageFileName,193std::string const& groupOrComponentName, bool isGroupName);194195/**196* Package the list of files and/or components which197* has been prepared by the beginning of DoPackage.198* @pre the @ref toplevel has been filled-in199* @pre the list of file @ref files has been populated200* @pre packageFileNames contains at least 1 entry201* @post packageFileNames may have been updated and contains202* the list of packages generated by the specific generator.203*/204virtual int PackageFiles();205virtual char const* GetInstallPath();206virtual char const* GetPackagingInstallPrefix();207208bool GenerateChecksumFile(cmCryptoHash& crypto,209cm::string_view filename) const;210bool CopyPackageFile(std::string const& srcFilePath,211cm::string_view filename) const;212213std::string FindTemplate(cm::string_view name,214cm::optional<cm::string_view> alt = cm::nullopt);215virtual bool ConfigureFile(std::string const& inName,216std::string const& outName,217bool copyOnly = false);218virtual bool ConfigureString(std::string const& input, std::string& output);219virtual int InitializeInternal();220221//! Run install commands if specified222virtual int InstallProjectViaInstallCommands(223bool setDestDir, std::string const& tempInstallDirectory);224virtual int InstallProjectViaInstallScript(225bool setDestDir, std::string const& tempInstallDirectory);226virtual int InstallProjectViaInstalledDirectories(227bool setDestDir, std::string const& tempInstallDirectory,228mode_t const* default_dir_mode);229virtual int InstallProjectViaInstallCMakeProjects(230bool setDestDir, std::string const& tempInstallDirectory,231mode_t const* default_dir_mode);232233virtual int RunPreinstallTarget(std::string const& installProjectName,234std::string const& installDirectory,235cmGlobalGenerator* globalGenerator,236std::string const& buildConfig);237virtual int InstallCMakeProject(238bool setDestDir, std::string const& installDirectory,239std::string const& baseTempInstallDirectory,240mode_t const* default_dir_mode, std::string const& component,241bool componentInstall, std::string const& installSubDirectory,242std::string const& buildConfig, std::string& absoluteDestFiles);243244/**245* The various level of support of246* CPACK_SET_DESTDIR used by the generator.247*/248enum CPackSetDestdirSupport249{250/* the generator works with or without it */251SETDESTDIR_SUPPORTED,252/* the generator works best if automatically handled */253SETDESTDIR_INTERNALLY_SUPPORTED,254/* no official support, use at your own risk */255SETDESTDIR_SHOULD_NOT_BE_USED,256/* officially NOT supported */257SETDESTDIR_UNSUPPORTED258};259260/**261* Does the CPack generator support CPACK_SET_DESTDIR?262* The default legacy value is 'SETDESTDIR_SUPPORTED' generator263* have to override it in order change this.264* @return CPackSetDestdirSupport265*/266virtual enum CPackSetDestdirSupport SupportsSetDestdir() const;267268/**269* Does the CPack generator support absolute path270* in INSTALL DESTINATION?271* The default legacy value is 'true' generator272* have to override it in order change this.273* @return true if supported false otherwise274*/275virtual bool SupportsAbsoluteDestination() const;276277/**278* Does the CPack generator support component installation?.279* Some Generators requires the user to set280* CPACK_<GENNAME>_COMPONENT_INSTALL in order to make this281* method return true.282* @return true if supported, false otherwise283*/284virtual bool SupportsComponentInstallation() const;285/**286* Does the currently running generator want a component installation.287* The generator may support component installation but he may288* be requiring monolithic install using CPACK_MONOLITHIC_INSTALL.289* @return true if component installation is supported and wanted.290*/291virtual bool WantsComponentInstallation() const;292virtual cmCPackInstallationType* GetInstallationType(293std::string const& projectName, std::string const& name);294virtual cmCPackComponent* GetComponent(std::string const& projectName,295std::string const& name);296virtual cmCPackComponentGroup* GetComponentGroup(297std::string const& projectName, std::string const& name);298299cmSystemTools::OutputOption GeneratorVerbose;300std::string Name;301302std::string InstallPath;303304/**305* The list of package file names.306* At beginning of DoPackage the (generic) generator will populate307* the list of desired package file names then it will308* call the redefined method PackageFiles which is may309* either use this set of names (usually on entry there should be310* only a single name) or update the vector with the list311* of created package file names.312*/313std::vector<std::string> packageFileNames;314315/**316* The directory where all the files to be packaged reside.317* If the installer support components there will be one318* sub-directory for each component. In those directories319* one will find the file belonging to the specified component.320*/321std::string toplevel;322323/**324* The complete list of files to be packaged.325* This list will be populated by DoPackage before326* PackageFiles is called.327*/328std::vector<std::string> files;329330std::vector<cmCPackInstallCMakeProject> CMakeProjects;331std::map<std::string, cmCPackInstallationType> InstallationTypes;332/**333* The set of components.334* If component installation is supported then this map335* contains the component specified in CPACK_COMPONENTS_ALL336*/337std::map<std::string, cmCPackComponent> Components;338std::map<std::string, cmCPackComponentGroup> ComponentGroups;339340/**341* If components are enabled, this enum represents the different342* ways of mapping components to package files.343*/344enum ComponentPackageMethod345{346/* one package for all components */347ONE_PACKAGE,348/* one package for each component */349ONE_PACKAGE_PER_COMPONENT,350/* one package for each group,351* with left over components in their own package */352ONE_PACKAGE_PER_GROUP,353UNKNOWN_COMPONENT_PACKAGE_METHOD354};355356/**357* The component package method358* The default is ONE_PACKAGE_PER_GROUP,359* and generators may override the default360* before PrepareGroupingKind() is called.361*/362ComponentPackageMethod componentPackageMethod;363364cmCPackLog* Logger;365bool Trace;366bool TraceExpand;367368cmMakefile* MakefileMap;369370private:371template <typename ValueType>372void StoreOption(std::string const& op, ValueType value);373template <typename ValueType>374void StoreOptionIfNotSet(std::string const& op, ValueType value);375};376377#define cmCPackTypeMacro(klass, superclass) \378using Superclass = superclass; \379const char* GetNameOfClass() override \380{ \381return #klass; \382} \383static cmCPackGenerator* CreateGenerator() \384{ \385return new klass; \386} \387class cmCPackTypeMacro_UseTrailingSemicolon388389#define cmCPackLogger(logType, msg) \390do { \391std::ostringstream cmCPackLog_msg; \392cmCPackLog_msg << msg; \393this->Logger->Log(logType, __FILE__, __LINE__, \394cmCPackLog_msg.str().c_str()); \395} while (false)396397398