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", "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 "
87 "CMakeGraphVizOptions.cmake for more." },
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 "
114 { "--compile-no-warning-as-error",
115 "Ignore COMPILE_WARNING_AS_ERROR property and "
116 "CMAKE_COMPILE_WARNING_AS_ERROR variable." },
117 # if !defined(CMAKE_BOOTSTRAP)
118 { "--profiling-format=<fmt>",
119 "Output data for profiling CMake scripts. Supported formats: "
121 { "--profiling-output=<file>",
122 "Select an output path for the profiling data enabled through "
123 "--profiling-format." },
130 int do_command(int ac, char const* const* av,
131 std::unique_ptr<cmConsoleBuf> consoleBuf)
133 std::vector<std::string> args;
134 args.reserve(ac - 1);
135 args.emplace_back(av[0]);
136 cm::append(args, av + 2, av + ac);
137 return cmcmd::ExecuteCMakeCommand(args, std::move(consoleBuf));
140 cmMakefile* cmakemainGetMakefile(cmake* cm)
142 if (cm && cm->GetDebugOutput()) {
143 cmGlobalGenerator* gg = cm->GetGlobalGenerator();
145 return gg->GetCurrentMakefile();
151 std::string cmakemainGetStack(cmake* cm)
154 cmMakefile* mf = cmakemainGetMakefile(cm);
156 msg = mf->FormatListFileStack();
158 msg = "\n Called from: " + msg;
165 void cmakemainMessageCallback(const std::string& m,
166 const cmMessageMetadata& md, cmake* cm)
169 // FIXME: On Windows we replace cerr's streambuf with a custom
170 // implementation that converts our internal UTF-8 encoding to the
171 // console's encoding. It also does *not* replace LF with CRLF.
172 // Since stderr does not convert encoding and does convert LF, we
173 // cannot use it to print messages. Another implementation will
174 // be needed to print colored messages on Windows.
175 static_cast<void>(md);
176 std::cerr << m << cmakemainGetStack(cm) << '\n' << std::flush;
178 cmsysTerminal_cfprintf(md.desiredColor, stderr, "%s", m.c_str());
179 fflush(stderr); // stderr is buffered in some cases.
180 std::cerr << cmakemainGetStack(cm) << '\n' << std::flush;
184 void cmakemainProgressCallback(const std::string& m, float prog, cmake* cm)
186 cmMakefile* mf = cmakemainGetMakefile(cm);
188 if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
189 dir = cmStrCat(' ', mf->GetCurrentSourceDirectory());
190 } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
191 dir = cmStrCat(' ', mf->GetCurrentBinaryDirectory());
194 if ((prog < 0) || (!dir.empty())) {
195 std::cout << "-- " << m << dir << cmakemainGetStack(cm) << std::endl;
199 int do_cmake(int ac, char const* const* av)
201 if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
202 std::cerr << "Current working directory cannot be established."
207 #ifndef CMAKE_BOOTSTRAP
209 doc.addCMakeStandardDocSections();
210 if (doc.CheckOptions(ac, av, "--")) {
211 // Construct and print requested documentation.
212 cmake hcm(cmake::RoleInternal, cmState::Unknown);
213 hcm.SetHomeDirectory("");
214 hcm.SetHomeOutputDirectory("");
217 // the command line args are processed here so that you can do
218 // -DCMAKE_MODULE_PATH=/some/path and have this value accessible here
219 std::vector<std::string> args(av, av + ac);
220 hcm.SetCacheArgs(args);
222 auto generators = hcm.GetGeneratorsDocumentation();
224 doc.SetName("cmake");
225 doc.SetSection("Name", cmDocumentationName);
226 doc.SetSection("Usage", cmDocumentationUsage);
228 doc.AppendSection("Usage", cmDocumentationUsageNote);
230 doc.AppendSection("Generators", generators);
231 doc.PrependSection("Options", cmDocumentationOptions);
233 return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
238 << "Bootstrap CMake should not be used outside CMake build process."
244 bool wizard_mode = false;
245 bool sysinfo = false;
246 bool list_cached = false;
247 bool list_all_cached = false;
248 bool list_help = false;
249 bool view_only = false;
250 cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
251 std::vector<std::string> parsedArgs;
253 using CommandArgument =
254 cmCommandLineArgument<bool(std::string const& value)>;
255 std::vector<CommandArgument> arguments = {
257 "-i", CommandArgument::Values::Zero,
258 [&wizard_mode](std::string const&) -> bool {
259 /* clang-format off */
261 "The \"cmake -i\" wizard mode is no longer supported.\n"
262 "Use the -D option to set cache values on the command line.\n"
263 "Use cmake-gui or ccmake for an interactive dialog.\n";
264 /* clang-format on */
268 CommandArgument{ "--system-information", CommandArgument::Values::Zero,
269 CommandArgument::setToTrue(sysinfo) },
270 CommandArgument{ "-N", CommandArgument::Values::Zero,
271 CommandArgument::setToTrue(view_only) },
272 CommandArgument{ "-LAH", CommandArgument::Values::Zero,
273 CommandArgument::setToTrue(list_all_cached, list_help) },
274 CommandArgument{ "-LA", CommandArgument::Values::Zero,
275 CommandArgument::setToTrue(list_all_cached) },
276 CommandArgument{ "-LH", CommandArgument::Values::Zero,
277 CommandArgument::setToTrue(list_cached, list_help) },
278 CommandArgument{ "-L", CommandArgument::Values::Zero,
279 CommandArgument::setToTrue(list_cached) },
280 CommandArgument{ "-P", "No script specified for argument -P",
281 CommandArgument::Values::One,
282 CommandArgument::RequiresSeparator::No,
283 [&](std::string const& value) -> bool {
284 workingMode = cmake::SCRIPT_MODE;
285 parsedArgs.emplace_back("-P");
286 parsedArgs.push_back(value);
289 CommandArgument{ "--find-package", CommandArgument::Values::Zero,
290 [&](std::string const&) -> bool {
291 workingMode = cmake::FIND_PACKAGE_MODE;
292 parsedArgs.emplace_back("--find-package");
295 CommandArgument{ "--list-presets", CommandArgument::Values::ZeroOrOne,
296 [&](std::string const& value) -> bool {
297 workingMode = cmake::HELP_MODE;
298 parsedArgs.emplace_back("--list-presets");
299 parsedArgs.emplace_back(value);
304 std::vector<std::string> inputArgs;
305 inputArgs.reserve(ac);
306 cm::append(inputArgs, av, av + ac);
308 for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
309 std::string const& arg = inputArgs[i];
310 bool matched = false;
311 for (auto const& m : arguments) {
312 if (m.matches(arg)) {
314 if (m.parse(arg, i, inputArgs)) {
317 return 1; // failed to parse
321 parsedArgs.emplace_back(av[i]);
330 cmake cm(cmake::RoleProject, cmState::Project);
331 cm.SetHomeDirectory("");
332 cm.SetHomeOutputDirectory("");
333 int ret = cm.GetSystemInformation(parsedArgs);
336 cmake::Role const role =
337 workingMode == cmake::SCRIPT_MODE ? cmake::RoleScript : cmake::RoleProject;
338 cmState::Mode mode = cmState::Unknown;
339 switch (workingMode) {
340 case cmake::NORMAL_MODE:
341 case cmake::HELP_MODE:
342 mode = cmState::Project;
344 case cmake::SCRIPT_MODE:
345 mode = cmState::Script;
347 case cmake::FIND_PACKAGE_MODE:
348 mode = cmState::FindPackage;
351 cmake cm(role, mode);
352 cm.SetHomeDirectory("");
353 cm.SetHomeOutputDirectory("");
354 cmSystemTools::SetMessageCallback(
355 [&cm](const std::string& msg, const cmMessageMetadata& md) {
356 cmakemainMessageCallback(msg, md, &cm);
358 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
359 cmakemainProgressCallback(msg, prog, &cm);
361 cm.SetWorkingMode(workingMode);
363 int res = cm.Run(parsedArgs, view_only);
364 if (list_cached || list_all_cached) {
365 std::cout << "-- Cache values" << std::endl;
366 std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
367 for (std::string const& k : keys) {
368 cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k);
369 if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
370 t != cmStateEnums::UNINITIALIZED) {
371 cmValue advancedProp =
372 cm.GetState()->GetCacheEntryProperty(k, "ADVANCED");
373 if (list_all_cached || !advancedProp) {
376 cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING");
377 std::cout << "// " << (help ? *help : "") << std::endl;
379 std::cout << k << ":" << cmState::CacheEntryTypeToString(t) << "="
380 << cm.GetState()->GetSafeCacheEntryValue(k) << std::endl;
382 std::cout << std::endl;
389 // Always return a non-negative value. Windows tools do not always
390 // interpret negative return values as errors.
397 #ifndef CMAKE_BOOTSTRAP
398 int extract_job_number(std::string const& command,
399 std::string const& jobString)
402 unsigned long numJobs = 0;
403 if (jobString.empty()) {
404 jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
405 } else if (cmStrToULong(jobString, &numJobs)) {
408 << "The <jobs> value requires a positive integer argument.\n\n";
409 } else if (numJobs > INT_MAX) {
410 std::cerr << "The <jobs> value is too large.\n\n";
412 jobs = static_cast<int>(numJobs);
415 std::cerr << "'" << command << "' invalid number '" << jobString
422 int do_build(int ac, char const* const* av)
424 #ifdef CMAKE_BOOTSTRAP
425 std::cerr << "This cmake does not support --build\n";
428 int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
429 std::vector<std::string> targets;
432 std::vector<std::string> nativeOptions;
433 bool nativeOptionsPassed = false;
434 bool cleanFirst = false;
435 bool foundClean = false;
436 bool foundNonClean = false;
437 PackageResolveMode resolveMode = PackageResolveMode::Default;
438 bool verbose = cmSystemTools::HasEnv("VERBOSE");
439 std::string presetName;
440 bool listPresets = false;
442 auto jLambda = [&](std::string const& value) -> bool {
443 jobs = extract_job_number("-j", value);
449 auto parallelLambda = [&](std::string const& value) -> bool {
450 jobs = extract_job_number("--parallel", value);
456 auto targetLambda = [&](std::string const& value) -> bool {
457 if (!value.empty()) {
458 std::vector<std::string> values = cmExpandedList(value);
459 for (auto const& v : values) {
460 targets.emplace_back(v);
464 foundNonClean = true;
471 auto resolvePackagesLambda = [&](std::string const& value) -> bool {
472 std::string v = value;
473 std::transform(v.begin(), v.end(), v.begin(), ::tolower);
476 resolveMode = PackageResolveMode::Force;
477 } else if (v == "only") {
478 resolveMode = PackageResolveMode::OnlyResolve;
479 } else if (v == "off") {
480 resolveMode = PackageResolveMode::Disable;
487 auto verboseLambda = [&](std::string const&) -> bool {
492 using CommandArgument =
493 cmCommandLineArgument<bool(std::string const& value)>;
495 std::vector<CommandArgument> arguments = {
496 CommandArgument{ "--preset", CommandArgument::Values::One,
497 CommandArgument::setToValue(presetName) },
498 CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
499 CommandArgument::setToTrue(listPresets) },
500 CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne,
501 CommandArgument::RequiresSeparator::No, jLambda },
502 CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
503 CommandArgument::RequiresSeparator::No, parallelLambda },
504 CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda },
505 CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
507 CommandArgument{ "--config", CommandArgument::Values::One,
508 CommandArgument::setToValue(config) },
509 CommandArgument{ "--clean-first", CommandArgument::Values::Zero,
510 CommandArgument::setToTrue(cleanFirst) },
511 CommandArgument{ "--resolve-package-references",
512 CommandArgument::Values::One, resolvePackagesLambda },
513 CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
514 CommandArgument{ "--verbose", CommandArgument::Values::Zero,
516 /* legacy option no-op*/
517 CommandArgument{ "--use-stderr", CommandArgument::Values::Zero,
518 [](std::string const&) -> bool { return true; } },
519 CommandArgument{ "--", CommandArgument::Values::Zero,
520 CommandArgument::setToTrue(nativeOptionsPassed) },
524 std::vector<std::string> inputArgs;
526 bool hasPreset = false;
527 for (int i = 2; i < ac; ++i) {
528 if (strcmp(av[i], "--list-presets") == 0 ||
529 cmHasLiteralPrefix(av[i], "--preset=") ||
530 strcmp(av[i], "--preset") == 0) {
537 inputArgs.reserve(ac - 2);
538 cm::append(inputArgs, av + 2, av + ac);
540 dir = cmSystemTools::CollapseFullPath(av[2]);
542 inputArgs.reserve(ac - 3);
543 cm::append(inputArgs, av + 3, av + ac);
546 decltype(inputArgs.size()) i = 0;
547 for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) {
549 std::string const& arg = inputArgs[i];
550 bool matched = false;
552 for (auto const& m : arguments) {
553 matched = m.matches(arg);
555 parsed = m.parse(arg, i, inputArgs);
559 if (!(matched && parsed)) {
562 std::cerr << "Unknown argument " << arg << std::endl;
568 if (nativeOptionsPassed) {
569 cm::append(nativeOptions, inputArgs.begin() + i, inputArgs.end());
573 if (foundClean && foundNonClean) {
574 std::cerr << "Error: Building 'clean' and other targets together "
580 if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
581 std::string parallel;
582 if (cmSystemTools::GetEnv("CMAKE_BUILD_PARALLEL_LEVEL", parallel)) {
583 if (parallel.empty()) {
584 jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
586 unsigned long numJobs = 0;
587 if (cmStrToULong(parallel, &numJobs)) {
589 std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
590 "requires a positive integer argument.\n\n";
592 } else if (numJobs > INT_MAX) {
593 std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
597 jobs = static_cast<int>(numJobs);
600 std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
601 << "invalid number '" << parallel << "' given.\n\n";
608 if (dir.empty() && presetName.empty() && !listPresets) {
609 /* clang-format off */
611 "Usage: cmake --build <dir> "
612 " [options] [-- [native-options]]\n"
613 " cmake --build --preset <preset>"
614 " [options] [-- [native-options]]\n"
616 " <dir> = Project binary directory to be built.\n"
617 " --preset <preset>, --preset=<preset>\n"
618 " = Specify a build preset.\n"
620 " = List available build presets.\n"
621 " --parallel [<jobs>], -j [<jobs>]\n"
622 " = Build in parallel using the given number of jobs. \n"
623 " If <jobs> is omitted the native build tool's \n"
624 " default number is used.\n"
625 " The CMAKE_BUILD_PARALLEL_LEVEL environment "
627 " specifies a default parallel level when this "
630 " --target <tgt>..., -t <tgt>... \n"
631 " = Build <tgt> instead of default targets.\n"
632 " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
633 " --clean-first = Build target 'clean' first, then build.\n"
634 " (To clean only, use --target 'clean'.)\n"
635 " --resolve-package-references={on|only|off}\n"
636 " = Restore/resolve package references during build.\n"
637 " --verbose, -v = Enable verbose output - if supported - including\n"
638 " the build commands to be executed. \n"
639 " -- = Pass remaining options to the native tool.\n"
641 /* clang-format on */
645 cmake cm(cmake::RoleInternal, cmState::Project);
646 cmSystemTools::SetMessageCallback(
647 [&cm](const std::string& msg, const cmMessageMetadata& md) {
648 cmakemainMessageCallback(msg, md, &cm);
650 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
651 cmakemainProgressCallback(msg, prog, &cm);
654 cmBuildOptions buildOptions(cleanFirst, false, resolveMode);
656 return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
657 std::move(nativeOptions), buildOptions, verbose, presetName,
662 bool parse_default_directory_permissions(const std::string& permissions,
663 std::string& parsedPermissionsVar)
665 std::vector<std::string> parsedPermissions;
672 DoingOwnerAssignment,
673 DoingGroupAssignment,
674 DoingWorldAssignment,
676 Doing doing = DoingNone;
678 auto uniquePushBack = [&parsedPermissions](const std::string& e) {
679 if (std::find(parsedPermissions.begin(), parsedPermissions.end(), e) ==
680 parsedPermissions.end()) {
681 parsedPermissions.push_back(e);
685 for (auto const& e : permissions) {
690 } else if (e == 'g') {
692 } else if (e == 'o') {
700 doing = DoingOwnerAssignment;
707 doing = DoingGroupAssignment;
714 doing = DoingWorldAssignment;
719 case DoingOwnerAssignment:
721 uniquePushBack("OWNER_READ");
722 } else if (e == 'w') {
723 uniquePushBack("OWNER_WRITE");
724 } else if (e == 'x') {
725 uniquePushBack("OWNER_EXECUTE");
726 } else if (e == ',') {
732 case DoingGroupAssignment:
734 uniquePushBack("GROUP_READ");
735 } else if (e == 'w') {
736 uniquePushBack("GROUP_WRITE");
737 } else if (e == 'x') {
738 uniquePushBack("GROUP_EXECUTE");
739 } else if (e == ',') {
745 case DoingWorldAssignment:
747 uniquePushBack("WORLD_READ");
748 } else if (e == 'w') {
749 uniquePushBack("WORLD_WRITE");
750 } else if (e == 'x') {
751 uniquePushBack("WORLD_EXECUTE");
752 } else if (e == ',') {
760 if (doing != DoingOwnerAssignment && doing != DoingGroupAssignment &&
761 doing != DoingWorldAssignment) {
765 std::ostringstream oss;
766 for (auto i = 0u; i < parsedPermissions.size(); i++) {
770 oss << parsedPermissions[i];
773 parsedPermissionsVar = oss.str();
777 int do_install(int ac, char const* const* av)
779 #ifdef CMAKE_BOOTSTRAP
780 std::cerr << "This cmake does not support --install\n";
786 std::string component;
787 std::string defaultDirectoryPermissions;
791 bool verbose = cmSystemTools::HasEnv("VERBOSE");
793 auto verboseLambda = [&](std::string const&) -> bool {
798 using CommandArgument =
799 cmCommandLineArgument<bool(std::string const& value)>;
801 std::vector<CommandArgument> arguments = {
802 CommandArgument{ "--config", CommandArgument::Values::One,
803 CommandArgument::setToValue(config) },
804 CommandArgument{ "--component", CommandArgument::Values::One,
805 CommandArgument::setToValue(component) },
807 "--default-directory-permissions", CommandArgument::Values::One,
808 CommandArgument::setToValue(defaultDirectoryPermissions) },
809 CommandArgument{ "--prefix", CommandArgument::Values::One,
810 CommandArgument::setToValue(prefix) },
811 CommandArgument{ "--strip", CommandArgument::Values::Zero,
812 CommandArgument::setToTrue(strip) },
813 CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
814 CommandArgument{ "--verbose", CommandArgument::Values::Zero,
819 dir = cmSystemTools::CollapseFullPath(av[2]);
821 std::vector<std::string> inputArgs;
822 inputArgs.reserve(ac - 3);
823 cm::append(inputArgs, av + 3, av + ac);
824 for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
826 std::string const& arg = inputArgs[i];
827 bool matched = false;
829 for (auto const& m : arguments) {
830 matched = m.matches(arg);
832 parsed = m.parse(arg, i, inputArgs);
836 if (!(matched && parsed)) {
839 std::cerr << "Unknown argument " << arg << std::endl;
847 /* clang-format off */
849 "Usage: cmake --install <dir> [options]\n"
851 " <dir> = Project binary directory to install.\n"
852 " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
853 " --component <comp> = Component-based install. Only install <comp>.\n"
854 " --default-directory-permissions <permission> \n"
855 " Default install permission. Use default permission <permission>.\n"
856 " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n"
857 " --strip = Performing install/strip.\n"
858 " -v --verbose = Enable verbose output.\n"
860 /* clang-format on */
864 cmake cm(cmake::RoleScript, cmState::Script);
866 cmSystemTools::SetMessageCallback(
867 [&cm](const std::string& msg, const cmMessageMetadata& md) {
868 cmakemainMessageCallback(msg, md, &cm);
870 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
871 cmakemainProgressCallback(msg, prog, &cm);
873 cm.SetHomeDirectory("");
874 cm.SetHomeOutputDirectory("");
875 cm.SetDebugOutputOn(verbose);
876 cm.SetWorkingMode(cmake::SCRIPT_MODE);
878 std::vector<std::string> args{ av[0] };
880 if (!prefix.empty()) {
881 args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
884 if (!component.empty()) {
885 args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
889 args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
892 if (!config.empty()) {
893 args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
896 if (!defaultDirectoryPermissions.empty()) {
897 std::string parsedPermissionsVar;
898 if (!parse_default_directory_permissions(defaultDirectoryPermissions,
899 parsedPermissionsVar)) {
900 std::cerr << "--default-directory-permissions is in incorrect format"
904 args.emplace_back("-DCMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS=" +
905 parsedPermissionsVar);
908 args.emplace_back("-P");
909 args.emplace_back(dir + "/cmake_install.cmake");
911 return cm.Run(args) ? 1 : 0;
915 int do_open(int ac, char const* const* av)
917 #ifdef CMAKE_BOOTSTRAP
918 std::cerr << "This cmake does not support --open\n";
928 Doing doing = DoingDir;
929 for (int i = 2; i < ac; ++i) {
932 dir = cmSystemTools::CollapseFullPath(av[i]);
936 std::cerr << "Unknown argument " << av[i] << std::endl;
942 std::cerr << "Usage: cmake --open <dir>\n";
946 cmake cm(cmake::RoleInternal, cmState::Unknown);
947 cmSystemTools::SetMessageCallback(
948 [&cm](const std::string& msg, const cmMessageMetadata& md) {
949 cmakemainMessageCallback(msg, md, &cm);
951 cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
952 cmakemainProgressCallback(msg, prog, &cm);
954 return cm.Open(dir, false) ? 0 : 1;
959 int main(int ac, char const* const* av)
961 cmSystemTools::EnsureStdPipes();
963 // Replace streambuf so we can output Unicode to console
964 auto consoleBuf = cm::make_unique<cmConsoleBuf>();
965 consoleBuf->SetUTF8Pipes();
967 cmsys::Encoding::CommandLineArguments args =
968 cmsys::Encoding::CommandLineArguments::Main(ac, av);
972 cmSystemTools::InitializeLibUV();
973 cmSystemTools::FindCMakeResources(av[0]);
975 if (strcmp(av[1], "--build") == 0) {
976 return do_build(ac, av);
978 if (strcmp(av[1], "--install") == 0) {
979 return do_install(ac, av);
981 if (strcmp(av[1], "--open") == 0) {
982 return do_open(ac, av);
984 if (strcmp(av[1], "-E") == 0) {
985 return do_command(ac, av, std::move(consoleBuf));
988 int ret = do_cmake(ac, av);
989 #ifndef CMAKE_BOOTSTRAP
990 cmDynamicLoader::FlushCache();
992 if (uv_loop_t* loop = uv_default_loop()) {