Browse Source

cmake: add '--install <dir>' option

Fixes: #19023
Jiang Yi 6 years ago
parent
commit
73f23d1e00

+ 1 - 1
Auxiliary/bash-completion/cmake

@@ -96,7 +96,7 @@ _cmake()
             _filedir
             return
             ;;
-        --build|--open)
+        --build|--install|--open)
             _filedir -d
             return
             ;;

+ 40 - 2
Help/manual/cmake.1.rst

@@ -16,6 +16,9 @@ Synopsis
  `Build a Project`_
   cmake --build <dir> [<options>] [-- <build-tool-options>]
 
+ `Install a Project`_
+  cmake --install <dir> [<options>]
+
  `Open a Project`_
   cmake --open <dir>
 
@@ -39,8 +42,8 @@ buildsystem generator CMake.  The above `Synopsis`_ lists various actions
 the tool can perform as described in sections below.
 
 To build a software project with CMake, `Generate a Project Buildsystem`_.
-Optionally use **cmake** to `Build a Project`_ or just run the
-corresponding build tool (e.g. ``make``) directly.  **cmake** can also
+Optionally use **cmake** to `Build a Project`_, `Install a Project`_ or just
+run the corresponding build tool (e.g. ``make``) directly.  **cmake** can also
 be used to `View Help`_.
 
 The other actions are meant for use by software developers writing
@@ -302,6 +305,41 @@ following options:
 
 Run ``cmake --build`` with no options for quick help.
 
+Install a Project
+=================
+
+CMake provides a command-line signature to install an already-generated
+project binary tree:
+
+.. code-block:: shell
+
+  cmake --install <dir> [<options>]
+
+This may be used after building a project to run installation without
+using the generated build system or the native build tool.
+The options are:
+
+``--install <dir>``
+  Project binary directory to install. This is required and must be first.
+
+``--config <cfg>``
+  For multi-configuration tools, choose configuration ``<cfg>``.
+
+``--component <comp>``
+  Component-based install. Only install component ``<comp>``.
+
+``--prefix <prefix>``
+  The installation prefix CMAKE_INSTALL_PREFIX.
+
+``--strip``
+  Strip before installing by setting CMAKE_INSTALL_DO_STRIP.
+
+``-v, --verbose``
+  Enable verbose output.
+
+  This option can be omitted if :envvar:`VERBOSE` environment variable is set.
+
+Run ``cmake --install`` with no options for quick help.
 
 Open a Project
 ==============

+ 6 - 0
Help/release/dev/cmake--install_option.rst

@@ -0,0 +1,6 @@
+cmake--install-option
+---------------------
+
+* A new ``--install`` option was added to :manual:`cmake(1)`.
+  This may be used after building a project to run installation without
+  using the generated build system or the native build tool.

+ 125 - 0
Source/cmakemain.cxx

@@ -23,6 +23,7 @@
 #  include "cmsys/ConsoleBuf.hxx"
 #endif
 
+#include <cassert>
 #include <ctype.h>
 #include <iostream>
 #include <string.h>
@@ -71,11 +72,20 @@ static const char* cmDocumentationUsageNote[][2] = {
     "                   the build commands to be executed. \n"                \
     "  --             = Pass remaining options to the native tool.\n"
 
+#  define CMAKE_INSTALL_OPTIONS                                               \
+    "  <dir>              = Project binary directory to install.\n"           \
+    "  --config <cfg>     = For multi-configuration tools, choose <cfg>.\n"   \
+    "  --component <comp> = Component-based install. Only install <comp>.\n"  \
+    "  --prefix <prefix>  = The installation prefix CMAKE_INSTALL_PREFIX.\n"  \
+    "  --strip            = Performing install/strip.\n"                      \
+    "  -v --verbose       = Enable verbose output.\n"
+
 static const char* cmDocumentationOptions[][2] = {
   CMAKE_STANDARD_OPTIONS_TABLE,
   { "-E", "CMake command mode." },
   { "-L[A][H]", "List non-advanced cached variables." },
   { "--build <dir>", "Build a CMake-generated project binary tree." },
+  { "--install <dir>", "Install a CMake-generated project binary tree." },
   { "--open <dir>", "Open generated project in the associated application." },
   { "-N", "View mode only." },
   { "-P <file>", "Process script mode." },
@@ -114,6 +124,7 @@ static int do_command(int ac, char const* const* av)
 
 int do_cmake(int ac, char const* const* av);
 static int do_build(int ac, char const* const* av);
+static int do_install(int ac, char const* const* av);
 static int do_open(int ac, char const* const* av);
 
 static cmMakefile* cmakemainGetMakefile(cmake* cm)
@@ -188,6 +199,9 @@ int main(int ac, char const* const* av)
     if (strcmp(av[1], "--build") == 0) {
       return do_build(ac, av);
     }
+    if (strcmp(av[1], "--install") == 0) {
+      return do_install(ac, av);
+    }
     if (strcmp(av[1], "--open") == 0) {
       return do_open(ac, av);
     }
@@ -523,6 +537,117 @@ static int do_build(int ac, char const* const* av)
 #endif
 }
 
+static int do_install(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+  std::cerr << "This cmake does not support --install\n";
+  return -1;
+#else
+  assert(1 < ac);
+
+  std::string config;
+  std::string component;
+  std::string prefix;
+  std::string dir;
+  bool strip = false;
+  bool verbose = cmSystemTools::HasEnv("VERBOSE");
+
+  enum Doing
+  {
+    DoingNone,
+    DoingDir,
+    DoingConfig,
+    DoingComponent,
+    DoingPrefix,
+  };
+
+  Doing doing = DoingDir;
+
+  for (int i = 2; i < ac; ++i) {
+    if (strcmp(av[i], "--config") == 0) {
+      doing = DoingConfig;
+    } else if (strcmp(av[i], "--component") == 0) {
+      doing = DoingComponent;
+    } else if (strcmp(av[i], "--prefix") == 0) {
+      doing = DoingPrefix;
+    } else if (strcmp(av[i], "--strip") == 0) {
+      strip = true;
+      doing = DoingNone;
+    } else if ((strcmp(av[i], "--verbose") == 0) ||
+               (strcmp(av[i], "-v") == 0)) {
+      verbose = true;
+      doing = DoingNone;
+    } else {
+      switch (doing) {
+        case DoingDir:
+          dir = cmSystemTools::CollapseFullPath(av[i]);
+          doing = DoingNone;
+          break;
+        case DoingConfig:
+          config = av[i];
+          doing = DoingNone;
+          break;
+        case DoingComponent:
+          component = av[i];
+          doing = DoingNone;
+          break;
+        case DoingPrefix:
+          prefix = av[i];
+          doing = DoingNone;
+          break;
+        default:
+          std::cerr << "Unknown argument " << av[i] << std::endl;
+          dir.clear();
+          break;
+      }
+    }
+  }
+
+  if (dir.empty()) {
+    std::cerr << "Usage: cmake --install <dir> "
+                 "[options]\nOptions:\n" CMAKE_INSTALL_OPTIONS;
+    return 1;
+  }
+
+  cmake cm(cmake::RoleScript, cmState::Script);
+
+  cmSystemTools::SetMessageCallback(
+    [&cm](const std::string& msg, const char* title) {
+      cmakemainMessageCallback(msg, title, &cm);
+    });
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+    cmakemainProgressCallback(msg, prog, &cm);
+  });
+  cm.SetHomeDirectory("");
+  cm.SetHomeOutputDirectory("");
+  cm.SetDebugOutputOn(verbose);
+  cm.SetWorkingMode(cmake::SCRIPT_MODE);
+
+  std::vector<std::string> args{ av[0] };
+
+  if (!prefix.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
+  }
+
+  if (!component.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
+  }
+
+  if (strip) {
+    args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
+  }
+
+  if (!config.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
+  }
+
+  args.emplace_back("-P");
+  args.emplace_back(dir + "/cmake_install.cmake");
+
+  return cm.Run(args) ? 1 : 0;
+#endif
+}
+
 static int do_open(int ac, char const* const* av)
 {
 #ifndef CMAKE_BUILD_WITH_CMAKE

+ 8 - 0
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -54,6 +54,14 @@ run_cmake_command(build-bad-dir
 run_cmake_command(build-bad-generator
   ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-generator)
 
+run_cmake_command(install-no-dir
+  ${CMAKE_COMMAND} --install)
+run_cmake_command(install-bad-dir
+  ${CMAKE_COMMAND} --install dir-does-not-exist)
+run_cmake_command(install-options-to-vars
+  ${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
+  --strip --prefix /var/test --config sample --component pack)
+
 run_cmake_command(cache-bad-entry
   ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-entry/)
 run_cmake_command(cache-empty-entry

+ 15 - 0
Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake

@@ -0,0 +1,15 @@
+if(CMAKE_INSTALL_PREFIX)
+  message("CMAKE_INSTALL_PREFIX is ${CMAKE_INSTALL_PREFIX}")
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+  message("CMAKE_INSTALL_COMPONENT is ${CMAKE_INSTALL_COMPONENT}")
+endif()
+
+if(CMAKE_INSTALL_CONFIG_NAME)
+  message("CMAKE_INSTALL_CONFIG_NAME is ${CMAKE_INSTALL_CONFIG_NAME}")
+endif()
+
+if(CMAKE_INSTALL_DO_STRIP)
+  message("CMAKE_INSTALL_DO_STRIP is ${CMAKE_INSTALL_DO_STRIP}")
+endif()

+ 1 - 0
Tests/RunCMake/CommandLine/install-bad-dir-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt

@@ -0,0 +1 @@
+^CMake Error: Error processing file:

+ 1 - 0
Tests/RunCMake/CommandLine/install-no-dir-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CommandLine/install-no-dir-stderr.txt

@@ -0,0 +1 @@
+^Usage: cmake --install <dir> \[options\]

+ 1 - 0
Tests/RunCMake/CommandLine/install-options-to-vars-result.txt

@@ -0,0 +1 @@
+0

+ 4 - 0
Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt

@@ -0,0 +1,4 @@
+CMAKE_INSTALL_PREFIX is /var/test
+CMAKE_INSTALL_COMPONENT is pack
+CMAKE_INSTALL_CONFIG_NAME is sample
+CMAKE_INSTALL_DO_STRIP is 1