Browse Source

ENH: Handle large object file lists on some platforms

  - Use a response file when enabled by
    CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_OBJECTS
  - Enable for C and CXX with cl (MSVC)
  - Enable for Fortran with ifort (Intel Fortran)
Brad King 17 years ago
parent
commit
dfe2ea6406

+ 4 - 2
Modules/Platform/Windows-ifort.cmake

@@ -9,8 +9,10 @@ ENDIF(CMAKE_VERBOSE_MAKEFILE)
 
 SET(CMAKE_Fortran_MODDIR_FLAG "-module:")
 
+SET(CMAKE_Fortran_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+
 SET(CMAKE_Fortran_CREATE_SHARED_LIBRARY 
- "link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE}  /out:<TARGET> /dll  <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+ "link ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE}  /out:<TARGET> /dll  <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
 
 SET(CMAKE_Fortran_CREATE_SHARED_MODULE ${CMAKE_Fortran_CREATE_SHARED_LIBRARY})
 
@@ -24,7 +26,7 @@ SET(CMAKE_Fortran_COMPILE_OBJECT
 SET(CMAKE_COMPILE_RESOURCE "rc <FLAGS> /fo<OBJECT> <SOURCE>")
 
 SET(CMAKE_Fortran_LINK_EXECUTABLE
-    "<CMAKE_Fortran_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> <OBJECTS> /Fe<TARGET> -link <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+    "<CMAKE_Fortran_COMPILER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} <FLAGS> /Fe<TARGET> -link <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
 
 SET(CMAKE_CREATE_WIN32_EXE /subsystem:windows)
 SET(CMAKE_CREATE_CONSOLE_EXE /subsystem:console)

+ 5 - 4
Modules/Platform/cl.cmake

@@ -17,7 +17,7 @@ ELSE(CMAKE_VERBOSE_MAKEFILE)
 ENDIF(CMAKE_VERBOSE_MAKEFILE)
 # create a shared C++ library
 SET(CMAKE_CXX_CREATE_SHARED_LIBRARY
-  "<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+  "<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
 SET(CMAKE_CXX_CREATE_SHARED_MODULE ${CMAKE_CXX_CREATE_SHARED_LIBRARY})
 
 # create a C shared library
@@ -40,12 +40,13 @@ SET(CMAKE_CXX_COMPILE_OBJECT
 SET(CMAKE_C_COMPILE_OBJECT
     "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
 
-
+SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
 SET(CMAKE_C_LINK_EXECUTABLE
-    "<CMAKE_C_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> <OBJECTS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+    "<CMAKE_C_COMPILER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} <FLAGS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
 
+SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
 SET(CMAKE_CXX_LINK_EXECUTABLE
-    "<CMAKE_CXX_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> <OBJECTS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+    "<CMAKE_CXX_COMPILER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} <FLAGS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
 
 SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE
     "<CMAKE_C_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> -E <SOURCE>${CMAKE_END_TEMP_FILE}")

+ 2 - 0
Source/cmDocumentVariables.cxx

@@ -1059,6 +1059,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
                      cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_<LANG>_STANDARD_LIBRARIES_INIT",
                      cmProperty::VARIABLE,0,0);
+  cm->DefineProperty("CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_OBJECTS",
+                     cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_EXECUTABLE_SUFFIX_<LANG>",
                      cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_EXE_LINK_DYNAMIC_<LANG>_FLAGS",

+ 24 - 1
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -328,6 +328,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
       }
     }
 
+  // Select whether to use a response file for objects.
+  bool useResponseFile = false;
+  {
+  std::string responseVar = "CMAKE_";
+  responseVar += linkLanguage;
+  responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
+  if(this->Makefile->IsOn(responseVar.c_str()))
+    {
+    useResponseFile = true;
+    }
+  }
+
   // Expand the rule variables.
   {
   // Set path conversion for link script shells.
@@ -343,7 +355,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   std::string variableNameExternal;
   this->WriteObjectsVariable(variableName, variableNameExternal);
   std::string buildObjs;
-  if(useLinkScript)
+  if(useResponseFile)
+    {
+    std::string objects;
+    this->WriteObjectsString(objects);
+    std::string objects_rsp =
+      this->CreateResponseFile("objects.rsp", objects, depends);
+    buildObjs = "@";
+    buildObjs += this->Convert(objects_rsp.c_str(),
+                               cmLocalGenerator::NONE,
+                               cmLocalGenerator::SHELL);
+    }
+  else if(useLinkScript)
     {
     this->WriteObjectsString(buildObjs);
     }

+ 27 - 1
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -567,6 +567,18 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
   // Determine whether a link script will be used.
   bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
 
+  // Select whether to use a response file for objects.
+  bool useResponseFile = false;
+  {
+  std::string responseVar = "CMAKE_";
+  responseVar += linkLanguage;
+  responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
+  if(this->Makefile->IsOn(responseVar.c_str()))
+    {
+    useResponseFile = true;
+    }
+  }
+
   // For static libraries there might be archiving rules.
   std::vector<std::string> archiveCreateCommands;
   std::vector<std::string> archiveAppendCommands;
@@ -605,6 +617,9 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
     // Archiving rules are always run with a link script.
     useLinkScript = true;
 
+    // Archiving rules never use a response file.
+    useResponseFile = false;
+
     // Limit the length of individual object lists to less than the
     // 32K command line length limit on Windows.  We could make this a
     // platform file variable but this should work everywhere.
@@ -631,7 +646,18 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
   std::string variableNameExternal;
   this->WriteObjectsVariable(variableName, variableNameExternal);
   std::string buildObjs;
-  if(useLinkScript)
+  if(useResponseFile)
+    {
+    std::string objects;
+    this->WriteObjectsString(objects);
+    std::string objects_rsp =
+      this->CreateResponseFile("objects.rsp", objects, depends);
+    buildObjs = "@";
+    buildObjs += this->Convert(objects_rsp.c_str(),
+                               cmLocalGenerator::NONE,
+                               cmLocalGenerator::SHELL);
+    }
+  else if(useLinkScript)
     {
     if(!useArchiveRules)
       {

+ 24 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -1583,6 +1583,30 @@ cmMakefileTargetGenerator
   makefile_depends.push_back(linkScriptName);
 }
 
+//----------------------------------------------------------------------------
+std::string
+cmMakefileTargetGenerator
+::CreateResponseFile(const char* name, std::string const& options,
+                     std::vector<std::string>& makefile_depends)
+{
+  // Create the response file.
+  std::string responseFileNameFull = this->TargetBuildDirectoryFull;
+  responseFileNameFull += "/";
+  responseFileNameFull += name;
+  cmGeneratedFileStream responseStream(responseFileNameFull.c_str());
+  responseStream << options << "\n";
+
+  // Add a dependency so the target will rebuild when the set of
+  // objects changes.
+  makefile_depends.push_back(responseFileNameFull);
+
+  // Construct the name to be used on the command line.
+  std::string responseFileName = this->TargetBuildDirectory;
+  responseFileName += "/";
+  responseFileName += name;
+  return responseFileName;
+}
+
 //----------------------------------------------------------------------------
 const char* cmMakefileTargetGenerator::GetFortranModuleDirectory()
 {

+ 7 - 0
Source/cmMakefileTargetGenerator.h

@@ -137,6 +137,13 @@ protected:
                         std::vector<std::string>& makefile_commands,
                         std::vector<std::string>& makefile_depends);
 
+  /** Create a response file with the given set of options.  Returns
+      the relative path from the target build working directory to the
+      response file name.  */
+  std::string CreateResponseFile(const char* name,
+                                 std::string const& options,
+                                 std::vector<std::string>& makefile_depends);
+
   virtual void CloseFileStreams();
   void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
                             std::string& linkFlags);