1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmConfigure.h" // IWYU pragma: keep
20 #include <cmext/algorithm>
24 #include "cmBuildOptions.h"
25 #include "cmCommandLineArgument.h"
26 #include "cmConsoleBuf.h"
27 #include "cmDocumentationEntry.h" // IWYU pragma: keep
28 #include "cmGlobalGenerator.h"
29 #include "cmMakefile.h"
30 #include "cmMessageMetadata.h"
32 #include "cmStateTypes.h"
33 #include "cmStringAlgorithms.h"
34 #include "cmSystemTools.h"
39 #ifndef CMAKE_BOOTSTRAP
40 # include "cmDocumentation.h"
41 # include "cmDynamicLoader.h"
44 #include "cmsys/Encoding.hxx"
45 #include "cmsys/Terminal.h"
48 #ifndef CMAKE_BOOTSTRAP
49 const char* cmDocumentationName[][2] = {
50 { nullptr, " cmake - Cross-Platform Makefile Generator." },
54 const char* cmDocumentationUsage[][2] = {
56 " cmake [options] <path-to-source>\n"
57 " cmake [options] <path-to-existing-build>\n"
58 " cmake [options] -S <path-to-source> -B <path-to-build>" },
60 "Specify a source directory to (re-)generate a build system for "
61 "it in the current working directory. Specify an existing build "
62 "directory to re-generate its build system." },
66 const char* cmDocumentationUsageNote[][2] = {
67 { nullptr, "Run 'cmake --help' for more information." },
71 const char* cmDocumentationOptions[][2] = {
72 CMAKE_STANDARD_OPTIONS_TABLE,
73 { "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
74 { "--list-presets[=<type>]", "List available presets." },
75 { "-E", "CMake command mode." },
76 { "-L[A][H]", "List non-advanced cached variables." },
78 "Configure a fresh build tree, removing any existing cache file." },
79 { "--build <dir>", "Build a CMake-generated project binary tree." },
80 { "--install <dir>", "Install a CMake-generated project binary tree." },
81 { "--open <dir>", "Open generated project in the associated application." },
82 { "-N", "View mode only." },
83 { "-P <file>", "Process script mode." },
84 { "--find-package", "Legacy pkg-config like mode. Do not use." },
85 { "--graphviz=<file>",
86 "Generate graphviz of dependencies, see CMakeGraphVizOptions.cmake for "
88 { "--system-information [file]", "Dump information about this system." },
89 { "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
90 "Set the verbosity of messages from CMake files. "
91 "--loglevel is also accepted for backward compatibility reasons." },
92 { "--log-context", "Prepend log messages with context, if given" },
93 { "--debug-trycompile",
94 "Do not delete the try_compile build tree. Only "
95 "useful on one try_compile at a time." },
96 { "--debug-output", "Put cmake in a debug mode." },
97 { "--debug-find", "Put cmake find in a debug mode." },
98 { "--debug-find-pkg=<pkg-name>[,...]",
99 "Limit cmake debug-find to the comma-separated list of packages" },
100 { "--debug-find-var=<var-name>[,...]",
101 "Limit cmake debug-find to the comma-separated list of result variables" },
102 { "--trace", "Put cmake in trace mode." },
103 { "--trace-expand", "Put cmake in trace mode with variable expansion." },
104 { "--trace-format=<human|json-v1>", "Set the output format of the trace." },
105 { "--trace-source=<file>",
106 "Trace only this CMake file/module. Multiple options allowed." },
107 { "--trace-redirect=<file>",
108 "Redirect trace output to a file instead of stderr." },
109 { "--warn-uninitialized", "Warn about uninitialized values." },
110 { "--no-warn-unused-cli", "Don't warn about command line options." },
111 { "--check-system-vars",
112 "Find problems with variable usage in system files." },
113 { "--compile-no-warning-as-error",
114 "Ignore COMPILE_WARNING_AS_ERROR property and "
115 "CMAKE_COMPILE_WARNING_AS_ERROR variable." },
116 # if !defined(CMAKE_BOOTSTRAP)
117 { "--profiling-format=<fmt>",
118 "Output data for profiling CMake scripts. Supported formats: "
120 { "--profiling-output=<file>",
121 "Select an output path for the profiling data enabled through "
122 "--profiling-format." },
129 int do_command(int ac, char const* const* av,
130 std::unique_ptr<cmConsoleBuf> consoleBuf)
132 std::vector<std::string> args;
133 args.reserve(ac - 1);
134 args.emplace_back(av[0]);
135 cm::append(args, av + 2, av + ac);
136 return cmcmd::ExecuteCMakeCommand(args, std::move(consoleBuf));
139 cmMakefile* cmakemainGetMakefile(cmake* cm)
141 if (cm && cm->GetDebugOutput()) {
142 cmGlobalGenerator* gg = cm->GetGlobalGenerator();
144 return gg->GetCurrentMakefile();
150 std::string cmakemainGetStack(cmake* cm)
153 cmMakefile* mf = cmakemainGetMakefile(cm);
155 msg = mf->FormatListFileStack();
157 msg = "\n Called from: " + msg;
164 void cmakemainMessageCallback(const std::string& m,
165 const cmMessageMetadata& md, cmake* cm)
168 // FIXME: On Windows we replace cerr's streambuf with a custom
169 // implementation that converts our internal UTF-8 encoding to the
170 // console's encoding. It also does *not* replace LF with CRLF.
171 // Since stderr does not convert encoding and does convert LF, we
172 // cannot use it to print messages. Another implementation will
173 // be needed to print colored messages on Windows.
174 static_cast<void>(md);
175 std::cerr << m << cmakemainGetStack(cm) << '\n' << std::flush;
177 cmsysTerminal_cfprintf(md.desiredColor, stderr, "%s", m.c_str());
178 fflush(stderr); // stderr is buffered in some cases.
179 std::cerr << cmakemainGetStack(cm) << '\n' << std::flush;
183 void cmakemainProgressCallback(const std::string& m, float prog, cmake* cm)
185 cmMakefile* mf = cmakemainGetMakefile(cm);
187 if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
188 dir = cmStrCat(' ', mf->GetCurrentSourceDirectory());
189 } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
190 dir = cmStrCat(' ', mf->GetCurrentBinaryDirectory());
193 if ((prog < 0) || (!dir.empty())) {
194 std::cout << "-- " << m << dir << cmakemainGetStack(cm) << std::endl;
198 int do_cmake(int ac, char const* const* av)
200 if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
201 std::cerr << "Current working directory cannot be established."
206 #ifndef CMAKE_BOOTSTRAP
208 doc.addCMakeStandardDocSections();
209 if (doc.CheckOptions(ac, av, "--")) {
210 // Construct and print requested documentation.
211 cmake hcm(cmake::RoleInternal, cmState::Unknown);
212 hcm.SetHomeDirectory("");
213 hcm.SetHomeOutputDirectory("");
216 // the command line args are processed here so that you can do
217 // -DCMAKE_MODULE_PATH=/some/path and have this value accessible here
218 std::vector<std::string> args(av, av + ac);
219 hcm.SetCacheArgs(args);
221 auto generators = hcm.GetGeneratorsDocumentation();
223 doc.SetName("cmake");
224 doc.SetSection("Name", cmDocumentationName);
225 doc.SetSection("Usage", cmDocumentationUsage);
227 doc.AppendSection("Usage", cmDocumentationUsageNote);
229 doc.AppendSection("Generators", generators);
230 doc.PrependSection("Options", cmDocumentationOptions);
232 return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
237 << "Bootstrap CMake should not be used outside CMake build process."
243 bool wizard_mode = false;
244 bool sysinfo = false;
245 bool list_cached = false;
246 bool list_all_cached = false;
247 bool list_help = false;
248 bool view_only = false;
249 cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
250 std::vector<std::string> parsedArgs;
252 using CommandArgument =
253 cmCommandLineArgument<bool(std::string const& value)>;
254 std::vector<CommandArgument> arguments = {
256 "-i", CommandArgument::Values::Zero,
257 [&wizard_mode](std::string const&) -> bool {
258 /* clang-format off */
260 "The \"cmake -i\" wizard mode is no longer supported.\n"
261 "Use the -D option to set cache values on the command line.\n"
262 "Use cmake-gui or ccmake for an interactive dialog.\n";
263 /* clang-format on */
267 CommandArgument{ "--system-information", CommandArgument::Values::Zero,
268 CommandArgument::setToTrue(sysinfo) },
269 CommandArgument{ "-N", CommandArgument::Values::Zero,
270 CommandArgument::setToTrue(view_only) },
271 CommandArgument{ "-LAH", CommandArgument::Values::Zero,
272 CommandArgument::setToTrue(list_all_cached, list_help) },
273 CommandArgument{ "-LA", CommandArgument::Values::Zero,
274 CommandArgument::setToTrue(list_all_cached) },
275 CommandArgument{ "-LH", CommandArgument::Values::Zero,
276 CommandArgument::setToTrue(list_cached, list_help) },
277 CommandArgument{ "-L", CommandArgument::Values::Zero,
278 CommandArgument::setToTrue(list_cached) },
279 CommandArgument{ "-P", "No script specified for argument -P",
280 CommandArgument::Values::One,
281 CommandArgument::RequiresSeparator::No,
282 [&](std::string const& value) -> bool {
283 workingMode = cmake::SCRIPT_MODE;
284 parsedArgs.emplace_back("-P");
285 parsedArgs.push_back(value);
288 CommandArgument{ "--find-package", CommandArgument::Values::Zero,
289 [&](std::string const&) -> bool {
290 workingMode = cmake::FIND_PACKAGE_MODE;
291 parsedArgs.emplace_back("--find-package");
294 CommandArgument{ "--list-presets", CommandArgument::Values::ZeroOrOne,
295 [&](std::string const& value) -> bool {
296 workingMode = cmake::HELP_MODE;
297 parsedArgs.emplace_back("--list-presets");
298 parsedArgs.emplace_back(value);
303 std::vector<std::string> inputArgs;
304 inputArgs.reserve(ac);
305 cm::append(inputArgs, av, av + ac);
307 for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
308 std::string const& arg = inputArgs[i];
309 bool matched = false;
310 for (auto const& m : arguments) {
311 if (m.matches(arg)) {
313 if (m.parse(arg, i, inputArgs)) {
316 return 1; // failed to parse
320 parsedArgs.emplace_back(av[i]);
329 cmake cm(cmake::RoleProject, cmState::Project);
330 cm.SetHomeDirectory("");
331 cm.SetHomeOutputDirectory("");
332 int ret = cm.GetSystemInformation(parsedArgs);
335 cmake::Role const role =
336 workingMode == cmake::SCRIPT_MODE ? cmake::RoleScript : cmake::RoleProject;
337 cmState::Mode mode = cmState::Unknown;
338 switch (workingMode) {
339 case cmake::NORMAL_MODE:
340 case cmake::HELP_MODE:
341 mode = cmState::Project;
343 case cmake::SCRIPT_MODE:
344 mode = cmState::Script;
346 case cmake::FIND_PACKAGE_MODE:
347 mode = cmState::FindPackage;
350 cmake cm(role, mode);
351 cm.SetHomeDirectory("");
352 cm.SetHomeOutputDirectory("");
353 cmSystemTools::SetMessageCallback(
354 [&cm](const std::string& msg, const cmMessageMetadata& md) {
355 cmakemainMessageCallback(msg, md, &cm);
357 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
358 cmakemainProgressCallback(msg, prog, &cm);
360 cm.SetWorkingMode(workingMode);
362 int res = cm.Run(parsedArgs, view_only);
363 if (list_cached || list_all_cached) {
364 std::cout << "-- Cache values" << std::endl;
365 std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
366 for (std::string const& k : keys) {
367 cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k);
368 if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
369 t != cmStateEnums::UNINITIALIZED) {
370 cmValue advancedProp =
371 cm.GetState()->GetCacheEntryProperty(k, "ADVANCED");
372 if (list_all_cached || !advancedProp) {
375 cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING");
376 std::cout << "// " << (help ? *help : "") << std::endl;
378 std::cout << k << ":" << cmState::CacheEntryTypeToString(t) << "="
379 << cm.GetState()->GetSafeCacheEntryValue(k) << std::endl;
381 std::cout << std::endl;
388 // Always return a non-negative value. Windows tools do not always
389 // interpret negative return values as errors.
396 #ifndef CMAKE_BOOTSTRAP
397 int extract_job_number(std::string const& command,
398 std::string const& jobString)
401 unsigned long numJobs = 0;
402 if (jobString.empty()) {
403 jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
404 } else if (cmStrToULong(jobString, &numJobs)) {
407 << "The <jobs> value requires a positive integer argument.\n\n";
408 } else if (numJobs > INT_MAX) {
409 std::cerr << "The <jobs> value is too large.\n\n";
411 jobs = static_cast<int>(numJobs);
414 std::cerr << "'" << command << "' invalid number '" << jobString
421 int do_build(int ac, char const* const* av)
423 #ifdef CMAKE_BOOTSTRAP
424 std::cerr << "This cmake does not support --build\n";
427 int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
428 std::vector<std::string> targets;
431 std::vector<std::string> nativeOptions;
432 bool nativeOptionsPassed = false;
433 bool cleanFirst = false;
434 bool foundClean = false;
435 bool foundNonClean = false;
436 PackageResolveMode resolveMode = PackageResolveMode::Default;
437 bool verbose = cmSystemTools::HasEnv("VERBOSE");
438 std::string presetName;
439 bool listPresets = false;
441 auto jLambda = [&](std::string const& value) -> bool {
442 jobs = extract_job_number("-j", value);
448 auto parallelLambda = [&](std::string const& value) -> bool {
449 jobs = extract_job_number("--parallel", value);
455 auto targetLambda = [&](std::string const& value) -> bool {
456 if (!value.empty()) {
457 std::vector<std::string> values = cmExpandedList(value);
458 for (auto const& v : values) {
459 targets.emplace_back(v);
463 foundNonClean = true;
470 auto resolvePackagesLambda = [&](std::string const& value) -> bool {
471 std::string v = value;
472 std::transform(v.begin(), v.end(), v.begin(), ::tolower);
475 resolveMode = PackageResolveMode::Force;
476 } else if (v == "only") {
477 resolveMode = PackageResolveMode::OnlyResolve;
478 } else if (v == "off") {
479 resolveMode = PackageResolveMode::Disable;
486 auto verboseLambda = [&](std::string const&) -> bool {
491 using CommandArgument =
492 cmCommandLineArgument<bool(std::string const& value)>;
494 std::vector<CommandArgument> arguments = {
495 CommandArgument{ "--preset", CommandArgument::Values::One,
496 CommandArgument::setToValue(presetName) },
497 CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
498 CommandArgument::setToTrue(listPresets) },
499 CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne,
500 CommandArgument::RequiresSeparator::No, jLambda },
501 CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
502 CommandArgument::RequiresSeparator::No, parallelLambda },
503 CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda },
504 CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
506 CommandArgument{ "--config", CommandArgument::Values::One,
507 CommandArgument::setToValue(config) },
508 CommandArgument{ "--clean-first", CommandArgument::Values::Zero,
509 CommandArgument::setToTrue(cleanFirst) },
510 CommandArgument{ "--resolve-package-references",
511 CommandArgument::Values::One, resolvePackagesLambda },
512 CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
513 CommandArgument{ "--verbose", CommandArgument::Values::Zero,
515 /* legacy option no-op*/
516 CommandArgument{ "--use-stderr", CommandArgument::Values::Zero,
517 [](std::string const&) -> bool { return true; } },
518 CommandArgument{ "--", CommandArgument::Values::Zero,
519 CommandArgument::setToTrue(nativeOptionsPassed) },
523 std::vector<std::string> inputArgs;
525 bool hasPreset = false;
526 for (int i = 2; i < ac; ++i) {
527 if (strcmp(av[i], "--list-presets") == 0 ||
528 cmHasLiteralPrefix(av[i], "--preset=") ||
529 strcmp(av[i], "--preset") == 0) {
536 inputArgs.reserve(ac - 2);
537 cm::append(inputArgs, av + 2, av + ac);
539 dir = cmSystemTools::CollapseFullPath(av[2]);
541 inputArgs.reserve(ac - 3);
542 cm::append(inputArgs, av + 3, av + ac);
545 decltype(inputArgs.size()) i = 0;
546 for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) {
548 std::string const& arg = inputArgs[i];
549 bool matched = false;
551 for (auto const& m : arguments) {
552 matched = m.matches(arg);
554 parsed = m.parse(arg, i, inputArgs);
558 if (!(matched && parsed)) {
561 std::cerr << "Unknown argument " << arg << std::endl;
567 if (nativeOptionsPassed) {
568 cm::append(nativeOptions, inputArgs.begin() + i, inputArgs.end());
572 if (foundClean && foundNonClean) {
573 std::cerr << "Error: Building 'clean' and other targets together "
579 if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
580 std::string parallel;
581 if (cmSystemTools::GetEnv("CMAKE_BUILD_PARALLEL_LEVEL", parallel)) {
582 if (parallel.empty()) {
583 jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
585 unsigned long numJobs = 0;
586 if (cmStrToULong(parallel, &numJobs)) {
588 std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
589 "requires a positive integer argument.\n\n";
591 } else if (numJobs > INT_MAX) {
592 std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
596 jobs = static_cast<int>(numJobs);
599 std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
600 << "invalid number '" << parallel << "' given.\n\n";
607 if (dir.empty() && presetName.empty() && !listPresets) {
608 /* clang-format off */
610 "Usage: cmake --build <dir> "
611 " [options] [-- [native-options]]\n"
612 " cmake --build --preset <preset>"
613 " [options] [-- [native-options]]\n"
615 " <dir> = Project binary directory to be built.\n"
616 " --preset <preset>, --preset=<preset>\n"
617 " = Specify a build preset.\n"
618 " --list-presets[=<type>]\n"
619 " = List available build presets.\n"
620 " --parallel [<jobs>], -j [<jobs>]\n"
621 " = Build in parallel using the given number of jobs. \n"
622 " If <jobs> is omitted the native build tool's \n"
623 " default number is used.\n"
624 " The CMAKE_BUILD_PARALLEL_LEVEL environment "
626 " specifies a default parallel level when this "
629 " -t <tgt>..., --target <tgt>...\n"
630 " = Build <tgt> instead of default targets.\n"
631 " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
632 " --clean-first = Build target 'clean' first, then build.\n"
633 " (To clean only, use --target 'clean'.)\n"
634 " --resolve-package-references={on|only|off}\n"
635 " = Restore/resolve package references during build.\n"
636 " -v, --verbose = Enable verbose output - if supported - including\n"
637 " the build commands to be executed. \n"
638 " -- = Pass remaining options to the native tool.\n"
640 /* clang-format on */
644 cmake cm(cmake::RoleInternal, cmState::Project);
645 cmSystemTools::SetMessageCallback(
646 [&cm](const std::string& msg, const cmMessageMetadata& md) {
647 cmakemainMessageCallback(msg, md, &cm);
649 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
650 cmakemainProgressCallback(msg, prog, &cm);
653 cmBuildOptions buildOptions(cleanFirst, false, resolveMode);
655 return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
656 std::move(nativeOptions), buildOptions, verbose, presetName,
661 bool parse_default_directory_permissions(const std::string& permissions,
662 std::string& parsedPermissionsVar)
664 std::vector<std::string> parsedPermissions;
671 DoingOwnerAssignment,
672 DoingGroupAssignment,
673 DoingWorldAssignment,
675 Doing doing = DoingNone;
677 auto uniquePushBack = [&parsedPermissions](const std::string& e) {
678 if (std::find(parsedPermissions.begin(), parsedPermissions.end(), e) ==
679 parsedPermissions.end()) {
680 parsedPermissions.push_back(e);
684 for (auto const& e : permissions) {
689 } else if (e == 'g') {
691 } else if (e == 'o') {
699 doing = DoingOwnerAssignment;
706 doing = DoingGroupAssignment;
713 doing = DoingWorldAssignment;
718 case DoingOwnerAssignment:
720 uniquePushBack("OWNER_READ");
721 } else if (e == 'w') {
722 uniquePushBack("OWNER_WRITE");
723 } else if (e == 'x') {
724 uniquePushBack("OWNER_EXECUTE");
725 } else if (e == ',') {
731 case DoingGroupAssignment:
733 uniquePushBack("GROUP_READ");
734 } else if (e == 'w') {
735 uniquePushBack("GROUP_WRITE");
736 } else if (e == 'x') {
737 uniquePushBack("GROUP_EXECUTE");
738 } else if (e == ',') {
744 case DoingWorldAssignment:
746 uniquePushBack("WORLD_READ");
747 } else if (e == 'w') {
748 uniquePushBack("WORLD_WRITE");
749 } else if (e == 'x') {
750 uniquePushBack("WORLD_EXECUTE");
751 } else if (e == ',') {
759 if (doing != DoingOwnerAssignment && doing != DoingGroupAssignment &&
760 doing != DoingWorldAssignment) {
764 std::ostringstream oss;
765 for (auto i = 0u; i < parsedPermissions.size(); i++) {
769 oss << parsedPermissions[i];
772 parsedPermissionsVar = oss.str();
776 int do_install(int ac, char const* const* av)
778 #ifdef CMAKE_BOOTSTRAP
779 std::cerr << "This cmake does not support --install\n";
785 std::string component;
786 std::string defaultDirectoryPermissions;
790 bool verbose = cmSystemTools::HasEnv("VERBOSE");
792 auto verboseLambda = [&](std::string const&) -> bool {
797 using CommandArgument =
798 cmCommandLineArgument<bool(std::string const& value)>;
800 std::vector<CommandArgument> arguments = {
801 CommandArgument{ "--config", CommandArgument::Values::One,
802 CommandArgument::setToValue(config) },
803 CommandArgument{ "--component", CommandArgument::Values::One,
804 CommandArgument::setToValue(component) },
806 "--default-directory-permissions", CommandArgument::Values::One,
807 CommandArgument::setToValue(defaultDirectoryPermissions) },
808 CommandArgument{ "--prefix", CommandArgument::Values::One,
809 CommandArgument::setToValue(prefix) },
810 CommandArgument{ "--strip", CommandArgument::Values::Zero,
811 CommandArgument::setToTrue(strip) },
812 CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
813 CommandArgument{ "--verbose", CommandArgument::Values::Zero,
818 dir = cmSystemTools::CollapseFullPath(av[2]);
820 std::vector<std::string> inputArgs;
821 inputArgs.reserve(ac - 3);
822 cm::append(inputArgs, av + 3, av + ac);
823 for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
825 std::string const& arg = inputArgs[i];
826 bool matched = false;
828 for (auto const& m : arguments) {
829 matched = m.matches(arg);
831 parsed = m.parse(arg, i, inputArgs);
835 if (!(matched && parsed)) {
838 std::cerr << "Unknown argument " << arg << std::endl;
846 /* clang-format off */
848 "Usage: cmake --install <dir> [options]\n"
850 " <dir> = Project binary directory to install.\n"
851 " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
852 " --component <comp> = Component-based install. Only install <comp>.\n"
853 " --default-directory-permissions <permission> \n"
854 " Default install permission. Use default permission <permission>.\n"
855 " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n"
856 " --strip = Performing install/strip.\n"
857 " -v --verbose = Enable verbose output.\n"
859 /* clang-format on */
863 cmake cm(cmake::RoleScript, cmState::Script);
865 cmSystemTools::SetMessageCallback(
866 [&cm](const std::string& msg, const cmMessageMetadata& md) {
867 cmakemainMessageCallback(msg, md, &cm);
869 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
870 cmakemainProgressCallback(msg, prog, &cm);
872 cm.SetHomeDirectory("");
873 cm.SetHomeOutputDirectory("");
874 cm.SetDebugOutputOn(verbose);
875 cm.SetWorkingMode(cmake::SCRIPT_MODE);
877 std::vector<std::string> args{ av[0] };
879 if (!prefix.empty()) {
880 args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
883 if (!component.empty()) {
884 args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
888 args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
891 if (!config.empty()) {
892 args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
895 if (!defaultDirectoryPermissions.empty()) {
896 std::string parsedPermissionsVar;
897 if (!parse_default_directory_permissions(defaultDirectoryPermissions,
898 parsedPermissionsVar)) {
899 std::cerr << "--default-directory-permissions is in incorrect format"
903 args.emplace_back("-DCMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS=" +
904 parsedPermissionsVar);
907 args.emplace_back("-P");
908 args.emplace_back(dir + "/cmake_install.cmake");
910 return cm.Run(args) ? 1 : 0;
914 int do_workflow(int ac, char const* const* av)
916 #ifdef CMAKE_BOOTSTRAP
917 std::cerr << "This cmake does not support --workflow\n";
920 using WorkflowListPresets = cmake::WorkflowListPresets;
921 using WorkflowFresh = cmake::WorkflowFresh;
922 std::string presetName;
923 auto listPresets = WorkflowListPresets::No;
924 auto fresh = WorkflowFresh::No;
926 using CommandArgument =
927 cmCommandLineArgument<bool(std::string const& value)>;
929 std::vector<CommandArgument> arguments = {
930 CommandArgument{ "--preset", CommandArgument::Values::One,
931 CommandArgument::setToValue(presetName) },
932 CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
933 [&listPresets](const std::string&) -> bool {
934 listPresets = WorkflowListPresets::Yes;
937 CommandArgument{ "--fresh", CommandArgument::Values::Zero,
938 [&fresh](const std::string&) -> bool {
939 fresh = WorkflowFresh::Yes;
944 std::vector<std::string> inputArgs;
946 inputArgs.reserve(ac - 2);
947 cm::append(inputArgs, av + 2, av + ac);
949 decltype(inputArgs.size()) i = 0;
950 for (; i < inputArgs.size(); ++i) {
951 std::string const& arg = inputArgs[i];
952 bool matched = false;
954 for (auto const& m : arguments) {
955 matched = m.matches(arg);
957 parsed = m.parse(arg, i, inputArgs);
961 if (!(matched && parsed)) {
964 listPresets = WorkflowListPresets::No;
965 std::cerr << "Unknown argument " << arg << std::endl;
971 if (presetName.empty() && listPresets == WorkflowListPresets::No) {
972 /* clang-format off */
974 "Usage: cmake --workflow [options]\n"
976 " --preset <preset> = Workflow preset to execute.\n"
977 " --list-presets = List available workflow presets.\n"
978 " --fresh = Configure a fresh build tree, removing any "
979 "existing cache file.\n"
981 /* clang-format on */
985 cmake cm(cmake::RoleInternal, cmState::Project);
986 cmSystemTools::SetMessageCallback(
987 [&cm](const std::string& msg, const cmMessageMetadata& md) {
988 cmakemainMessageCallback(msg, md, &cm);
990 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
991 cmakemainProgressCallback(msg, prog, &cm);
994 return cm.Workflow(presetName, listPresets, fresh);
998 int do_open(int ac, char const* const* av)
1000 #ifdef CMAKE_BOOTSTRAP
1001 std::cerr << "This cmake does not support --open\n";
1011 Doing doing = DoingDir;
1012 for (int i = 2; i < ac; ++i) {
1015 dir = cmSystemTools::CollapseFullPath(av[i]);
1019 std::cerr << "Unknown argument " << av[i] << std::endl;
1025 std::cerr << "Usage: cmake --open <dir>\n";
1029 cmake cm(cmake::RoleInternal, cmState::Unknown);
1030 cmSystemTools::SetMessageCallback(
1031 [&cm](const std::string& msg, const cmMessageMetadata& md) {
1032 cmakemainMessageCallback(msg, md, &cm);
1034 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
1035 cmakemainProgressCallback(msg, prog, &cm);
1037 return cm.Open(dir, false) ? 0 : 1;
1042 int main(int ac, char const* const* av)
1044 cmSystemTools::EnsureStdPipes();
1046 // Replace streambuf so we can output Unicode to console
1047 auto consoleBuf = cm::make_unique<cmConsoleBuf>();
1048 consoleBuf->SetUTF8Pipes();
1050 cmsys::Encoding::CommandLineArguments args =
1051 cmsys::Encoding::CommandLineArguments::Main(ac, av);
1055 cmSystemTools::InitializeLibUV();
1056 cmSystemTools::FindCMakeResources(av[0]);
1058 if (strcmp(av[1], "--build") == 0) {
1059 return do_build(ac, av);
1061 if (strcmp(av[1], "--install") == 0) {
1062 return do_install(ac, av);
1064 if (strcmp(av[1], "--open") == 0) {
1065 return do_open(ac, av);
1067 if (strcmp(av[1], "--workflow") == 0) {
1068 return do_workflow(ac, av);
1070 if (strcmp(av[1], "-E") == 0) {
1071 return do_command(ac, av, std::move(consoleBuf));
1074 int ret = do_cmake(ac, av);
1075 #ifndef CMAKE_BOOTSTRAP
1076 cmDynamicLoader::FlushCache();
1078 if (uv_loop_t* loop = uv_default_loop()) {
1079 uv_loop_close(loop);