CPack/Deb: Add ability to split out debug symbols into .ddeb package

This commit is contained in:
Andrew Fuller
2018-09-21 20:19:31 +00:00
parent 42fbff45e4
commit d8a3939aef
10 changed files with 746 additions and 423 deletions
+20
View File
@@ -518,6 +518,26 @@ List of CPack Deb generator specific variables:
This value is not interpreted. It is possible to pass an optional
revision number of the referenced source package as well.
Packaging of debug information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dbgsym packages contain debug symbols for debugging packaged binaries.
Dbgsym packaging has its own set of variables:
.. variable:: CPACK_DEBIAN_DEBUGINFO_PACKAGE
CPACK_DEBIAN_<component>_DEBUGINFO_PACKAGE
Enable generation of dbgsym .ddeb package(s).
* Mandatory : NO
* Default : OFF
.. note::
Binaries must contain debug symbols before packaging so use either ``Debug``
or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
Building Debian packages on Windows
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,6 @@
cpack-deb-dbgsym-ddeb
---------------------
* The :cpack_gen:`CPack Deb Generator` learned to split debug symbols into
a corresponding .ddeb package when ``CPACK_DEBIAN_DEBUGINFO_PACKAGE`` is
set.
+96 -4
View File
@@ -64,6 +64,8 @@ function(cpack_deb_prepare_package_vars)
endif()
set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}")
set(DBGSYMDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}-dbgsym")
file(REMOVE_RECURSE "${DBGSYMDIR}")
# per component automatic discover: some of the component might not have
# binaries.
@@ -80,7 +82,10 @@ function(cpack_deb_prepare_package_vars)
endif()
endif()
if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OR CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS)
cpack_deb_variable_fallback("CPACK_DEBIAN_DEBUGINFO_PACKAGE"
"CPACK_DEBIAN_${_local_component_name}_DEBUGINFO_PACKAGE"
"CPACK_DEBIAN_DEBUGINFO_PACKAGE")
if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OR CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS OR CPACK_DEBIAN_DEBUGINFO_PACKAGE)
# Generating binary list - Get type of all install files
file(GLOB_RECURSE FILE_PATHS_ LIST_DIRECTORIES false RELATIVE "${WDIR}" "${WDIR}/*")
@@ -114,6 +119,81 @@ function(cpack_deb_prepare_package_vars)
string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
list(APPEND CPACK_DEB_SHARED_OBJECT_FILES "${CMAKE_MATCH_1}")
endif()
if(_FILE MATCHES "ELF.*not stripped")
string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
list(APPEND CPACK_DEB_UNSTRIPPED_FILES "${CMAKE_MATCH_1}")
endif()
endforeach()
endif()
find_program(READELF_EXECUTABLE NAMES readelf)
if(CPACK_DEBIAN_DEBUGINFO_PACKAGE AND CPACK_DEB_UNSTRIPPED_FILES)
find_program(OBJCOPY_EXECUTABLE NAMES objcopy)
if(NOT OBJCOPY_EXECUTABLE)
message(FATAL_ERROR "debuginfo packages require the objcopy tool")
endif()
if(NOT READELF_EXECUTABLE)
message(FATAL_ERROR "debuginfo packages require the readelf tool")
endif()
file(RELATIVE_PATH _DBGSYM_ROOT "${CPACK_TEMPORARY_DIRECTORY}" "${DBGSYMDIR}")
foreach(_FILE IN LISTS CPACK_DEB_UNSTRIPPED_FILES)
# Get the file's Build ID
execute_process(COMMAND env LC_ALL=C ${READELF_EXECUTABLE} -n "${_FILE}"
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
OUTPUT_VARIABLE READELF_OUTPUT
RESULT_VARIABLE READELF_RESULT
ERROR_VARIABLE READELF_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE )
if(NOT READELF_RESULT EQUAL 0)
message(FATAL_ERROR "CPackDeb: readelf: '${READELF_ERROR}';\n"
"executed command: '${READELF_EXECUTABLE} -n ${_FILE}'")
endif()
if(READELF_OUTPUT MATCHES "Build ID: ([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z]*)")
set(_BUILD_ID_START ${CMAKE_MATCH_1})
set(_BUILD_ID_REMAINING ${CMAKE_MATCH_2})
list(APPEND BUILD_IDS ${_BUILD_ID_START}${_BUILD_ID_REMAINING})
else()
message(FATAL_ERROR "Unable to determine Build ID for ${_FILE}")
endif()
# Split out the debug symbols from the binaries
set(_FILE_DBGSYM ${_DBGSYM_ROOT}/usr/lib/debug/.build-id/${_BUILD_ID_START}/${_BUILD_ID_REMAINING}.debug)
get_filename_component(_OUT_DIR "${_FILE_DBGSYM}" DIRECTORY)
file(MAKE_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}/${_OUT_DIR}")
execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --only-keep-debug "${_FILE}" "${_FILE_DBGSYM}"
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
OUTPUT_VARIABLE OBJCOPY_OUTPUT
RESULT_VARIABLE OBJCOPY_RESULT
ERROR_VARIABLE OBJCOPY_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE )
if(NOT OBJCOPY_RESULT EQUAL 0)
message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
"executed command: '${OBJCOPY_EXECUTABLE} --only-keep-debug ${_FILE} ${_FILE_DBGSYM}'")
endif()
execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --strip-unneeded ${_FILE}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
OUTPUT_VARIABLE OBJCOPY_OUTPUT
RESULT_VARIABLE OBJCOPY_RESULT
ERROR_VARIABLE OBJCOPY_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE )
if(NOT OBJCOPY_RESULT EQUAL 0)
message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
"executed command: '${OBJCOPY_EXECUTABLE} --strip-debug ${_FILE}'")
endif()
execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
OUTPUT_VARIABLE OBJCOPY_OUTPUT
RESULT_VARIABLE OBJCOPY_RESULT
ERROR_VARIABLE OBJCOPY_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE )
if(NOT OBJCOPY_RESULT EQUAL 0)
message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
"executed command: '${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}'")
endif()
endforeach()
endif()
@@ -450,8 +530,6 @@ function(cpack_deb_prepare_package_vars)
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
endif()
find_program(READELF_EXECUTABLE NAMES readelf)
if(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS)
if(READELF_EXECUTABLE)
foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
@@ -507,18 +585,24 @@ function(cpack_deb_prepare_package_vars)
# <foo>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb
set(CPACK_OUTPUT_FILE_NAME
"${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
set(CPACK_DBGSYM_OUTPUT_FILE_NAME
"${CPACK_DEBIAN_PACKAGE_NAME}-dbgsym_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.ddeb")
else()
if(NOT CPACK_DEBIAN_FILE_NAME MATCHES ".*\\.(deb|ipk)")
message(FATAL_ERROR "'${CPACK_DEBIAN_FILE_NAME}' is not a valid DEB package file name as it must end with '.deb' or '.ipk'!")
endif()
set(CPACK_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
endif()
set(CPACK_TEMPORARY_PACKAGE_FILE_NAME "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_OUTPUT_FILE_NAME}")
get_filename_component(BINARY_DIR "${CPACK_OUTPUT_FILE_PATH}" DIRECTORY)
set(CPACK_OUTPUT_FILE_PATH "${BINARY_DIR}/${CPACK_OUTPUT_FILE_NAME}")
endif() # else() back compatibility - don't change the name
else()
# back compatibility - don't change the name
string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
endif()
# Print out some debug information if we were asked for that
if(CPACK_DEBIAN_PACKAGE_DEBUG)
@@ -579,6 +663,14 @@ function(cpack_deb_prepare_package_vars)
set(GEN_CPACK_DEBIAN_GENERATE_POSTINST "${CPACK_DEBIAN_GENERATE_POSTINST}" PARENT_SCOPE)
set(GEN_CPACK_DEBIAN_GENERATE_POSTRM "${CPACK_DEBIAN_GENERATE_POSTRM}" PARENT_SCOPE)
set(GEN_WDIR "${WDIR}" PARENT_SCOPE)
set(GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE "${CPACK_DEBIAN_DEBUGINFO_PACKAGE}" PARENT_SCOPE)
if(BUILD_IDS)
set(GEN_DBGSYMDIR "${DBGSYMDIR}" PARENT_SCOPE)
set(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DBGSYM_OUTPUT_FILE_NAME}" PARENT_SCOPE)
string(REPLACE ";" " " BUILD_IDS "${BUILD_IDS}")
set(GEN_BUILD_IDS "${BUILD_IDS}" PARENT_SCOPE)
endif()
endfunction()
cpack_deb_prepare_package_vars()
+584 -408
View File
@@ -12,11 +12,430 @@
#include "cm_sys_stat.h"
#include "cmsys/Glob.hxx"
#include <map>
#include <ostream>
#include <set>
#include <string.h>
#include <utility>
namespace {
class DebGenerator
{
public:
DebGenerator(cmCPackLog* logger, std::string const& outputName,
std::string const& workDir, std::string const& topLevelDir,
std::string const& temporaryDir,
const char* debianCompressionType,
const char* debianArchiveType,
std::map<std::string, std::string> const& controlValues,
bool genShLibs, std::string const& shLibsFilename,
bool genPostInst, std::string const& postInst, bool genPostRm,
std::string const& postRm, const char* controlExtra,
bool permissionStrctPolicy,
std::vector<std::string> const& packageFiles);
bool generate() const;
private:
void generateDebianBinaryFile() const;
void generateControlFile() const;
bool generateDataTar() const;
std::string generateMD5File() const;
bool generateControlTar(std::string const& md5Filename) const;
bool generateDeb() const;
cmCPackLog* Logger;
const std::string OutputName;
const std::string WorkDir;
std::string CompressionSuffix;
const std::string TopLevelDir;
const std::string TemporaryDir;
const char* DebianArchiveType;
const std::map<std::string, std::string> ControlValues;
const bool GenShLibs;
const std::string ShLibsFilename;
const bool GenPostInst;
const std::string PostInst;
const bool GenPostRm;
const std::string PostRm;
const char* ControlExtra;
const bool PermissionStrictPolicy;
const std::vector<std::string> PackageFiles;
cmArchiveWrite::Compress TarCompressionType;
};
DebGenerator::DebGenerator(
cmCPackLog* logger, std::string const& outputName,
std::string const& workDir, std::string const& topLevelDir,
std::string const& temporaryDir, const char* debianCompressionType,
const char* debianArchiveType,
std::map<std::string, std::string> const& controlValues, bool genShLibs,
std::string const& shLibsFilename, bool genPostInst,
std::string const& postInst, bool genPostRm, std::string const& postRm,
const char* controlExtra, bool permissionStrictPolicy,
std::vector<std::string> const& packageFiles)
: Logger(logger)
, OutputName(outputName)
, WorkDir(workDir)
, TopLevelDir(topLevelDir)
, TemporaryDir(temporaryDir)
, DebianArchiveType(debianArchiveType ? debianArchiveType : "paxr")
, ControlValues(controlValues)
, GenShLibs(genShLibs)
, ShLibsFilename(shLibsFilename)
, GenPostInst(genPostInst)
, PostInst(postInst)
, GenPostRm(genPostRm)
, PostRm(postRm)
, ControlExtra(controlExtra)
, PermissionStrictPolicy(permissionStrictPolicy)
, PackageFiles(packageFiles)
{
if (!debianCompressionType) {
debianCompressionType = "gzip";
}
if (!strcmp(debianCompressionType, "lzma")) {
CompressionSuffix = ".lzma";
TarCompressionType = cmArchiveWrite::CompressLZMA;
} else if (!strcmp(debianCompressionType, "xz")) {
CompressionSuffix = ".xz";
TarCompressionType = cmArchiveWrite::CompressXZ;
} else if (!strcmp(debianCompressionType, "bzip2")) {
CompressionSuffix = ".bz2";
TarCompressionType = cmArchiveWrite::CompressBZip2;
} else if (!strcmp(debianCompressionType, "gzip")) {
CompressionSuffix = ".gz";
TarCompressionType = cmArchiveWrite::CompressGZip;
} else if (!strcmp(debianCompressionType, "none")) {
CompressionSuffix.clear();
TarCompressionType = cmArchiveWrite::CompressNone;
} else {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error unrecognized compression type: "
<< debianCompressionType << std::endl);
}
}
bool DebGenerator::generate() const
{
generateDebianBinaryFile();
generateControlFile();
if (!generateDataTar()) {
return false;
}
std::string md5Filename = generateMD5File();
if (!generateControlTar(md5Filename)) {
return false;
}
return generateDeb();
}
void DebGenerator::generateDebianBinaryFile() const
{
// debian-binary file
const std::string dbfilename = WorkDir + "/debian-binary";
cmGeneratedFileStream out(dbfilename);
out << "2.0";
out << std::endl; // required for valid debian package
}
void DebGenerator::generateControlFile() const
{
std::string ctlfilename = WorkDir + "/control";
cmGeneratedFileStream out(ctlfilename);
for (auto const& kv : ControlValues) {
out << kv.first << ": " << kv.second << "\n";
}
unsigned long totalSize = 0;
{
std::string dirName = TemporaryDir;
dirName += '/';
for (std::string const& file : PackageFiles) {
totalSize += cmSystemTools::FileLength(file);
}
}
out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
out << std::endl;
}
bool DebGenerator::generateDataTar() const
{
std::string filename_data_tar = WorkDir + "/data.tar" + CompressionSuffix;
cmGeneratedFileStream fileStream_data_tar;
fileStream_data_tar.Open(filename_data_tar, false, true);
if (!fileStream_data_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \""
<< filename_data_tar << "\" for writing" << std::endl);
return false;
}
cmArchiveWrite data_tar(fileStream_data_tar, TarCompressionType,
DebianArchiveType);
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
data_tar.SetUIDAndGID(0u, 0u);
data_tar.SetUNAMEAndGNAME("root", "root");
// now add all directories which have to be compressed
// collect all top level install dirs for that
// e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
// give /usr and /opt
size_t topLevelLength = WorkDir.length();
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"WDIR: \"" << WorkDir << "\", length = " << topLevelLength
<< std::endl);
std::set<std::string> orderedFiles;
// we have to reconstruct the parent folders as well
for (std::string currentPath : PackageFiles) {
while (currentPath != WorkDir) {
// the last one IS WorkDir, but we do not want this one:
// XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
// should not add XXX/application
orderedFiles.insert(currentPath);
currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
}
}
for (std::string const& file : orderedFiles) {
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"FILEIT: \"" << file << "\"" << std::endl);
std::string::size_type slashPos = file.find('/', topLevelLength + 1);
std::string relativeDir =
file.substr(topLevelLength, slashPos - topLevelLength);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
#ifdef WIN32
std::string mode_t_adt_filename = file + ":cmake_mode_t";
cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
mode_t permissions = 0;
if (permissionStream) {
permissionStream >> std::oct >> permissions;
}
if (permissions != 0) {
data_tar.SetPermissions(permissions);
} else if (cmSystemTools::FileIsDirectory(file)) {
data_tar.SetPermissions(0755);
} else {
data_tar.ClearPermissions();
}
#endif
// do not recurse because the loop will do it
if (!data_tar.Add(file, topLevelLength, ".", false)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem adding file to tar:"
<< std::endl
<< "#top level directory: " << WorkDir << std::endl
<< "#file: " << file << std::endl
<< "#error:" << data_tar.GetError() << std::endl);
return false;
}
}
return true;
}
std::string DebGenerator::generateMD5File() const
{
std::string md5filename = WorkDir + "/md5sums";
cmGeneratedFileStream out(md5filename);
std::string topLevelWithTrailingSlash = TemporaryDir;
topLevelWithTrailingSlash += '/';
for (std::string const& file : PackageFiles) {
// hash only regular files
if (cmSystemTools::FileIsDirectory(file) ||
cmSystemTools::FileIsSymlink(file)) {
continue;
}
std::string output =
cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
if (output.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem computing the md5 of " << file << std::endl);
}
output += " " + file + "\n";
// debian md5sums entries are like this:
// 014f3604694729f3bf19263bac599765 usr/bin/ccmake
// thus strip the full path (with the trailing slash)
cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
"");
out << output;
}
// each line contains a eol.
// Do not end the md5sum file with yet another (invalid)
return md5filename;
}
bool DebGenerator::generateControlTar(std::string const& md5Filename) const
{
std::string filename_control_tar = WorkDir + "/control.tar.gz";
cmGeneratedFileStream fileStream_control_tar;
fileStream_control_tar.Open(filename_control_tar, false, true);
if (!fileStream_control_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \""
<< filename_control_tar << "\" for writing" << std::endl);
return false;
}
cmArchiveWrite control_tar(fileStream_control_tar,
cmArchiveWrite::CompressGZip, DebianArchiveType);
// sets permissions and uid/gid for the files
control_tar.SetUIDAndGID(0u, 0u);
control_tar.SetUNAMEAndGNAME("root", "root");
/* permissions are set according to
https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
and
https://lintian.debian.org/tags/control-file-has-bad-permissions.html
*/
const mode_t permission644 = 0644;
const mode_t permissionExecute = 0111;
const mode_t permission755 = permission644 | permissionExecute;
// for md5sum and control (that we have generated here), we use 644
// (RW-R--R--)
// so that deb lintian doesn't warn about it
control_tar.SetPermissions(permission644);
// adds control and md5sums
if (!control_tar.Add(md5Filename, WorkDir.length(), ".") ||
!control_tar.Add(WorkDir + "/control", WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << WorkDir << std::endl
<< "#file: \"control\" or \"md5sums\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
// adds generated shlibs file
if (GenShLibs) {
if (!control_tar.Add(ShLibsFilename, WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << WorkDir << std::endl
<< "#file: \"shlibs\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
}
// adds LDCONFIG related files
if (GenPostInst) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(PostInst, WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << WorkDir << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
control_tar.SetPermissions(permission644);
}
if (GenPostRm) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(PostRm, WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << WorkDir << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
control_tar.SetPermissions(permission644);
}
// for the other files, we use
// -either the original permission on the files
// -either a permission strictly defined by the Debian policies
if (ControlExtra) {
// permissions are now controlled by the original file permissions
static const char* strictFiles[] = { "config", "postinst", "postrm",
"preinst", "prerm" };
std::set<std::string> setStrictFiles(
strictFiles, strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
// default
control_tar.ClearPermissions();
std::vector<std::string> controlExtraList;
cmSystemTools::ExpandListArgument(ControlExtra, controlExtraList);
for (std::string const& i : controlExtraList) {
std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
std::string localcopy = WorkDir + "/" + filenamename;
if (PermissionStrictPolicy) {
control_tar.SetPermissions(
setStrictFiles.count(filenamename) ? permission755 : permission644);
}
// if we can copy the file, it means it does exist, let's add it:
if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
control_tar.Add(localcopy, WorkDir.length(), ".");
}
}
}
return true;
}
bool DebGenerator::generateDeb() const
{
// ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
// A debian package .deb is simply an 'ar' archive. The only subtle
// difference is that debian uses the BSD ar style archive whereas most
// Linux distro have a GNU ar.
// See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
std::string const outputPath = TopLevelDir + "/" + OutputName;
std::string const tlDir = WorkDir + "/";
cmGeneratedFileStream debStream;
debStream.Open(outputPath, false, true);
cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
deb.SetUIDAndGID(0u, 0u);
deb.SetUNAMEAndGNAME("root", "root");
if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
!deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
!deb.Add(tlDir + "data.tar" + CompressionSuffix, tlDir.length())) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error creating debian package:"
<< std::endl
<< "#top level directory: " << TopLevelDir << std::endl
<< "#file: " << OutputName << std::endl
<< "#error:" << deb.GetError() << std::endl);
return false;
}
return true;
}
} // end anonymous namespace
cmCPackDebGenerator::cmCPackDebGenerator()
{
}
@@ -68,18 +487,20 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
return retval;
}
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_WDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
{ // Isolate globbing of binaries vs. dbgsyms
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_WDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
}
packageFiles = gl.GetFiles();
}
packageFiles = gl.GetFiles();
int res = createDeb();
if (res != 1) {
@@ -90,6 +511,32 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
packageFileName += "/";
packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
packageFileNames.push_back(std::move(packageFileName));
if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE")) {
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
}
packageFiles = gl.GetFiles();
res = createDbgsymDDeb();
if (res != 1) {
retval = 0;
}
// add the generated package to package file names list
packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
packageFileName += "/";
packageFileName += this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME");
packageFileNames.push_back(std::move(packageFileName));
}
return retval;
}
@@ -234,112 +681,81 @@ int cmCPackDebGenerator::PackageFiles()
int cmCPackDebGenerator::createDeb()
{
// debian-binary file
const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
const std::string dbfilename = strGenWDIR + "/debian-binary";
{ // the scope is needed for cmGeneratedFileStream
cmGeneratedFileStream out(dbfilename);
out << "2.0";
out << std::endl; // required for valid debian package
}
// control file
std::string ctlfilename = strGenWDIR + "/control";
std::map<std::string, std::string> controlValues;
// debian policy enforce lower case for package name
// mandatory entries:
std::string debian_pkg_name = cmsys::SystemTools::LowerCase(
controlValues["Package"] = cmsys::SystemTools::LowerCase(
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
const char* debian_pkg_version =
controlValues["Version"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
const char* debian_pkg_section =
controlValues["Section"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
const char* debian_pkg_priority =
controlValues["Priority"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
const char* debian_pkg_arch =
controlValues["Architecture"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
const char* maintainer =
controlValues["Maintainer"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
const char* desc = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
controlValues["Description"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
// optional entries
const char* debian_pkg_dep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
const char* debian_pkg_rec =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
const char* debian_pkg_sug =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
const char* debian_pkg_url =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
const char* debian_pkg_predep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
const char* debian_pkg_enhances =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
const char* debian_pkg_breaks =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
const char* debian_pkg_conflicts =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
const char* debian_pkg_provides =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
const char* debian_pkg_replaces =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
const char* debian_pkg_source =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
{ // the scope is needed for cmGeneratedFileStream
cmGeneratedFileStream out(ctlfilename);
out << "Package: " << debian_pkg_name << "\n";
out << "Version: " << debian_pkg_version << "\n";
out << "Section: " << debian_pkg_section << "\n";
out << "Priority: " << debian_pkg_priority << "\n";
out << "Architecture: " << debian_pkg_arch << "\n";
if (debian_pkg_source && *debian_pkg_source) {
out << "Source: " << debian_pkg_source << "\n";
}
if (debian_pkg_dep && *debian_pkg_dep) {
out << "Depends: " << debian_pkg_dep << "\n";
}
if (debian_pkg_rec && *debian_pkg_rec) {
out << "Recommends: " << debian_pkg_rec << "\n";
}
if (debian_pkg_sug && *debian_pkg_sug) {
out << "Suggests: " << debian_pkg_sug << "\n";
}
if (debian_pkg_url && *debian_pkg_url) {
out << "Homepage: " << debian_pkg_url << "\n";
}
if (debian_pkg_predep && *debian_pkg_predep) {
out << "Pre-Depends: " << debian_pkg_predep << "\n";
}
if (debian_pkg_enhances && *debian_pkg_enhances) {
out << "Enhances: " << debian_pkg_enhances << "\n";
}
if (debian_pkg_breaks && *debian_pkg_breaks) {
out << "Breaks: " << debian_pkg_breaks << "\n";
}
if (debian_pkg_conflicts && *debian_pkg_conflicts) {
out << "Conflicts: " << debian_pkg_conflicts << "\n";
}
if (debian_pkg_provides && *debian_pkg_provides) {
out << "Provides: " << debian_pkg_provides << "\n";
}
if (debian_pkg_replaces && *debian_pkg_replaces) {
out << "Replaces: " << debian_pkg_replaces << "\n";
}
unsigned long totalSize = 0;
{
std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
dirName += '/';
for (std::string const& file : packageFiles) {
totalSize += cmSystemTools::FileLength(file);
}
}
out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
out << "Maintainer: " << maintainer << "\n";
out << "Description: " << desc << "\n";
out << std::endl;
if (debian_pkg_source && *debian_pkg_source) {
controlValues["Source"] = debian_pkg_source;
}
const char* debian_pkg_dep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
if (debian_pkg_dep && *debian_pkg_dep) {
controlValues["Depends"] = debian_pkg_dep;
}
const char* debian_pkg_rec =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
if (debian_pkg_rec && *debian_pkg_rec) {
controlValues["Recommends"] = debian_pkg_rec;
}
const char* debian_pkg_sug =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
if (debian_pkg_sug && *debian_pkg_sug) {
controlValues["Suggests"] = debian_pkg_sug;
}
const char* debian_pkg_url =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
if (debian_pkg_url && *debian_pkg_url) {
controlValues["Homepage"] = debian_pkg_url;
}
const char* debian_pkg_predep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
if (debian_pkg_predep && *debian_pkg_predep) {
controlValues["Pre-Depends"] = debian_pkg_predep;
}
const char* debian_pkg_enhances =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
if (debian_pkg_enhances && *debian_pkg_enhances) {
controlValues["Enhances"] = debian_pkg_enhances;
}
const char* debian_pkg_breaks =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
if (debian_pkg_breaks && *debian_pkg_breaks) {
controlValues["Breaks"] = debian_pkg_breaks;
}
const char* debian_pkg_conflicts =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
if (debian_pkg_conflicts && *debian_pkg_conflicts) {
controlValues["Conflicts"] = debian_pkg_conflicts;
}
const char* debian_pkg_provides =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
if (debian_pkg_provides && *debian_pkg_provides) {
controlValues["Provides"] = debian_pkg_provides;
}
const char* debian_pkg_replaces =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
if (debian_pkg_replaces && *debian_pkg_replaces) {
controlValues["Replaces"] = debian_pkg_replaces;
}
const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
const std::string shlibsfilename = strGenWDIR + "/shlibs";
const char* debian_pkg_shlibs =
@@ -371,314 +787,74 @@ int cmCPackDebGenerator::createDeb()
"fi\n";
}
cmArchiveWrite::Compress tar_compression_type = cmArchiveWrite::CompressGZip;
const char* debian_compression_type =
this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE");
if (!debian_compression_type) {
debian_compression_type = "gzip";
DebGenerator gen(
Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm,
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"),
this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
packageFiles);
if (!gen.generate()) {
return 0;
}
return 1;
}
int cmCPackDebGenerator::createDbgsymDDeb()
{
// Packages containing debug symbols follow the same structure as .debs
// but have different metadata and content.
std::map<std::string, std::string> controlValues;
// debian policy enforce lower case for package name
std::string packageNameLower = cmsys::SystemTools::LowerCase(
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
const char* debian_pkg_version =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
controlValues["Package"] = packageNameLower + "-dbgsym";
controlValues["Package-Type"] = "ddeb";
controlValues["Version"] = debian_pkg_version;
controlValues["Auto-Built-Package"] = "debug-symbols";
controlValues["Depends"] = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") +
std::string(" (= ") + debian_pkg_version + ")";
controlValues["Section"] = "debug";
controlValues["Priority"] = "optional";
controlValues["Architecture"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
controlValues["Maintainer"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
controlValues["Description"] =
std::string("debug symbols for ") + packageNameLower;
const char* debian_pkg_source =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
if (debian_pkg_source && *debian_pkg_source) {
controlValues["Source"] = debian_pkg_source;
}
const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS");
if (debian_build_ids && *debian_build_ids) {
controlValues["Build-Ids"] = debian_build_ids;
}
std::string compression_suffix;
if (!strcmp(debian_compression_type, "lzma")) {
compression_suffix = ".lzma";
tar_compression_type = cmArchiveWrite::CompressLZMA;
} else if (!strcmp(debian_compression_type, "xz")) {
compression_suffix = ".xz";
tar_compression_type = cmArchiveWrite::CompressXZ;
} else if (!strcmp(debian_compression_type, "bzip2")) {
compression_suffix = ".bz2";
tar_compression_type = cmArchiveWrite::CompressBZip2;
} else if (!strcmp(debian_compression_type, "gzip")) {
compression_suffix = ".gz";
tar_compression_type = cmArchiveWrite::CompressGZip;
} else if (!strcmp(debian_compression_type, "none")) {
compression_suffix.clear();
tar_compression_type = cmArchiveWrite::CompressNone;
} else {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error unrecognized compression type: "
<< debian_compression_type << std::endl);
}
DebGenerator gen(
Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
this->GetOption("GEN_DBGSYMDIR"),
const char* debian_archive_type =
this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE");
if (!debian_archive_type) {
debian_archive_type = "paxr";
}
this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
false, "", false, "", nullptr,
this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
packageFiles);
std::string filename_data_tar =
strGenWDIR + "/data.tar" + compression_suffix;
// atomic file generation for data.tar
{
cmGeneratedFileStream fileStream_data_tar;
fileStream_data_tar.Open(filename_data_tar, false, true);
if (!fileStream_data_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \""
<< filename_data_tar << "\" for writing" << std::endl);
return 0;
}
cmArchiveWrite data_tar(fileStream_data_tar, tar_compression_type,
debian_archive_type);
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
data_tar.SetUIDAndGID(0u, 0u);
data_tar.SetUNAMEAndGNAME("root", "root");
// now add all directories which have to be compressed
// collect all top level install dirs for that
// e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
// give /usr and /opt
size_t topLevelLength = strGenWDIR.length();
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"WDIR: \"" << strGenWDIR << "\", length = " << topLevelLength
<< std::endl);
std::set<std::string> orderedFiles;
// we have to reconstruct the parent folders as well
for (std::string currentPath : packageFiles) {
while (currentPath != strGenWDIR) {
// the last one IS strGenWDIR, but we do not want this one:
// XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
// should not add XXX/application
orderedFiles.insert(currentPath);
currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
}
}
for (std::string const& file : orderedFiles) {
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"FILEIT: \"" << file << "\"" << std::endl);
std::string::size_type slashPos = file.find('/', topLevelLength + 1);
std::string relativeDir =
file.substr(topLevelLength, slashPos - topLevelLength);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
#ifdef WIN32
std::string mode_t_adt_filename = file + ":cmake_mode_t";
cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
mode_t permissions = 0;
if (permissionStream) {
permissionStream >> std::oct >> permissions;
}
if (permissions != 0) {
data_tar.SetPermissions(permissions);
} else if (cmSystemTools::FileIsDirectory(file)) {
data_tar.SetPermissions(0755);
} else {
data_tar.ClearPermissions();
}
#endif
// do not recurse because the loop will do it
if (!data_tar.Add(file, topLevelLength, ".", false)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem adding file to tar:"
<< std::endl
<< "#top level directory: " << strGenWDIR << std::endl
<< "#file: " << file << std::endl
<< "#error:" << data_tar.GetError() << std::endl);
return 0;
}
}
} // scope for file generation
std::string md5filename = strGenWDIR + "/md5sums";
{
// the scope is needed for cmGeneratedFileStream
cmGeneratedFileStream out(md5filename);
std::string topLevelWithTrailingSlash =
this->GetOption("CPACK_TEMPORARY_DIRECTORY");
topLevelWithTrailingSlash += '/';
for (std::string const& file : packageFiles) {
// hash only regular files
if (cmSystemTools::FileIsDirectory(file) ||
cmSystemTools::FileIsSymlink(file)) {
continue;
}
std::string output =
cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
if (output.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem computing the md5 of " << file << std::endl);
}
output += " " + file + "\n";
// debian md5sums entries are like this:
// 014f3604694729f3bf19263bac599765 usr/bin/ccmake
// thus strip the full path (with the trailing slash)
cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
"");
out << output;
}
// each line contains a eol.
// Do not end the md5sum file with yet another (invalid)
}
std::string filename_control_tar = strGenWDIR + "/control.tar.gz";
// atomic file generation for control.tar
{
cmGeneratedFileStream fileStream_control_tar;
fileStream_control_tar.Open(filename_control_tar, false, true);
if (!fileStream_control_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \"" << filename_control_tar
<< "\" for writing"
<< std::endl);
return 0;
}
cmArchiveWrite control_tar(fileStream_control_tar,
cmArchiveWrite::CompressGZip,
debian_archive_type);
// sets permissions and uid/gid for the files
control_tar.SetUIDAndGID(0u, 0u);
control_tar.SetUNAMEAndGNAME("root", "root");
/* permissions are set according to
https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
and
https://lintian.debian.org/tags/control-file-has-bad-permissions.html
*/
const mode_t permission644 = 0644;
const mode_t permissionExecute = 0111;
const mode_t permission755 = permission644 | permissionExecute;
// for md5sum and control (that we have generated here), we use 644
// (RW-R--R--)
// so that deb lintian doesn't warn about it
control_tar.SetPermissions(permission644);
// adds control and md5sums
if (!control_tar.Add(md5filename, strGenWDIR.length(), ".") ||
!control_tar.Add(strGenWDIR + "/control", strGenWDIR.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << strGenWDIR << std::endl
<< "#file: \"control\" or \"md5sums\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return 0;
}
// adds generated shlibs file
if (gen_shibs) {
if (!control_tar.Add(shlibsfilename, strGenWDIR.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << strGenWDIR << std::endl
<< "#file: \"shlibs\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return 0;
}
}
// adds LDCONFIG related files
if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(postinst, strGenWDIR.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << strGenWDIR << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return 0;
}
control_tar.SetPermissions(permission644);
}
if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(postrm, strGenWDIR.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << strGenWDIR << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return 0;
}
control_tar.SetPermissions(permission644);
}
// for the other files, we use
// -either the original permission on the files
// -either a permission strictly defined by the Debian policies
const char* controlExtra =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA");
if (controlExtra) {
// permissions are now controlled by the original file permissions
const bool permissionStrictPolicy =
this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION");
static const char* strictFiles[] = { "config", "postinst", "postrm",
"preinst", "prerm" };
std::set<std::string> setStrictFiles(
strictFiles,
strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
// default
control_tar.ClearPermissions();
std::vector<std::string> controlExtraList;
cmSystemTools::ExpandListArgument(controlExtra, controlExtraList);
for (std::string const& i : controlExtraList) {
std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
std::string localcopy = strGenWDIR + "/" + filenamename;
if (permissionStrictPolicy) {
control_tar.SetPermissions(setStrictFiles.count(filenamename)
? permission755
: permission644);
}
// if we can copy the file, it means it does exist, let's add it:
if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
control_tar.Add(localcopy, strGenWDIR.length(), ".");
}
}
}
}
// ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
// A debian package .deb is simply an 'ar' archive. The only subtle
// difference is that debian uses the BSD ar style archive whereas most
// Linux distro have a GNU ar.
// See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
std::string const outputDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
std::string const outputName = this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
std::string const outputPath = outputDir + "/" + outputName;
std::string const tlDir = strGenWDIR + "/";
cmGeneratedFileStream debStream;
debStream.Open(outputPath, false, true);
cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
deb.SetUIDAndGID(0u, 0u);
deb.SetUNAMEAndGNAME("root", "root");
if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
!deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
!deb.Add(tlDir + "data.tar" + compression_suffix, tlDir.length())) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error creating debian package:"
<< std::endl
<< "#top level directory: " << outputDir << std::endl
<< "#file: " << outputName << std::endl
<< "#error:" << deb.GetError() << std::endl);
if (!gen.generate()) {
return 0;
}
return 1;
+2
View File
@@ -65,6 +65,8 @@ protected:
private:
int createDeb();
int createDbgsymDDeb();
std::vector<std::string> packageFiles;
};
+1 -1
View File
@@ -1,4 +1,4 @@
set(ALL_FILES_GLOB "*.deb")
set(ALL_FILES_GLOB "*.deb" "*.ddeb")
function(getPackageContent FILE RESULT_VAR)
execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${DPKG_EXECUTABLE} -c "${FILE}"
+1 -1
View File
@@ -6,7 +6,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
# run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM" false "MONOLITHIC;COMPONENT")
run_cpack_test(CUSTOM_NAMES "RPM;DEB;TGZ" true "COMPONENT")
run_cpack_test(DEBUGINFO "RPM" true "COMPONENT")
run_cpack_test(DEBUGINFO "RPM;DEB" true "COMPONENT")
run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM;DEB" false "MONOLITHIC;COMPONENT")
run_cpack_test(DEPENDENCIES "RPM;DEB" true "COMPONENT")
run_cpack_test(DIST "RPM" false "MONOLITHIC")
+1 -1
View File
@@ -92,7 +92,7 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
# check that there were no extra files generated
foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
file(GLOB foundAll_ RELATIVE "${bin_dir}" "${all_files_glob_}")
list(APPEND allFoundFiles_ "${foundAll_}")
list(APPEND allFoundFiles_ ${foundAll_})
endforeach()
list(LENGTH foundFiles_ foundFilesCount_)
@@ -3,16 +3,39 @@ set(whitespaces_ "[\t\n\r ]*")
set(EXPECTED_FILES_COUNT "5")
set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
set(EXPECTED_FILE_1_NAME "Debuginfo")
if(GENERATOR_TYPE STREQUAL "RPM")
set(NAME "Debuginfo")
set(DEBUG_SUFFIX "debuginfo")
set(PKG "rpm")
set(DEBUG_PKG "rpm")
elseif(GENERATOR_TYPE STREQUAL "DEB")
set(NAME "debuginfo")
set(DEBUG_SUFFIX "dbgsym")
set(PKG "deb")
set(DEBUG_PKG "ddeb")
endif()
set(EXPECTED_FILE_1_NAME "${NAME}")
set(EXPECTED_FILE_1_COMPONENT "applications")
set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.rpm")
set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.rpm")
set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
set(EXPECTED_FILE_4_NAME "Debuginfo")
set(EXPECTED_FILE_4_COMPONENT "applications-debuginfo")
set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
if(GENERATOR_TYPE STREQUAL "RPM")
set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
elseif(GENERATOR_TYPE STREQUAL "DEB")
set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
endif()
if(GENERATOR_TYPE STREQUAL "RPM")
set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
elseif(GENERATOR_TYPE STREQUAL "DEB")
set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
endif()
@@ -29,12 +29,16 @@ install(TARGETS test_lib DESTINATION bas COMPONENT libs)
set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
set(CPACK_DEBIAN_APPLICATIONS_FILE_NAME "DEB-DEFAULT")
set(CPACK_DEBIAN_APPLICATIONS_DEBUGINFO_PACKAGE ON)
# test that components with debuginfo enabled still honor
# CPACK_PACKAGE_FILE_NAME setting
set(CPACK_RPM_PACKAGE_NAME "Debuginfo")
set(CPACK_PACKAGE_FILE_NAME "TestDinfo-pkg")
set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
set(CPACK_DEBIAN_PACKAGE_NAME "Debuginfo")
set(CPACK_DEBIAN_LIBS_DEBUGINFO_PACKAGE ON)
# test debuginfo package rename
set(CPACK_RPM_DEBUGINFO_FILE_NAME