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")
|
||||
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)
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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 = "";
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue