diff options
Diffstat (limited to 'qmake/generators/makefile.cpp')
-rw-r--r-- | qmake/generators/makefile.cpp | 345 |
1 files changed, 216 insertions, 129 deletions
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 0fbfd0c9ef..482ef2e269 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the qmake application of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "makefile.h" #include "option.h" @@ -41,7 +16,7 @@ #include <qdebug.h> #include <qbuffer.h> #include <qdatetime.h> -#include <qregexp.h> +#include <qtversion.h> #if defined(Q_OS_UNIX) #include <unistd.h> @@ -64,7 +39,7 @@ using namespace QMakeInternal; bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const { int argv0 = -1; - for(int i = 0; i < cmdline.count(); ++i) { + for(int i = 0; i < cmdline.size(); ++i) { if(!cmdline.at(i).contains('=')) { argv0 = i; break; @@ -138,7 +113,7 @@ MakefileGenerator::initOutPaths() if(!fi.makeAbsolute()) { QString cache_r = fi.path(), pwd = Option::output_dir; if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) { - pwd = root + pwd.mid(cache_r.length()); + pwd = root + pwd.mid(cache_r.size()); if(exists(pwd)) v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", ProStringList(pwd)); } @@ -174,6 +149,9 @@ MakefileGenerator::initOutPaths() if (noIO() || (project->first("TEMPLATE") == "subdirs")) continue; + if (inhibitMakeDirOutPath(dkey)) + continue; + QString path = project->first(dkey).toQString(); //not to be changed any further path = fileFixify(path, FileFixifyBackwards); debug_msg(3, "Fixed output_dir %s (%s) into %s", dirs[x], @@ -217,6 +195,18 @@ MakefileGenerator::initOutPaths() } } +/* + * For the given directory path, return true if MakefileGenerator::initOutPaths() should inhibit the + * creation of the directory. Overload this in subclasses. + */ +bool +MakefileGenerator::inhibitMakeDirOutPath(const ProKey &path) const +{ + Q_UNUSED(path); + return false; +} + + QMakeProject *MakefileGenerator::projectFile() const { @@ -248,7 +238,7 @@ MakefileGenerator::findFilesInVPATH(ProStringList l, uchar flags, const QString { ProStringList vpath; const ProValueMap &v = project->variables(); - for(int val_it = 0; val_it < l.count(); ) { + for(int val_it = 0; val_it < l.size(); ) { bool remove_file = false; ProString &val = l[val_it]; if(!val.isEmpty()) { @@ -298,23 +288,23 @@ MakefileGenerator::findFilesInVPATH(ProStringList l, uchar flags, const QString real_dir = dir; if(!(flags & VPATH_NoFixify)) real_dir = fileFixify(real_dir, FileFixifyBackwards) + '/'; - regex.remove(0, dir.length()); + regex.remove(0, dir.size()); } if(real_dir.isEmpty() || exists(real_dir)) { QStringList files = QDir(real_dir).entryList(QStringList(regex), QDir::NoDotAndDotDot | QDir::AllEntries); if(files.isEmpty()) { - debug_msg(1, "%s:%d Failure to find %s in vpath (%s)", - __FILE__, __LINE__, val.toLatin1().constData(), + debug_msg(1, "makefile.cpp:%d Failure to find %s in vpath (%s)", + __LINE__, val.toLatin1().constData(), vpath.join(QString("::")).toLatin1().constData()); - if(flags & VPATH_RemoveMissingFiles) + if (flags & VPATH_RemoveMissingFiles) remove_file = true; - else if(flags & VPATH_WarnMissingFiles) + if (flags & VPATH_WarnMissingFiles) warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); } else { l.removeAt(val_it); QString a; - for(int i = (int)files.count()-1; i >= 0; i--) { + for(int i = (int)files.size()-1; i >= 0; i--) { a = real_dir + files[i]; if(!(flags & VPATH_NoFixify)) a = fileFixify(a); @@ -322,12 +312,12 @@ MakefileGenerator::findFilesInVPATH(ProStringList l, uchar flags, const QString } } } else { - debug_msg(1, "%s:%d Cannot match %s%s, as %s does not exist.", - __FILE__, __LINE__, real_dir.toLatin1().constData(), + debug_msg(1, "makefile.cpp:%d Cannot match %s%s, as %s does not exist.", + __LINE__, real_dir.toLatin1().constData(), regex.toLatin1().constData(), real_dir.toLatin1().constData()); - if(flags & VPATH_RemoveMissingFiles) + if (flags & VPATH_RemoveMissingFiles) remove_file = true; - else if(flags & VPATH_WarnMissingFiles) + if (flags & VPATH_WarnMissingFiles) warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); } } @@ -348,9 +338,14 @@ MakefileGenerator::initCompiler(const MakefileGenerator::Compiler &comp) // find all the relevant file inputs if(!init_compiler_already.contains(comp.variable_in)) { init_compiler_already.insert(comp.variable_in, true); - if(!noIO()) - l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ? - VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_" + comp.variable_in); + if(!noIO()) { + uchar flags = 0; + if (comp.flags & Compiler::CompilerRemoveNoExist) + flags |= VPATH_RemoveMissingFiles; + if (comp.flags & Compiler::CompilerWarnNoExist) + flags |= VPATH_WarnMissingFiles; + l = findFilesInVPATH(l, flags, "VPATH_" + comp.variable_in); + } } } @@ -478,12 +473,12 @@ MakefileGenerator::init() continue; } const ProStringList &tinn = v[innkey], &toutn = v[outnkey]; - if (tinn.length() != 1) { + if (tinn.size() != 1) { warn_msg(WarnLogic, "Substitute '%s.input' does not have exactly one value", sub.toLatin1().constData()); continue; } - if (toutn.length() != 1) { + if (toutn.size() != 1) { warn_msg(WarnLogic, "Substitute '%s.output' does not have exactly one value", sub.toLatin1().constData()); continue; @@ -501,7 +496,7 @@ MakefileGenerator::init() inn.toLatin1().constData()); continue; } - outn = fileFixify(inn.left(inn.length() - 3), FileFixifyBackwards); + outn = fileFixify(inn.left(inn.size() - 3), FileFixifyBackwards); } const ProKey confign(sub + ".CONFIG"); @@ -522,7 +517,7 @@ MakefileGenerator::init() QString line = QString::fromLatin1(in.readLine()); if (line.startsWith("!!IF ")) { if (state.isEmpty() || state.top() == IN_CONDITION) { - QString test = line.mid(5, line.length()-(5+1)); + QString test = line.mid(5, line.size()-(5+1)); if (project->test(test, inn, count)) state.push(IN_CONDITION); else @@ -535,7 +530,7 @@ MakefileGenerator::init() warn_msg(WarnLogic, "(%s:%d): Unexpected else condition", in.fileName().toLatin1().constData(), count); } else if (state.top() == PENDING_CONDITION) { - QString test = line.mid(7, line.length()-(7+1)); + QString test = line.mid(7, line.size()-(7+1)); if (project->test(test, inn, count)) { state.pop(); state.push(IN_CONDITION); @@ -602,7 +597,7 @@ MakefileGenerator::init() int x; //build up a list of compilers - QVector<Compiler> compilers; + QList<Compiler> compilers; { const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", nullptr }; for(x = 0; builtins[x]; ++x) { @@ -623,6 +618,10 @@ MakefileGenerator::init() const ProStringList &config = v[ProKey(*it + ".CONFIG")]; if (config.indexOf("ignore_no_exist") != -1) compiler.flags |= Compiler::CompilerRemoveNoExist; + else + compiler.flags |= Compiler::CompilerWarnNoExist; + if (config.indexOf("remove_no_exist") != -1) + compiler.flags |= Compiler::CompilerRemoveNoExist; if (config.indexOf("no_dependencies") != -1) compiler.flags |= Compiler::CompilerNoCheckDeps; if (config.indexOf("add_inputs_as_makefile_deps") != -1) @@ -644,12 +643,12 @@ MakefileGenerator::init() } { //do the path fixifying ProStringList paths; - for(x = 0; x < compilers.count(); ++x) { + for(x = 0; x < compilers.size(); ++x) { if(!paths.contains(compilers.at(x).variable_in)) paths << compilers.at(x).variable_in; } paths << "INCLUDEPATH" << "QMAKE_INTERNAL_INCLUDED_FILES" << "PRECOMPILED_HEADER"; - for(int y = 0; y < paths.count(); y++) { + for(int y = 0; y < paths.size(); y++) { ProStringList &l = v[paths[y].toKey()]; for (ProStringList::Iterator it = l.begin(); it != l.end(); ++it) { if((*it).isEmpty()) @@ -663,7 +662,7 @@ MakefileGenerator::init() if(noIO() || !doDepends() || project->isActiveConfig("GNUmake")) QMakeSourceFileInfo::setDependencyMode(QMakeSourceFileInfo::NonRecursive); - for(x = 0; x < compilers.count(); ++x) + for(x = 0; x < compilers.size(); ++x) initCompiler(compilers.at(x)); //merge actual compiler outputs into their variable_out. This is done last so that @@ -765,7 +764,7 @@ MakefileGenerator::init() ProStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"]; if(project->isActiveConfig("depend_includepath")) incDirs += v["INCLUDEPATH"]; - QVector<QMakeLocalFileName> deplist; + QList<QMakeLocalFileName> deplist; deplist.reserve(incDirs.size()); for (ProStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it) deplist.append(QMakeLocalFileName((*it).toQString())); @@ -774,7 +773,7 @@ MakefileGenerator::init() incDirs.join(QString(" :: ")).toLatin1().constData()); //add to dependency engine - for(x = 0; x < compilers.count(); ++x) { + for(x = 0; x < compilers.size(); ++x) { const MakefileGenerator::Compiler &comp = compilers.at(x); if(!(comp.flags & Compiler::CompilerNoCheckDeps)) { const ProKey ikey(comp.variable_in); @@ -830,14 +829,14 @@ MakefileGenerator::init() QString dir, regex = Option::normalizePath(dep); if (regex.lastIndexOf('/') != -1) { dir = regex.left(regex.lastIndexOf('/') + 1); - regex.remove(0, dir.length()); + regex.remove(0, dir.size()); } QStringList files = QDir(dir).entryList(QStringList(regex)); if(files.isEmpty()) { warn_msg(WarnLogic, "Dependency for [%s]: Not found %s", (*file_it).toLatin1().constData(), dep.toLatin1().constData()); } else { - for(int i = 0; i < files.count(); i++) + for(int i = 0; i < files.size(); i++) out_deps.append(dir + files[i]); } } @@ -941,9 +940,16 @@ MakefileGenerator::filterIncludedFiles(const char *var) auto isIncluded = [this](const ProString &input) { return QMakeSourceFileInfo::included(input.toQString()) > 0; }; - inputs.erase(std::remove_if(inputs.begin(), inputs.end(), - isIncluded), - inputs.end()); + inputs.removeIf(isIncluded); +} + +void MakefileGenerator::processSources() +{ + if (project->isActiveConfig("compile_included_sources")) + return; + + filterIncludedFiles("SOURCES"); + filterIncludedFiles("GENERATED_SOURCES"); } static QString @@ -1034,7 +1040,7 @@ MakefileGenerator::writeProjectMakefile() //install t << "install: "; - for (SubTarget *s : qAsConst(targets)) + for (SubTarget *s : std::as_const(targets)) t << s->target << '-'; t << "install " << Qt::endl; @@ -1176,7 +1182,7 @@ QString MakefileGenerator::filePrefixRoot(const QString &root, const QString &path) { QString ret(path); - if(path.length() > 2 && path[1] == ':') //c:\foo + if(path.size() > 2 && path[1] == ':') //c:\foo ret.insert(2, root); else ret.prepend(root); @@ -1252,14 +1258,14 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) qPrintable(wild), qPrintable((*it).toQString()), qPrintable(base_path)); } else { - QString dir_sfx = dirstr.mid(base_path.length()); + QString dir_sfx = dirstr.mid(base_path.size()); dst_dir += dir_sfx; if (!dir_sfx.isEmpty() && !made_dirs.contains(dir_sfx)) { made_dirs.insert(dir_sfx); QString tmp_dst = fileFixify(dst_dir, FileFixifyAbsolute, false); tmp_dst.chop(1); inst << mkdir_p_asstring(filePrefixRoot(root, tmp_dst)); - for (int i = dst.length(); i < dst_dir.length(); i++) { + for (int i = dst.size(); i < dst_dir.size(); i++) { if (dst_dir.at(i) == Option::dir_sep) { QString subd = dst_dir.left(i); if (!removed_dirs.contains(subd)) { @@ -1287,7 +1293,14 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) else cmd = QLatin1String("$(QINSTALL)"); cmd += " " + escapeFilePath(wild) + " " + escapeFilePath(dst_file); - inst << cmd; + + QString sedArgs = createSedArgs(ProKey("QMAKE_INSTALL_REPLACE"), fi.fileName()); + if (!sedArgs.isEmpty()) + inst << "$(SED) " + sedArgs + ' ' + escapeFilePath(wild) + " > " + + escapeFilePath(dst_file); + else + inst << cmd; + if (!noStrip && !project->isActiveConfig("debug_info") && !project->isActiveConfig("nostrip") && !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP")) inst << QString("-") + var("QMAKE_STRIP") + " " + @@ -1312,7 +1325,7 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) inst << cmd; uninst.append(rm_dir_contents + " " + escapeFilePath(filePrefixRoot(root, fileFixify(dst_dir + filestr, FileFixifyAbsolute, false)))); } - for(int x = 0; x < files.count(); x++) { + for(int x = 0; x < files.size(); x++) { QString file = files[x]; uninst.append(rm_dir_contents + " " + escapeFilePath(filePrefixRoot(root, fileFixify(dst_dir + file, FileFixifyAbsolute, false)))); QFileInfo fi(fileInfo(dirstr + file)); @@ -1612,7 +1625,7 @@ MakefileGenerator::replaceExtraCompilerVariables( QFileInfo fi(fileInfo(Option::normalizePath(in.at(i)))); QString ext; // Ensure complementarity with QMAKE_FILE_BASE - int baseLen = fi.completeBaseName().length(); + int baseLen = fi.completeBaseName().size(); if(baseLen == 0) ext = fi.fileName(); else @@ -1678,7 +1691,7 @@ MakefileGenerator::replaceExtraCompilerVariables( fullVal = val.join(' '); } ret.replace(match.capturedStart(), match.capturedLength(), fullVal); - rep = match.capturedStart(), fullVal.length(); + rep += fullVal.size(); } else { rep = match.capturedEnd(); } @@ -1827,7 +1840,7 @@ static QStringList splitDeps(const QString &indeps, bool lineMode) QString MakefileGenerator::resolveDependency(const QDir &outDir, const QString &file) { - const QVector<QMakeLocalFileName> &depdirs = QMakeSourceFileInfo::dependencyPaths(); + const QList<QMakeLocalFileName> &depdirs = QMakeSourceFileInfo::dependencyPaths(); for (const auto &depdir : depdirs) { const QString &local = depdir.local(); QString lf = outDir.absoluteFilePath(local + '/' + file); @@ -1879,7 +1892,7 @@ void MakefileGenerator::callExtraCompilerDependCommand(const ProString &extraCom return; QDir outDir(Option::output_dir); QStringList dep_cmd_deps = splitDeps(indeps, dep_lines); - for (int i = 0; i < dep_cmd_deps.count(); ++i) { + for (int i = 0; i < dep_cmd_deps.size(); ++i) { QString &file = dep_cmd_deps[i]; const QString absFile = outDir.absoluteFilePath(file); if (absFile == file) { @@ -1957,7 +1970,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) if (raw_clean.isEmpty()) raw_clean << tmp_out; QString tmp_clean; - for (const QString &rc : qAsConst(raw_clean)) + for (const QString &rc : std::as_const(raw_clean)) tmp_clean += ' ' + escapeFilePath(Option::fixPathToTargetOS(rc)); QString tmp_clean_cmds = project->values(ProKey(*it + ".clean_commands")).join(' '); if(!tmp_inputs.isEmpty()) @@ -1982,7 +1995,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) for (ProStringList::ConstIterator input = tmp_inputs.cbegin(); input != tmp_inputs.cend(); ++input) { QString tinp = (*input).toQString(); QString out = replaceExtraCompilerVariables(tmp_out, tinp, QString(), NoShell); - for (const QString &rc : qAsConst(raw_clean)) { + for (const QString &rc : std::as_const(raw_clean)) { dels << ' ' + escapeFilePath(fileFixify( replaceExtraCompilerVariables(rc, tinp, out, NoShell), FileFixifyFromOutdir)); @@ -1993,9 +2006,9 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) } else { QString files; const int commandlineLimit = 2047; // NT limit, expanded - for (const QString &file : qAsConst(dels)) { - if(del_statement.length() + files.length() + - qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) { + for (const QString &file : std::as_const(dels)) { + if(del_statement.size() + files.size() + + qMax(fixEnvVariables(file).size(), file.size()) > commandlineLimit) { cleans.append(files); files.clear(); } @@ -2215,6 +2228,7 @@ MakefileGenerator::writeDummyMakefile(QTextStream &t) << "@echo \"Skipped.\"\n\n"; writeMakeQmake(t); t << "FORCE:\n\n"; + suppressBuiltinRules(t); return true; } @@ -2229,6 +2243,7 @@ MakefileGenerator::writeMakefile(QTextStream &t) writeInstalls(t); t << "FORCE:\n\n"; + suppressBuiltinRules(t); return true; } @@ -2257,11 +2272,11 @@ QString MakefileGenerator::buildArgs(bool withExtra) { QString ret; - for (const QString &arg : qAsConst(Option::globals->qmake_args)) + for (const QString &arg : std::as_const(Option::globals->qmake_args)) ret += " " + shellQuote(arg); if (withExtra && !Option::globals->qmake_extra_args.isEmpty()) { ret += " --"; - for (const QString &arg : qAsConst(Option::globals->qmake_extra_args)) + for (const QString &arg : std::as_const(Option::globals->qmake_extra_args)) ret += " " + shellQuote(arg); } return ret; @@ -2376,7 +2391,7 @@ MakefileGenerator::findSubDirsSubTargets() const if(new_slsh != -1) basename = basename.mid(new_slsh+1); if(st->profile != basename + Option::pro_ext) - st->makefile += "." + st->profile.left(st->profile.length() - Option::pro_ext.length()); + st->makefile += "." + st->profile.left(st->profile.size() - Option::pro_ext.size()); } } const ProKey dkey(fixedSubdir + ".depends"); @@ -2515,7 +2530,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) out_directory += Option::dir_sep; if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) - out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); + out_directory = Option::output_dir + out_directory.mid(abs_source_path.size()); QString out_directory_cdin = out_directory.isEmpty() ? QString("\n\t") : "\n\tcd " + escapeFilePath(out_directory) + " && "; @@ -2528,7 +2543,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT out = subtarget->makefile; in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute)); if(out.startsWith(in_directory)) - out = out.mid(in_directory.length()); + out = out.mid(in_directory.size()); out = escapeFilePath(out); t << subtarget->target << "-qmake_all: "; if (flags & SubTargetOrdered) { @@ -2693,7 +2708,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) out_directory += Option::dir_sep; if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) - out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); + out_directory = Option::output_dir + out_directory.mid(abs_source_path.size()); if(!recurse.contains(subtarget->name)) continue; @@ -2708,7 +2723,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT out = subtarget->makefile; in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute)); if (out.startsWith(in_directory)) - out = out.mid(in_directory.length()); + out = out.mid(in_directory.size()); out = escapeFilePath(out); } @@ -2750,6 +2765,13 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT writeInstalls(t, true); } t << "FORCE:\n\n"; + suppressBuiltinRules(t); +} + +void +MakefileGenerator::suppressBuiltinRules(QTextStream &t) const +{ + t << ".SUFFIXES:\n\n"; } void @@ -2798,7 +2820,7 @@ MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll) QFileInfo MakefileGenerator::fileInfo(QString file) const { - static QHash<FileInfoCacheKey, QFileInfo> *cache = nullptr; + Q_CONSTINIT static QHash<FileInfoCacheKey, QFileInfo> *cache = nullptr; static QFileInfo noInfo = QFileInfo(); if(!cache) { cache = new QHash<FileInfoCacheKey, QFileInfo>; @@ -2837,7 +2859,7 @@ MakefileGenerator::fixLibFlags(const ProKey &var) const ProStringList &in = project->values(var); ProStringList ret; - ret.reserve(in.length()); + ret.reserve(in.size()); for (const ProString &v : in) ret << fixLibFlag(v); return ret; @@ -3003,7 +3025,7 @@ MakefileGenerator::fileFixify(const QString &file, FileFixifyTypes fix, bool can if(ret == match_dir) { ret = ""; } else if(ret.startsWith(match_dir + Option::dir_sep)) { - ret = ret.mid(match_dir.length() + Option::dir_sep.length()); + ret = ret.mid(match_dir.size() + Option::dir_sep.size()); } else { //figure out the depth int depth = 4; @@ -3025,7 +3047,7 @@ MakefileGenerator::fileFixify(const QString &file, FileFixifyTypes fix, bool can break; if(ret.startsWith(match_dir + Option::dir_sep)) { //concat - int remlen = ret.length() - (match_dir.length() + 1); + int remlen = ret.size() - (match_dir.size() + 1); if(remlen < 0) remlen = 0; ret = ret.right(remlen); @@ -3096,15 +3118,15 @@ MakefileGenerator::findFileForDep(const QMakeLocalFileName &dep, const QMakeLoca if(Option::output_dir != qmake_getpwd() && QDir::isRelativePath(dep.real())) { //is it from the shadow tree - QVector<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); + QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); depdirs.prepend(fileInfo(file.real()).absoluteDir().path()); QString pwd = qmake_getpwd(); - if(pwd.at(pwd.length()-1) != '/') + if(pwd.at(pwd.size()-1) != '/') pwd += '/'; - for(int i = 0; i < depdirs.count(); i++) { + for(int i = 0; i < depdirs.size(); i++) { QString dir = depdirs.at(i).real(); if(!QDir::isRelativePath(dir) && dir.startsWith(pwd)) - dir = dir.mid(pwd.length()); + dir = dir.mid(pwd.size()); if(QDir::isRelativePath(dir)) { if(!dir.endsWith(Option::dir_sep)) dir += Option::dir_sep; @@ -3220,7 +3242,7 @@ MakefileGenerator::pkgConfigFileName(bool fixify) ret = project->first("TARGET").toQString(); int slsh = ret.lastIndexOf(Option::dir_sep); if (slsh != -1) - ret = ret.right(ret.length() - slsh - 1); + ret = ret.right(ret.size() - slsh - 1); if (ret.startsWith("lib")) ret = ret.mid(3); int dot = ret.indexOf('.'); @@ -3414,35 +3436,43 @@ static QString windowsifyPath(const QString &str) return QString(str).replace('/', QLatin1String("\\\\\\\\")); } -QString MakefileGenerator::installMetaFile(const ProKey &replace_rule, const QString &src, const QString &dst) +QString MakefileGenerator::createSedArgs(const ProKey &replace_rule, const QString &file_name) const { - QString ret; - if (project->isEmpty(replace_rule) - || project->isActiveConfig("no_sed_meta_install")) { - ret += "$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst); - } else { - QString sedargs; + QString sedargs; + if (!project->isEmpty(replace_rule) && !project->isActiveConfig("no_sed_meta_install")) { const ProStringList &replace_rules = project->values(replace_rule); for (int r = 0; r < replace_rules.size(); ++r) { const ProString match = project->first(ProKey(replace_rules.at(r) + ".match")), - replace = project->first(ProKey(replace_rules.at(r) + ".replace")); - if (!match.isEmpty() /*&& match != replace*/) { + replace = project->first(ProKey(replace_rules.at(r) + ".replace")), + filename = project->first(ProKey(replace_rules.at(r) + ".filename")); + if (!match.isEmpty() /*&& match != replace*/ + && (filename.isEmpty() || filename == file_name)) { sedargs += " -e " + shellQuote("s," + match + "," + replace + ",g"); - if (isWindowsShell() && project->first(ProKey(replace_rules.at(r) + ".CONFIG")).contains("path")) - sedargs += " -e " + shellQuote("s," + windowsifyPath(match.toQString()) - + "," + windowsifyPath(replace.toQString()) + ",gi"); + if (isWindowsShell() + && project->first(ProKey(replace_rules.at(r) + ".CONFIG")).contains("path")) + sedargs += " -e " + + shellQuote("s," + windowsifyPath(match.toQString()) + "," + + windowsifyPath(replace.toQString()) + ",gi"); } } - if (sedargs.isEmpty()) { - ret += "$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst); - } else { - ret += "$(SED) " + sedargs + ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst); - } + } + return sedargs; +} + +QString MakefileGenerator::installMetaFile(const ProKey &replace_rule, const QString &src, + const QString &dst) const +{ + QString ret; + QString sedargs = createSedArgs(replace_rule); + if (sedargs.isEmpty()) { + ret = "$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst); + } else { + ret = "$(SED) " + sedargs + ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst); } return ret; } -QString MakefileGenerator::shellQuote(const QString &str) +QString MakefileGenerator::shellQuote(const QString &str) const { return isWindowsShell() ? IoUtils::shellQuoteWin(str) : IoUtils::shellQuoteUnix(str); } @@ -3456,28 +3486,85 @@ ProKey MakefileGenerator::fullTargetVariable() const return "TARGET"; } -void MakefileGenerator::createResponseFile(const QString &fileName, const ProStringList &objList) -{ +/* + * Create a response file and return its file name. + */ +QString MakefileGenerator::createResponseFile( + const QString &baseName, + const ProStringList &objList, + const QString &prefix) const +{ + QString fileName = baseName + '.' + var("QMAKE_ORIG_TARGET"); + if (!var("BUILD_NAME").isEmpty()) + fileName += '.' + var("BUILD_NAME"); + if (!var("MAKEFILE").isEmpty()) + fileName += '.' + var("MAKEFILE"); 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(); - } + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + fprintf(stderr, "Error: Cannot open response file '%s' for writing.\n", + qPrintable(filePath)); + exit(1); + } + 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 << prefix << path << Qt::endl; + } + t.flush(); + file.close(); + return fileName; +} + +/* + * If the threshold for response files are overstepped, create a response file for the linker + * command line. + */ +MakefileGenerator::LinkerResponseFileInfo MakefileGenerator::maybeCreateLinkerResponseFile() const +{ + bool useLinkObjectMax = false; + bool ok; + int threshold = project->first("QMAKE_RESPONSEFILE_THRESHOLD").toInt(&ok); + if (!ok) { + threshold = project->first("QMAKE_LINK_OBJECT_MAX").toInt(&ok); + if (ok) + useLinkObjectMax = true; + } + if (!ok) + return {}; + + ProStringList linkerInputs = project->values("OBJECTS"); + if (useLinkObjectMax) { + // When using QMAKE_LINK_OBJECT_MAX, the number of object files (regardless of their path + // length) decides whether to use a response file. This is far from being a useful + // heuristic but let's keep this behavior for backwards compatibility. + if (linkerInputs.size() < threshold) + return {}; + } else { + // When using QMAKE_REPONSEFILE_THRESHOLD, try to determine the command line length of the + // inputs. + linkerInputs += project->values("LIBS"); + int totalLength = std::accumulate(linkerInputs.cbegin(), linkerInputs.cend(), 0, + [](int total, const ProString &input) { + return total + input.size() + 1; + }); + if (totalLength < threshold) + return {}; + } + + return { + createResponseFile(fileVar("OBJECTS_DIR") + var("QMAKE_LINK_OBJECT_SCRIPT"), linkerInputs), + useLinkObjectMax + }; } QT_END_NAMESPACE |