Browse Source

CMake: Add -T option to choose a generator toolset

Reject the option by default.  It will be implemented on a per-generator
basis.  Pass the setting into try_compile project generation.  Add cache
entry CMAKE_GENERATOR_TOOLSET and associated variable documentation to
hold the value persistently.

Add a RunCMake.GeneratorToolset test to cover basic "-T" option cases.
Verify that CMAKE_GENERATOR_TOOLSET is empty without -T, that -T is
rejected when the generator doesn't support it, and that two -T options
are always rejected.
Brad King 13 years ago
parent
commit
4fd5342956

+ 8 - 0
Source/cmDocumentVariables.cxx

@@ -254,6 +254,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
      "for the respective IDE. This IDE project file generator is stored in "
      "CMAKE_EXTRA_GENERATOR (e.g. \"Eclipse CDT4\").",false,
      "Variables that Provide Information");
+  cm->DefineProperty
+    ("CMAKE_GENERATOR_TOOLSET", cmProperty::VARIABLE,
+     "Native build system toolset name specified by user.",
+     "Some CMake generators support a toolset name to be given to the "
+     "native build system to choose a compiler.  "
+     "If the user specifies a toolset name (e.g. via the cmake -T option) "
+     "the value will be available in this variable.",false,
+     "Variables that Provide Information");
   cm->DefineProperty
     ("CMAKE_HOME_DIRECTORY", cmProperty::VARIABLE,
      "Path to top of source tree.",

+ 14 - 0
Source/cmGlobalGenerator.cxx

@@ -79,6 +79,20 @@ cmGlobalGenerator::~cmGlobalGenerator()
   this->ClearGeneratorTargets();
 }
 
+bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts)
+{
+  cmOStringStream e;
+  e <<
+    "Generator\n"
+    "  " << this->GetName() << "\n"
+    "does not support toolset specification, but toolset\n"
+    "  " << ts << "\n"
+    "was specified.";
+  this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
+                                    cmListFileBacktrace());
+  return false;
+}
+
 void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang,
                                                 cmMakefile *mf,
                                                 bool optional)

+ 4 - 0
Source/cmGlobalGenerator.h

@@ -49,6 +49,10 @@ public:
   ///! Get the name for this generator
   virtual const char *GetName() const { return "Generic"; };
 
+  /** Set the generator-specific toolset name.  Returns true if toolset
+      is supported and false otherwise.  */
+  virtual bool SetGeneratorToolset(std::string const& ts);
+
   /**
    * Create LocalGenerators and process the CMakeLists files. This does not
    * actually produce any makefiles, DSPs, etc.

+ 1 - 0
Source/cmMakefile.cxx

@@ -2973,6 +2973,7 @@ int cmMakefile::TryCompile(const char *srcdir, const char *bindir,
   cm.SetStartDirectory(srcdir);
   cm.SetStartOutputDirectory(bindir);
   cm.SetCMakeCommand(cmakeCommand.c_str());
+  cm.SetGeneratorToolset(this->GetCMakeInstance()->GetGeneratorToolset());
   cm.LoadCache();
   if(!gg->IsMultiConfig())
     {

+ 55 - 0
Source/cmake.cxx

@@ -659,6 +659,7 @@ void cmake::SetArgs(const std::vector<std::string>& args,
                     bool directoriesSetBefore)
 {
   bool directoriesSet = directoriesSetBefore;
+  bool haveToolset = false;
   for(unsigned int i=1; i < args.size(); ++i)
     {
     std::string arg = args[i];
@@ -787,6 +788,27 @@ void cmake::SetArgs(const std::vector<std::string>& args,
                    "uninitialized variables.\n";
       this->SetCheckSystemVars(true);
       }
+    else if(arg.find("-T",0) == 0)
+      {
+      std::string value = arg.substr(2);
+      if(value.size() == 0)
+        {
+        ++i;
+        if(i >= args.size())
+          {
+          cmSystemTools::Error("No toolset specified for -T");
+          return;
+          }
+        value = args[i];
+        }
+      if(haveToolset)
+        {
+        cmSystemTools::Error("Multiple -T options not allowed");
+        return;
+        }
+      this->GeneratorToolset = value;
+      haveToolset = true;
+      }
     else if(arg.find("-G",0) == 0)
       {
       std::string value = arg.substr(2);
@@ -2282,6 +2304,39 @@ int cmake::ActualConfigure()
                                 cmCacheManager::INTERNAL);
     }
 
+  if(const char* tsName =
+     this->CacheManager->GetCacheValue("CMAKE_GENERATOR_TOOLSET"))
+    {
+    if(this->GeneratorToolset.empty())
+      {
+      this->GeneratorToolset = tsName;
+      }
+    else if(this->GeneratorToolset != tsName)
+      {
+      std::string message = "Error: generator toolset: ";
+      message += this->GeneratorToolset;
+      message += "\nDoes not match the toolset used previously: ";
+      message += tsName;
+      message +=
+        "\nEither remove the CMakeCache.txt file or choose a different"
+        " binary directory.";
+      cmSystemTools::Error(message.c_str());
+      return -2;
+      }
+    }
+  else
+    {
+    this->CacheManager->AddCacheEntry("CMAKE_GENERATOR_TOOLSET",
+                                      this->GeneratorToolset.c_str(),
+                                      "Name of generator toolset.",
+                                      cmCacheManager::INTERNAL);
+    }
+  if(!this->GeneratorToolset.empty() &&
+     !this->GlobalGenerator->SetGeneratorToolset(this->GeneratorToolset))
+    {
+    return -2;
+    }
+
   // reset any system configuration information, except for when we are
   // InTryCompile. With TryCompile the system info is taken from the parent's
   // info to save time

+ 13 - 0
Source/cmake.h

@@ -187,6 +187,14 @@ class cmake
   ///! Get the names of the current registered generators
   void GetRegisteredGenerators(std::vector<std::string>& names);
 
+  ///! Set the name of the selected generator-specific toolset.
+  void SetGeneratorToolset(std::string const& ts)
+    { this->GeneratorToolset = ts; }
+
+  ///! Get the name of the selected generator-specific toolset.
+  std::string const& GetGeneratorToolset() const
+    { return this->GeneratorToolset; }
+
   ///! get the cmCachemManager used by this invocation of cmake
   cmCacheManager *GetCacheManager() { return this->CacheManager; }
 
@@ -418,6 +426,7 @@ protected:
   std::string StartOutputDirectory;
   bool SuppressDevWarnings;
   bool DoSuppressDevWarnings;
+  std::string GeneratorToolset;
 
   ///! read in a cmake list file to initialize the cache
   void ReadListFile(const std::vector<std::string>& args, const char *path);
@@ -528,6 +537,10 @@ private:
    "A makefile generator is responsible for generating a particular build " \
    "system.  Possible generator names are specified in the Generators " \
    "section."},\
+  {"-T <toolset-name>", "Specify toolset name if supported by generator.", \
+   "Some CMake generators support a toolset name to be given to the " \
+   "native build system to choose a compiler.  " \
+   "See native build system documentation for allowed toolset names."}, \
   {"-Wno-dev", "Suppress developer warnings.",\
    "Suppress warnings that are meant for the author"\
    " of the CMakeLists.txt files."},\

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -47,6 +47,7 @@ endmacro()
 
 add_RunCMake_test(CMP0019)
 add_RunCMake_test(GeneratorExpression)
+add_RunCMake_test(GeneratorToolset)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(ObjectLibrary)

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolset-result.txt

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

+ 10 - 0
Tests/RunCMake/GeneratorToolset/BadToolset-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error:
+  Generator
+
+    .*
+
+  does not support toolset specification, but toolset
+
+    Bad Toolset
+
+  was specified.$

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolset.cmake

@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")

+ 3 - 0
Tests/RunCMake/GeneratorToolset/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 1 - 0
Tests/RunCMake/GeneratorToolset/NoToolset-result.txt

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

+ 4 - 0
Tests/RunCMake/GeneratorToolset/NoToolset-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at NoToolset.cmake:2 \(message\):
+  CMAKE_GENERATOR_TOOLSET is empty as expected.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 7 - 0
Tests/RunCMake/GeneratorToolset/NoToolset.cmake

@@ -0,0 +1,7 @@
+if("x${CMAKE_GENERATOR_TOOLSET}" STREQUAL "x")
+  message(FATAL_ERROR "CMAKE_GENERATOR_TOOLSET is empty as expected.")
+else()
+  message(FATAL_ERROR
+    "CMAKE_GENERATOR_TOOLSET is \"${CMAKE_GENERATOR_TOOLSET}\" "
+    "but should be empty!")
+endif()

+ 11 - 0
Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake

@@ -0,0 +1,11 @@
+include(RunCMake)
+
+run_cmake(NoToolset)
+
+set(RunCMake_TEST_OPTIONS -T "Bad Toolset")
+run_cmake(BadToolset)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS -T "Toolset 1" "-TToolset 2")
+run_cmake(TwoToolsets)
+unset(RunCMake_TEST_OPTIONS)

+ 1 - 0
Tests/RunCMake/GeneratorToolset/TwoToolsets-result.txt

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

+ 1 - 0
Tests/RunCMake/GeneratorToolset/TwoToolsets-stderr.txt

@@ -0,0 +1 @@
+CMake Error: Multiple -T options not allowed

+ 1 - 0
Tests/RunCMake/GeneratorToolset/TwoToolsets.cmake

@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")

+ 4 - 0
Tests/RunCMake/RunCMake.cmake

@@ -29,9 +29,13 @@ function(run_cmake test)
   set(RunCMake_TEST_BINARY_DIR "${top_bin}/${test}-build")
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  if(NOT DEFINED RunCMake_TEST_OPTIONS)
+    set(RunCMake_TEST_OPTIONS "")
+  endif()
   execute_process(
     COMMAND ${CMAKE_COMMAND} "${RunCMake_TEST_SOURCE_DIR}"
               -G "${RunCMake_GENERATOR}" -DRunCMake_TEST=${test}
+              ${RunCMake_TEST_OPTIONS}
     WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
     OUTPUT_VARIABLE actual_stdout
     ERROR_VARIABLE actual_stderr