summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmGlobalGenerator.cxx36
-rw-r--r--Source/cmGlobalGenerator.h17
-rw-r--r--Source/cmInstallScriptHandler.cxx119
-rw-r--r--Source/cmInstallScriptHandler.h40
-rw-r--r--Source/cmLocalGenerator.cxx1
-rw-r--r--Source/cmake.cxx1
-rw-r--r--Source/cmakemain.cxx68
8 files changed, 267 insertions, 17 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 185ebfe..1d2b7dd 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -336,6 +336,8 @@ add_library(
cmInstallTargetGenerator.cxx
cmInstallDirectoryGenerator.h
cmInstallDirectoryGenerator.cxx
+ cmInstallScriptHandler.h
+ cmInstallScriptHandler.cxx
cmJSONHelpers.cxx
cmJSONHelpers.h
cmJSONState.cxx
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index bf2f0fc..9edbce3 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -135,6 +135,13 @@ cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
cm->GetState()->SetWatcomWMake(false);
cm->GetState()->SetWindowsShell(false);
cm->GetState()->SetWindowsVSIDE(false);
+
+#if !defined(CMAKE_BOOTSTRAP)
+ Json::StreamWriterBuilder wbuilder;
+ wbuilder["indentation"] = "\t";
+ this->JsonWriter =
+ std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
+#endif
}
cmGlobalGenerator::~cmGlobalGenerator()
@@ -1758,6 +1765,30 @@ void cmGlobalGenerator::Generate()
}
}
+#if !defined(CMAKE_BOOTSTRAP)
+void cmGlobalGenerator::WriteJsonContent(const std::string& path,
+ const Json::Value& value) const
+{
+ cmsys::ofstream ftmp(path.c_str());
+ this->JsonWriter->write(value, &ftmp);
+ ftmp << '\n';
+ ftmp.close();
+}
+
+void cmGlobalGenerator::WriteInstallJson() const
+{
+ if (this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
+ "INSTALL_PARALLEL")) {
+ Json::Value index(Json::objectValue);
+ index["InstallScripts"] = Json::arrayValue;
+ for (const auto& file : this->InstallScripts) {
+ index["InstallScripts"].append(file);
+ }
+ this->WriteJsonContent("CMakeFiles/InstallScripts.json", index);
+ }
+}
+#endif
+
bool cmGlobalGenerator::ComputeTargetDepends()
{
cmComputeTargetDepends ctd(this);
@@ -3732,3 +3763,8 @@ cmGlobalGenerator::StripCommandStyle cmGlobalGenerator::GetStripCommandStyle(
return StripCommandStyle::Default;
#endif
}
+
+void cmGlobalGenerator::AddInstallScript(std::string const& file)
+{
+ this->InstallScripts.push_back(file);
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 33c9889..5011c17 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -91,6 +91,9 @@ struct GeneratedMakeCommand
bool RequiresOutputForward = false;
};
}
+namespace Json {
+class StreamWriter;
+}
/** \class cmGlobalGenerator
* \brief Responsible for overseeing the generation process for the entire tree
@@ -655,6 +658,8 @@ public:
bool CheckCMP0171() const;
+ void AddInstallScript(std::string const& file);
+
protected:
// for a project collect all its targets by following depend
// information, and also collect all the targets
@@ -674,6 +679,12 @@ protected:
virtual bool ComputeTargetDepends();
+#if !defined(CMAKE_BOOTSTRAP)
+ void WriteJsonContent(const std::string& fname,
+ const Json::Value& value) const;
+ void WriteInstallJson() const;
+#endif
+
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
bool ApplyCXXStdTargets();
@@ -790,6 +801,10 @@ private:
std::map<std::string, int> LanguageToLinkerPreference;
std::map<std::string, std::string> LanguageToOriginalSharedLibFlags;
+#if !defined(CMAKE_BOOTSTRAP)
+ std::unique_ptr<Json::StreamWriter> JsonWriter;
+#endif
+
#ifdef __APPLE__
std::map<std::string, StripCommandStyle> StripCommandStyleMap;
#endif
@@ -882,6 +897,8 @@ private:
std::map<std::string, cmInstallRuntimeDependencySet*>
RuntimeDependencySetsByName;
+ std::vector<std::string> InstallScripts;
+
#if !defined(CMAKE_BOOTSTRAP)
// Pool of file locks
cmFileLockPool FileLockPool;
diff --git a/Source/cmInstallScriptHandler.cxx b/Source/cmInstallScriptHandler.cxx
new file mode 100644
index 0000000..ad1e5cb
--- /dev/null
+++ b/Source/cmInstallScriptHandler.cxx
@@ -0,0 +1,119 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmInstallScriptHandler.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/uv.h>
+
+#include "cmJSONState.h"
+#include "cmProcessOutput.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
+
+using InstallScript = cmInstallScriptHandler::InstallScript;
+
+cmInstallScriptHandler::cmInstallScriptHandler(const std::string& binary_dir,
+ std::vector<std::string>& args)
+{
+ const std::string& file =
+ cmStrCat(binary_dir, "/CMakeFiles/InstallScripts.json");
+ if (cmSystemTools::FileExists(file)) {
+ int compare;
+ cmSystemTools::FileTimeCompare(
+ cmStrCat(binary_dir, "/CMakeFiles/cmake.check_cache"), file, &compare);
+ if (compare < 1) {
+ args.insert(args.end() - 1, "-DCMAKE_INSTALL_LOCAL_ONLY=1");
+ Json::CharReaderBuilder rbuilder;
+ auto JsonReader =
+ std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
+ std::vector<char> content;
+ Json::Value value;
+ cmJSONState state(file, &value);
+ for (auto const& script : value["InstallScripts"]) {
+ this->commands.push_back(args);
+ this->commands.back().emplace_back(script.asCString());
+ }
+ }
+ }
+}
+
+bool cmInstallScriptHandler::isParallel()
+{
+ return !this->commands.empty();
+}
+
+int cmInstallScriptHandler::install(unsigned int j)
+{
+ cm::uv_loop_ptr loop;
+ loop.init();
+ std::vector<InstallScript> scripts;
+ for (auto const& cmd : this->commands) {
+ scripts.push_back(InstallScript(cmd));
+ }
+ std::size_t working = 0;
+ std::size_t installed = 0;
+ std::size_t i = 0;
+
+ while (installed < scripts.size()) {
+ for (auto queue = std::min(j - working, scripts.size() - i); queue > 0;
+ --queue) {
+ scripts[i].start(loop, [&scripts, &working, &installed, i]() {
+ scripts[i].printResult(++installed, scripts.size());
+ --working;
+ });
+ ++i;
+ }
+ uv_run(loop, UV_RUN_DEFAULT);
+ }
+ return 0;
+}
+
+InstallScript::InstallScript(const std::vector<std::string>& cmd)
+{
+ this->name = cmSystemTools::RelativePath(
+ cmSystemTools::GetCurrentWorkingDirectory(), cmd.back());
+ this->command = cmd;
+}
+
+void InstallScript::start(cm::uv_loop_ptr& loop,
+ std::function<void()> callback)
+{
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(this->command)
+ .SetExternalLoop(*loop)
+ .SetMergedBuiltinStreams();
+ this->chain = cm::make_unique<cmUVProcessChain>(builder.Start());
+ this->pipe.init(this->chain->GetLoop(), 0);
+ uv_pipe_open(this->pipe, this->chain->OutputStream());
+ this->streamHandler = cmUVStreamRead(
+ this->pipe,
+ [this](std::vector<char> data) {
+ std::string strdata;
+ cmProcessOutput(cmProcessOutput::Auto)
+ .DecodeText(data.data(), data.size(), strdata);
+ this->output.push_back(strdata);
+ },
+ std::move(callback));
+}
+
+void InstallScript::printResult(std::size_t n, std::size_t total)
+{
+ cmSystemTools::Stdout(cmStrCat("[", n, "/", total, "] ", this->name, "\n"));
+ for (auto const& line : this->output) {
+ cmSystemTools::Stdout(line);
+ }
+}
diff --git a/Source/cmInstallScriptHandler.h b/Source/cmInstallScriptHandler.h
new file mode 100644
index 0000000..3cd6164
--- /dev/null
+++ b/Source/cmInstallScriptHandler.h
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
+
+class cmInstallScriptHandler
+{
+public:
+ cmInstallScriptHandler() = default;
+ cmInstallScriptHandler(const std::string&, std::vector<std::string>&);
+ bool isParallel();
+ int install(unsigned int j);
+ class InstallScript
+ {
+ public:
+ InstallScript(const std::vector<std::string>&);
+ void start(cm::uv_loop_ptr&, std::function<void()>);
+ void printResult(std::size_t n, std::size_t total);
+
+ private:
+ std::vector<std::string> command;
+ std::vector<std::string> output;
+ std::string name;
+ std::unique_ptr<cmUVProcessChain> chain;
+ std::unique_ptr<cmUVStreamReadHandle> streamHandler;
+ cm::uv_pipe_ptr pipe;
+ };
+
+private:
+ std::vector<std::vector<std::string>> commands;
+};
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index e6d56d3..2d038b4 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -500,6 +500,7 @@ void cmLocalGenerator::GenerateInstallRules()
toplevel_install = 1;
}
file += "/cmake_install.cmake";
+ this->GetGlobalGenerator()->AddInstallScript(file);
cmGeneratedFileStream fout(file);
fout.SetCopyIfDifferent(true);
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 775265f..7c64cee 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -2936,6 +2936,7 @@ int cmake::Generate()
this->SaveCache(this->GetHomeOutputDirectory());
#if !defined(CMAKE_BOOTSTRAP)
+ this->GetGlobalGenerator()->WriteInstallJson();
this->FileAPI->WriteReplies();
#endif
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 8462734..7729785 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -17,6 +17,7 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
#include <cmext/algorithm>
#include <cm3p/uv.h>
@@ -26,6 +27,7 @@
#include "cmConsoleBuf.h"
#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
+#include "cmInstallScriptHandler.h"
#include "cmList.h"
#include "cmMakefile.h"
#include "cmMessageMetadata.h"
@@ -429,6 +431,17 @@ int extract_job_number(std::string const& command,
}
return jobs;
}
+std::function<bool(std::string const&)> extract_job_number_lambda_builder(
+ std::string& dir, int& jobs, const std::string& flag)
+{
+ return [&dir, &jobs, flag](std::string const& value) -> bool {
+ jobs = extract_job_number(flag, value);
+ if (jobs < 0) {
+ dir.clear();
+ }
+ return true;
+ };
+};
#endif
int do_build(int ac, char const* const* av)
@@ -451,20 +464,10 @@ int do_build(int ac, char const* const* av)
std::string presetName;
bool listPresets = false;
- auto jLambda = [&](std::string const& value) -> bool {
- jobs = extract_job_number("-j", value);
- if (jobs < 0) {
- dir.clear();
- }
- return true;
- };
- auto parallelLambda = [&](std::string const& value) -> bool {
- jobs = extract_job_number("--parallel", value);
- if (jobs < 0) {
- dir.clear();
- }
- return true;
- };
+ auto jLambda = extract_job_number_lambda_builder(dir, jobs, "-j");
+ auto parallelLambda =
+ extract_job_number_lambda_builder(dir, jobs, "--parallel");
+
auto targetLambda = [&](std::string const& value) -> bool {
if (!value.empty()) {
cmList values{ value };
@@ -787,9 +790,14 @@ int do_install(int ac, char const* const* av)
std::string defaultDirectoryPermissions;
std::string prefix;
std::string dir;
+ int jobs = 0;
bool strip = false;
bool verbose = cmSystemTools::HasEnv("VERBOSE");
+ auto jLambda = extract_job_number_lambda_builder(dir, jobs, "-j");
+ auto parallelLambda =
+ extract_job_number_lambda_builder(dir, jobs, "--parallel");
+
auto verboseLambda = [&](std::string const&) -> bool {
verbose = true;
return true;
@@ -806,6 +814,9 @@ int do_install(int ac, char const* const* av)
CommandArgument{
"--default-directory-permissions", CommandArgument::Values::One,
CommandArgument::setToValue(defaultDirectoryPermissions) },
+ CommandArgument{ "-j", CommandArgument::Values::One, jLambda },
+ CommandArgument{ "--parallel", CommandArgument::Values::One,
+ parallelLambda },
CommandArgument{ "--prefix", CommandArgument::Values::One,
CommandArgument::setToValue(prefix) },
CommandArgument{ "--strip", CommandArgument::Values::Zero,
@@ -822,7 +833,6 @@ int do_install(int ac, char const* const* av)
inputArgs.reserve(ac - 3);
cm::append(inputArgs, av + 3, av + ac);
for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
-
std::string const& arg = inputArgs[i];
bool matched = false;
bool parsed = false;
@@ -853,6 +863,10 @@ int do_install(int ac, char const* const* av)
" --component <comp> = Component-based install. Only install <comp>.\n"
" --default-directory-permissions <permission> \n"
" Default install permission. Use default permission <permission>.\n"
+ " -j <jobs> --parallel <jobs>\n"
+ " Build in parallel using the given number of jobs. \n"
+ " The CMAKE_INSTALL_PARALLEL_LEVEL environment variable\n"
+ " specifies a default parallel level when this option is not given.\n"
" --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n"
" --strip = Performing install/strip.\n"
" -v --verbose = Enable verbose output.\n"
@@ -906,9 +920,29 @@ int do_install(int ac, char const* const* av)
}
args.emplace_back("-P");
- args.emplace_back(dir + "/cmake_install.cmake");
- return cm.Run(args) ? 1 : 0;
+ auto handler = cmInstallScriptHandler(dir, args);
+ int ret = 0;
+ if (!handler.isParallel()) {
+ args.emplace_back(cmStrCat(dir, "/cmake_install.cmake"));
+ ret = int(bool(cm.Run(args)));
+ } else {
+ if (!jobs) {
+ jobs = 1;
+ auto envvar = cmSystemTools::GetEnvVar("CMAKE_INSTALL_PARALLEL_LEVEL");
+ if (envvar.has_value()) {
+ jobs = extract_job_number("", envvar.value());
+ if (jobs < 1) {
+ std::cerr << "Value of CMAKE_INSTALL_PARALLEL_LEVEL environment"
+ " variable must be a positive integer.\n";
+ return 1;
+ }
+ }
+ }
+ ret = handler.install(jobs);
+ }
+
+ return int(ret > 0);
#endif
}