Merge topic 'cpack-external'

4c71548766 Help: Add release notes for CPack External generator
47c87cdd1f Help: Add documentation for CPack External generator
2ef966bc77 Testing: Add test for CPack External generator
80914d88da CPack: Add "CPack External" generator
3ced881db6 cmCPackGenerator: Store CPACK_INSTALL_CMAKE_PROJECTS in an internal field
4938abb600 cmCPackGenerator: Refactor InstallProjectViaInstallCMakeProjects()

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2142
This commit is contained in:
Brad King
2018-07-03 14:54:57 +00:00
committed by Kitware Robot
23 changed files with 1369 additions and 291 deletions
+249
View File
@@ -0,0 +1,249 @@
CPack External Generator
------------------------
CPack provides many generators to create packages for a variety of platforms
and packaging systems. The intention is for CMake/CPack to be a complete
end-to-end solution for building and packaging a software project. However, it
may not always be possible to use CPack for the entire packaging process, due
to either technical limitations or policies that require the use of certain
tools. For this reason, CPack provides the "External" generator, which allows
external packaging software to take advantage of some of the functionality
provided by CPack, such as component installation and the dependency graph.
The CPack External generator doesn't actually package any files. Instead, it
generates a .json file containing the CPack internal metadata, which gives
external software information on how to package the software. This metadata
file contains a list of CPack components and component groups, the various
options passed to :command:`cpack_add_component` and
:command:`cpack_add_component_group`, the dependencies between the components
and component groups, and various other options passed to CPack.
Format
^^^^^^
The file produced by the CPack External generator is a .json file with an
object as its root. This root object will always provide two fields:
``formatVersionMajor`` and ``formatVersionMinor``, which are always integers
that describe the output format of the generator. Backwards-compatible changes
to the output format (for example, adding a new field that didn't exist before)
cause the minor version to be incremented, and backwards-incompatible changes
(for example, deleting a field or changing its meaning) cause the major version
to be incremented and the minor version reset to 0. The format version is
always of the format ``major.minor``. In other words, it always has exactly two
parts, separated by a period.
You can request one or more specific versions of the output format as described
below with :variable:`CPACK_EXT_REQUESTED_VERSIONS`. The output format will
have a major version that exactly matches the requested major version, and a
minor version that is greater than or equal to the requested minor version. If
no version is requested with :variable:`CPACK_EXT_REQUESTED_VERSIONS`, the
latest known major version is used by default. Currently, the only supported
format is 1.0, which is described below.
Version 1.0
***********
In addition to the standard format fields, format version 1.0 provides the
following fields in the root:
``components``
The ``components`` field is an object with component names as the keys and
objects describing the components as the values. The component objects have
the following fields:
``name``
The name of the component. This is always the same as the key in the
``components`` object.
``displayName``
The value of the ``DISPLAY_NAME`` field passed to
:command:`cpack_add_component`.
``description``
The value of the ``DESCRIPTION`` field passed to
:command:`cpack_add_component`.
``isHidden``
True if ``HIDDEN`` was passed to :command:`cpack_add_component`, false if
it was not.
``isRequired``
True if ``REQUIRED`` was passed to :command:`cpack_add_component`, false if
it was not.
``isDisabledByDefault``
True if ``DISABLED`` was passed to :command:`cpack_add_component`, false if
it was not.
``group``
Only present if ``GROUP`` was passed to :command:`cpack_add_component`. If
so, this field is a string value containing the component's group.
``dependencies``
An array of components the component depends on. This contains the values
in the ``DEPENDS`` argument passed to :command:`cpack_add_component`. If no
``DEPENDS`` argument was passed, this is an empty list.
``installationTypes``
An array of installation types the component is part of. This contains the
values in the ``INSTALL_TYPES`` argument passed to
:command:`cpack_add_component`. If no ``INSTALL_TYPES`` argument was
passed, this is an empty list.
``isDownloaded``
True if ``DOWNLOADED`` was passed to :command:`cpack_add_component`, false
if it was not.
``archiveFile``
The name of the archive file passed with the ``ARCHIVE_FILE`` argument to
:command:`cpack_add_component`. If no ``ARCHIVE_FILE`` argument was passed,
this is an empty string.
``componentGroups``
The ``componentGroups`` field is an object with component group names as the
keys and objects describing the component groups as the values. The component
group objects have the following fields:
``name``
The name of the component group. This is always the same as the key in the
``componentGroups`` object.
``displayName``
The value of the ``DISPLAY_NAME`` field passed to
:command:`cpack_add_component_group`.
``description``
The value of the ``DESCRIPTION`` field passed to
:command:`cpack_add_component_group`.
``parentGroup``
Only present if ``PARENT_GROUP`` was passed to
:command:`cpack_add_component_group`. If so, this field is a string value
containing the component group's parent group.
``isExpandedByDefault``
True if ``EXPANDED`` was passed to :command:`cpack_add_component_group`,
false if it was not.
``isBold``
True if ``BOLD_TITLE`` was passed to :command:`cpack_add_component_group`,
false if it was not.
``components``
An array of names of components that are direct members of the group
(components that have this group as their ``GROUP``). Components of
subgroups are not included.
``subgroups``
An array of names of component groups that are subgroups of the group
(groups that have this group as their ``PARENT_GROUP``).
``installationTypes``
The ``installationTypes`` field is an object with installation type names as
the keys and objects describing the installation types as the values. The
installation type objects have the following fields:
``name``
The name of the installation type. This is always the same as the key in
the ``installationTypes`` object.
``displayName``
The value of the ``DISPLAY_NAME`` field passed to
:command:`cpack_add_install_type`.
``index``
The integer index of the installation type in the list.
``projects``
The ``projects`` field is an array of objects describing CMake projects which
comprise the CPack project. The values in this field are derived from
:variable:`CPACK_INSTALL_CMAKE_PROJECTS`. In most cases, this will be only a
single project. The project objects have the following fields:
``projectName``
The project name passed to :variable:`CPACK_INSTALL_CMAKE_PROJECTS`.
``component``
The name of the component or component set which comprises the project.
``directory``
The build directory of the CMake project. This is the directory which
contains the ``cmake_install.cmake`` script.
``subDirectory``
The subdirectory to install the project into inside the CPack package.
``packageName``
The package name given in :variable:`CPACK_PACKAGE_NAME`. Only present if
this option is set.
``packageVersion``
The package version given in :variable:`CPACK_PACKAGE_VERSION`. Only present
if this option is set.
``packageDescriptionFile``
The package description file given in
:variable:`CPACK_PACKAGE_DESCRIPTION_FILE`. Only present if this option is
set.
``packageDescriptionSummary``
The package description summary given in
:variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`. Only present if this option is
set.
``buildConfig``
The build configuration given to CPack with the ``-C`` option. Only present
if this option is set.
``defaultDirectoryPermissions``
The default directory permissions given in
:variable:`CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`. Only present if this
option is set.
``setDestdir``
True if :variable:`CPACK_SET_DESTDIR` is true, false if it is not.
``packagingInstallPrefix``
The install prefix given in :variable:`CPACK_PACKAGING_INSTALL_PREFIX`. Only
present if :variable:`CPACK_SET_DESTDIR` is true.
``stripFiles``
True if :variable:`CPACK_STRIP_FILES` is true, false if it is not.
``warnOnAbsoluteInstallDestination``
True if :variable:`CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION` is true, false
if it is not.
``errorOnAbsoluteInstallDestination``
True if :variable:`CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` is true,
false if it is not.
Variables specific to CPack External generator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. variable:: CPACK_EXT_REQUESTED_VERSIONS
This variable is used to request a specific version of the CPack External
generator. It is a list of ``major.minor`` values, separated by semicolons.
If this variable is set to a non-empty value, the CPack External generator
will iterate through each item in the list to search for a version that it
knows how to generate. Requested versions should be listed in order of
descending preference by the client software, as the first matching version
in the list will be generated.
The generator knows how to generate the version if it has a versioned
generator whose major version exactly matches the requested major version,
and whose minor version is greater than or equal to the requested minor
version. For example, if ``CPACK_EXT_REQUESTED_VERSIONS`` contains 1.0, and
the CPack External generator knows how to generate 1.1, it will generate 1.1.
If the generator doesn't know how to generate a version in the list, it skips
the version and looks at the next one. If it doesn't know how to generate any
of the requested versions, an error is thrown.
If this variable is not set, or is empty, the CPack External generator will
generate the highest major and minor version that it knows how to generate.
If an invalid version is encountered in ``CPACK_EXT_REQUESTED_VERSIONS`` (one
that doesn't match ``major.minor``, where ``major`` and ``minor`` are
integers), it is ignored.
+1
View File
@@ -18,6 +18,7 @@ Generators
/cpack_gen/cygwin
/cpack_gen/deb
/cpack_gen/dmg
/cpack_gen/external
/cpack_gen/freebsd
/cpack_gen/ifw
/cpack_gen/nsis
+8
View File
@@ -0,0 +1,8 @@
cpack-external
--------------
* CPack gained a new :cpack_gen:`CPack External Generator` which is used to
export the CPack metadata in a format that other software can understand. The
intention of this generator is to allow external packaging software to take
advantage of CPack's features when it may not be possible to use CPack for
the entire packaging process.
+53
View File
@@ -0,0 +1,53 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
if(NOT "${CPACK_EXT_REQUESTED_VERSIONS}" STREQUAL "")
unset(_found_major)
foreach(_req_version IN LISTS CPACK_EXT_REQUESTED_VERSIONS)
if(_req_version MATCHES "^([0-9]+)\\.([0-9]+)$")
set(_req_major "${CMAKE_MATCH_1}")
set(_req_minor "${CMAKE_MATCH_2}")
foreach(_known_version IN LISTS CPACK_EXT_KNOWN_VERSIONS)
string(REGEX MATCH
"^([0-9]+)\\.([0-9]+)$"
_known_version_dummy
"${_known_version}"
)
set(_known_major "${CMAKE_MATCH_1}")
set(_known_minor "${CMAKE_MATCH_2}")
if(_req_major EQUAL _known_major AND NOT _known_minor LESS _req_minor)
set(_found_major "${_known_major}")
set(_found_minor "${_known_minor}")
break()
endif()
endforeach()
if(DEFINED _found_major)
break()
endif()
endif()
endforeach()
if(DEFINED _found_major)
set(CPACK_EXT_SELECTED_MAJOR "${_found_major}")
set(CPACK_EXT_SELECTED_MINOR "${_found_minor}")
set(CPACK_EXT_SELECTED_VERSION "${_found_major}.${_found_minor}")
else()
message(FATAL_ERROR
"Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS"
)
endif()
else()
list(GET CPACK_EXT_KNOWN_VERSIONS 0 CPACK_EXT_SELECTED_VERSION)
string(REGEX MATCH
"^([0-9]+)\\.([0-9]+)$"
_dummy
"${CPACK_EXT_SELECTED_VERSION}"
)
set(CPACK_EXT_SELECTED_MAJOR "${CMAKE_MATCH_1}")
set(CPACK_EXT_SELECTED_MINOR "${CMAKE_MATCH_2}")
endif()
+2 -1
View File
@@ -886,6 +886,8 @@ include_directories(
set(CPACK_SRCS
CPack/cmCPackArchiveGenerator.cxx
CPack/cmCPackComponentGroup.cxx
CPack/cmCPackDebGenerator.cxx
CPack/cmCPackExtGenerator.cxx
CPack/cmCPackGeneratorFactory.cxx
CPack/cmCPackGenerator.cxx
CPack/cmCPackLog.cxx
@@ -898,7 +900,6 @@ set(CPACK_SRCS
CPack/cmCPackTarCompressGenerator.cxx
CPack/cmCPackZIPGenerator.cxx
CPack/cmCPack7zGenerator.cxx
CPack/cmCPackDebGenerator.cxx
)
# CPack IFW generator
set(CPACK_SRCS ${CPACK_SRCS}
+25
View File
@@ -143,4 +143,29 @@ public:
std::vector<cmCPackComponentGroup*> Subgroups;
};
/** \class cmCPackInstallCMakeProject
* \brief A single quadruplet from the CPACK_INSTALL_CMAKE_PROJECTS variable.
*/
class cmCPackInstallCMakeProject
{
public:
/// The directory of the CMake project.
std::string Directory;
/// The name of the CMake project.
std::string ProjectName;
/// The name of the component (or component set) to install.
std::string Component;
/// The subdirectory to install into.
std::string SubDirectory;
/// The list of installation types.
std::vector<cmCPackInstallationType*> InstallationTypes;
/// The list of components.
std::vector<cmCPackComponent*> Components;
};
#endif
+291
View File
@@ -0,0 +1,291 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCPackExtGenerator.h"
#include "cmAlgorithms.h"
#include "cmCPackComponentGroup.h"
#include "cmCPackLog.h"
#include "cmSystemTools.h"
#include "cm_jsoncpp_value.h"
#include "cm_jsoncpp_writer.h"
#include "cmsys/FStream.hxx"
#include <utility>
#include <vector>
int cmCPackExtGenerator::InitializeInternal()
{
this->SetOption("CPACK_EXT_KNOWN_VERSIONS", "1.0");
if (!this->ReadListFile("Internal/CPack/CPackExt.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while executing CPackExt.cmake" << std::endl);
return 0;
}
std::string major = this->GetOption("CPACK_EXT_SELECTED_MAJOR");
if (major == "1") {
this->Generator = cm::make_unique<cmCPackExtVersion1Generator>(this);
}
return this->Superclass::InitializeInternal();
}
int cmCPackExtGenerator::PackageFiles()
{
Json::StreamWriterBuilder builder;
builder["indentation"] = " ";
std::string filename = "package.json";
if (!this->packageFileNames.empty()) {
filename = this->packageFileNames[0];
}
cmsys::ofstream fout(filename.c_str());
std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
Json::Value root(Json::objectValue);
if (!this->Generator->WriteToJSON(root)) {
return 0;
}
if (jout->write(root, &fout)) {
return 0;
}
return 1;
}
bool cmCPackExtGenerator::SupportsComponentInstallation() const
{
return true;
}
int cmCPackExtGenerator::InstallProjectViaInstallCommands(
bool setDestDir, const std::string& tempInstallDirectory)
{
(void)setDestDir;
(void)tempInstallDirectory;
return 1;
}
int cmCPackExtGenerator::InstallProjectViaInstallScript(
bool setDestDir, const std::string& tempInstallDirectory)
{
(void)setDestDir;
(void)tempInstallDirectory;
return 1;
}
int cmCPackExtGenerator::InstallProjectViaInstalledDirectories(
bool setDestDir, const std::string& tempInstallDirectory,
const mode_t* default_dir_mode)
{
(void)setDestDir;
(void)tempInstallDirectory;
(void)default_dir_mode;
return 1;
}
int cmCPackExtGenerator::RunPreinstallTarget(
const std::string& installProjectName, const std::string& installDirectory,
cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
{
(void)installProjectName;
(void)installDirectory;
(void)globalGenerator;
(void)buildConfig;
return 1;
}
int cmCPackExtGenerator::InstallCMakeProject(
bool setDestDir, const std::string& installDirectory,
const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
const std::string& component, bool componentInstall,
const std::string& installSubDirectory, const std::string& buildConfig,
std::string& absoluteDestFiles)
{
(void)setDestDir;
(void)installDirectory;
(void)baseTempInstallDirectory;
(void)default_dir_mode;
(void)component;
(void)componentInstall;
(void)installSubDirectory;
(void)buildConfig;
(void)absoluteDestFiles;
return 1;
}
cmCPackExtGenerator::cmCPackExtVersionGenerator::cmCPackExtVersionGenerator(
cmCPackExtGenerator* parent)
: Parent(parent)
{
}
int cmCPackExtGenerator::cmCPackExtVersionGenerator::WriteVersion(
Json::Value& root)
{
root["formatVersionMajor"] = this->GetVersionMajor();
root["formatVersionMinor"] = this->GetVersionMinor();
return 1;
}
int cmCPackExtGenerator::cmCPackExtVersionGenerator::WriteToJSON(
Json::Value& root)
{
if (!this->WriteVersion(root)) {
return 0;
}
const char* packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
if (packageName) {
root["packageName"] = packageName;
}
const char* packageVersion =
this->Parent->GetOption("CPACK_PACKAGE_VERSION");
if (packageVersion) {
root["packageVersion"] = packageVersion;
}
const char* packageDescriptionFile =
this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
if (packageDescriptionFile) {
root["packageDescriptionFile"] = packageDescriptionFile;
}
const char* packageDescriptionSummary =
this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY");
if (packageDescriptionSummary) {
root["packageDescriptionSummary"] = packageDescriptionSummary;
}
const char* buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
if (buildConfigCstr) {
root["buildConfig"] = buildConfigCstr;
}
const char* defaultDirectoryPermissions =
this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
if (defaultDirectoryPermissions && *defaultDirectoryPermissions) {
root["defaultDirectoryPermissions"] = defaultDirectoryPermissions;
}
if (cmSystemTools::IsInternallyOn(
this->Parent->GetOption("CPACK_SET_DESTDIR"))) {
root["setDestdir"] = true;
root["packagingInstallPrefix"] =
this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
} else {
root["setDestdir"] = false;
}
root["stripFiles"] =
!cmSystemTools::IsOff(this->Parent->GetOption("CPACK_STRIP_FILES"));
root["warnOnAbsoluteInstallDestination"] =
this->Parent->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION");
root["errorOnAbsoluteInstallDestination"] =
this->Parent->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION");
Json::Value& projects = root["projects"] = Json::Value(Json::arrayValue);
for (auto& project : this->Parent->CMakeProjects) {
Json::Value jsonProject(Json::objectValue);
jsonProject["projectName"] = project.ProjectName;
jsonProject["component"] = project.Component;
jsonProject["directory"] = project.Directory;
jsonProject["subDirectory"] = project.SubDirectory;
Json::Value& installationTypes = jsonProject["installationTypes"] =
Json::Value(Json::arrayValue);
for (auto& installationType : project.InstallationTypes) {
installationTypes.append(installationType->Name);
}
Json::Value& components = jsonProject["components"] =
Json::Value(Json::arrayValue);
for (auto& component : project.Components) {
components.append(component->Name);
}
projects.append(jsonProject);
}
Json::Value& installationTypes = root["installationTypes"] =
Json::Value(Json::objectValue);
for (auto& installationType : this->Parent->InstallationTypes) {
Json::Value& jsonInstallationType =
installationTypes[installationType.first] =
Json::Value(Json::objectValue);
jsonInstallationType["name"] = installationType.second.Name;
jsonInstallationType["displayName"] = installationType.second.DisplayName;
jsonInstallationType["index"] = installationType.second.Index;
}
Json::Value& components = root["components"] =
Json::Value(Json::objectValue);
for (auto& component : this->Parent->Components) {
Json::Value& jsonComponent = components[component.first] =
Json::Value(Json::objectValue);
jsonComponent["name"] = component.second.Name;
jsonComponent["displayName"] = component.second.DisplayName;
if (component.second.Group) {
jsonComponent["group"] = component.second.Group->Name;
}
jsonComponent["isRequired"] = component.second.IsRequired;
jsonComponent["isHidden"] = component.second.IsHidden;
jsonComponent["isDisabledByDefault"] =
component.second.IsDisabledByDefault;
jsonComponent["isDownloaded"] = component.second.IsDownloaded;
jsonComponent["description"] = component.second.Description;
jsonComponent["archiveFile"] = component.second.ArchiveFile;
Json::Value& cmpInstallationTypes = jsonComponent["installationTypes"] =
Json::Value(Json::arrayValue);
for (auto& installationType : component.second.InstallationTypes) {
cmpInstallationTypes.append(installationType->Name);
}
Json::Value& dependencies = jsonComponent["dependencies"] =
Json::Value(Json::arrayValue);
for (auto& dep : component.second.Dependencies) {
dependencies.append(dep->Name);
}
}
Json::Value& groups = root["componentGroups"] =
Json::Value(Json::objectValue);
for (auto& group : this->Parent->ComponentGroups) {
Json::Value& jsonGroup = groups[group.first] =
Json::Value(Json::objectValue);
jsonGroup["name"] = group.second.Name;
jsonGroup["displayName"] = group.second.DisplayName;
jsonGroup["description"] = group.second.Description;
jsonGroup["isBold"] = group.second.IsBold;
jsonGroup["isExpandedByDefault"] = group.second.IsExpandedByDefault;
if (group.second.ParentGroup) {
jsonGroup["parentGroup"] = group.second.ParentGroup->Name;
}
Json::Value& subgroups = jsonGroup["subgroups"] =
Json::Value(Json::arrayValue);
for (auto& subgroup : group.second.Subgroups) {
subgroups.append(subgroup->Name);
}
Json::Value& groupComponents = jsonGroup["components"] =
Json::Value(Json::arrayValue);
for (auto& component : group.second.Components) {
groupComponents.append(component->Name);
}
}
return 1;
}
+86
View File
@@ -0,0 +1,86 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCPackExtGenerator_h
#define cmCPackExtGenerator_h
#include "cmCPackGenerator.h"
#include "cm_sys_stat.h"
#include <memory>
#include <string>
class cmGlobalGenerator;
namespace Json {
class Value;
}
/** \class cmCPackExtGenerator
* \brief A generator for CPack External packaging tools
*/
class cmCPackExtGenerator : public cmCPackGenerator
{
public:
cmCPackTypeMacro(cmCPackExtGenerator, cmCPackGenerator);
const char* GetOutputExtension() override { return ".json"; }
protected:
int InitializeInternal() override;
int PackageFiles() override;
bool SupportsComponentInstallation() const override;
int InstallProjectViaInstallCommands(
bool setDestDir, const std::string& tempInstallDirectory) override;
int InstallProjectViaInstallScript(
bool setDestDir, const std::string& tempInstallDirectory) override;
int InstallProjectViaInstalledDirectories(
bool setDestDir, const std::string& tempInstallDirectory,
const mode_t* default_dir_mode) override;
int RunPreinstallTarget(const std::string& installProjectName,
const std::string& installDirectory,
cmGlobalGenerator* globalGenerator,
const std::string& buildConfig) override;
int InstallCMakeProject(bool setDestDir, const std::string& installDirectory,
const std::string& baseTempInstallDirectory,
const mode_t* default_dir_mode,
const std::string& component, bool componentInstall,
const std::string& installSubDirectory,
const std::string& buildConfig,
std::string& absoluteDestFiles) override;
private:
class cmCPackExtVersionGenerator
{
public:
cmCPackExtVersionGenerator(cmCPackExtGenerator* parent);
virtual ~cmCPackExtVersionGenerator() = default;
virtual int WriteToJSON(Json::Value& root);
protected:
virtual int GetVersionMajor() = 0;
virtual int GetVersionMinor() = 0;
int WriteVersion(Json::Value& root);
cmCPackExtGenerator* Parent;
};
class cmCPackExtVersion1Generator : public cmCPackExtVersionGenerator
{
public:
using cmCPackExtVersionGenerator::cmCPackExtVersionGenerator;
protected:
int GetVersionMajor() override { return 1; }
int GetVersionMinor() override { return 0; }
};
std::unique_ptr<cmCPackExtVersionGenerator> Generator;
};
#endif
+310 -286
View File
@@ -545,10 +545,13 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
++it;
std::string installProjectName = *it;
++it;
std::string installComponent = *it;
cmCPackInstallCMakeProject project;
project.Directory = installDirectory;
project.ProjectName = installProjectName;
project.Component = *it;
++it;
std::string installSubDirectory = *it;
std::string installFile = installDirectory + "/cmake_install.cmake";
project.SubDirectory = *it;
std::vector<std::string> componentsVector;
@@ -559,34 +562,36 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
* - the user did not request Monolithic install
* (this works at CPack time too)
*/
if (this->SupportsComponentInstallation() &
if (this->SupportsComponentInstallation() &&
!(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
// Determine the installation types for this project (if provided).
std::string installTypesVar = "CPACK_" +
cmSystemTools::UpperCase(installComponent) + "_INSTALL_TYPES";
cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
const char* installTypes = this->GetOption(installTypesVar);
if (installTypes && *installTypes) {
std::vector<std::string> installTypesVector;
cmSystemTools::ExpandListArgument(installTypes, installTypesVector);
for (std::string const& installType : installTypesVector) {
this->GetInstallationType(installProjectName, installType);
project.InstallationTypes.push_back(
this->GetInstallationType(project.ProjectName, installType));
}
}
// Determine the set of components that will be used in this project
std::string componentsVar =
"CPACK_COMPONENTS_" + cmSystemTools::UpperCase(installComponent);
"CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component);
const char* components = this->GetOption(componentsVar);
if (components && *components) {
cmSystemTools::ExpandListArgument(components, componentsVector);
for (std::string const& comp : componentsVector) {
GetComponent(installProjectName, comp);
project.Components.push_back(
this->GetComponent(project.ProjectName, comp));
}
componentInstall = true;
}
}
if (componentsVector.empty()) {
componentsVector.push_back(installComponent);
componentsVector.push_back(project.Component);
}
const char* buildConfigCstr = this->GetOption("CPACK_BUILD_CONFIG");
@@ -606,293 +611,27 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
// on windows.
cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
// Does this generator require pre-install?
if (const char* preinstall =
globalGenerator->GetPreinstallTargetName()) {
std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
preinstall, buildConfig, "", false);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Install command: " << buildCommand << std::endl);
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Run preinstall target for: " << installProjectName
<< std::endl);
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
buildCommand.c_str(), &output, &output, &retVal,
installDirectory.c_str(), this->GeneratorVerbose,
cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
tmpFile += "/PreinstallOutput.log";
cmGeneratedFileStream ofs(tmpFile.c_str());
ofs << "# Run command: " << buildCommand << std::endl
<< "# Directory: " << installDirectory << std::endl
<< "# Output:" << std::endl
<< output << std::endl;
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem running install command: "
<< buildCommand << std::endl
<< "Please check " << tmpFile << " for errors"
<< std::endl);
return 0;
}
if (!this->RunPreinstallTarget(project.ProjectName, project.Directory,
globalGenerator, buildConfig)) {
return 0;
}
delete globalGenerator;
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Install project: " << installProjectName << std::endl);
"- Install project: " << project.ProjectName << std::endl);
// Run the installation for each component
for (std::string const& component : componentsVector) {
std::string tempInstallDirectory = baseTempInstallDirectory;
installComponent = component;
if (componentInstall) {
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Install component: " << installComponent
<< std::endl);
}
cmake cm(cmake::RoleScript);
cm.SetHomeDirectory("");
cm.SetHomeOutputDirectory("");
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cm.AddCMakePaths();
cm.SetProgressCallback(cmCPackGeneratorProgress, this);
cm.SetTrace(this->Trace);
cm.SetTraceExpand(this->TraceExpand);
cmGlobalGenerator gg(&cm);
cmMakefile mf(&gg, cm.GetCurrentSnapshot());
if (!installSubDirectory.empty() && installSubDirectory != "/" &&
installSubDirectory != ".") {
tempInstallDirectory += installSubDirectory;
}
if (componentInstall) {
tempInstallDirectory += "/";
// Some CPack generators would rather chose
// the local installation directory suffix.
// Some (e.g. RPM) use
// one install directory for each component **GROUP**
// instead of the default
// one install directory for each component.
tempInstallDirectory +=
GetComponentInstallDirNameSuffix(installComponent);
if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
tempInstallDirectory += "/";
tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
}
}
const char* default_dir_inst_permissions =
this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
if (default_dir_inst_permissions && *default_dir_inst_permissions) {
mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
default_dir_inst_permissions);
}
if (!setDestDir) {
tempInstallDirectory += this->GetPackagingInstallPrefix();
}
if (setDestDir) {
// For DESTDIR based packaging, use the *project*
// CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
// value of the project's CMAKE_INSTALL_PREFIX is sent in here as
// the value of the CPACK_INSTALL_PREFIX variable.
//
// If DESTDIR has been 'internally set ON' this means that
// the underlying CPack specific generator did ask for that
// In this case we may override CPACK_INSTALL_PREFIX with
// CPACK_PACKAGING_INSTALL_PREFIX
// I know this is tricky and awkward but it's the price for
// CPACK_SET_DESTDIR backward compatibility.
if (cmSystemTools::IsInternallyOn(
this->GetOption("CPACK_SET_DESTDIR"))) {
this->SetOption("CPACK_INSTALL_PREFIX",
this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
}
std::string dir;
if (this->GetOption("CPACK_INSTALL_PREFIX")) {
dir += this->GetOption("CPACK_INSTALL_PREFIX");
}
mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
cmCPackLogger(
cmCPackLog::LOG_DEBUG,
"- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
<< std::endl);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
<< std::endl);
// Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
// exists:
//
if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) {
dir = tempInstallDirectory + dir;
} else {
dir = tempInstallDirectory + "/" + dir;
}
/*
* We must re-set DESTDIR for each component
* We must not add the CPACK_INSTALL_PREFIX part because
* it will be added using the override of CMAKE_INSTALL_PREFIX
* The main reason for this awkward trick is that
* are using DESTDIR for 2 different reasons:
* - Because it was asked by the CPack Generator or the user
* using CPACK_SET_DESTDIR
* - Because it was already used for component install
* in order to put things in subdirs...
*/
cmSystemTools::PutEnv(std::string("DESTDIR=") +
tempInstallDirectory);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Creating directory: '" << dir << "'" << std::endl);
if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
cmCPackLogger(
cmCPackLog::LOG_ERROR,
"Problem creating temporary directory: " << dir << std::endl);
return 0;
}
} else {
mf.AddDefinition("CMAKE_INSTALL_PREFIX",
tempInstallDirectory.c_str());
if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
default_dir_mode)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem creating temporary directory: "
<< tempInstallDirectory << std::endl);
return 0;
}
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Using non-DESTDIR install... (mf.AddDefinition)"
<< std::endl);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Setting CMAKE_INSTALL_PREFIX to '"
<< tempInstallDirectory << "'" << std::endl);
}
if (!buildConfig.empty()) {
mf.AddDefinition("BUILD_TYPE", buildConfig.c_str());
}
std::string installComponentLowerCase =
cmSystemTools::LowerCase(installComponent);
if (installComponentLowerCase != "all") {
mf.AddDefinition("CMAKE_INSTALL_COMPONENT",
installComponent.c_str());
}
// strip on TRUE, ON, 1, one or several file names, but not on
// FALSE, OFF, 0 and an empty string
if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) {
mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
}
// Remember the list of files before installation
// of the current component (if we are in component install)
std::string const& InstallPrefix = tempInstallDirectory;
std::vector<std::string> filesBefore;
std::string findExpr = tempInstallDirectory;
if (componentInstall) {
cmsys::Glob glB;
findExpr += "/*";
glB.RecurseOn();
glB.SetRecurseListDirs(true);
glB.FindFiles(findExpr);
filesBefore = glB.GetFiles();
std::sort(filesBefore.begin(), filesBefore.end());
}
// If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
// then forward request to cmake_install.cmake script
if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
}
// If current CPack generator does support
// ABSOLUTE INSTALL DESTINATION or CPack has been asked for
// then ask cmake_install.cmake script to error out
// as soon as it occurs (before installing file)
if (!SupportsAbsoluteDestination() ||
this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
}
// do installation
int res = mf.ReadListFile(installFile.c_str());
// forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
// to CPack (may be used by generators like CPack RPM or DEB)
// in order to transparently handle ABSOLUTE PATH
if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
mf.AddDefinition(
"CPACK_ABSOLUTE_DESTINATION_FILES",
mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
}
// Now rebuild the list of files after installation
// of the current component (if we are in component install)
if (componentInstall) {
cmsys::Glob glA;
glA.RecurseOn();
glA.SetRecurseListDirs(true);
glA.SetRecurseThroughSymlinks(false);
glA.FindFiles(findExpr);
std::vector<std::string> filesAfter = glA.GetFiles();
std::sort(filesAfter.begin(), filesAfter.end());
std::vector<std::string>::iterator diff;
std::vector<std::string> result(filesAfter.size());
diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
filesBefore.begin(), filesBefore.end(),
result.begin());
std::vector<std::string>::iterator fit;
std::string localFileName;
// Populate the File field of each component
for (fit = result.begin(); fit != diff; ++fit) {
localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
localFileName =
localFileName.substr(localFileName.find_first_not_of('/'));
Components[installComponent].Files.push_back(localFileName);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"Adding file <"
<< localFileName << "> to component <"
<< installComponent << ">" << std::endl);
}
}
if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
if (!absoluteDestFiles.empty()) {
absoluteDestFiles += ";";
}
absoluteDestFiles +=
mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"Got some ABSOLUTE DESTINATION FILES: "
<< absoluteDestFiles << std::endl);
// define component specific var
if (componentInstall) {
std::string absoluteDestFileComponent =
std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
GetComponentInstallDirNameSuffix(installComponent);
if (nullptr != this->GetOption(absoluteDestFileComponent)) {
std::string absoluteDestFilesListComponent =
this->GetOption(absoluteDestFileComponent);
absoluteDestFilesListComponent += ";";
absoluteDestFilesListComponent +=
mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
this->SetOption(absoluteDestFileComponent,
absoluteDestFilesListComponent.c_str());
} else {
this->SetOption(
absoluteDestFileComponent,
mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
}
}
}
if (cmSystemTools::GetErrorOccuredFlag() || !res) {
if (!this->InstallCMakeProject(
setDestDir, project.Directory, baseTempInstallDirectory,
default_dir_mode, component, componentInstall,
project.SubDirectory, buildConfig, absoluteDestFiles)) {
return 0;
}
}
this->CMakeProjects.push_back(project);
}
}
this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
@@ -900,6 +639,291 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
return 1;
}
int cmCPackGenerator::RunPreinstallTarget(
const std::string& installProjectName, const std::string& installDirectory,
cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
{
// Does this generator require pre-install?
if (const char* preinstall = globalGenerator->GetPreinstallTargetName()) {
std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
preinstall, buildConfig, "", false);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Install command: " << buildCommand << std::endl);
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Run preinstall target for: " << installProjectName
<< std::endl);
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
buildCommand.c_str(), &output, &output, &retVal,
installDirectory.c_str(), this->GeneratorVerbose, cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
tmpFile += "/PreinstallOutput.log";
cmGeneratedFileStream ofs(tmpFile.c_str());
ofs << "# Run command: " << buildCommand << std::endl
<< "# Directory: " << installDirectory << std::endl
<< "# Output:" << std::endl
<< output << std::endl;
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem running install command: "
<< buildCommand << std::endl
<< "Please check " << tmpFile << " for errors"
<< std::endl);
return 0;
}
}
return 1;
}
int cmCPackGenerator::InstallCMakeProject(
bool setDestDir, const std::string& installDirectory,
const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
const std::string& component, bool componentInstall,
const std::string& installSubDirectory, const std::string& buildConfig,
std::string& absoluteDestFiles)
{
std::string tempInstallDirectory = baseTempInstallDirectory;
std::string installFile = installDirectory + "/cmake_install.cmake";
if (componentInstall) {
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Install component: " << component << std::endl);
}
cmake cm(cmake::RoleScript);
cm.SetHomeDirectory("");
cm.SetHomeOutputDirectory("");
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cm.AddCMakePaths();
cm.SetProgressCallback(cmCPackGeneratorProgress, this);
cm.SetTrace(this->Trace);
cm.SetTraceExpand(this->TraceExpand);
cmGlobalGenerator gg(&cm);
cmMakefile mf(&gg, cm.GetCurrentSnapshot());
if (!installSubDirectory.empty() && installSubDirectory != "/" &&
installSubDirectory != ".") {
tempInstallDirectory += installSubDirectory;
}
if (componentInstall) {
tempInstallDirectory += "/";
// Some CPack generators would rather chose
// the local installation directory suffix.
// Some (e.g. RPM) use
// one install directory for each component **GROUP**
// instead of the default
// one install directory for each component.
tempInstallDirectory += GetComponentInstallDirNameSuffix(component);
if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
tempInstallDirectory += "/";
tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
}
}
const char* default_dir_inst_permissions =
this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
if (default_dir_inst_permissions && *default_dir_inst_permissions) {
mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
default_dir_inst_permissions);
}
if (!setDestDir) {
tempInstallDirectory += this->GetPackagingInstallPrefix();
}
if (setDestDir) {
// For DESTDIR based packaging, use the *project*
// CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
// value of the project's CMAKE_INSTALL_PREFIX is sent in here as
// the value of the CPACK_INSTALL_PREFIX variable.
//
// If DESTDIR has been 'internally set ON' this means that
// the underlying CPack specific generator did ask for that
// In this case we may override CPACK_INSTALL_PREFIX with
// CPACK_PACKAGING_INSTALL_PREFIX
// I know this is tricky and awkward but it's the price for
// CPACK_SET_DESTDIR backward compatibility.
if (cmSystemTools::IsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"))) {
this->SetOption("CPACK_INSTALL_PREFIX",
this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
}
std::string dir;
if (this->GetOption("CPACK_INSTALL_PREFIX")) {
dir += this->GetOption("CPACK_INSTALL_PREFIX");
}
mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
cmCPackLogger(
cmCPackLog::LOG_DEBUG,
"- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
<< std::endl);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
<< std::endl);
// Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
// exists:
//
if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) {
dir = tempInstallDirectory + dir;
} else {
dir = tempInstallDirectory + "/" + dir;
}
/*
* We must re-set DESTDIR for each component
* We must not add the CPACK_INSTALL_PREFIX part because
* it will be added using the override of CMAKE_INSTALL_PREFIX
* The main reason for this awkward trick is that
* are using DESTDIR for 2 different reasons:
* - Because it was asked by the CPack Generator or the user
* using CPACK_SET_DESTDIR
* - Because it was already used for component install
* in order to put things in subdirs...
*/
cmSystemTools::PutEnv(std::string("DESTDIR=") + tempInstallDirectory);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Creating directory: '" << dir << "'" << std::endl);
if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem creating temporary directory: " << dir
<< std::endl);
return 0;
}
} else {
mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
default_dir_mode)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem creating temporary directory: "
<< tempInstallDirectory << std::endl);
return 0;
}
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Using non-DESTDIR install... (mf.AddDefinition)"
<< std::endl);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Setting CMAKE_INSTALL_PREFIX to '" << tempInstallDirectory
<< "'" << std::endl);
}
if (!buildConfig.empty()) {
mf.AddDefinition("BUILD_TYPE", buildConfig.c_str());
}
std::string installComponentLowerCase = cmSystemTools::LowerCase(component);
if (installComponentLowerCase != "all") {
mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component.c_str());
}
// strip on TRUE, ON, 1, one or several file names, but not on
// FALSE, OFF, 0 and an empty string
if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) {
mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
}
// Remember the list of files before installation
// of the current component (if we are in component install)
std::string const& InstallPrefix = tempInstallDirectory;
std::vector<std::string> filesBefore;
std::string findExpr = tempInstallDirectory;
if (componentInstall) {
cmsys::Glob glB;
findExpr += "/*";
glB.RecurseOn();
glB.SetRecurseListDirs(true);
glB.FindFiles(findExpr);
filesBefore = glB.GetFiles();
std::sort(filesBefore.begin(), filesBefore.end());
}
// If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
// then forward request to cmake_install.cmake script
if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
}
// If current CPack generator does support
// ABSOLUTE INSTALL DESTINATION or CPack has been asked for
// then ask cmake_install.cmake script to error out
// as soon as it occurs (before installing file)
if (!SupportsAbsoluteDestination() ||
this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
}
// do installation
int res = mf.ReadListFile(installFile.c_str());
// forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
// to CPack (may be used by generators like CPack RPM or DEB)
// in order to transparently handle ABSOLUTE PATH
if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES",
mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
}
// Now rebuild the list of files after installation
// of the current component (if we are in component install)
if (componentInstall) {
cmsys::Glob glA;
glA.RecurseOn();
glA.SetRecurseListDirs(true);
glA.SetRecurseThroughSymlinks(false);
glA.FindFiles(findExpr);
std::vector<std::string> filesAfter = glA.GetFiles();
std::sort(filesAfter.begin(), filesAfter.end());
std::vector<std::string>::iterator diff;
std::vector<std::string> result(filesAfter.size());
diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
filesBefore.begin(), filesBefore.end(),
result.begin());
std::vector<std::string>::iterator fit;
std::string localFileName;
// Populate the File field of each component
for (fit = result.begin(); fit != diff; ++fit) {
localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
localFileName =
localFileName.substr(localFileName.find_first_not_of('/'));
Components[component].Files.push_back(localFileName);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"Adding file <" << localFileName << "> to component <"
<< component << ">" << std::endl);
}
}
if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
if (!absoluteDestFiles.empty()) {
absoluteDestFiles += ";";
}
absoluteDestFiles += mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles
<< std::endl);
// define component specific var
if (componentInstall) {
std::string absoluteDestFileComponent =
std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
GetComponentInstallDirNameSuffix(component);
if (nullptr != this->GetOption(absoluteDestFileComponent)) {
std::string absoluteDestFilesListComponent =
this->GetOption(absoluteDestFileComponent);
absoluteDestFilesListComponent += ";";
absoluteDestFilesListComponent +=
mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
this->SetOption(absoluteDestFileComponent,
absoluteDestFilesListComponent.c_str());
} else {
this->SetOption(absoluteDestFileComponent,
mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
}
}
}
if (cmSystemTools::GetErrorOccuredFlag() || !res) {
return 0;
}
return 1;
}
bool cmCPackGenerator::ReadListFile(const char* moduleName)
{
bool retval;
+13
View File
@@ -15,6 +15,7 @@
#include "cm_sys_stat.h"
class cmCPackLog;
class cmGlobalGenerator;
class cmInstalledFile;
class cmMakefile;
@@ -185,6 +186,17 @@ protected:
bool setDestDir, const std::string& tempInstallDirectory,
const mode_t* default_dir_mode);
virtual int RunPreinstallTarget(const std::string& installProjectName,
const std::string& installDirectory,
cmGlobalGenerator* globalGenerator,
const std::string& buildConfig);
virtual int InstallCMakeProject(
bool setDestDir, const std::string& installDirectory,
const std::string& baseTempInstallDirectory,
const mode_t* default_dir_mode, const std::string& component,
bool componentInstall, const std::string& installSubDirectory,
const std::string& buildConfig, std::string& absoluteDestFiles);
/**
* The various level of support of
* CPACK_SET_DESTDIR used by the generator.
@@ -271,6 +283,7 @@ protected:
*/
std::vector<std::string> files;
std::vector<cmCPackInstallCMakeProject> CMakeProjects;
std::map<std::string, cmCPackInstallationType> InstallationTypes;
/**
* The set of components.
+5
View File
@@ -12,6 +12,7 @@
# include "cmCPackFreeBSDGenerator.h"
#endif
#include "cmCPackDebGenerator.h"
#include "cmCPackExtGenerator.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
#include "cmCPackNSISGenerator.h"
@@ -110,6 +111,10 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
this->RegisterGenerator("NuGet", "NuGet packages",
cmCPackNuGetGenerator::CreateGenerator);
}
if (cmCPackExtGenerator::CanGenerate()) {
this->RegisterGenerator("Ext", "CPack External packages",
cmCPackExtGenerator::CreateGenerator);
}
#ifdef __APPLE__
if (cmCPackDragNDropGenerator::CanGenerate()) {
this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",
+1 -1
View File
@@ -422,7 +422,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
add_RunCMake_test(ctest_labels_for_subprojects)
endif()
add_RunCMake_test_group(CPack "DEB;RPM;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ")
add_RunCMake_test_group(CPack "DEB;RPM;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;Ext")
# add a test to make sure symbols are exported from a shared library
# for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
add_RunCMake_test(AutoExportDll)
+31
View File
@@ -0,0 +1,31 @@
function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
set(${RESULT_VAR} "${NAME}-${VERSION}-*.json" PARENT_SCOPE)
endfunction()
function(getPackageContentList FILE RESULT_VAR)
set("${RESULT_VAR}" "" PARENT_SCOPE)
endfunction()
function(toExpectedContentList FILE_NO CONTENT_VAR)
set("${CONTENT_VAR}" "" PARENT_SCOPE)
endfunction()
set(ALL_FILES_GLOB "*.json")
function(check_ext_json EXPECTED_FILE ACTUAL_FILE)
file(READ "${EXPECTED_FILE}" _expected_regex)
file(READ "${ACTUAL_FILE}" _actual_contents)
string(REGEX REPLACE "\n+$" "" _expected_regex "${_expected_regex}")
string(REGEX REPLACE "\n+$" "" _actual_contents "${_actual_contents}")
if(NOT "${_actual_contents}" MATCHES "${_expected_regex}")
message(FATAL_ERROR
"Output JSON does not match expected regex.\n"
"Expected regex:\n"
"${_expected_regex}\n"
"Actual output:\n"
"${_actual_contents}\n"
)
endif()
endfunction()
+2 -1
View File
@@ -18,7 +18,7 @@ run_cpack_test(GENERATE_SHLIBS_LDCONFIG "DEB" true "COMPONENT")
run_cpack_test(INSTALL_SCRIPTS "RPM" false "COMPONENT")
run_cpack_test(LONG_FILENAMES "DEB" false "MONOLITHIC")
run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM" false "COMPONENT")
run_cpack_test(MINIMAL "RPM;DEB;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ" false "MONOLITHIC;COMPONENT")
run_cpack_test(MINIMAL "RPM;DEB;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;Ext" false "MONOLITHIC;COMPONENT")
run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false "MONOLITHIC")
run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM" false "COMPONENT")
run_cpack_test(PER_COMPONENT_FIELDS "RPM;DEB" false "COMPONENT")
@@ -31,3 +31,4 @@ run_cpack_test(USER_FILELIST "RPM" false "MONOLITHIC")
run_cpack_test(MD5SUMS "DEB" false "MONOLITHIC;COMPONENT")
run_cpack_test(CPACK_INSTALL_SCRIPT "ZIP" false "MONOLITHIC")
run_cpack_test(DEB_PACKAGE_VERSION_BACK_COMPATIBILITY "DEB" false "MONOLITHIC;COMPONENT")
run_cpack_test_subtests(EXT "none;good;good_multi;bad_major;bad_minor;invalid_good;invalid_bad" "Ext" false "MONOLITHIC;COMPONENT")
+6 -2
View File
@@ -56,8 +56,12 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
set(EXPECTED_FILE_CONTENT_${file_no_} "${EXPECTED_FILE_CONTENT_${file_no_}_LIST}")
toExpectedContentList("${file_no_}" "EXPECTED_FILE_CONTENT_${file_no_}")
list(SORT PACKAGE_CONTENT)
list(SORT EXPECTED_FILE_CONTENT_${file_no_})
if(NOT PACKAGE_CONTENT STREQUAL "")
list(SORT PACKAGE_CONTENT)
endif()
if(NOT EXPECTED_FILE_CONTENT_${file_no_} STREQUAL "")
list(SORT EXPECTED_FILE_CONTENT_${file_no_})
endif()
if(PACKAGE_CONTENT STREQUAL EXPECTED_FILE_CONTENT_${file_no_})
set(expected_content_list TRUE)
@@ -0,0 +1,6 @@
if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)$")
set(EXPECTED_FILES_COUNT "1")
set(EXPECTED_FILE_CONTENT_1_LIST "/share;/share/cpack-test;/share/cpack-test/f1.txt;/share/cpack-test/f2.txt;/share/cpack-test/f3.txt;/share/cpack-test/f4.txt")
else()
set(EXPECTED_FILES_COUNT "0")
endif()
@@ -0,0 +1,3 @@
if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)")
check_ext_json("${src_dir}/tests/EXT/expected-json-1.0.txt" "${FOUND_FILE_1}")
endif()
@@ -0,0 +1,6 @@
CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
CPack Error: Error while executing CPackExt\.cmake
CPack Error: Cannot initialize the generator Ext
@@ -0,0 +1,6 @@
CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
CPack Error: Error while executing CPackExt\.cmake
CPack Error: Cannot initialize the generator Ext
@@ -0,0 +1,176 @@
^\{
"componentGroups" :[ ]
\{
"f12" :[ ]
\{
"components" :[ ]
\[
"f1",
"f2"
\],
"description" : "Component group for files 1 and 2",
"displayName" : "Files 1 and 2",
"isBold" : false,
"isExpandedByDefault" : false,
"name" : "f12",
"parentGroup" : "f1234",
"subgroups" : \[\]
\},
"f1234" :[ ]
\{
"components" : \[\],
"description" : "Component group for all files",
"displayName" : "Files 1-4",
"isBold" : false,
"isExpandedByDefault" : false,
"name" : "f1234",
"subgroups" :[ ]
\[
"f12",
"f34"
\]
\},
"f34" :[ ]
\{
"components" :[ ]
\[
"f3",
"f4"
\],
"description" : "Component group for files 3 and 4",
"displayName" : "Files 3 and 4",
"isBold" : false,
"isExpandedByDefault" : false,
"name" : "f34",
"parentGroup" : "f1234",
"subgroups" : \[\]
\}
\},
"components" :[ ]
\{
"f1" :[ ]
\{
"archiveFile" : "",
"dependencies" : \[\],
"description" : "Component for file 1",
"displayName" : "File 1",
"group" : "f12",
"installationTypes" :[ ]
\[
"full",
"f12"
\],
"isDisabledByDefault" : false,
"isDownloaded" : false,
"isHidden" : false,
"isRequired" : false,
"name" : "f1"
\},
"f2" :[ ]
\{
"archiveFile" : "",
"dependencies" :[ ]
\[
"f1"
\],
"description" : "Component for file 2",
"displayName" : "File 2",
"group" : "f12",
"installationTypes" :[ ]
\[
"full",
"f12"
\],
"isDisabledByDefault" : false,
"isDownloaded" : false,
"isHidden" : false,
"isRequired" : false,
"name" : "f2"
\},
"f3" :[ ]
\{
"archiveFile" : "",
"dependencies" :[ ]
\[
"f1",
"f2"
\],
"description" : "Component for file 3",
"displayName" : "File 3",
"group" : "f34",
"installationTypes" :[ ]
\[
"full"
\],
"isDisabledByDefault" : false,
"isDownloaded" : false,
"isHidden" : false,
"isRequired" : false,
"name" : "f3"
\},
"f4" :[ ]
\{
"archiveFile" : "",
"dependencies" :[ ]
\[
"f2",
"f3",
"f1"
\],
"description" : "Component for file 4",
"displayName" : "File 4",
"group" : "f34",
"installationTypes" :[ ]
\[
"full"
\],
"isDisabledByDefault" : false,
"isDownloaded" : false,
"isHidden" : false,
"isRequired" : false,
"name" : "f4"
\}
\},
"errorOnAbsoluteInstallDestination" : false,
"formatVersionMajor" : 1,
"formatVersionMinor" : 0,
"installationTypes" :[ ]
\{
"f12" :[ ]
\{
"displayName" : "Only files 1 and 2",
"index" : 2,
"name" : "f12"
\},
"full" :[ ]
\{
"displayName" : "Full installation",
"index" : 1,
"name" : "full"
\}
\},
"packageDescriptionFile" : ".*/Templates/CPack\.GenericDescription\.txt",
"packageDescriptionSummary" : "EXT-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type built using CMake",
"packageName" : "ext",
"packageVersion" : "0\.1\.1",
"projects" :[ ]
\[
\{
"component" : "ALL",
"components" :[ ]
\[
"f1",
"f2",
"f3",
"f4"
\],
"directory" : ".*/Tests/RunCMake/Ext/CPack/EXT-build-(none|good(_multi)?|invalid_good)-subtest",
"installationTypes" : \[\],
"projectName" : "EXT-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type",
"subDirectory" : "/"
\}
\],
"setDestdir" : false,
"stripFiles" : false,
"warnOnAbsoluteInstallDestination" : false
\}$
@@ -0,0 +1,6 @@
CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
CPack Error: Error while executing CPackExt\.cmake
CPack Error: Cannot initialize the generator Ext
+83
View File
@@ -0,0 +1,83 @@
include(CPackComponent)
if(RunCMake_SUBTEST_SUFFIX STREQUAL "none")
unset(CPACK_EXT_REQUESTED_VERSIONS)
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good")
set(CPACK_EXT_REQUESTED_VERSIONS "1.0")
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good_multi")
set(CPACK_EXT_REQUESTED_VERSIONS "1.0;2.0")
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_major")
set(CPACK_EXT_REQUESTED_VERSIONS "2.0")
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_minor")
set(CPACK_EXT_REQUESTED_VERSIONS "1.1")
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_good")
set(CPACK_EXT_REQUESTED_VERSIONS "1;1.0")
elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_bad")
set(CPACK_EXT_REQUESTED_VERSIONS "1")
endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" test1)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" test2)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" test3)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" test4)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" DESTINATION share/cpack-test COMPONENT f1)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" DESTINATION share/cpack-test COMPONENT f2)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" DESTINATION share/cpack-test COMPONENT f3)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" DESTINATION share/cpack-test COMPONENT f4)
cpack_add_component(f1
DISPLAY_NAME "File 1"
DESCRIPTION "Component for file 1"
GROUP f12
INSTALL_TYPES full f12
)
cpack_add_component(f2
DISPLAY_NAME "File 2"
DESCRIPTION "Component for file 2"
GROUP f12
DEPENDS f1
INSTALL_TYPES full f12
)
cpack_add_component(f3
DISPLAY_NAME "File 3"
DESCRIPTION "Component for file 3"
GROUP f34
DEPENDS f1 f2
INSTALL_TYPES full
)
cpack_add_component(f4
DISPLAY_NAME "File 4"
DESCRIPTION "Component for file 4"
GROUP f34
DEPENDS f2 f3 f1
INSTALL_TYPES full
)
cpack_add_component_group(f12
DISPLAY_NAME "Files 1 and 2"
DESCRIPTION "Component group for files 1 and 2"
PARENT_GROUP f1234
)
cpack_add_component_group(f34
DISPLAY_NAME "Files 3 and 4"
DESCRIPTION "Component group for files 3 and 4"
PARENT_GROUP f1234
)
cpack_add_component_group(f1234
DISPLAY_NAME "Files 1-4"
DESCRIPTION "Component group for all files"
)
cpack_add_install_type(full
DISPLAY_NAME "Full installation"
)
cpack_add_install_type(f12
DISPLAY_NAME "Only files 1 and 2"
)