Be able to create a response file for other generators too

When building an application for Android on Windows it is possible that
the command line will be too long when doing the link step. So the code
for generating a response file is moved to MakefileGenerator so it can
be used by the other generators easily. The same variables used by
MinGW can be used elsewhere then.

Fixes: QTBUG-71940
Change-Id: I6c331d12e9541a90a4a95e0154d0ea1c056489bc
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Andy Shaw 2019-11-04 15:54:24 +01:00
parent 4ada4f283e
commit b274f656b8
6 changed files with 87 additions and 58 deletions

View File

@ -70,6 +70,11 @@ QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined
QMAKE_LFLAGS_RPATH = -Wl,-rpath=
QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link=
equals(QMAKE_HOST.os, Windows) {
QMAKE_LINK_OBJECT_MAX = 10
QMAKE_LINK_OBJECT_SCRIPT = object_script
}
QMAKE_LIBS_X11 =
QMAKE_LIBS_THREAD =
QMAKE_LIBS_OPENGL =

View File

@ -3455,4 +3455,28 @@ ProKey MakefileGenerator::fullTargetVariable() const
return "TARGET";
}
void MakefileGenerator::createResponseFile(const QString &fileName, const ProStringList &objList)
{
QString filePath = Option::output_dir + QDir::separator() + fileName;
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream t(&file);
for (ProStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
QString path = (*it).toQString();
// In response files, whitespace and special characters are
// escaped with a backslash; backslashes themselves can either
// be escaped into double backslashes, or, as this is a list of
// path names, converted to forward slashes.
path.replace(QLatin1Char('\\'), QLatin1String("/"))
.replace(QLatin1Char(' '), QLatin1String("\\ "))
.replace(QLatin1Char('\t'), QLatin1String("\\\t"))
.replace(QLatin1Char('"'), QLatin1String("\\\""))
.replace(QLatin1Char('\''), QLatin1String("\\'"));
t << path << Qt::endl;
}
t.flush();
file.close();
}
}
QT_END_NAMESPACE

View File

@ -257,6 +257,7 @@ protected:
const QStringRef &fixedBase, int slashOff);
bool processPrlFileCore(QString &origFile, const QStringRef &origName,
const QString &fixedFile);
void createResponseFile(const QString &fileName, const ProStringList &objList);
public:
QMakeProject *projectFile() const;

View File

@ -58,7 +58,7 @@ protected:
void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags) override;
void writeMakeParts(QTextStream &);
bool writeMakefile(QTextStream &) override;
std::pair<bool, QString> writeObjectsPart(QTextStream &, bool do_incremental);
private:
void init2();
ProStringList libdirToFlags(const ProKey &key);

View File

@ -246,38 +246,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << "####### Files\n\n";
// This is used by the dist target.
t << "SOURCES = " << fileVarList("SOURCES") << ' ' << fileVarList("GENERATED_SOURCES") << Qt::endl;
if(do_incremental) {
const ProStringList &objs = project->values("OBJECTS");
const ProStringList &incrs = project->values("QMAKE_INCREMENTAL");
ProStringList incrs_out;
t << "OBJECTS = ";
for (ProStringList::ConstIterator objit = objs.begin(); objit != objs.end(); ++objit) {
bool increment = false;
for (ProStringList::ConstIterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
if ((*objit).toQString().indexOf(QRegExp((*incrit).toQString(), Qt::CaseSensitive,
QRegExp::Wildcard)) != -1) {
increment = true;
incrs_out.append((*objit));
break;
}
}
if(!increment)
t << "\\\n\t\t" << (*objit);
}
if(incrs_out.count() == objs.count()) { //we just switched places, no real incrementals to be done!
t << escapeFilePaths(incrs_out).join(QString(" \\\n\t\t")) << Qt::endl;
} else if(!incrs_out.count()) {
t << Qt::endl;
} else {
src_incremental = true;
t << Qt::endl;
t << "INCREMENTAL_OBJECTS = "
<< escapeFilePaths(incrs_out).join(QString(" \\\n\t\t")) << Qt::endl;
}
} else {
// Used all over the place in both deps and commands.
t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << Qt::endl;
}
auto objectParts = writeObjectsPart(t, do_incremental);
src_incremental = objectParts.first;
if(do_incremental && !src_incremental)
do_incremental = false;
t << "DIST = " << valList(fileFixify(project->values("DISTFILES").toQStringList())) << " "
@ -513,7 +483,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << mkdir_p_asstring(destdir) << "\n\t";
if (!project->isEmpty("QMAKE_PRE_LINK"))
t << var("QMAKE_PRE_LINK") << "\n\t";
t << "$(LINK) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)";
t << "$(LINK) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(TARGET) "
<< objectParts.second << " $(OBJCOMP) $(LIBS)";
if (!project->isEmpty("QMAKE_POST_LINK"))
t << "\n\t" << var("QMAKE_POST_LINK");
}
@ -1545,4 +1516,56 @@ UnixMakefileGenerator::writeLibtoolFile()
"libdir='" << Option::fixPathToTargetOS(install_dir.toQString(), false) << "'\n";
}
std::pair<bool, QString> UnixMakefileGenerator::writeObjectsPart(QTextStream &t, bool do_incremental)
{
bool src_incremental = false;
QString objectsLinkLine;
const ProStringList &objs = project->values("OBJECTS");
if (do_incremental) {
const ProStringList &incrs = project->values("QMAKE_INCREMENTAL");
ProStringList incrs_out;
t << "OBJECTS = ";
for (ProStringList::ConstIterator objit = objs.begin(); objit != objs.end(); ++objit) {
bool increment = false;
for (ProStringList::ConstIterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
if ((*objit).toQString().indexOf(QRegExp((*incrit).toQString(), Qt::CaseSensitive,
QRegExp::Wildcard)) != -1) {
increment = true;
incrs_out.append((*objit));
break;
}
}
if (!increment)
t << "\\\n\t\t" << (*objit);
}
if (incrs_out.count() == objs.count()) { //we just switched places, no real incrementals to be done!
t << escapeFilePaths(incrs_out).join(QString(" \\\n\t\t")) << endl;
} else if (!incrs_out.count()) {
t << endl;
} else {
src_incremental = true;
t << endl;
t << "INCREMENTAL_OBJECTS = "
<< escapeFilePaths(incrs_out).join(QString(" \\\n\t\t")) << endl;
}
} else {
const ProString &objMax = project->first("QMAKE_LINK_OBJECT_MAX");
// Used all over the place in both deps and commands.
if (objMax.isEmpty() || project->values("OBJECTS").count() < objMax.toInt()) {
objectsLinkLine = "$(OBJECTS)";
} else {
QString ld_response_file = fileVar("OBJECTS_DIR");
ld_response_file += var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
if (!var("BUILD_NAME").isEmpty())
ld_response_file += "." + var("BUILD_NAME");
if (!var("MAKEFILE").isEmpty())
ld_response_file += "." + var("MAKEFILE");
createResponseFile(ld_response_file, objs);
objectsLinkLine = "@" + escapeFilePath(ld_response_file);
}
t << "OBJECTS = " << valList(escapeDependencyPaths(objs)) << endl;
}
return std::make_pair(src_incremental, objectsLinkLine);
}
QT_END_NAMESPACE

View File

@ -115,30 +115,6 @@ QString MingwMakefileGenerator::installRoot() const
return QStringLiteral("$(INSTALL_ROOT:@msyshack@%=%)");
}
static void createResponseFile(const QString &fileName, const ProStringList &objList)
{
QString filePath = Option::output_dir + QDir::separator() + fileName;
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream t(&file);
for (ProStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
QString path = (*it).toQString();
// In response files, whitespace and special characters are
// escaped with a backslash; backslashes themselves can either
// be escaped into double backslashes, or, as this is a list of
// path names, converted to forward slashes.
path.replace(QLatin1Char('\\'), QLatin1String("/"))
.replace(QLatin1Char(' '), QLatin1String("\\ "))
.replace(QLatin1Char('\t'), QLatin1String("\\\t"))
.replace(QLatin1Char('"'), QLatin1String("\\\""))
.replace(QLatin1Char('\''), QLatin1String("\\'"));
t << path << Qt::endl;
}
t.flush();
file.close();
}
}
void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
{
writeStandardParts(t);