瀏覽代碼

BUG: 4244, add a --build option to cmake that can build projects configured by CMake

Bill Hoffman 17 年之前
父節點
當前提交
1777bb502a

+ 7 - 4
Source/cmGlobalGenerator.cxx

@@ -1117,7 +1117,9 @@ int cmGlobalGenerator::Build(
   const char *makeCommandCSTR,
   const char *config,
   bool clean, bool fast,
-  double timeout)
+  double timeout,
+  bool verbose,
+  const char* extraOptions)
 {
   /**
    * Run an executable command and put the stdout in output.
@@ -1155,7 +1157,7 @@ int cmGlobalGenerator::Build(
       }
 
     if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), outputPtr,
-                                         &retVal, 0, false, timeout))
+                                         &retVal, 0, verbose, timeout))
       {
       cmSystemTools::SetRunCommandHideConsole(hideconsole);
       cmSystemTools::Error("Generator: execution of make clean failed.");
@@ -1178,7 +1180,8 @@ int cmGlobalGenerator::Build(
   // now build
   std::string makeCommand =
     this->GenerateBuildCommand(makeCommandCSTR, projectName,
-                               0, target, config, false, fast);
+                               extraOptions, target, 
+                               config, false, fast);
   if(output)
     {
     *output += "\nRun Build Command:";
@@ -1187,7 +1190,7 @@ int cmGlobalGenerator::Build(
     }
   
   if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), outputPtr,
-                                       &retVal, 0, false, timeout))
+                                       &retVal, 0, verbose, timeout))
     {
     cmSystemTools::SetRunCommandHideConsole(hideconsole);
     cmSystemTools::Error

+ 9 - 7
Source/cmGlobalGenerator.h

@@ -105,13 +105,15 @@ public:
                     std::string *output, 
                     const char *makeProgram, const char *config,
                     bool clean, bool fast,
-                    double timeout);
-  virtual std::string GenerateBuildCommand
-  (const char* makeProgram,
-   const char *projectName, const char* additionalOptions, 
-   const char *targetName,
-   const char* config, bool ignoreErrors, bool fast);
-
+                    double timeout, bool verbose=false,
+                    const char* extraOptions = 0);
+  
+  virtual std::string GenerateBuildCommand(
+    const char* makeProgram,
+    const char *projectName, const char* additionalOptions, 
+    const char *targetName,
+    const char* config, bool ignoreErrors, bool fast);
+  
 
   ///! Set the CMake instance
   void SetCMakeInstance(cmake *cm);

+ 4 - 0
Source/cmProjectCommand.cxx

@@ -57,6 +57,10 @@ bool cmProjectCommand
   if(!this->Makefile->GetDefinition("CMAKE_PROJECT_NAME"))
     {
     this->Makefile->AddDefinition("CMAKE_PROJECT_NAME", args[0].c_str());
+    this->Makefile->AddCacheDefinition
+      ("CMAKE_PROJECT_NAME",
+       args[0].c_str(),
+       "Value Computed by CMake", cmCacheManager::STATIC);
     }
 
   std::vector<std::string> languages;

+ 88 - 2
Source/cmake.cxx

@@ -36,6 +36,7 @@
 # include <cmsys/Terminal.h>
 #endif
 
+#include <cmsys/CommandLineArguments.hxx>
 #include <cmsys/Directory.hxx>
 #include <cmsys/Process.h>
 #include <cmsys/Glob.hxx>
@@ -947,7 +948,8 @@ void CMakeCommandUsage(const char* program)
   errorStream
     << "cmake bootstrap\n";
 #endif
-
+  // If you add new commands, change here, 
+  // and in cmakemain.cxx in the options table
   errorStream
     << "Usage: " << program << " -E [command] [arguments ...]\n"
     << "Available commands: \n"
@@ -973,6 +975,7 @@ void CMakeCommandUsage(const char* program)
     << "  time command [args] ...   - run command and return elapsed time\n"
     << "  touch file                - touch a file.\n"
     << "  touch_nocreate file       - touch a file but do not create it.\n"
+    << "  build build_dir           - build the project in build_dir.\n"
 #if defined(_WIN32) && !defined(__CYGWIN__)
     << "  write_regv key value      - write registry value\n"
     << "  delete_regv key           - delete registry value\n"
@@ -987,6 +990,7 @@ void CMakeCommandUsage(const char* program)
 
 int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
 {
+  // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
   if (args.size() > 1)
     {
     // Copy file
@@ -1188,7 +1192,6 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
         << "\n";
       return ret;
       }
-
     // Command to calculate the md5sum of a file
     else if (args[1] == "md5sum" && args.size() >= 3)
       {
@@ -4329,3 +4332,86 @@ std::vector<std::string> const& cmake::GetDebugConfigs()
     }
   return this->DebugConfigs;
 }
+
+
+int cmake::Build(const std::string& dir,
+                 const std::string& target,
+                 const std::string& config,
+                 const std::string& extraBuildOptions,
+                 bool clean)
+{ 
+  if(!cmSystemTools::FileIsDirectory(dir.c_str()))
+    {
+    std::cerr << "Error: " << dir << " is not a directory\n";
+    return 1;
+    }
+  std::string cachePath = dir;
+  cmSystemTools::ConvertToUnixSlashes(cachePath);
+  cmCacheManager* cachem = this->GetCacheManager();
+  cmCacheManager::CacheIterator it = cachem->NewIterator();
+  if(!cachem->LoadCache(cachePath.c_str()))
+    {
+    std::cerr << "Error: could not load cache\n";
+    return 1;
+    }
+  if(!it.Find("CMAKE_GENERATOR"))
+    {
+    std::cerr << "Error: could find generator in Cache\n";
+    return 1;
+    }
+  cmGlobalGenerator* gen =
+    this->CreateGlobalGenerator(it.GetValue());
+  std::string output;
+  std::string projName;
+  std::string makeProgram;
+  if(!it.Find("CMAKE_PROJECT_NAME"))
+    {
+    std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+    return 1;
+    }
+  projName = it.GetValue();
+  if(!it.Find("CMAKE_MAKE_PROGRAM"))
+    {
+    std::cerr << "Error: could not find CMAKE_MAKE_PROGRAM in Cache\n";
+    return 1;
+    }
+  makeProgram = it.GetValue();
+  return gen->Build(0, dir.c_str(),
+                    projName.c_str(), target.c_str(),
+                    &output, 
+                    makeProgram.c_str(),
+                    config.c_str(), clean, false, 0, true);
+}
+
+int cmake::DoBuild(int ac, char* av[])
+{
+  std::string target;
+  std::string config = "Debug";
+  std::string extraBuildOptions;
+  std::string dir;
+  bool clean = false;
+  cmsys::CommandLineArguments arg;
+  arg.Initialize(ac, av);
+  typedef cmsys::CommandLineArguments argT;
+  arg.AddArgument("--build", argT::SPACE_ARGUMENT, &dir, 
+                  "Build a configured cmake project --build dir.");
+  arg.AddArgument("--target", argT::SPACE_ARGUMENT, &target, 
+                  "Specifiy the target to build,"
+                  " if missing, all targets are built.");
+  arg.AddArgument("--config", argT::SPACE_ARGUMENT, &config, 
+                  "Specify configuration to build"
+                  " if missing Debug is built.");
+  arg.AddArgument("--extra-options", argT::SPACE_ARGUMENT, &extraBuildOptions, 
+                  "Specify extra options to pass to build program,"
+                  " for example with gmake -jN.");
+  arg.AddArgument("--clean", argT::NO_ARGUMENT, &clean, 
+                  "Clean before building.");
+  if ( !arg.Parse() )
+    {
+    std::cerr << "Problem parsing --build arguments:\n";
+    std::cerr << arg.GetHelp() << "\n";
+    return 1;
+    }
+  cmake cm;
+  return cm.Build(dir, target, config, extraBuildOptions, clean);
+}

+ 7 - 0
Source/cmake.h

@@ -356,7 +356,14 @@ class cmake
   /** Display a message to the user.  */
   void IssueMessage(cmake::MessageType t, std::string const& text,
                     cmListFileBacktrace const& backtrace);
+  //  * run the --build option
+  static int DoBuild(int ac, char* av[]);
 protected:
+  int Build(const std::string& dir,
+            const std::string& target,
+            const std::string& config,
+            const std::string& extraBuildOptions,
+            bool clean);
   void InitializeProperties();
   int HandleDeleteCacheVariables(const char* var);
   cmPropertyMap Properties;

+ 15 - 0
Source/cmakemain.cxx

@@ -85,6 +85,11 @@ static const char * cmDocumentationOptions[][3] =
    "variables being created. If A is specified, then it will display also "
    "advanced variables. If H is specified, it will also display help for "
    "each variable."},
+  {"--build dir", "Build a configured cmake tree found in dir.",
+   "This option will use the native build tool from the command line to"
+   " build the project. Other options that can be specified with this one" 
+   " are --target, --config, --extra-options, and --clean.  For complete "
+   "help run --build with no options."},
   {"-N", "View mode only.",
    "Only load the cache. Do not actually run configure and generate steps."},
   {"-P <file>", "Process script mode.",
@@ -407,6 +412,7 @@ int do_cmake(int ac, char** av)
   bool list_help = false;
   bool view_only = false;
   bool script_mode = false;
+  bool build = false;
   std::vector<std::string> args;
   for(int i =0; i < ac; ++i)
     {
@@ -414,6 +420,10 @@ int do_cmake(int ac, char** av)
       {
       wiz = true;
       }
+    else if(!command && strcmp(av[i], "--build") == 0)
+      {
+      return cmake::DoBuild(ac, av);
+      }
     else if(!command && strcmp(av[i], "--system-information") == 0)
       {
       sysinfo = true;
@@ -465,6 +475,11 @@ int do_cmake(int ac, char** av)
       args.push_back(av[i]);
       }
     }
+  if(build)
+    {
+    int ret = cmake::DoBuild(ac, av);
+    return ret;
+    }
   if(command)
     {
     int ret = cmake::ExecuteCMakeCommand(args);

+ 51 - 0
Tests/CMakeBuildTest.cmake.in

@@ -0,0 +1,51 @@
+# create the binary directory
+make_directory("@CMAKE_BUILD_TEST_BINARY_DIR@")
+
+# run cmake in the binary directory 
+execute_process(COMMAND "@CMAKE_CMAKE_COMMAND@"
+  "@CMAKE_BUILD_TEST_SOURCE_DIR@"  
+  "-G@CMAKE_TEST_GENERATOR@"
+  WORKING_DIRECTORY "@CMAKE_BUILD_TEST_BINARY_DIR@"
+  RESULT_VARIABLE RESULT)
+if(RESULT)
+  message(FATAL_ERROR "Error running cmake command")
+endif(RESULT)
+
+# Now use the --build option to build the project
+execute_process(COMMAND "@CMAKE_CMAKE_COMMAND@" 
+  --build "@CMAKE_BUILD_TEST_BINARY_DIR@" --config Debug
+  RESULT_VARIABLE RESULT)
+if(RESULT)
+  message(FATAL_ERROR "Error running cmake --build")
+endif(RESULT)
+
+# check for configuration types
+set(CMAKE_CONFIGURATION_TYPES @CMAKE_CONFIGURATION_TYPES@)
+# run the executable out of the Debug directory if there 
+# are configuration types
+if(CMAKE_CONFIGURATION_TYPES)
+  set(RUN_TEST "@CMAKE_BUILD_TEST_BINARY_DIR@/Debug/COnly")
+else(CMAKE_CONFIGURATION_TYPES)
+  set(RUN_TEST "@CMAKE_BUILD_TEST_BINARY_DIR@/COnly")
+endif(CMAKE_CONFIGURATION_TYPES)
+# run the test results
+message("running [${RUN_TEST}]")
+execute_process(COMMAND "${RUN_TEST}" RESULT_VARIABLE RESULT)
+if(RESULT)
+  message(FATAL_ERROR "Error running test COnly")
+endif(RESULT)
+
+# build it again with clean and only COnly target
+execute_process(COMMAND "@CMAKE_CMAKE_COMMAND@" 
+  --build "@CMAKE_BUILD_TEST_BINARY_DIR@" --config Debug 
+  --clean --target COnly
+  RESULT_VARIABLE RESULT)
+if(RESULT)
+  message(FATAL_ERROR "Error running cmake --build")
+endif(RESULT)
+
+# run it again after clean 
+execute_process(COMMAND "${RUN_TEST}" RESULT_VARIABLE RESULT)
+if(RESULT)
+  message(FATAL_ERROR "Error running test COnly after clean ")
+endif(RESULT)

+ 6 - 0
Tests/CMakeLists.txt

@@ -96,6 +96,12 @@ IF(BUILD_TESTING)
   ADD_TEST_MACRO(ExportImport ExportImport)
   ADD_TEST_MACRO(Unset Unset)
 
+  SET(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
+  SET(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
+  CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CMakeBuildTest.cmake.in"
+    "${CMake_BINARY_DIR}/Tests/CMakeBuildTest.cmake" @ONLY)
+  ADD_TEST(CMakeBuildTest ${CMAKE_CMAKE_COMMAND} -P
+    "${CMake_BINARY_DIR}/Tests/CMakeBuildTest.cmake")
 
   # If we are running right now with a UnixMakefiles based generator,
   # build the "Simple" test with the ExtraGenerators, if available