From 66e0b4212fbbaaf3c5aa5af6a51aa3a5af002edf Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 29 Jan 2008 20:46:25 -0500 Subject: ENH: Added build rule variables CMAKE__ARCHIVE_CREATE, CMAKE__ARCHIVE_APPEND, and CMAKE__ARCHIVE_FINISH to support creation of static archive libraries out of a large number of objects. See bug #6284. --- Modules/Platform/Windows-gcc.cmake | 11 +++ Source/cmDocumentVariables.cxx | 29 +++++++- Source/cmMakefileLibraryTargetGenerator.cxx | 106 ++++++++++++++++++++++++--- Source/cmMakefileTargetGenerator.cxx | 107 ++++++++++++++++++++-------- Source/cmMakefileTargetGenerator.h | 2 + 5 files changed, 215 insertions(+), 40 deletions(-) diff --git a/Modules/Platform/Windows-gcc.cmake b/Modules/Platform/Windows-gcc.cmake index 805b451..51857eb 100644 --- a/Modules/Platform/Windows-gcc.cmake +++ b/Modules/Platform/Windows-gcc.cmake @@ -53,3 +53,14 @@ IF(MSYS OR MINGW) SET(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic") ENDFOREACH(type) ENDIF(MSYS OR MINGW) + +# Create archiving rules to support large object file lists for static +# libraries. +IF(MSYS OR MINGW) + SET(CMAKE_C_ARCHIVE_CREATE " cr ") + SET(CMAKE_C_ARCHIVE_APPEND " r ") + SET(CMAKE_C_ARCHIVE_FINISH " ") + SET(CMAKE_CXX_ARCHIVE_CREATE ${CMAKE_C_ARCHIVE_CREATE}) + SET(CMAKE_CXX_ARCHIVE_APPEND ${CMAKE_C_ARCHIVE_APPEND}) + SET(CMAKE_CXX_ARCHIVE_FINISH ${CMAKE_C_ARCHIVE_FINISH}) +ENDIF(MSYS OR MINGW) diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 4c33014..bcc9e8c 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -944,7 +944,34 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "This is a rule variable that tells CMake how " "to create a static library for the language .",false, "Variables for Languages"); - + + cm->DefineProperty + ("CMAKE__ARCHIVE_CREATE", cmProperty::VARIABLE, + "Rule variable to create a new static archive.", + "This is a rule variable that tells CMake how to create a static " + "archive. It is used in place of CMAKE__CREATE_STATIC_LIBRARY " + "on some platforms in order to support large object counts. " + "See also CMAKE__ARCHIVE_APPEND and CMAKE__ARCHIVE_FINISH.", + false, "Variables for Languages"); + + cm->DefineProperty + ("CMAKE__ARCHIVE_APPEND", cmProperty::VARIABLE, + "Rule variable to append to a static archive.", + "This is a rule variable that tells CMake how to append to a static " + "archive. It is used in place of CMAKE__CREATE_STATIC_LIBRARY " + "on some platforms in order to support large object counts. " + "See also CMAKE__ARCHIVE_CREATE and CMAKE__ARCHIVE_FINISH.", + false, "Variables for Languages"); + + cm->DefineProperty + ("CMAKE__ARCHIVE_FINISH", cmProperty::VARIABLE, + "Rule variable to finish an existing static archive.", + "This is a rule variable that tells CMake how to finish a static " + "archive. It is used in place of CMAKE__CREATE_STATIC_LIBRARY " + "on some platforms in order to support large object counts. " + "See also CMAKE__ARCHIVE_CREATE and CMAKE__ARCHIVE_APPEND.", + false, "Variables for Languages"); + cm->DefineProperty ("CMAKE__IGNORE_EXTENSIONS", cmProperty::VARIABLE, "File extensions that should be ignored by the build.", diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 9ab4649..a81cfd6 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -668,12 +668,45 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules // Determine whether a link script will be used. bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); - // Construct the main link rule. - std::vector real_link_commands; - std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); - cmSystemTools::ExpandListArgument(linkRule, real_link_commands); + // For static libraries there might be archiving rules. + std::vector archiveCreateCommands; + std::vector archiveAppendCommands; + std::vector archiveFinishCommands; + std::string::size_type archiveCommandLimit = std::string::npos; + if(useLinkScript && this->Target->GetType() == cmTarget::STATIC_LIBRARY) + { + std::string arCreateVar = "CMAKE_"; + arCreateVar += linkLanguage; + arCreateVar += "_ARCHIVE_CREATE"; + if(const char* rule = this->Makefile->GetDefinition(arCreateVar.c_str())) + { + cmSystemTools::ExpandListArgument(rule, archiveCreateCommands); + } + std::string arAppendVar = "CMAKE_"; + arAppendVar += linkLanguage; + arAppendVar += "_ARCHIVE_APPEND"; + if(const char* rule = this->Makefile->GetDefinition(arAppendVar.c_str())) + { + cmSystemTools::ExpandListArgument(rule, archiveAppendCommands); + } + std::string arFinishVar = "CMAKE_"; + arFinishVar += linkLanguage; + arFinishVar += "_ARCHIVE_FINISH"; + if(const char* rule = this->Makefile->GetDefinition(arFinishVar.c_str())) + { + cmSystemTools::ExpandListArgument(rule, archiveFinishCommands); + } + + // 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. + archiveCommandLimit = 30000; + } + bool useArchiveRules = + !archiveCreateCommands.empty() && !archiveAppendCommands.empty(); // Expand the rule variables. + std::vector real_link_commands; { // Collect up flags to link in needed libraries. cmOStringStream linklibs; @@ -687,7 +720,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string buildObjs; if(useLinkScript) { - this->WriteObjectsString(buildObjs); + if(!useArchiveRules) + { + this->WriteObjectsString(buildObjs); + } } else { @@ -768,12 +804,64 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules linkLanguage, langFlags); } vars.LanguageCompileFlags = langFlags.c_str(); - // Expand placeholders in the commands. + + // Construct the main link rule and expand placeholders. this->LocalGenerator->TargetImplib = targetOutPathImport; - for(std::vector::iterator i = real_link_commands.begin(); - i != real_link_commands.end(); ++i) + if(useArchiveRules) + { + // Construct the individual object list strings. + std::vector object_strings; + this->WriteObjectsStrings(object_strings, archiveCommandLimit); + + // Create the archive with the first set of objects. + std::vector::iterator osi = object_strings.begin(); { - this->LocalGenerator->ExpandRuleVariables(*i, vars); + vars.Objects = osi->c_str(); + for(std::vector::const_iterator + i = archiveCreateCommands.begin(); + i != archiveCreateCommands.end(); ++i) + { + std::string cmd = *i; + this->LocalGenerator->ExpandRuleVariables(cmd, vars); + real_link_commands.push_back(cmd); + } + } + // Append to the archive with the other object sets. + for(++osi; osi != object_strings.end(); ++osi) + { + vars.Objects = osi->c_str(); + for(std::vector::const_iterator + i = archiveAppendCommands.begin(); + i != archiveAppendCommands.end(); ++i) + { + std::string cmd = *i; + this->LocalGenerator->ExpandRuleVariables(cmd, vars); + real_link_commands.push_back(cmd); + } + } + // Finish the archive. + vars.Objects = ""; + for(std::vector::const_iterator + i = archiveFinishCommands.begin(); + i != archiveFinishCommands.end(); ++i) + { + std::string cmd = *i; + this->LocalGenerator->ExpandRuleVariables(cmd, vars); + real_link_commands.push_back(cmd); + } + } + else + { + // Get the set of commands. + std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); + cmSystemTools::ExpandListArgument(linkRule, real_link_commands); + + // Expand placeholders. + for(std::vector::iterator i = real_link_commands.begin(); + i != real_link_commands.end(); ++i) + { + this->LocalGenerator->ExpandRuleVariables(*i, vars); + } } this->LocalGenerator->TargetImplib = ""; } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0c550ef..3e8084c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1200,49 +1200,96 @@ void cmMakefileTargetGenerator ::WriteObjectsString(std::string& buildObjs) { - std::string object; - const char* no_quoted = - this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS"); - const char* space = ""; - for(std::vector::const_iterator i = this->Objects.begin(); - i != this->Objects.end(); ++i) + std::vector objStrings; + this->WriteObjectsStrings(objStrings); + buildObjs = objStrings[0]; +} + +//---------------------------------------------------------------------------- +class cmMakefileTargetGeneratorObjectStrings +{ +public: + cmMakefileTargetGeneratorObjectStrings(std::vector& strings, + cmMakefile* mf, + cmLocalUnixMakefileGenerator3* lg, + std::string::size_type limit): + Strings(strings), Makefile(mf), LocalGenerator(lg), LengthLimit(limit) { - if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() ) + this->NoQuotes = mf->IsOn("CMAKE_NO_QUOTED_OBJECTS"); + this->Space = ""; + } + void Feed(std::string const& obj) + { + // Construct the name of the next object. + if(this->NoQuotes) { - continue; + this->NextObject = + this->LocalGenerator->Convert(obj.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); } - buildObjs += space; - space = " "; - if(no_quoted) + else { - buildObjs += - this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); + this->NextObject = + this->LocalGenerator->ConvertToQuotedOutputPath(obj.c_str()); } - else + + // Roll over to next string if the limit will be exceeded. + if(this->LengthLimit != std::string::npos && + (this->CurrentString.length() + 1 + this->NextObject.length() + > this->LengthLimit)) { - buildObjs += - this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); + this->Strings.push_back(this->CurrentString); + this->CurrentString = ""; + this->Space = ""; } + + // Separate from previous object. + this->CurrentString += this->Space; + this->Space = " "; + + // Append this object. + this->CurrentString += this->NextObject; + } + void Done() + { + this->Strings.push_back(this->CurrentString); + } +private: + std::vector& Strings; + cmMakefile* Makefile; + cmLocalUnixMakefileGenerator3* LocalGenerator; + std::string::size_type LengthLimit; + bool NoQuotes; + std::string CurrentString; + std::string NextObject; + const char* Space; +}; + +//---------------------------------------------------------------------------- +void +cmMakefileTargetGenerator +::WriteObjectsStrings(std::vector& objStrings, + std::string::size_type limit) +{ + cmMakefileTargetGeneratorObjectStrings + helper(objStrings, this->Makefile, this->LocalGenerator, limit); + for(std::vector::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) + { + if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() ) + { + continue; + } + helper.Feed(*i); } for(std::vector::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - buildObjs += space; - space = " "; - if(no_quoted) - { - buildObjs += - this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - } - else - { - buildObjs += - this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); - } + helper.Feed(*i); } + helper.Done(); } //---------------------------------------------------------------------------- diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index e997a0a..f645eab 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -107,6 +107,8 @@ protected: void WriteObjectsVariable(std::string& variableName, std::string& variableNameExternal); void WriteObjectsString(std::string& buildObjs); + void WriteObjectsStrings(std::vector& objStrings, + std::string::size_type limit = std::string::npos); // write the driver rule to build target outputs void WriteTargetDriverRule(const char* main_output, bool relink); -- cgit v0.12