cli tar: support multithreading compression

Fixes: #27420
This commit is contained in:
AJIOB
2025-11-28 23:49:53 +03:00
committed by Alex Overchenko
parent 93aa407481
commit cbf71b21b2
14 changed files with 120 additions and 4 deletions

View File

@@ -1491,6 +1491,17 @@ Available commands are:
Specify modification time recorded in tarball entries. Specify modification time recorded in tarball entries.
.. option:: --cmake-tar-threads=<number>
.. versionadded:: 4.3
Use the ``<number>`` threads to operate on the archive. Currently only
multi-threaded compression is supported.
If set to ``0``, the number of available cores on the machine will be
used instead. Note that not all compression modes support threading
in all environments.
.. option:: --touch .. option:: --touch
.. versionadded:: 3.24 .. versionadded:: 3.24

View File

@@ -0,0 +1,4 @@
cli-tar-multithread
-------------------
* The :manual:`cmake(1)` ``-E tar`` tool supports multithreading operations

View File

@@ -2378,7 +2378,8 @@ bool cmSystemTools::CreateTar(std::string const& outFileName,
std::string const& workingDirectory, std::string const& workingDirectory,
cmTarCompression compressType, bool verbose, cmTarCompression compressType, bool verbose,
std::string const& mtime, std::string const& mtime,
std::string const& format, int compressionLevel) std::string const& format, int compressionLevel,
int numThreads)
{ {
#if !defined(CMAKE_BOOTSTRAP) #if !defined(CMAKE_BOOTSTRAP)
cmWorkingDirectory workdir(cmSystemTools::GetLogicalWorkingDirectory()); cmWorkingDirectory workdir(cmSystemTools::GetLogicalWorkingDirectory());
@@ -2414,7 +2415,7 @@ bool cmSystemTools::CreateTar(std::string const& outFileName,
} }
cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format, cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format,
compressionLevel); compressionLevel, numThreads);
if (!a.Open()) { if (!a.Open()) {
cmSystemTools::Error(a.GetError()); cmSystemTools::Error(a.GetError());

View File

@@ -566,7 +566,7 @@ public:
cmTarCompression compressType, bool verbose, cmTarCompression compressType, bool verbose,
std::string const& mtime = std::string(), std::string const& mtime = std::string(),
std::string const& format = std::string(), std::string const& format = std::string(),
int compressionLevel = 0); int compressionLevel = 0, int numThreads = 1);
static bool ExtractTar(std::string const& inFileName, static bool ExtractTar(std::string const& inFileName,
std::vector<std::string> const& files, std::vector<std::string> const& files,
cmTarExtractTimestamps extractTimestamps, cmTarExtractTimestamps extractTimestamps,

View File

@@ -5,6 +5,7 @@
#include <functional> #include <functional>
#include <iomanip> #include <iomanip>
#include <iterator> #include <iterator>
#include <limits>
#include <cm/optional> #include <cm/optional>
#include <cmext/algorithm> #include <cmext/algorithm>
@@ -1582,6 +1583,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
std::vector<std::string> files; std::vector<std::string> files;
std::string mtime; std::string mtime;
std::string format; std::string format;
int numThreads = 1;
cmSystemTools::cmTarExtractTimestamps extractTimestamps = cmSystemTools::cmTarExtractTimestamps extractTimestamps =
cmSystemTools::cmTarExtractTimestamps::Yes; cmSystemTools::cmTarExtractTimestamps::Yes;
cmSystemTools::cmTarCompression compress = cmSystemTools::cmTarCompression compress =
@@ -1597,6 +1599,31 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
++nCompress; ++nCompress;
} else if (cmHasLiteralPrefix(arg, "--mtime=")) { } else if (cmHasLiteralPrefix(arg, "--mtime=")) {
mtime = arg.substr(8); mtime = arg.substr(8);
} else if (cmHasLiteralPrefix(arg, "--cmake-tar-threads=")) {
std::string const& numThreadsStr = arg.substr(20);
long numThreadsLong = 0;
if (!cmStrToLong(numThreadsStr, &numThreadsLong)) {
cmSystemTools::Error(
cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
"' - not a number"));
return 1;
}
if (numThreadsLong >
std::numeric_limits<decltype(numThreads)>::max()) {
cmSystemTools::Error(
cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
"' - too large"));
return 1;
}
if (numThreadsLong <
std::numeric_limits<decltype(numThreads)>::min()) {
cmSystemTools::Error(
cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
"' - too small"));
return 1;
}
numThreads = static_cast<decltype(numThreads)>(numThreadsLong);
} else if (cmHasLiteralPrefix(arg, "--files-from=")) { } else if (cmHasLiteralPrefix(arg, "--files-from=")) {
std::string const& files_from = arg.substr(13); std::string const& files_from = arg.substr(13);
if (!cmTarFilesFrom(files_from, files)) { if (!cmTarFilesFrom(files_from, files)) {
@@ -1677,7 +1704,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
std::cerr << "tar: No files or directories specified\n"; std::cerr << "tar: No files or directories specified\n";
} }
if (!cmSystemTools::CreateTar(outFile, files, {}, compress, verbose, if (!cmSystemTools::CreateTar(outFile, files, {}, compress, verbose,
mtime, format)) { mtime, format, 0, numThreads)) {
cmSystemTools::Error("Problem creating tar: " + outFile); cmSystemTools::Error("Problem creating tar: " + outFile);
return 1; return 1;
} }

View File

@@ -32,6 +32,16 @@ run_cmake(paxr)
run_cmake(paxr-bz2) run_cmake(paxr-bz2)
run_cmake(zip) run_cmake(zip)
# Check the --cmake-tar-threads option
external_command_test(bad-threads-not-a-number tar cvf bad.tar --cmake-tar-threads=nan .)
run_cmake(threads-7zip)
run_cmake(threads-bz2)
run_cmake(threads-gz)
run_cmake(threads-xz)
run_cmake(threads-zstd)
run_cmake(threads-zip)
# Extracting only selected files or directories # Extracting only selected files or directories
run_cmake(zip-filtered) run_cmake(zip-filtered)

View File

@@ -0,0 +1 @@
^CMake Error: Invalid --cmake-tar-threads value: 'nan' - not a number$

View File

@@ -0,0 +1,10 @@
set(OUTPUT_NAME "test.7z")
set(COMPRESSION_FLAGS cvf)
set(COMPRESSION_OPTIONS --format=7zip --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS xvf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
check_magic("377abcaf271c" LIMIT 6 HEX)

View File

@@ -0,0 +1,10 @@
set(OUTPUT_NAME "test.tar.bz2")
set(COMPRESSION_FLAGS cvjf)
set(COMPRESSION_OPTIONS --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS xvjf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
check_magic("425a68" LIMIT 3 HEX)

View File

@@ -0,0 +1,10 @@
set(OUTPUT_NAME "test.tar.gz")
set(COMPRESSION_FLAGS -cvzf)
set(COMPRESSION_OPTIONS --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS -xvzf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
check_magic("1f8b" LIMIT 2 HEX)

View File

@@ -0,0 +1,10 @@
set(OUTPUT_NAME "test.tar.xz")
set(COMPRESSION_FLAGS cvJf)
set(COMPRESSION_OPTIONS --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS xvJf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
check_magic("fd377a585a00" LIMIT 6 HEX)

View File

@@ -0,0 +1,10 @@
set(OUTPUT_NAME "test.zip")
set(COMPRESSION_FLAGS cvf)
set(COMPRESSION_OPTIONS --format=zip --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS xvf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
check_magic("504b0304" LIMIT 4 HEX)

View File

@@ -0,0 +1,11 @@
set(OUTPUT_NAME "test.tar.zstd")
set(COMPRESSION_FLAGS cvf)
set(COMPRESSION_OPTIONS --zstd --cmake-tar-threads=4)
set(DECOMPRESSION_FLAGS xvf)
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
# libarchive 3.8.2 enables a checksum feature; older versions do not.
check_magic("^28b52ffd0[04]58$" LIMIT 6 HEX)