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:
parent
44cf465ff5
commit
66e0b4212f
|
@ -53,3 +53,14 @@ IF(MSYS OR MINGW)
|
||||||
SET(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
|
SET(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
|
||||||
ENDFOREACH(type)
|
ENDFOREACH(type)
|
||||||
ENDIF(MSYS OR MINGW)
|
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)
|
||||||
|
|
|
@ -944,7 +944,34 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
||||||
"This is a rule variable that tells CMake how "
|
"This is a rule variable that tells CMake how "
|
||||||
"to create a static library for the language <LANG>.",false,
|
"to create a static library for the language <LANG>.",false,
|
||||||
"Variables for Languages");
|
"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
|
cm->DefineProperty
|
||||||
("CMAKE_<LANG>_IGNORE_EXTENSIONS", cmProperty::VARIABLE,
|
("CMAKE_<LANG>_IGNORE_EXTENSIONS", cmProperty::VARIABLE,
|
||||||
"File extensions that should be ignored by the build.",
|
"File extensions that should be ignored by the build.",
|
||||||
|
|
|
@ -668,12 +668,45 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
|
||||||
// Determine whether a link script will be used.
|
// Determine whether a link script will be used.
|
||||||
bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
|
bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
|
||||||
|
|
||||||
// Construct the main link rule.
|
// For static libraries there might be archiving rules.
|
||||||
std::vector<std::string> real_link_commands;
|
std::vector<std::string> archiveCreateCommands;
|
||||||
std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
|
std::vector<std::string> archiveAppendCommands;
|
||||||
cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
|
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.
|
// Expand the rule variables.
|
||||||
|
std::vector<std::string> real_link_commands;
|
||||||
{
|
{
|
||||||
// Collect up flags to link in needed libraries.
|
// Collect up flags to link in needed libraries.
|
||||||
cmOStringStream linklibs;
|
cmOStringStream linklibs;
|
||||||
|
@ -687,7 +720,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
|
||||||
std::string buildObjs;
|
std::string buildObjs;
|
||||||
if(useLinkScript)
|
if(useLinkScript)
|
||||||
{
|
{
|
||||||
this->WriteObjectsString(buildObjs);
|
if(!useArchiveRules)
|
||||||
|
{
|
||||||
|
this->WriteObjectsString(buildObjs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -768,12 +804,64 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
|
||||||
linkLanguage, langFlags);
|
linkLanguage, langFlags);
|
||||||
}
|
}
|
||||||
vars.LanguageCompileFlags = langFlags.c_str();
|
vars.LanguageCompileFlags = langFlags.c_str();
|
||||||
// Expand placeholders in the commands.
|
|
||||||
|
// Construct the main link rule and expand placeholders.
|
||||||
this->LocalGenerator->TargetImplib = targetOutPathImport;
|
this->LocalGenerator->TargetImplib = targetOutPathImport;
|
||||||
for(std::vector<std::string>::iterator i = real_link_commands.begin();
|
if(useArchiveRules)
|
||||||
i != real_link_commands.end(); ++i)
|
|
||||||
{
|
{
|
||||||
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 = "";
|
this->LocalGenerator->TargetImplib = "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1200,10 +1200,80 @@ void
|
||||||
cmMakefileTargetGenerator
|
cmMakefileTargetGenerator
|
||||||
::WriteObjectsString(std::string& buildObjs)
|
::WriteObjectsString(std::string& buildObjs)
|
||||||
{
|
{
|
||||||
std::string object;
|
std::vector<std::string> objStrings;
|
||||||
const char* no_quoted =
|
this->WriteObjectsStrings(objStrings);
|
||||||
this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS");
|
buildObjs = objStrings[0];
|
||||||
const char* space = "";
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
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();
|
for(std::vector<std::string>::const_iterator i = this->Objects.begin();
|
||||||
i != this->Objects.end(); ++i)
|
i != this->Objects.end(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -1211,38 +1281,15 @@ cmMakefileTargetGenerator
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
buildObjs += space;
|
helper.Feed(*i);
|
||||||
space = " ";
|
|
||||||
if(no_quoted)
|
|
||||||
{
|
|
||||||
buildObjs +=
|
|
||||||
this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
|
|
||||||
cmLocalGenerator::SHELL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buildObjs +=
|
|
||||||
this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(std::vector<std::string>::const_iterator i =
|
for(std::vector<std::string>::const_iterator i =
|
||||||
this->ExternalObjects.begin();
|
this->ExternalObjects.begin();
|
||||||
i != this->ExternalObjects.end(); ++i)
|
i != this->ExternalObjects.end(); ++i)
|
||||||
{
|
{
|
||||||
buildObjs += space;
|
helper.Feed(*i);
|
||||||
space = " ";
|
|
||||||
if(no_quoted)
|
|
||||||
{
|
|
||||||
buildObjs +=
|
|
||||||
this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
|
|
||||||
cmLocalGenerator::SHELL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buildObjs +=
|
|
||||||
this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
helper.Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -107,6 +107,8 @@ protected:
|
||||||
void WriteObjectsVariable(std::string& variableName,
|
void WriteObjectsVariable(std::string& variableName,
|
||||||
std::string& variableNameExternal);
|
std::string& variableNameExternal);
|
||||||
void WriteObjectsString(std::string& buildObjs);
|
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
|
// write the driver rule to build target outputs
|
||||||
void WriteTargetDriverRule(const char* main_output, bool relink);
|
void WriteTargetDriverRule(const char* main_output, bool relink);
|
||||||
|
|
Loading…
Reference in New Issue