ENH: Added build rule variables CMAKE_<LANG>_ARCHIVE_CREATE, CMAKE_<LANG>_ARCHIVE_APPEND, and CMAKE_<LANG>_ARCHIVE_FINISH to support creation of static archive libraries out of a large number of objects. See bug #6284.

This commit is contained in:
Brad King 2008-01-29 20:46:25 -05:00
parent 44cf465ff5
commit 66e0b4212f
5 changed files with 215 additions and 40 deletions

View File

@ -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 "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
SET(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> r <TARGET> <LINK_FLAGS> <OBJECTS>")
SET(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
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)

View File

@ -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 <LANG>.",false,
"Variables for Languages");
cm->DefineProperty
("CMAKE_<LANG>_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_<LANG>_CREATE_STATIC_LIBRARY "
"on some platforms in order to support large object counts. "
"See also CMAKE_<LANG>_ARCHIVE_APPEND and CMAKE_<LANG>_ARCHIVE_FINISH.",
false, "Variables for Languages");
cm->DefineProperty
("CMAKE_<LANG>_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_<LANG>_CREATE_STATIC_LIBRARY "
"on some platforms in order to support large object counts. "
"See also CMAKE_<LANG>_ARCHIVE_CREATE and CMAKE_<LANG>_ARCHIVE_FINISH.",
false, "Variables for Languages");
cm->DefineProperty
("CMAKE_<LANG>_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_<LANG>_CREATE_STATIC_LIBRARY "
"on some platforms in order to support large object counts. "
"See also CMAKE_<LANG>_ARCHIVE_CREATE and CMAKE_<LANG>_ARCHIVE_APPEND.",
false, "Variables for Languages");
cm->DefineProperty
("CMAKE_<LANG>_IGNORE_EXTENSIONS", cmProperty::VARIABLE,
"File extensions that should be ignored by the build.",

View File

@ -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<std::string> 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<std::string> archiveCreateCommands;
std::vector<std::string> archiveAppendCommands;
std::vector<std::string> 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<std::string> 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<std::string>::iterator i = real_link_commands.begin();
i != real_link_commands.end(); ++i)
if(useArchiveRules)
{
this->LocalGenerator->ExpandRuleVariables(*i, vars);
// Construct the individual object list strings.
std::vector<std::string> object_strings;
this->WriteObjectsStrings(object_strings, archiveCommandLimit);
// Create the archive with the first set of objects.
std::vector<std::string>::iterator osi = object_strings.begin();
{
vars.Objects = osi->c_str();
for(std::vector<std::string>::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<std::string>::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<std::string>::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<std::string>::iterator i = real_link_commands.begin();
i != real_link_commands.end(); ++i)
{
this->LocalGenerator->ExpandRuleVariables(*i, vars);
}
}
this->LocalGenerator->TargetImplib = "";
}

View File

@ -1200,10 +1200,80 @@ void
cmMakefileTargetGenerator
::WriteObjectsString(std::string& buildObjs)
{
std::string object;
const char* no_quoted =
this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS");
const char* space = "";
std::vector<std::string> objStrings;
this->WriteObjectsStrings(objStrings);
buildObjs = objStrings[0];
}
//----------------------------------------------------------------------------
class cmMakefileTargetGeneratorObjectStrings
{
public:
cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings,
cmMakefile* mf,
cmLocalUnixMakefileGenerator3* lg,
std::string::size_type limit):
Strings(strings), Makefile(mf), LocalGenerator(lg), LengthLimit(limit)
{
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)
{
this->NextObject =
this->LocalGenerator->Convert(obj.c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::SHELL);
}
else
{
this->NextObject =
this->LocalGenerator->ConvertToQuotedOutputPath(obj.c_str());
}
// 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))
{
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<std::string>& 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<std::string>& objStrings,
std::string::size_type limit)
{
cmMakefileTargetGeneratorObjectStrings
helper(objStrings, this->Makefile, this->LocalGenerator, limit);
for(std::vector<std::string>::const_iterator i = this->Objects.begin();
i != this->Objects.end(); ++i)
{
@ -1211,38 +1281,15 @@ cmMakefileTargetGenerator
{
continue;
}
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);
}
for(std::vector<std::string>::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();
}
//----------------------------------------------------------------------------

View File

@ -107,6 +107,8 @@ protected:
void WriteObjectsVariable(std::string& variableName,
std::string& variableNameExternal);
void WriteObjectsString(std::string& buildObjs);
void WriteObjectsStrings(std::vector<std::string>& 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);