summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
Diffstat (limited to 'qmake')
-rw-r--r--qmake/Makefile.unix6
-rw-r--r--qmake/Makefile.win321
-rw-r--r--qmake/doc/src/qmake-manual.qdoc85
-rw-r--r--qmake/generators/mac/pbuilder_pbx.cpp31
-rw-r--r--qmake/generators/mac/pbuilder_pbx.h2
-rw-r--r--qmake/generators/makefile.cpp197
-rw-r--r--qmake/generators/makefile.h7
-rw-r--r--qmake/generators/projectgenerator.cpp17
-rw-r--r--qmake/generators/unix/unixmake.cpp12
-rw-r--r--qmake/generators/unix/unixmake2.cpp26
-rw-r--r--qmake/generators/win32/mingw_make.cpp18
-rw-r--r--qmake/generators/win32/mingw_make.h2
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp5
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp23
-rw-r--r--qmake/generators/win32/winmakefile.cpp25
-rw-r--r--qmake/generators/win32/winmakefile.h2
-rw-r--r--qmake/library/proitems.h49
-rw-r--r--qmake/library/qmakebuiltins.cpp1468
-rw-r--r--qmake/library/qmakeevaluator.cpp23
-rw-r--r--qmake/library/qmakeevaluator.h10
-rw-r--r--qmake/library/qmakeevaluator_p.h22
-rw-r--r--qmake/main.cpp34
-rw-r--r--qmake/meta.cpp121
-rw-r--r--qmake/meta.h9
-rw-r--r--qmake/project.cpp10
25 files changed, 1075 insertions, 1130 deletions
diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix
index 426387f0c2..29461be5c5 100644
--- a/qmake/Makefile.unix
+++ b/qmake/Makefile.unix
@@ -18,7 +18,7 @@ OBJS = \
#qt code (please keep in order matching DEPEND_SRC)
QOBJS = \
qtextcodec.o qutfcodec.o \
- qglobal.o qlogging.o qmalloc.o qnumeric.o qoperatingsystemversion.o qrandom.o \
+ qendian.o qglobal.o qlogging.o qmalloc.o qnumeric.o qoperatingsystemversion.o qrandom.o \
qabstractfileengine.o qbuffer.o qdatastream.o qdebug.o \
qdir.o qdiriterator.o \
qfile.o qfiledevice.o qfileinfo.o qfilesystemengine.o \
@@ -68,6 +68,7 @@ DEPEND_SRC = \
$(QMKGENSRC)/xmloutput.cpp \
$(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp \
$(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp \
+ $(SOURCE_PATH)/src/corelib/global/qendian.cpp \
$(SOURCE_PATH)/src/corelib/global/qglobal.cpp \
$(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp \
$(SOURCE_PATH)/src/corelib/global/qlogging.cpp \
@@ -295,6 +296,9 @@ qdebug.o: $(SOURCE_PATH)/src/corelib/io/qdebug.cpp
qmalloc.o: $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
+qendian.o: $(SOURCE_PATH)/src/corelib/global/qendian.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $<
+
qglobal.o: $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32
index 5292332187..a1699bd6f8 100644
--- a/qmake/Makefile.win32
+++ b/qmake/Makefile.win32
@@ -83,6 +83,7 @@ QTOBJS= \
qfsfileengine_win.obj \
qsystemlibrary.obj \
qfileinfo.obj \
+ qendian.obj \
qglobal.obj \
qhash.obj \
qiodevice.obj \
diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc
index b07ded3888..409062cf49 100644
--- a/qmake/doc/src/qmake-manual.qdoc
+++ b/qmake/doc/src/qmake-manual.qdoc
@@ -956,14 +956,35 @@
default is used.
\row \li thread \li Thread support is enabled. This is enabled when CONFIG
includes \c qt, which is the default.
+ \row \li c99 \li C99 support is enabled. This option has no effect if
+ the compiler does not support C99, or can't select the C standard.
+ By default, the compiler default is used.
+ \row \li c11 \li C11 support is enabled. This option has no effect if
+ the compiler does not support C11, or can't select the C standard.
+ By default, the compiler default is used.
+ \row \li strict_c \li Disables support for C compiler extensions.
+ By default, they are enabled.
\row \li c++11 \li C++11 support is enabled. This option has no effect if
- the compiler does not support C++11.
- By default, support is disabled.
+ the compiler does not support C++11, or can't select the C++ standard.
+ By default, support is enabled.
\row \li c++14 \li C++14 support is enabled. This option has no effect if
- the compiler does not support C++14.
+ the compiler does not support C++14, or can't select the C++ standard.
+ By default, the compiler default is used.
+ \row \li c++1z \li C++17 support is enabled. This option has no effect if
+ the compiler does not support C++17, or can't select the C++ standard.
By default, support is disabled.
+ \row \li strict_c++ \li Disables support for C++ compiler extensions.
+ By default, they are enabled.
\row \li depend_includepath \li Appending the value of INCLUDEPATH to
DEPENDPATH is enabled. Set by default.
+ \row \li lrelease \li Run \c lrelease for all files listed in
+ \l TRANSLATIONS and \l EXTRA_TRANSLATIONS. If \c embed_translations
+ is not set, install the generated .qm files into
+ QM_FILES_INSTALL_PATH. Use QMAKE_LRELEASE_FLAGS to add options to
+ the lrelease call. Not set by default.
+ \row \li embed_translations \li Embed the generated translations from
+ \c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
+ Requires \c lrelease to be set, too. Not set by default.
\endtable
When you use the \c debug_and_release option (which is the default under
@@ -1149,6 +1170,24 @@
Specifies where to copy the \l{#TARGET}{target} dll.
+ \target EXTRA_TRANSLATIONS
+ \section1 EXTRA_TRANSLATIONS
+
+ Specifies a list of translation (.ts) files that contain
+ translations of the user interface text into non-native languages.
+
+ In contrast to \l TRANSLATIONS, translation files in \c EXTRA_TRANSLATIONS
+ will be processed only by \l{Using lrelease}{lrelease}, not
+ \l{Using lupdate}{lupdate}.
+
+ You can use \l{CONFIG}{CONFIG += lrelease} to automatically compile the
+ files during the build, and
+ \l{CONFIG}{CONFIG += lrelease embed_translations} to make them available in
+ \l{The Qt Resource System}.
+
+ See the \l{Qt Linguist Manual} for more information about
+ internationalization (i18n) and localization (l10n) with Qt.
+
\target FORMS
\section1 FORMS
@@ -1419,6 +1458,21 @@
\note Do not attempt to overwrite the value of this variable.
+ \target QM_FILES_RESOURCE_PREFIX
+ \section1 QM_FILES_RESOURCE_PREFIX
+
+ Specifies the directory in the resource system where \c .qm files will
+ be made available by \l{CONFIG}{CONFIG += embed_translations}.
+
+ The default is \c{:/i18n/}.
+
+ \target QM_FILES_INSTALL_PATH
+ \section1 QM_FILES_INSTALL_PATH
+
+ Specifies the target directory \c .qm files generated by
+ \l{CONFIG}{CONFIG += lrelease} will be installed to. Does not have any
+ effect if \l{CONFIG}{CONFIG += embed_translations} is set.
+
\target QMAKE_systemvariable
\section1 QMAKE
@@ -2134,6 +2188,12 @@
value of this variable is typically handled by qmake or
\l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
+ \target QMAKE_LRELEASE_FLAGS
+ \section1 QMAKE_LRELEASE_FLAGS
+
+ List of additional options passed to \l{Using lrelease}{lrelease} when
+ enabled through \l{CONFIG}{CONFIG += lrelease}.
+
\section1 QMAKE_OBJECTIVE_CFLAGS
Specifies the Objective C/C++ compiler flags for building
@@ -2342,9 +2402,7 @@
This variable is used to customize the list of options passed to the
\l{uic}{User Interface Compiler} in each of the build rules where it is
- used. For example, \c{-no-stringliteral} can be passed to use QLatin1String
- instead of QStringLiteral in generated code (which is the default for
- dynamic libraries).
+ used.
\section1 QMAKE_WATCHOS_DEPLOYMENT_TARGET
@@ -2613,11 +2671,21 @@
determine how the project is built, it is necessary to declare TEMPLATE on
the command line rather than use the \c -t option.
+ \target TRANSLATIONS
\section1 TRANSLATIONS
Specifies a list of translation (.ts) files that contain
translations of the user interface text into non-native languages.
+ Translation files in \c TRANSLATIONS will be processed by both
+ \l{Using lrelease}{lrelease} and \l{Using lupdate} tools. Use
+ \l EXTRA_TRANSLATIONS if you want only \c lrelease to process a file.
+
+ You can use \l{CONFIG}{CONFIG += lrelease} to automatically compile the
+ files during the build, and
+ \l{CONFIG}{CONFIG += lrelease embed_translations} to make them available in
+ \l{The Qt Resource System}.
+
See the \l{Qt Linguist Manual} for more information about
internationalization (i18n) and localization (l10n) with Qt.
@@ -4511,6 +4579,11 @@
\li The dependencies for the output only get generated from the depends
member and from nowhere else.
\row
+ \li dep_lines
+ \li The output from the .depend_command is interpreted to be one file
+ per line. The default is to split on whitespace and is maintained
+ only for backwards compatibility reasons.
+ \row
\li no_link
\li Indicates that the output should not be added to the list of objects
to be linked in.
diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp
index a0aea70dc5..13d707a881 100644
--- a/qmake/generators/mac/pbuilder_pbx.cpp
+++ b/qmake/generators/mac/pbuilder_pbx.cpp
@@ -542,6 +542,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QTextStream mkt(&mkf);
writeHeader(mkt);
mkt << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ project->values("QMAKE_MAKE_QMAKE_EXTRA_COMMANDS")
+ << "@echo 'warning: Xcode project has been regenerated, custom settings have been lost. " \
+ "Use CONFIG+=no_autoqmake to prevent this behavior in the future, " \
+ "at the cost of requiring manual project change tracking.'";
writeMakeQmake(mkt);
mkt.flush();
mkf.close();
@@ -848,7 +852,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
encode the version number in the Project file which might be a bad
things in days to come? --Sam
*/
- QString lib_file = QMakeMetaInfo::findLib(Option::normalizePath((*lit) + Option::dir_sep + lib));
+ QString lib_file = QMakeMetaInfo::checkLib(Option::normalizePath(
+ (*lit) + Option::dir_sep + lib + Option::prl_ext));
if (!lib_file.isEmpty()) {
QMakeMetaInfo libinfo(project);
if(libinfo.readLib(lib_file)) {
@@ -1782,6 +1787,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
schemeData.replace(QLatin1String("@QMAKE_ORIG_TARGET@"), target);
schemeData.replace(QLatin1String("@TARGET_PBX_KEY@"), keyFor(pbx_dir + "QMAKE_PBX_TARGET"));
schemeData.replace(QLatin1String("@TEST_BUNDLE_PBX_KEY@"), keyFor("QMAKE_TEST_BUNDLE_REFERENCE"));
+ schemeData.replace(QLatin1String("@QMAKE_RELATIVE_PBX_DIR@"), fileFixify(pbx_dir));
QTextStream outputSchemeStream(&outputSchemeFile);
outputSchemeStream << schemeData;
@@ -1876,33 +1882,28 @@ ProjectBuilderMakefileGenerator::keyFor(const QString &block)
bool
ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) const
{
- if(QDir::isRelativePath(file.fileName()))
- file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ Q_ASSERT_X(QDir::isRelativePath(file.fileName()), "ProjectBuilderMakefileGenerator",
+ "runQMake() should have normalized the filename and made it relative");
+
QFileInfo fi(fileInfo(file.fileName()));
- if(fi.suffix() != "pbxproj" || file.fileName().isEmpty()) {
+ if (fi.suffix() != "pbxproj") {
QString output = file.fileName();
- if(fi.isDir())
- output += QDir::separator();
- if(!output.endsWith(projectSuffix())) {
- if(file.fileName().isEmpty() || fi.isDir()) {
- if(project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
+ if (!output.endsWith(projectSuffix())) {
+ if (fi.fileName().isEmpty()) {
+ if (project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
output += fileInfo(project->projectFile()).baseName();
else
output += project->first("QMAKE_ORIG_TARGET").toQString();
}
output += projectSuffix() + QDir::separator();
- } else if(output[(int)output.length() - 1] != QDir::separator()) {
+ } else {
output += QDir::separator();
}
output += QString("project.pbxproj");
file.setFileName(output);
- bool ret = UnixMakefileGenerator::openOutput(file, build);
- ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
- Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
- return ret;
}
- ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir;
+ pbx_dir = Option::output_dir + Option::dir_sep + file.fileName().section(Option::dir_sep, 0, 0);
return UnixMakefileGenerator::openOutput(file, build);
}
diff --git a/qmake/generators/mac/pbuilder_pbx.h b/qmake/generators/mac/pbuilder_pbx.h
index 1d5cbc538d..f92436c215 100644
--- a/qmake/generators/mac/pbuilder_pbx.h
+++ b/qmake/generators/mac/pbuilder_pbx.h
@@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE
class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
{
bool writingUnixMakefileGenerator;
- QString pbx_dir;
+ mutable QString pbx_dir;
int pbuilderVersion() const;
bool writeSubDirs(QTextStream &);
bool writeMakeParts(QTextStream &);
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
index 73e09a1025..fd8c0a965c 100644
--- a/qmake/generators/makefile.cpp
+++ b/qmake/generators/makefile.cpp
@@ -876,20 +876,37 @@ MakefileGenerator::init()
}
bool
-MakefileGenerator::processPrlFile(QString &file)
+MakefileGenerator::processPrlFile(QString &file, bool baseOnly)
{
- bool try_replace_file = false;
QString f = fileFixify(file, FileFixifyBackwards);
- QString meta_file = QMakeMetaInfo::findLib(f);
- if (!meta_file.isEmpty()) {
- try_replace_file = true;
- } else {
- QString tmp = f;
- int ext = tmp.lastIndexOf('.');
- if(ext != -1)
- tmp = tmp.left(ext);
- meta_file = QMakeMetaInfo::findLib(tmp);
+ // Explicitly given full .prl name
+ if (!baseOnly && f.endsWith(Option::prl_ext))
+ return processPrlFileCore(file, QStringRef(), f);
+ // Explicitly given or derived (from -l) base name
+ if (processPrlFileCore(file, QStringRef(), f + Option::prl_ext))
+ return true;
+ if (!baseOnly) {
+ // Explicitly given full library name
+ int off = qMax(f.lastIndexOf('/'), f.lastIndexOf('\\')) + 1;
+ int ext = f.midRef(off).lastIndexOf('.');
+ if (ext != -1)
+ return processPrlFileBase(file, f.midRef(off), f.leftRef(off + ext), off);
}
+ return false;
+}
+
+bool
+MakefileGenerator::processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff)
+{
+ return processPrlFileCore(origFile, origName, fixedBase + Option::prl_ext);
+}
+
+bool
+MakefileGenerator::processPrlFileCore(QString &origFile, const QStringRef &origName,
+ const QString &fixedFile)
+{
+ const QString meta_file = QMakeMetaInfo::checkLib(fixedFile);
if (meta_file.isEmpty())
return false;
QMakeMetaInfo libinfo(project);
@@ -898,9 +915,33 @@ MakefileGenerator::processPrlFile(QString &file)
fprintf(stderr, "Error processing meta file %s\n", meta_file.toLatin1().constData());
return false;
}
- if (project->isActiveConfig("no_read_prl_" + libinfo.type().toLower())) {
- debug_msg(2, "Ignored meta file %s [%s]",
- meta_file.toLatin1().constData(), libinfo.type().toLatin1().constData());
+ if (project->isActiveConfig("no_read_prl_qmake")) {
+ debug_msg(2, "Ignored meta file %s", meta_file.toLatin1().constData());
+ return false;
+ }
+ ProString tgt = libinfo.first("QMAKE_PRL_TARGET");
+ if (tgt.isEmpty()) {
+ fprintf(stderr, "Error: %s does not define QMAKE_PRL_TARGET\n",
+ meta_file.toLatin1().constData());
+ return false;
+ }
+ if (!tgt.contains('.') && !libinfo.values("QMAKE_PRL_CONFIG").contains("lib_bundle")) {
+ fprintf(stderr, "Error: %s defines QMAKE_PRL_TARGET without extension\n",
+ meta_file.toLatin1().constData());
+ return false;
+ }
+ if (origName.isEmpty()) {
+ // We got a .prl file as input, replace it with an actual library.
+ int off = qMax(origFile.lastIndexOf('/'), origFile.lastIndexOf('\\')) + 1;
+ debug_msg(1, " Replacing library reference %s with %s",
+ origFile.mid(off).toLatin1().constData(),
+ tgt.toQString().toLatin1().constData());
+ origFile.replace(off, 1000, tgt.toQString());
+ } else if (tgt != origName) {
+ // We got an actual library as input, and found the wrong .prl for it.
+ debug_msg(2, "Mismatched meta file %s (want %s, got %s)",
+ meta_file.toLatin1().constData(),
+ origName.toLatin1().constData(), tgt.toLatin1().constData());
return false;
}
project->values("QMAKE_CURRENT_PRL_LIBS") = libinfo.values("QMAKE_PRL_LIBS");
@@ -909,23 +950,6 @@ MakefileGenerator::processPrlFile(QString &file)
for (const ProString &def : libinfo.values("QMAKE_PRL_DEFINES"))
if (!defs.contains(def) && prl_defs.contains(def))
defs.append(def);
- if (try_replace_file) {
- ProString tgt = libinfo.first("QMAKE_PRL_TARGET");
- if (tgt.isEmpty()) {
- fprintf(stderr, "Error: %s does not define QMAKE_PRL_TARGET\n",
- meta_file.toLatin1().constData());
- } else if (!tgt.contains('.')
- && !libinfo.values("QMAKE_PRL_CONFIG").contains("lib_bundle")) {
- fprintf(stderr, "Error: %s defines QMAKE_PRL_TARGET without extension\n",
- meta_file.toLatin1().constData());
- } else {
- int off = qMax(file.lastIndexOf('/'), file.lastIndexOf('\\')) + 1;
- debug_msg(1, " Replacing library reference %s with %s",
- file.mid(off).toLatin1().constData(),
- tgt.toQString().toLatin1().constData());
- file.replace(off, 1000, tgt.toQString());
- }
- }
QString mf = fileFixify(meta_file);
if (!project->values("QMAKE_PRL_INTERNAL_FILES").contains(mf))
project->values("QMAKE_PRL_INTERNAL_FILES").append(mf);
@@ -1815,12 +1839,27 @@ MakefileGenerator::writeExtraTargets(QTextStream &t)
}
}
+static QStringList splitDeps(const QString &indeps, bool lineMode)
+{
+ if (!lineMode)
+ return indeps.simplified().split(' ');
+ QStringList deps = indeps.split('\n', QString::SkipEmptyParts);
+#ifdef Q_OS_WIN
+ for (auto &dep : deps) {
+ if (dep.endsWith(QLatin1Char('\r')))
+ dep.chop(1);
+ }
+#endif
+ return deps;
+}
+
void
MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
{
QString clean_targets;
const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const ProStringList &config = project->values(ProKey(*it + ".CONFIG"));
QString tmp_out = fileFixify(project->first(ProKey(*it + ".output")).toQString(),
FileFixifyFromOutdir);
const QString tmp_cmd = project->values(ProKey(*it + ".commands")).join(' ');
@@ -1831,6 +1870,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
+ IoUtils::shellQuote(Option::fixPathToLocalOS(Option::output_dir, false))
+ QLatin1String(" && ");
}
+ const bool dep_lines = (config.indexOf("dep_lines") != -1);
const ProStringList &vars = project->values(ProKey(*it + ".variables"));
if(tmp_out.isEmpty() || tmp_cmd.isEmpty())
continue;
@@ -1847,7 +1887,6 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
}
t << "compiler_" << (*it) << "_make_all:";
- const ProStringList &config = project->values(ProKey(*it + ".CONFIG"));
if (config.indexOf("combine") != -1) {
// compilers with a combined input only have one output
QString input = project->first(ProKey(*it + ".output")).toQString();
@@ -1954,12 +1993,13 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
QT_PCLOSE(proc);
if(!indeps.isEmpty()) {
QDir outDir(Option::output_dir);
- // ### This is basically fubar. Add 'lines' flag to CONFIG?
- QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ QStringList dep_cmd_deps = splitDeps(indeps, dep_lines);
for(int i = 0; i < dep_cmd_deps.count(); ++i) {
QString &file = dep_cmd_deps[i];
QString absFile = outDir.absoluteFilePath(file);
- if (exists(absFile)) {
+ if (absFile == file) {
+ // already absolute; don't do any checks.
+ } else if (exists(absFile)) {
file = absFile;
} else {
QString localFile;
@@ -1978,7 +2018,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
" prints paths relative to source directory",
(*it).toLatin1().constData());
else
- file.clear();
+ file = absFile; // fallback for generated resources
} else {
file = localFile;
}
@@ -2048,12 +2088,13 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
QT_PCLOSE(proc);
if(!indeps.isEmpty()) {
QDir outDir(Option::output_dir);
- // ### This is basically fubar. Add 'lines' flag to CONFIG?
- QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ QStringList dep_cmd_deps = splitDeps(indeps, dep_lines);
for(int i = 0; i < dep_cmd_deps.count(); ++i) {
QString &file = dep_cmd_deps[i];
QString absFile = outDir.absoluteFilePath(file);
- if (exists(absFile)) {
+ if (absFile == file) {
+ // already absolute; don't do any checks.
+ } else if (exists(absFile)) {
file = absFile;
} else {
QString localFile;
@@ -2072,7 +2113,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
" prints paths relative to source directory",
(*it).toLatin1().constData());
else
- file.clear();
+ file = absFile; // fallback for generated resources
} else {
file = localFile;
}
@@ -2730,6 +2771,9 @@ MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll)
const ProStringList &included = escapeDependencyPaths(project->values("QMAKE_INTERNAL_INCLUDED_FILES"));
t << included.join(QString(" \\\n\t\t")) << "\n\t"
<< qmake << endl;
+ const ProStringList &extraCommands = project->values("QMAKE_MAKE_QMAKE_EXTRA_COMMANDS");
+ if (!extraCommands.isEmpty())
+ t << "\t" << extraCommands.join(QString("\n\t")) << endl;
for(int include = 0; include < included.size(); ++include) {
const ProString &i = included.at(include);
if(!i.isEmpty())
@@ -3132,54 +3176,31 @@ MakefileGenerator::specdir()
bool
MakefileGenerator::openOutput(QFile &file, const QString &build) const
{
- {
- QString outdir;
- if(!file.fileName().isEmpty()) {
- if(QDir::isRelativePath(file.fileName()))
- file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
- QFileInfo fi(fileInfo(file.fileName()));
- if(fi.isDir())
- outdir = file.fileName() + '/';
- }
- if(!outdir.isEmpty() || file.fileName().isEmpty()) {
- QString fname = "Makefile";
- if(!project->isEmpty("MAKEFILE"))
- fname = project->first("MAKEFILE").toQString();
- file.setFileName(outdir + fname);
- }
- }
- if(QDir::isRelativePath(file.fileName())) {
- QString fname = Option::output_dir; //pwd when qmake was run
- if(!fname.endsWith("/"))
- fname += "/";
- fname += file.fileName();
- file.setFileName(fname);
- }
- if(!build.isEmpty())
+ debug_msg(3, "asked to open output file '%s' in %s",
+ qPrintable(file.fileName()), qPrintable(Option::output_dir));
+
+ if (file.fileName().isEmpty()) {
+ file.setFileName(!project->isEmpty("MAKEFILE")
+ ? project->first("MAKEFILE").toQString() : "Makefile");
+ }
+
+ file.setFileName(QDir(Option::output_dir).absoluteFilePath(file.fileName()));
+
+ if (!build.isEmpty())
file.setFileName(file.fileName() + "." + build);
- if(project->isEmpty("QMAKE_MAKEFILE"))
+
+ if (project->isEmpty("QMAKE_MAKEFILE"))
project->values("QMAKE_MAKEFILE").append(file.fileName());
+
+ // Make required directories. Note that we do this based on the
+ // filename, not Option::output_dir, as the filename may include
+ // generator specific directories not included in output_dir.
int slsh = file.fileName().lastIndexOf('/');
- if(slsh != -1)
+ if (slsh != -1)
mkdir(file.fileName().left(slsh));
- if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
- QFileInfo fi(fileInfo(Option::output.fileName()));
- QString od;
- if(fi.isSymLink())
- od = fileInfo(fi.readLink()).absolutePath();
- else
- od = fi.path();
- od = QDir::fromNativeSeparators(od);
- if(QDir::isRelativePath(od)) {
- QString dir = Option::output_dir;
- if (!dir.endsWith('/') && !od.isEmpty())
- dir += '/';
- od.prepend(dir);
- }
- Option::output_dir = od;
- return true;
- }
- return false;
+
+ debug_msg(3, "opening output file %s", qPrintable(file.fileName()));
+ return file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
}
QString
@@ -3315,10 +3336,8 @@ MakefileGenerator::writePkgConfigFile()
t << "Libs: ";
QString pkgConfiglibName;
if (target_mode == TARG_MAC_MODE && project->isActiveConfig("lib_bundle")) {
- if (libDir != QLatin1String("/System/Library/Frameworks")
- && libDir != QLatin1String("/Library/Frameworks")) {
+ if (libDir != QLatin1String("/Library/Frameworks"))
t << "-F${libdir} ";
- }
ProString bundle;
if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
bundle = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME");
@@ -3363,6 +3382,10 @@ MakefileGenerator::writePkgConfigFile()
;
if (!project->values("QMAKE_DEFAULT_INCDIRS").contains(includeDir))
t << "-I${includedir}";
+ if (target_mode == TARG_MAC_MODE && project->isActiveConfig("lib_bundle")
+ && libDir != QLatin1String("/Library/Frameworks")) {
+ t << " -F${libdir}";
+ }
t << endl;
// requires
diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h
index f32bec650e..6b9bd43cae 100644
--- a/qmake/generators/makefile.h
+++ b/qmake/generators/makefile.h
@@ -198,7 +198,7 @@ protected:
//for prl
QString prlFileName(bool fixify=true);
void writePrlFile();
- bool processPrlFile(QString &);
+ bool processPrlFile(QString &, bool baseOnly);
virtual void writePrlFile(QTextStream &);
//make sure libraries are found
@@ -246,6 +246,11 @@ protected:
QString installMetaFile(const ProKey &replace_rule, const QString &src, const QString &dst);
+ virtual bool processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff);
+ bool processPrlFileCore(QString &origFile, const QStringRef &origName,
+ const QString &fixedFile);
+
public:
MakefileGenerator();
virtual ~MakefileGenerator();
diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp
index 073d315aab..27b7e9dfdc 100644
--- a/qmake/generators/projectgenerator.cpp
+++ b/qmake/generators/projectgenerator.cpp
@@ -473,18 +473,11 @@ ProjectGenerator::getWritableVar(const char *vk, bool)
bool
ProjectGenerator::openOutput(QFile &file, const QString &build) const
{
- QString outdir;
- if(!file.fileName().isEmpty()) {
- QFileInfo fi(fileInfo(file.fileName()));
- if(fi.isDir())
- outdir = fi.path() + QDir::separator();
- }
- if(!outdir.isEmpty() || file.fileName().isEmpty()) {
- QString dir = qmake_getpwd();
- int s = dir.lastIndexOf('/');
- if(s != -1)
- dir = dir.right(dir.length() - (s + 1));
- file.setFileName(outdir + dir + Option::pro_ext);
+ ProString fileName = file.fileName();
+ if (!fileName.endsWith(Option::pro_ext)) {
+ if (fileName.isEmpty())
+ fileName = fileInfo(Option::output_dir).fileName();
+ file.setFileName(fileName + Option::pro_ext);
}
return MakefileGenerator::openOutput(file, build);
}
diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp
index 894020d2bd..52d34ef513 100644
--- a/qmake/generators/unix/unixmake.cpp
+++ b/qmake/generators/unix/unixmake.cpp
@@ -443,7 +443,7 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
dep_it != libdirs.end(); ++dep_it) {
QString libBase = (*dep_it).local() + '/'
+ project->first("QMAKE_PREFIX_SHLIB") + lib;
- if (linkPrl && processPrlFile(libBase))
+ if (linkPrl && processPrlFile(libBase, true))
goto found;
for (ProStringList::Iterator extit = extens.begin(); extit != extens.end(); ++extit) {
if (exists(libBase + '.' + (*extit)))
@@ -471,12 +471,12 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
}
for (const QMakeLocalFileName &dir : qAsConst(frameworkdirs)) {
QString frameworkDirectory = dir.local() + "/" + frameworkName + + ".framework/";
- QString suffixedPrl = frameworkDirectory + opt + Option::prl_ext;
- if (processPrlFile(suffixedPrl))
+ QString suffixedPrl = frameworkDirectory + opt;
+ if (processPrlFile(suffixedPrl, true))
break;
if (hasSuffix) {
- QString unsuffixedPrl = frameworkDirectory + frameworkName + Option::prl_ext;
- if (processPrlFile(unsuffixedPrl))
+ QString unsuffixedPrl = frameworkDirectory + frameworkName;
+ if (processPrlFile(unsuffixedPrl, true))
break;
}
}
@@ -487,7 +487,7 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
}
}
} else if (linkPrl) {
- processPrlFile(opt);
+ processPrlFile(opt, false);
}
ProStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS");
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
index ecb0de3b52..bda44eaa67 100644
--- a/qmake/generators/unix/unixmake2.cpp
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -280,11 +280,11 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
if (destd.endsWith('\\'))
destd += '\\';
t << "DESTDIR = " << destd << endl;
- t << "TARGET = " << fileVar("TARGET") << endl; // ### mixed use!
+ t << "TARGET = " << fileVar("TARGET") << endl;
if(project->isActiveConfig("plugin")) {
t << "TARGETD = " << fileVar("TARGET") << endl;
} else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty()) {
- t << "TARGETA = " << fileVar("TARGETA") << endl; // ### mixed use!
+ t << "TARGETA = " << fileVar("TARGETA") << endl;
if(!project->isEmpty("QMAKE_BUNDLE")) {
t << "TARGETD = " << fileVar("TARGET_x.y") << endl;
t << "TARGET0 = " << fileVar("TARGET_") << endl;
@@ -502,7 +502,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\n\t" << var("QMAKE_POST_LINK");
t << endl << endl;
} else {
- t << "$(TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) "
+ t << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) "
<< target_deps << ' ' << depVar("POST_TARGETDEPS") << "\n\t";
if (project->first("TEMPLATE") != "aux") {
if (!destdir.isEmpty())
@@ -515,7 +515,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
}
t << endl << endl;
}
- allDeps = " $(TARGET)";
+ allDeps = ' ' + depVar("TARGET");
} else if(!project->isActiveConfig("staticlib")) {
QString destdir_r = project->first("DESTDIR").toQString(), incr_deps;
if(!project->isEmpty("QMAKE_BUNDLE")) {
@@ -580,14 +580,14 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
}
//real target
- t << destdir_d << "$(TARGET): " << depVar("PRE_TARGETDEPS") << ' '
+ t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << ' '
<< incr_deps << " $(SUBLIBS) " << target_deps << ' ' << depVar("POST_TARGETDEPS");
} else {
- t << destdir_d << "$(TARGET): " << depVar("PRE_TARGETDEPS")
+ t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS")
<< " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps
<< ' ' << depVar("POST_TARGETDEPS");
}
- allDeps = ' ' + destdir_d + "$(TARGET)";
+ allDeps = ' ' + destdir_d + depVar("TARGET");
if(!destdir.isEmpty())
t << "\n\t" << mkdir_p_asstring(destdir, false);
if(!project->isEmpty("QMAKE_PRE_LINK"))
@@ -604,7 +604,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << "\n\t" << var("QMAKE_POST_LINK");
t << endl << endl;
} else if(!project->isEmpty("QMAKE_BUNDLE")) {
- bundledFiles << destdir_r + "$(TARGET)";
+ bundledFiles << destdir_r + var("TARGET");
t << "\n\t"
<< "-$(DEL_FILE) $(TARGET) $(TARGET0) $(DESTDIR)$(TARGET0)\n\t"
<< var("QMAKE_LINK_SHLIB_CMD") << "\n\t"
@@ -669,8 +669,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
t << endl << endl;
if (! project->isActiveConfig("plugin")) {
- t << "staticlib: $(TARGETA)\n\n";
- t << "$(TARGETA): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
+ t << "staticlib: " << depVar("TARGETA") << "\n\n";
+ t << depVar("TARGETA") << ": " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
if(do_incremental)
t << " $(INCREMENTAL_OBJECTS)";
t << ' ' << depVar("POST_TARGETDEPS") << "\n\t";
@@ -690,11 +690,11 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
QString destdir_r = project->first("DESTDIR").toQString();
QString destdir_d = escapeDependencyPath(destdir_r);
QString destdir = escapeFilePath(destdir_r);
- allDeps = ' ' + destdir_d + "$(TARGET)"
+ allDeps = ' ' + destdir_d + depVar("TARGET")
+ varGlue("QMAKE_AR_SUBLIBS", ' ' + destdir_d, ' ' + destdir_d, "");
t << "staticlib: " << destdir_d << "$(TARGET)\n\n";
if(project->isEmpty("QMAKE_AR_SUBLIBS")) {
- t << destdir_d << "$(TARGET): " << depVar("PRE_TARGETDEPS")
+ t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS")
<< " $(OBJECTS) $(OBJCOMP) " << depVar("POST_TARGETDEPS") << "\n\t";
if(!destdir.isEmpty())
t << mkdir_p_asstring(destdir, false) << "\n\t";
@@ -719,7 +719,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
QString ar;
ProString lib = destdir + escapeFilePath(*libit);
if((*libit) == "$(TARGET)") {
- t << destdir_d << "$(TARGET): " << depVar("PRE_TARGETDEPS")
+ t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS")
<< ' ' << depVar("POST_TARGETDEPS") << valList(escapeDependencyPaths(build)) << "\n\t";
ar = project->first("QMAKE_AR_CMD").toQString();
ar.replace(QLatin1String("$(OBJECTS)"), escapeFilePaths(build).join(' '));
diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp
index 6fcfe96380..95f69dbbc3 100644
--- a/qmake/generators/win32/mingw_make.cpp
+++ b/qmake/generators/win32/mingw_make.cpp
@@ -73,6 +73,19 @@ MingwMakefileGenerator::parseLibFlag(const ProString &flag, ProString *arg)
return MakefileGenerator::parseLibFlag(flag, arg);
}
+bool MingwMakefileGenerator::processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff)
+{
+ if (origName.startsWith("lib")) {
+ QString newFixedBase = fixedBase.left(slashOff) + fixedBase.mid(slashOff + 3);
+ if (Win32MakefileGenerator::processPrlFileBase(origFile, origName,
+ QStringRef(&newFixedBase), slashOff)) {
+ return true;
+ }
+ }
+ return Win32MakefileGenerator::processPrlFileBase(origFile, origName, fixedBase, slashOff);
+}
+
bool MingwMakefileGenerator::writeMakefile(QTextStream &t)
{
writeHeader(t);
@@ -312,8 +325,9 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
{
t << "first: all\n";
t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName()))
- << ' ' << depVar("ALL_DEPS") << " $(DESTDIR_TARGET)\n\n";
- t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
+ << ' ' << depVar("ALL_DEPS") << ' ' << depVar("DEST_TARGET") << "\n\n";
+ t << depVar("DEST_TARGET") << ": "
+ << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
if (project->first("TEMPLATE") == "aux") {
t << "\n\n";
return;
diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h
index 6f041cfd4a..934d28456d 100644
--- a/qmake/generators/win32/mingw_make.h
+++ b/qmake/generators/win32/mingw_make.h
@@ -42,6 +42,8 @@ protected:
using MakefileGenerator::escapeDependencyPath;
virtual QString escapeDependencyPath(const QString &path) const;
virtual ProString fixLibFlag(const ProString &lib);
+ virtual bool processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff);
virtual QString getManifestFileForRcFile() const;
bool writeMakefile(QTextStream &);
void init();
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
index 92b4eb5054..a1e3c08a7e 100644
--- a/qmake/generators/win32/msvc_nmake.cpp
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -584,8 +584,9 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
t << "first: all\n";
t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName()))
- << ' ' << depVar("ALL_DEPS") << " $(DESTDIR_TARGET)\n\n";
- t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
+ << ' ' << depVar("ALL_DEPS") << ' ' << depVar("DEST_TARGET") << "\n\n";
+ t << depVar("DEST_TARGET") << ": "
+ << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
if (templateName == "aux") {
t << "\n\n";
return;
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
index 24d1657552..b812e3a326 100644
--- a/qmake/generators/win32/msvc_vcproj.cpp
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -1617,20 +1617,15 @@ QString VcprojGenerator::replaceExtraCompilerVariables(
bool VcprojGenerator::openOutput(QFile &file, const QString &/*build*/) const
{
- QString outdir;
- if(!file.fileName().isEmpty()) {
- QFileInfo fi(fileInfo(file.fileName()));
- if(fi.isDir())
- outdir = file.fileName() + QDir::separator();
- }
- if(!outdir.isEmpty() || file.fileName().isEmpty()) {
- ProString ext = project->first("VCPROJ_EXTENSION");
- if(project->first("TEMPLATE") == "vcsubdirs")
- ext = project->first("VCSOLUTION_EXTENSION");
- ProString outputName = project->first("TARGET");
- if (!project->first("MAKEFILE").isEmpty())
- outputName = project->first("MAKEFILE");
- file.setFileName(outdir + outputName + ext);
+ ProString fileName = file.fileName();
+ ProString extension = project->first("TEMPLATE") == "vcsubdirs"
+ ? project->first("VCSOLUTION_EXTENSION") : project->first("VCPROJ_EXTENSION");
+ if (!fileName.endsWith(extension)) {
+ if (fileName.isEmpty()) {
+ fileName = !project->first("MAKEFILE").isEmpty()
+ ? project->first("MAKEFILE") : project->first("TARGET");
+ }
+ file.setFileName(fileName + extension);
}
return Win32MakefileGenerator::openOutput(file, QString());
}
diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp
index bca27b7044..318ce50661 100644
--- a/qmake/generators/win32/winmakefile.cpp
+++ b/qmake/generators/win32/winmakefile.cpp
@@ -106,7 +106,7 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin();
dir_it != dirs.end(); ++dir_it) {
QString cand = (*dir_it).real() + Option::dir_sep + lib;
- if (linkPrl && processPrlFile(cand)) {
+ if (linkPrl && processPrlFile(cand, true)) {
(*it) = cand;
goto found;
}
@@ -124,13 +124,13 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
} else if (linkPrl && type == LibFlagFile) {
QString lib = opt.toQString();
if (fileInfo(lib).isAbsolute()) {
- if (processPrlFile(lib))
+ if (processPrlFile(lib, false))
(*it) = lib;
} else {
for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin();
dir_it != dirs.end(); ++dir_it) {
QString cand = (*dir_it).real() + Option::dir_sep + lib;
- if (processPrlFile(cand)) {
+ if (processPrlFile(cand, false)) {
(*it) = cand;
break;
}
@@ -163,6 +163,23 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
return true;
}
+bool Win32MakefileGenerator::processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff)
+{
+ if (MakefileGenerator::processPrlFileBase(origFile, origName, fixedBase, slashOff))
+ return true;
+ for (int off = fixedBase.length(); off > slashOff; off--) {
+ if (!fixedBase.at(off - 1).isDigit()) {
+ if (off != fixedBase.length()) {
+ return MakefileGenerator::processPrlFileBase(
+ origFile, origName, fixedBase.left(off), slashOff);
+ }
+ break;
+ }
+ }
+ return false;
+}
+
void Win32MakefileGenerator::processVars()
{
if (project->first("TEMPLATE").endsWith("aux"))
@@ -563,7 +580,7 @@ void Win32MakefileGenerator::writeStandardParts(QTextStream &t)
t << "DIST = " << fileVarList("DISTFILES") << ' '
<< fileVarList("HEADERS") << ' ' << fileVarList("SOURCES") << endl;
- t << "QMAKE_TARGET = " << fileVar("QMAKE_ORIG_TARGET") << endl;
+ t << "QMAKE_TARGET = " << fileVar("QMAKE_ORIG_TARGET") << endl; // unused
// The comment is important to maintain variable compatibility with Unix
// Makefiles, while not interpreting a trailing-slash as a linebreak
t << "DESTDIR = " << escapeFilePath(destDir) << " #avoid trailing-slash linebreak\n";
diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h
index b85a6b67df..a2a0c9a63c 100644
--- a/qmake/generators/win32/winmakefile.h
+++ b/qmake/generators/win32/winmakefile.h
@@ -58,6 +58,8 @@ protected:
virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg);
virtual ProString fixLibFlag(const ProString &lib);
+ virtual bool processPrlFileBase(QString &origFile, const QStringRef &origName,
+ const QStringRef &fixedBase, int slashOff);
void processVars();
void fixTargetExt();
diff --git a/qmake/library/proitems.h b/qmake/library/proitems.h
index 1d7ebed3aa..fcb6869780 100644
--- a/qmake/library/proitems.h
+++ b/qmake/library/proitems.h
@@ -229,6 +229,55 @@ inline bool operator!=(const QString &that, const ProString &other)
QTextStream &operator<<(QTextStream &t, const ProString &str);
+// This class manages read-only access to a ProString via a raw data QString
+// temporary, ensuring that the latter is accessed exclusively.
+class ProStringRoUser
+{
+public:
+ ProStringRoUser(QString &rs)
+ {
+ Q_ASSERT(rs.isDetached() || rs.isEmpty());
+ m_rs = &rs;
+ }
+ ProStringRoUser(const ProString &ps, QString &rs)
+ : ProStringRoUser(rs)
+ {
+ ps.toQString(rs);
+ }
+ // No destructor, as a RAII pattern cannot be used: references to the
+ // temporary string can legitimately outlive instances of this class
+ // (if they are held by Qt, e.g. in QRegExp).
+ QString &set(const ProString &ps) { return ps.toQString(*m_rs); }
+ QString &str() { return *m_rs; }
+
+protected:
+ QString *m_rs;
+};
+
+// This class manages read-write access to a ProString via a raw data QString
+// temporary, ensuring that the latter is accessed exclusively, and that raw
+// data does not leak outside its source's refcounting.
+class ProStringRwUser : public ProStringRoUser
+{
+public:
+ ProStringRwUser(QString &rs)
+ : ProStringRoUser(rs), m_ps(0) {}
+ ProStringRwUser(const ProString &ps, QString &rs)
+ : ProStringRoUser(ps, rs), m_ps(&ps) {}
+ QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); }
+ ProString extract(const QString &s) const
+ { return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); }
+ ProString extract(const QString &s, const ProStringRwUser &other) const
+ {
+ if (other.m_ps && s.isSharedWith(*other.m_rs))
+ return *other.m_ps;
+ return extract(s);
+ }
+
+private:
+ const ProString *m_ps;
+};
+
class ProStringList : public QVector<ProString> {
public:
ProStringList() {}
diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp
index 6907dfc01d..fda1e1c593 100644
--- a/qmake/library/qmakebuiltins.cpp
+++ b/qmake/library/qmakebuiltins.cpp
@@ -105,109 +105,138 @@ enum TestFunc {
T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE, T_RELOAD_PROPERTIES
};
+QMakeBuiltin::QMakeBuiltin(const QMakeBuiltinInit &d)
+ : index(d.func), minArgs(qMax(0, d.min_args)), maxArgs(d.max_args)
+{
+ static const char * const nstr[6] = { "no", "one", "two", "three", "four", "five" };
+ // For legacy reasons, there is actually no such thing as "no arguments"
+ // - there is only "empty first argument", which needs to be mapped back.
+ // -1 means "one, which may be empty", which is effectively zero, except
+ // for the error message if there are too many arguments.
+ int dmin = qAbs(d.min_args);
+ int dmax = d.max_args;
+ if (dmax == QMakeBuiltinInit::VarArgs) {
+ Q_ASSERT_X(dmin < 2, "init", d.name);
+ if (dmin == 1) {
+ Q_ASSERT_X(d.args != nullptr, "init", d.name);
+ usage = fL1S("%1(%2) requires at least one argument.")
+ .arg(fL1S(d.name), fL1S(d.args));
+ }
+ return;
+ }
+ int arange = dmax - dmin;
+ Q_ASSERT_X(arange >= 0, "init", d.name);
+ Q_ASSERT_X(d.args != nullptr, "init", d.name);
+ usage = arange > 1
+ ? fL1S("%1(%2) requires %3 to %4 arguments.")
+ .arg(fL1S(d.name), fL1S(d.args), fL1S(nstr[dmin]), fL1S(nstr[dmax]))
+ : arange > 0
+ ? fL1S("%1(%2) requires %3 or %4 arguments.")
+ .arg(fL1S(d.name), fL1S(d.args), fL1S(nstr[dmin]), fL1S(nstr[dmax]))
+ : dmax != 1
+ ? fL1S("%1(%2) requires %3 arguments.")
+ .arg(fL1S(d.name), fL1S(d.args), fL1S(nstr[dmax]))
+ : fL1S("%1(%2) requires one argument.")
+ .arg(fL1S(d.name), fL1S(d.args));
+}
+
void QMakeEvaluator::initFunctionStatics()
{
- static const struct {
- const char * const name;
- const ExpandFunc func;
- } expandInits[] = {
- { "member", E_MEMBER },
- { "str_member", E_STR_MEMBER },
- { "first", E_FIRST },
- { "take_first", E_TAKE_FIRST },
- { "last", E_LAST },
- { "take_last", E_TAKE_LAST },
- { "size", E_SIZE },
- { "str_size", E_STR_SIZE },
- { "cat", E_CAT },
- { "fromfile", E_FROMFILE },
- { "eval", E_EVAL },
- { "list", E_LIST },
- { "sprintf", E_SPRINTF },
- { "format_number", E_FORMAT_NUMBER },
- { "num_add", E_NUM_ADD },
- { "join", E_JOIN },
- { "split", E_SPLIT },
- { "basename", E_BASENAME },
- { "dirname", E_DIRNAME },
- { "section", E_SECTION },
- { "find", E_FIND },
- { "system", E_SYSTEM },
- { "unique", E_UNIQUE },
- { "sorted", E_SORTED },
- { "reverse", E_REVERSE },
- { "quote", E_QUOTE },
- { "escape_expand", E_ESCAPE_EXPAND },
- { "upper", E_UPPER },
- { "lower", E_LOWER },
- { "title", E_TITLE },
- { "re_escape", E_RE_ESCAPE },
- { "val_escape", E_VAL_ESCAPE },
- { "files", E_FILES },
- { "prompt", E_PROMPT },
- { "replace", E_REPLACE },
- { "sort_depends", E_SORT_DEPENDS },
- { "resolve_depends", E_RESOLVE_DEPENDS },
- { "enumerate_vars", E_ENUMERATE_VARS },
- { "shadowed", E_SHADOWED },
- { "absolute_path", E_ABSOLUTE_PATH },
- { "relative_path", E_RELATIVE_PATH },
- { "clean_path", E_CLEAN_PATH },
- { "system_path", E_SYSTEM_PATH },
- { "shell_path", E_SHELL_PATH },
- { "system_quote", E_SYSTEM_QUOTE },
- { "shell_quote", E_SHELL_QUOTE },
- { "getenv", E_GETENV },
+ static const QMakeBuiltinInit expandInits[] = {
+ { "member", E_MEMBER, 1, 3, "var, [start, [end]]" },
+ { "str_member", E_STR_MEMBER, -1, 3, "str, [start, [end]]" },
+ { "first", E_FIRST, 1, 1, "var" },
+ { "take_first", E_TAKE_FIRST, 1, 1, "var" },
+ { "last", E_LAST, 1, 1, "var" },
+ { "take_last", E_TAKE_LAST, 1, 1, "var" },
+ { "size", E_SIZE, 1, 1, "var" },
+ { "str_size", E_STR_SIZE, -1, 1, "str" },
+ { "cat", E_CAT, 1, 2, "file, [mode=true|blob|lines]" },
+ { "fromfile", E_FROMFILE, 2, 2, "file, var" },
+ { "eval", E_EVAL, 1, 1, "var" },
+ { "list", E_LIST, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "sprintf", E_SPRINTF, 1, QMakeBuiltinInit::VarArgs, "format, ..." },
+ { "format_number", E_FORMAT_NUMBER, 1, 2, "number, [options...]" },
+ { "num_add", E_NUM_ADD, 1, QMakeBuiltinInit::VarArgs, "num, ..." },
+ { "join", E_JOIN, 1, 4, "var, [glue, [before, [after]]]" },
+ { "split", E_SPLIT, 1, 2, "var, sep" },
+ { "basename", E_BASENAME, 1, 1, "var" },
+ { "dirname", E_DIRNAME, 1, 1, "var" },
+ { "section", E_SECTION, 3, 4, "var, sep, begin, [end]" },
+ { "find", E_FIND, 2, 2, "var, str" },
+ { "system", E_SYSTEM, 1, 3, "command, [mode], [stsvar]" },
+ { "unique", E_UNIQUE, 1, 1, "var" },
+ { "sorted", E_SORTED, 1, 1, "var" },
+ { "reverse", E_REVERSE, 1, 1, "var" },
+ { "quote", E_QUOTE, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "escape_expand", E_ESCAPE_EXPAND, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "upper", E_UPPER, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "lower", E_LOWER, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "title", E_TITLE, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "re_escape", E_RE_ESCAPE, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "val_escape", E_VAL_ESCAPE, 1, 1, "var" },
+ { "files", E_FILES, 1, 2, "pattern, [recursive=false]" },
+ { "prompt", E_PROMPT, 1, 2, "question, [decorate=true]" },
+ { "replace", E_REPLACE, 3, 3, "var, before, after" },
+ { "sort_depends", E_SORT_DEPENDS, 1, 4, "var, [prefix, [suffixes, [prio-suffix]]]" },
+ { "resolve_depends", E_RESOLVE_DEPENDS, 1, 4, "var, [prefix, [suffixes, [prio-suffix]]]" },
+ { "enumerate_vars", E_ENUMERATE_VARS, 0, 0, "" },
+ { "shadowed", E_SHADOWED, 1, 1, "path" },
+ { "absolute_path", E_ABSOLUTE_PATH, -1, 2, "path, [base]" },
+ { "relative_path", E_RELATIVE_PATH, -1, 2, "path, [base]" },
+ { "clean_path", E_CLEAN_PATH, -1, 1, "path" },
+ { "system_path", E_SYSTEM_PATH, -1, 1, "path" },
+ { "shell_path", E_SHELL_PATH, -1, 1, "path" },
+ { "system_quote", E_SYSTEM_QUOTE, -1, 1, "arg" },
+ { "shell_quote", E_SHELL_QUOTE, -1, 1, "arg" },
+ { "getenv", E_GETENV, 1, 1, "arg" },
};
statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0])));
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
- statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func);
+ statics.expands.insert(ProKey(expandInits[i].name), QMakeBuiltin(expandInits[i]));
- static const struct {
- const char * const name;
- const TestFunc func;
- } testInits[] = {
- { "requires", T_REQUIRES },
- { "greaterThan", T_GREATERTHAN },
- { "lessThan", T_LESSTHAN },
- { "equals", T_EQUALS },
- { "isEqual", T_EQUALS },
- { "versionAtLeast", T_VERSION_AT_LEAST },
- { "versionAtMost", T_VERSION_AT_MOST },
- { "exists", T_EXISTS },
- { "export", T_EXPORT },
- { "clear", T_CLEAR },
- { "unset", T_UNSET },
- { "eval", T_EVAL },
- { "CONFIG", T_CONFIG },
- { "if", T_IF },
- { "isActiveConfig", T_CONFIG },
- { "system", T_SYSTEM },
- { "discard_from", T_DISCARD_FROM },
- { "defined", T_DEFINED },
- { "contains", T_CONTAINS },
- { "infile", T_INFILE },
- { "count", T_COUNT },
- { "isEmpty", T_ISEMPTY },
+ static const QMakeBuiltinInit testInits[] = {
+ { "requires", T_REQUIRES, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "greaterThan", T_GREATERTHAN, 2, 2, "var, val" },
+ { "lessThan", T_LESSTHAN, 2, 2, "var, val" },
+ { "equals", T_EQUALS, 2, 2, "var, val" },
+ { "isEqual", T_EQUALS, 2, 2, "var, val" },
+ { "versionAtLeast", T_VERSION_AT_LEAST, 2, 2, "var, version" },
+ { "versionAtMost", T_VERSION_AT_MOST, 2, 2, "var, version" },
+ { "exists", T_EXISTS, 1, 1, "file" },
+ { "export", T_EXPORT, 1, 1, "var" },
+ { "clear", T_CLEAR, 1, 1, "var" },
+ { "unset", T_UNSET, 1, 1, "var" },
+ { "eval", T_EVAL, 0, QMakeBuiltinInit::VarArgs, nullptr },
+ { "CONFIG", T_CONFIG, 1, 2, "config, [mutuals]" },
+ { "if", T_IF, 1, 1, "condition" },
+ { "isActiveConfig", T_CONFIG, 1, 2, "config, [mutuals]" },
+ { "system", T_SYSTEM, 1, 1, "exec" },
+ { "discard_from", T_DISCARD_FROM, 1, 1, "file" },
+ { "defined", T_DEFINED, 1, 2, "object, [\"test\"|\"replace\"|\"var\"]" },
+ { "contains", T_CONTAINS, 2, 3, "var, val, [mutuals]" },
+ { "infile", T_INFILE, 2, 3, "file, var, [values]" },
+ { "count", T_COUNT, 2, 3, "var, count, [op=operator]" },
+ { "isEmpty", T_ISEMPTY, 1, 1, "var" },
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
- { "parseJson", T_PARSE_JSON },
+ { "parseJson", T_PARSE_JSON, 2, 2, "var, into" },
#endif
- { "load", T_LOAD },
- { "include", T_INCLUDE },
- { "debug", T_DEBUG },
- { "log", T_LOG },
- { "message", T_MESSAGE },
- { "warning", T_WARNING },
- { "error", T_ERROR },
- { "mkpath", T_MKPATH },
- { "write_file", T_WRITE_FILE },
- { "touch", T_TOUCH },
- { "cache", T_CACHE },
- { "reload_properties", T_RELOAD_PROPERTIES },
+ { "load", T_LOAD, 1, 2, "feature, [ignore_errors=false]" },
+ { "include", T_INCLUDE, 1, 3, "file, [into, [silent]]" },
+ { "debug", T_DEBUG, 2, 2, "level, message" },
+ { "log", T_LOG, 1, 1, "message" },
+ { "message", T_MESSAGE, 1, 1, "message" },
+ { "warning", T_WARNING, 1, 1, "message" },
+ { "error", T_ERROR, 0, 1, "message" },
+ { "mkpath", T_MKPATH, 1, 1, "path" },
+ { "write_file", T_WRITE_FILE, 1, 3, "name, [content var, [append] [exe]]" },
+ { "touch", T_TOUCH, 2, 2, "file, reffile" },
+ { "cache", T_CACHE, 0, 3, "[var], [set|add|sub] [transient] [super|stash], [srcvar]" },
+ { "reload_properties", T_RELOAD_PROPERTIES, 0, 0, "" },
};
statics.functions.reserve((int)(sizeof(testInits)/sizeof(testInits[0])));
for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
- statics.functions.insert(ProKey(testInits[i].name), testInits[i].func);
+ statics.functions.insert(ProKey(testInits[i].name), QMakeBuiltin(testInits[i]));
}
static bool isTrue(const ProString &str)
@@ -234,8 +263,9 @@ QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringLis
}
}
if (!ok) {
- evalError(fL1S("%1() argument 2 (start) '%2' invalid.")
- .arg(func.toQString(m_tmp1), start_str.toQString(m_tmp2)));
+ ProStringRoUser u1(func, m_tmp1);
+ ProStringRoUser u2(start_str, m_tmp2);
+ evalError(fL1S("%1() argument 2 (start) '%2' invalid.").arg(u1.str(), u2.str()));
return false;
}
} else {
@@ -243,8 +273,9 @@ QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringLis
if (args.count() == 3)
*end = args.at(2).toInt(&ok);
if (!ok) {
- evalError(fL1S("%1() argument 3 (end) '%2' invalid.")
- .arg(func.toQString(m_tmp1), args.at(2).toQString(m_tmp2)));
+ ProStringRoUser u1(func, m_tmp1);
+ ProStringRoUser u2(args.at(2), m_tmp2);
+ evalError(fL1S("%1() argument 3 (end) '%2' invalid.").arg(u1.str(), u2.str()));
return false;
}
}
@@ -550,11 +581,33 @@ void QMakeEvaluator::populateDeps(
}
}
+QString QMakeEvaluator::filePathArg0(const ProStringList &args)
+{
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ QString fn = resolvePath(u1.str());
+ fn.detach();
+ return fn;
+}
+
+QString QMakeEvaluator::filePathEnvArg0(const ProStringList &args)
+{
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ QString fn = resolvePath(m_option->expandEnvVars(u1.str()));
+ fn.detach();
+ return fn;
+}
+
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
- int func_t, const ProKey &func, const ProStringList &args, ProStringList &ret)
+ const QMakeBuiltin &adef, const ProKey &func, const ProStringList &args, ProStringList &ret)
{
traceMsg("calling built-in $$%s(%s)", dbgKey(func), dbgSepStrList(args));
+ int asz = args.size() > 1 ? args.size() : args.at(0).isEmpty() ? 0 : 1;
+ if (asz < adef.minArgs || asz > adef.maxArgs) {
+ evalError(adef.usage);
+ return ReturnTrue;
+ }
+ int func_t = adef.index;
switch (func_t) {
case E_BASENAME:
case E_DIRNAME:
@@ -565,319 +618,264 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
int beg = 0;
int end = -1;
if (func_t == E_SECTION) {
- if (args.count() != 3 && args.count() != 4) {
- evalError(fL1S("section(var, sep, begin, end) requires three or four arguments."));
- } else {
- var = args[0];
- sep = args.at(1).toQString();
- beg = args.at(2).toInt();
- if (args.count() == 4)
- end = args.at(3).toInt();
- }
+ var = args[0];
+ sep = args.at(1).toQString();
+ beg = args.at(2).toInt();
+ if (args.count() == 4)
+ end = args.at(3).toInt();
} else {
- if (args.count() != 1) {
- evalError(fL1S("%1(var) requires one argument.").arg(func.toQStringView()));
- } else {
- var = args[0];
- regexp = true;
- sep = QLatin1String("[\\\\/]");
- if (func_t == E_DIRNAME)
- end = -2;
- else
- beg = -1;
- }
+ var = args[0];
+ regexp = true;
+ sep = QLatin1String("[\\\\/]");
+ if (func_t == E_DIRNAME)
+ end = -2;
+ else
+ beg = -1;
}
if (!var.isEmpty()) {
const auto strings = values(map(var));
if (regexp) {
QRegExp sepRx(sep);
for (const ProString &str : strings) {
- const QString &rstr = str.toQString(m_tmp[m_toggle ^= 1]).section(sepRx, beg, end);
- ret << (rstr.isSharedWith(m_tmp[m_toggle]) ? str : ProString(rstr).setSource(str));
+ ProStringRwUser u1(str, m_tmp[m_toggle ^= 1]);
+ ret << u1.extract(u1.str().section(sepRx, beg, end));
}
} else {
for (const ProString &str : strings) {
- const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
- ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
+ ProStringRwUser u1(str, m_tmp1);
+ ret << u1.extract(u1.str().section(sep, beg, end));
}
}
}
break;
}
- case E_SPRINTF:
- if (args.count() < 1) {
- evalError(fL1S("sprintf(format, ...) requires at least one argument."));
- } else {
- QString tmp = args.at(0).toQString(m_tmp1);
- for (int i = 1; i < args.count(); ++i)
- tmp = tmp.arg(args.at(i).toQStringView());
- ret << (tmp.isSharedWith(m_tmp1) ? args.at(0) : ProString(tmp).setSource(args.at(0)));
- }
+ case E_SPRINTF: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ QString tmp = u1.str();
+ for (int i = 1; i < args.count(); ++i)
+ tmp = tmp.arg(args.at(i).toQStringView());
+ ret << u1.extract(tmp);
break;
- case E_FORMAT_NUMBER:
- if (args.count() > 2) {
- evalError(fL1S("format_number(number[, options...]) requires one or two arguments."));
- } else {
- int ibase = 10;
- int obase = 10;
- int width = 0;
- bool zeropad = false;
- bool leftalign = false;
- enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
- if (args.count() >= 2) {
- const auto opts = split_value_list(args.at(1).toQStringRef());
- for (const ProString &opt : opts) {
- if (opt.startsWith(QLatin1String("ibase="))) {
- ibase = opt.mid(6).toInt();
- } else if (opt.startsWith(QLatin1String("obase="))) {
- obase = opt.mid(6).toInt();
- } else if (opt.startsWith(QLatin1String("width="))) {
- width = opt.mid(6).toInt();
- } else if (opt == QLatin1String("zeropad")) {
- zeropad = true;
- } else if (opt == QLatin1String("padsign")) {
- sign = PadSign;
- } else if (opt == QLatin1String("alwayssign")) {
- sign = AlwaysSign;
- } else if (opt == QLatin1String("leftalign")) {
- leftalign = true;
- } else {
- evalError(fL1S("format_number(): invalid format option %1.")
- .arg(opt.toQStringView()));
- goto formfail;
- }
+ }
+ case E_FORMAT_NUMBER: {
+ int ibase = 10;
+ int obase = 10;
+ int width = 0;
+ bool zeropad = false;
+ bool leftalign = false;
+ enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
+ if (args.count() >= 2) {
+ const auto opts = split_value_list(args.at(1).toQStringRef());
+ for (const ProString &opt : opts) {
+ if (opt.startsWith(QLatin1String("ibase="))) {
+ ibase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("obase="))) {
+ obase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("width="))) {
+ width = opt.mid(6).toInt();
+ } else if (opt == QLatin1String("zeropad")) {
+ zeropad = true;
+ } else if (opt == QLatin1String("padsign")) {
+ sign = PadSign;
+ } else if (opt == QLatin1String("alwayssign")) {
+ sign = AlwaysSign;
+ } else if (opt == QLatin1String("leftalign")) {
+ leftalign = true;
+ } else {
+ evalError(fL1S("format_number(): invalid format option %1.")
+ .arg(opt.toQStringView()));
+ goto allfail;
}
}
- if (args.at(0).contains(QLatin1Char('.'))) {
- evalError(fL1S("format_number(): floats are currently not supported."));
- break;
+ }
+ if (args.at(0).contains(QLatin1Char('.'))) {
+ evalError(fL1S("format_number(): floats are currently not supported."));
+ break;
+ }
+ bool ok;
+ qlonglong num = args.at(0).toLongLong(&ok, ibase);
+ if (!ok) {
+ evalError(fL1S("format_number(): malformed number %2 for base %1.")
+ .arg(ibase).arg(args.at(0).toQStringView()));
+ break;
+ }
+ QString outstr;
+ if (num < 0) {
+ num = -num;
+ outstr = QLatin1Char('-');
+ } else if (sign == AlwaysSign) {
+ outstr = QLatin1Char('+');
+ } else if (sign == PadSign) {
+ outstr = QLatin1Char(' ');
+ }
+ QString numstr = QString::number(num, obase);
+ int space = width - outstr.length() - numstr.length();
+ if (space <= 0) {
+ outstr += numstr;
+ } else if (leftalign) {
+ outstr += numstr + QString(space, QLatin1Char(' '));
+ } else if (zeropad) {
+ outstr += QString(space, QLatin1Char('0')) + numstr;
+ } else {
+ outstr.prepend(QString(space, QLatin1Char(' ')));
+ outstr += numstr;
+ }
+ ret += ProString(outstr);
+ break;
+ }
+ case E_NUM_ADD: {
+ qlonglong sum = 0;
+ for (const ProString &arg : qAsConst(args)) {
+ if (arg.contains(QLatin1Char('.'))) {
+ evalError(fL1S("num_add(): floats are currently not supported."));
+ goto allfail;
}
bool ok;
- qlonglong num = args.at(0).toLongLong(&ok, ibase);
+ qlonglong num = arg.toLongLong(&ok);
if (!ok) {
- evalError(fL1S("format_number(): malformed number %2 for base %1.")
- .arg(ibase).arg(args.at(0).toQStringView()));
- break;
- }
- QString outstr;
- if (num < 0) {
- num = -num;
- outstr = QLatin1Char('-');
- } else if (sign == AlwaysSign) {
- outstr = QLatin1Char('+');
- } else if (sign == PadSign) {
- outstr = QLatin1Char(' ');
- }
- QString numstr = QString::number(num, obase);
- int space = width - outstr.length() - numstr.length();
- if (space <= 0) {
- outstr += numstr;
- } else if (leftalign) {
- outstr += numstr + QString(space, QLatin1Char(' '));
- } else if (zeropad) {
- outstr += QString(space, QLatin1Char('0')) + numstr;
- } else {
- outstr.prepend(QString(space, QLatin1Char(' ')));
- outstr += numstr;
+ evalError(fL1S("num_add(): malformed number %1.")
+ .arg(arg.toQStringView()));
+ goto allfail;
}
- ret += ProString(outstr);
+ sum += num;
}
- formfail:
- break;
- case E_NUM_ADD:
- if (args.count() < 1 || args.at(0).isEmpty()) {
- evalError(fL1S("num_add(num, ...) requires at least one argument."));
- } else {
- qlonglong sum = 0;
- for (const ProString &arg : qAsConst(args)) {
- if (arg.contains(QLatin1Char('.'))) {
- evalError(fL1S("num_add(): floats are currently not supported."));
- goto nafail;
- }
- bool ok;
- qlonglong num = arg.toLongLong(&ok);
- if (!ok) {
- evalError(fL1S("num_add(): malformed number %1.")
- .arg(arg.toQStringView()));
- goto nafail;
- }
- sum += num;
- }
- ret += ProString(QString::number(sum));
- }
- nafail:
+ ret += ProString(QString::number(sum));
break;
+ }
case E_JOIN: {
- if (args.count() < 1 || args.count() > 4) {
- evalError(fL1S("join(var, glue, before, after) requires one to four arguments."));
- } else {
- ProString glue, before, after;
- if (args.count() >= 2)
- glue = args.at(1);
- if (args.count() >= 3)
- before = args[2];
- if (args.count() == 4)
- after = args[3];
- const ProStringList &var = values(map(args.at(0)));
- if (!var.isEmpty()) {
- int src = currentFileId();
- for (const ProString &v : var)
- if (int s = v.sourceFile()) {
- src = s;
- break;
- }
- ret << ProString(before + var.join(glue) + after).setSource(src);
- }
+ ProString glue, before, after;
+ if (args.count() >= 2)
+ glue = args.at(1);
+ if (args.count() >= 3)
+ before = args[2];
+ if (args.count() == 4)
+ after = args[3];
+ const ProStringList &var = values(map(args.at(0)));
+ if (!var.isEmpty()) {
+ int src = currentFileId();
+ for (const ProString &v : var)
+ if (int s = v.sourceFile()) {
+ src = s;
+ break;
+ }
+ ret << ProString(before + var.join(glue) + after).setSource(src);
}
break;
}
- case E_SPLIT:
- if (args.count() < 1 || args.count() > 2) {
- evalError(fL1S("split(var, sep) requires one or two arguments."));
- } else {
- const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
- const auto vars = values(map(args.at(0)));
- for (const ProString &var : vars) {
- // FIXME: this is inconsistent with the "there are no empty strings" dogma.
- const auto splits = var.toQStringRef().split(sep, QString::KeepEmptyParts);
- for (const auto &splt : splits)
- ret << ProString(splt).setSource(var);
- }
+ case E_SPLIT: {
+ ProStringRoUser u1(m_tmp1);
+ const QString &sep = (args.count() == 2) ? u1.set(args.at(1)) : statics.field_sep;
+ const auto vars = values(map(args.at(0)));
+ for (const ProString &var : vars) {
+ // FIXME: this is inconsistent with the "there are no empty strings" dogma.
+ const auto splits = var.toQStringRef().split(sep, QString::KeepEmptyParts);
+ for (const auto &splt : splits)
+ ret << ProString(splt).setSource(var);
}
break;
- case E_MEMBER:
- if (args.count() < 1 || args.count() > 3) {
- evalError(fL1S("member(var, start, end) requires one to three arguments."));
- } else {
- const ProStringList &src = values(map(args.at(0)));
- int start, end;
- if (getMemberArgs(func, src.size(), args, &start, &end)) {
- ret.reserve(qAbs(end - start) + 1);
- if (start < end) {
- for (int i = start; i <= end && src.size() >= i; i++)
- ret += src.at(i);
- } else {
- for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
- ret += src.at(i);
- }
+ }
+ case E_MEMBER: {
+ const ProStringList &src = values(map(args.at(0)));
+ int start, end;
+ if (getMemberArgs(func, src.size(), args, &start, &end)) {
+ ret.reserve(qAbs(end - start) + 1);
+ if (start < end) {
+ for (int i = start; i <= end && src.size() >= i; i++)
+ ret += src.at(i);
+ } else {
+ for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
+ ret += src.at(i);
}
}
break;
- case E_STR_MEMBER:
- if (args.count() < 1 || args.count() > 3) {
- evalError(fL1S("str_member(str, start, end) requires one to three arguments."));
- } else {
- const ProString &src = args.at(0);
- int start, end;
- if (getMemberArgs(func, src.size(), args, &start, &end)) {
- QString res;
- res.reserve(qAbs(end - start) + 1);
- if (start < end) {
- for (int i = start; i <= end && src.size() >= i; i++)
- res += src.at(i);
- } else {
- for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
- res += src.at(i);
- }
- ret += ProString(res);
+ }
+ case E_STR_MEMBER: {
+ const ProString &src = args.at(0);
+ int start, end;
+ if (getMemberArgs(func, src.size(), args, &start, &end)) {
+ QString res;
+ res.reserve(qAbs(end - start) + 1);
+ if (start < end) {
+ for (int i = start; i <= end && src.size() >= i; i++)
+ res += src.at(i);
+ } else {
+ for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
+ res += src.at(i);
}
+ ret += ProString(res);
}
break;
+ }
case E_FIRST:
- case E_LAST:
- if (args.count() != 1) {
- evalError(fL1S("%1(var) requires one argument.").arg(func.toQStringView()));
- } else {
- const ProStringList &var = values(map(args.at(0)));
- if (!var.isEmpty()) {
- if (func_t == E_FIRST)
- ret.append(var[0]);
- else
- ret.append(var.last());
- }
+ case E_LAST: {
+ const ProStringList &var = values(map(args.at(0)));
+ if (!var.isEmpty()) {
+ if (func_t == E_FIRST)
+ ret.append(var[0]);
+ else
+ ret.append(var.last());
}
break;
+ }
case E_TAKE_FIRST:
- case E_TAKE_LAST:
- if (args.count() != 1) {
- evalError(fL1S("%1(var) requires one argument.").arg(func.toQStringView()));
- } else {
- ProStringList &var = valuesRef(map(args.at(0)));
- if (!var.isEmpty()) {
- if (func_t == E_TAKE_FIRST)
- ret.append(var.takeFirst());
- else
- ret.append(var.takeLast());
- }
+ case E_TAKE_LAST: {
+ ProStringList &var = valuesRef(map(args.at(0)));
+ if (!var.isEmpty()) {
+ if (func_t == E_TAKE_FIRST)
+ ret.append(var.takeFirst());
+ else
+ ret.append(var.takeLast());
}
break;
+ }
case E_SIZE:
- if (args.count() != 1)
- evalError(fL1S("size(var) requires one argument."));
- else
- ret.append(ProString(QString::number(values(map(args.at(0))).size())));
+ ret.append(ProString(QString::number(values(map(args.at(0))).size())));
break;
case E_STR_SIZE:
- if (args.count() != 1)
- evalError(fL1S("str_size(str) requires one argument."));
- else
- ret.append(ProString(QString::number(args.at(0).size())));
+ ret.append(ProString(QString::number(args.at(0).size())));
break;
- case E_CAT:
- if (args.count() < 1 || args.count() > 2) {
- evalError(fL1S("cat(file, singleline=true) requires one or two arguments."));
- } else {
- QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
- fn.detach();
-
- bool blob = false;
- bool lines = false;
- bool singleLine = true;
- if (args.count() > 1) {
- if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
- singleLine = false;
- else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
- blob = true;
- else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
- lines = true;
- }
-
- QFile qfile(fn);
- if (qfile.open(QIODevice::ReadOnly)) {
- QTextStream stream(&qfile);
- if (blob) {
- ret += ProString(stream.readAll());
- } else {
- while (!stream.atEnd()) {
- if (lines) {
- ret += ProString(stream.readLine());
- } else {
- const QString &line = stream.readLine();
- ret += split_value_list(QStringRef(&line).trimmed());
- if (!singleLine)
- ret += ProString("\n");
- }
+ case E_CAT: {
+ bool blob = false;
+ bool lines = false;
+ bool singleLine = true;
+ if (args.count() > 1) {
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
+ singleLine = false;
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ blob = true;
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ lines = true;
+ }
+ QString fn = filePathEnvArg0(args);
+ QFile qfile(fn);
+ if (qfile.open(QIODevice::ReadOnly)) {
+ QTextStream stream(&qfile);
+ if (blob) {
+ ret += ProString(stream.readAll());
+ } else {
+ while (!stream.atEnd()) {
+ if (lines) {
+ ret += ProString(stream.readLine());
+ } else {
+ const QString &line = stream.readLine();
+ ret += split_value_list(QStringRef(&line).trimmed());
+ if (!singleLine)
+ ret += ProString("\n");
}
}
}
}
break;
- case E_FROMFILE:
- if (args.count() != 2) {
- evalError(fL1S("fromfile(file, variable) requires two arguments."));
- } else {
- ProValueMap vars;
- QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
- fn.detach();
- if (evaluateFileInto(fn, &vars, LoadProOnly) == ReturnTrue)
- ret = vars.value(map(args.at(1)));
- }
+ }
+ case E_FROMFILE: {
+ ProValueMap vars;
+ QString fn = filePathEnvArg0(args);
+ if (evaluateFileInto(fn, &vars, LoadProOnly) == ReturnTrue)
+ ret = vars.value(map(args.at(1)));
break;
+ }
case E_EVAL:
- if (args.count() != 1)
- evalError(fL1S("eval(variable) requires one argument."));
- else
- ret += values(map(args.at(0)));
+ ret += values(map(args.at(0)));
break;
case E_LIST: {
QString tmp;
@@ -888,84 +886,68 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
lst += split_value_list(arg.toQStringRef(), arg.sourceFile()); // Relies on deep copy
m_valuemapStack.top()[ret.at(0).toKey()] = lst;
break; }
- case E_FIND:
- if (args.count() != 2) {
- evalError(fL1S("find(var, str) requires two arguments."));
- } else {
- QRegExp regx(args.at(1).toQString());
- const auto vals = values(map(args.at(0)));
- for (const ProString &val : vals) {
- if (regx.indexIn(val.toQString(m_tmp[m_toggle ^= 1])) != -1)
- ret += val;
- }
+ case E_FIND: {
+ QRegExp regx(args.at(1).toQString());
+ const auto vals = values(map(args.at(0)));
+ for (const ProString &val : vals) {
+ ProStringRoUser u1(val, m_tmp[m_toggle ^= 1]);
+ if (regx.indexIn(u1.str()) != -1)
+ ret += val;
}
break;
- case E_SYSTEM:
- if (!m_skipLevel) {
- if (args.count() < 1 || args.count() > 3) {
- evalError(fL1S("system(command, [mode], [stsvar]) requires one to three arguments."));
+ }
+ case E_SYSTEM: {
+ if (m_skipLevel)
+ break;
+ bool blob = false;
+ bool lines = false;
+ bool singleLine = true;
+ if (args.count() > 1) {
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
+ singleLine = false;
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ blob = true;
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ lines = true;
+ }
+ int exitCode;
+ QByteArray bytes = getCommandOutput(args.at(0).toQString(), &exitCode);
+ if (args.count() > 2 && !args.at(2).isEmpty()) {
+ m_valuemapStack.top()[args.at(2).toKey()] =
+ ProStringList(ProString(QString::number(exitCode)));
+ }
+ if (lines) {
+ QTextStream stream(bytes);
+ while (!stream.atEnd())
+ ret += ProString(stream.readLine());
+ } else {
+ QString output = QString::fromLocal8Bit(bytes);
+ if (blob) {
+ ret += ProString(output);
} else {
- bool blob = false;
- bool lines = false;
- bool singleLine = true;
- if (args.count() > 1) {
- if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
- singleLine = false;
- else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
- blob = true;
- else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
- lines = true;
- }
- int exitCode;
- QByteArray bytes = getCommandOutput(args.at(0).toQString(), &exitCode);
- if (args.count() > 2 && !args.at(2).isEmpty()) {
- m_valuemapStack.top()[args.at(2).toKey()] =
- ProStringList(ProString(QString::number(exitCode)));
- }
- if (lines) {
- QTextStream stream(bytes);
- while (!stream.atEnd())
- ret += ProString(stream.readLine());
- } else {
- QString output = QString::fromLocal8Bit(bytes);
- if (blob) {
- ret += ProString(output);
- } else {
- output.replace(QLatin1Char('\t'), QLatin1Char(' '));
- if (singleLine)
- output.replace(QLatin1Char('\n'), QLatin1Char(' '));
- ret += split_value_list(QStringRef(&output));
- }
- }
+ output.replace(QLatin1Char('\t'), QLatin1Char(' '));
+ if (singleLine)
+ output.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ ret += split_value_list(QStringRef(&output));
}
}
break;
+ }
case E_UNIQUE:
- if (args.count() != 1) {
- evalError(fL1S("unique(var) requires one argument."));
- } else {
- ret = values(map(args.at(0)));
- ret.removeDuplicates();
- }
+ ret = values(map(args.at(0)));
+ ret.removeDuplicates();
break;
case E_SORTED:
- if (args.count() != 1) {
- evalError(fL1S("sorted(var) requires one argument."));
- } else {
- ret = values(map(args.at(0)));
- std::sort(ret.begin(), ret.end());
- }
+ ret = values(map(args.at(0)));
+ std::sort(ret.begin(), ret.end());
break;
- case E_REVERSE:
- if (args.count() != 1) {
- evalError(fL1S("reverse(var) requires one argument."));
- } else {
- ProStringList var = values(args.at(0).toKey());
- for (int i = 0; i < var.size() / 2; i++)
- qSwap(var[i], var[var.size() - i - 1]);
- ret += var;
- }
+ case E_REVERSE: {
+ ProStringList var = values(args.at(0).toKey());
+ for (int i = 0; i < var.size() / 2; i++)
+ qSwap(var[i], var[var.size() - i - 1]);
+ ret += var;
break;
+ }
case E_QUOTE:
ret += args;
break;
@@ -1004,25 +986,23 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
break;
case E_RE_ESCAPE:
for (int i = 0; i < args.size(); ++i) {
- const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1));
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
+ ProStringRwUser u1(args.at(i), m_tmp1);
+ ret << u1.extract(QRegExp::escape(u1.str()));
}
break;
- case E_VAL_ESCAPE:
- if (args.count() != 1) {
- evalError(fL1S("val_escape(var) requires one argument."));
- } else {
- const ProStringList &vals = values(args.at(0).toKey());
- ret.reserve(vals.size());
- for (const ProString &str : vals)
- ret += ProString(quoteValue(str));
- }
+ case E_VAL_ESCAPE: {
+ const ProStringList &vals = values(args.at(0).toKey());
+ ret.reserve(vals.size());
+ for (const ProString &str : vals)
+ ret += ProString(quoteValue(str));
break;
+ }
case E_UPPER:
case E_LOWER:
case E_TITLE:
for (int i = 0; i < args.count(); ++i) {
- QString rstr = args.at(i).toQString(m_tmp1);
+ ProStringRwUser u1(args.at(i), m_tmp1);
+ QString rstr = u1.str();
if (func_t == E_UPPER) {
rstr = rstr.toUpper();
} else {
@@ -1030,134 +1010,119 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
if (func_t == E_TITLE && rstr.length() > 0)
rstr[0] = rstr.at(0).toTitleCase();
}
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
+ ret << u1.extract(rstr);
}
break;
- case E_FILES:
- if (args.count() != 1 && args.count() != 2) {
- evalError(fL1S("files(pattern, recursive=false) requires one or two arguments."));
+ case E_FILES: {
+ bool recursive = false;
+ if (args.count() == 2)
+ recursive = isTrue(args.at(1));
+ QStringList dirs;
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ QString r = m_option->expandEnvVars(u1.str())
+ .replace(QLatin1Char('\\'), QLatin1Char('/'));
+ QString pfx;
+ if (IoUtils::isRelativePath(r)) {
+ pfx = currentDirectory();
+ if (!pfx.endsWith(QLatin1Char('/')))
+ pfx += QLatin1Char('/');
+ }
+ int slash = r.lastIndexOf(QLatin1Char('/'));
+ if (slash != -1) {
+ dirs.append(r.left(slash+1));
+ r = r.mid(slash+1);
} else {
- bool recursive = false;
- if (args.count() == 2)
- recursive = isTrue(args.at(1));
- QStringList dirs;
- QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1))
- .replace(QLatin1Char('\\'), QLatin1Char('/'));
- QString pfx;
- if (IoUtils::isRelativePath(r)) {
- pfx = currentDirectory();
- if (!pfx.endsWith(QLatin1Char('/')))
- pfx += QLatin1Char('/');
- }
- int slash = r.lastIndexOf(QLatin1Char('/'));
- if (slash != -1) {
- dirs.append(r.left(slash+1));
- r = r.mid(slash+1);
- } else {
- dirs.append(QString());
- }
+ dirs.append(QString());
+ }
- r.detach(); // Keep m_tmp out of QRegExp's cache
- QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
- for (int d = 0; d < dirs.count(); d++) {
- QString dir = dirs[d];
- QDir qdir(pfx + dir);
- for (int i = 0; i < (int)qdir.count(); ++i) {
- if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
- continue;
- QString fname = dir + qdir[i];
- if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) {
- if (recursive)
- dirs.append(fname + QLatin1Char('/'));
- }
- if (regex.exactMatch(qdir[i]))
- ret += ProString(fname).setSource(currentFileId());
+ r.detach(); // Keep m_tmp out of QRegExp's cache
+ QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
+ for (int d = 0; d < dirs.count(); d++) {
+ QString dir = dirs[d];
+ QDir qdir(pfx + dir);
+ for (int i = 0; i < (int)qdir.count(); ++i) {
+ if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
+ continue;
+ QString fname = dir + qdir[i];
+ if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) {
+ if (recursive)
+ dirs.append(fname + QLatin1Char('/'));
}
+ if (regex.exactMatch(qdir[i]))
+ ret += ProString(fname).setSource(currentFileId());
}
}
break;
+ }
#ifdef PROEVALUATOR_FULL
case E_PROMPT: {
- if (args.count() != 1 && args.count() != 2) {
- evalError(fL1S("prompt(question, [decorate=true]) requires one or two arguments."));
-// } else if (currentFileName() == QLatin1String("-")) {
-// evalError(fL1S("prompt(question) cannot be used when '-o -' is used"));
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ QString msg = m_option->expandEnvVars(u1.str());
+ bool decorate = true;
+ if (args.count() == 2)
+ decorate = isTrue(args.at(1));
+ if (decorate) {
+ if (!msg.endsWith(QLatin1Char('?')))
+ msg += QLatin1Char('?');
+ fprintf(stderr, "Project PROMPT: %s ", qPrintable(msg));
} else {
- QString msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp1));
- bool decorate = true;
- if (args.count() == 2)
- decorate = isTrue(args.at(1));
- if (decorate) {
- if (!msg.endsWith(QLatin1Char('?')))
- msg += QLatin1Char('?');
- fprintf(stderr, "Project PROMPT: %s ", qPrintable(msg));
- } else {
- fputs(qPrintable(msg), stderr);
- }
- QFile qfile;
- if (qfile.open(stdin, QIODevice::ReadOnly)) {
- QTextStream t(&qfile);
- const QString &line = t.readLine();
- if (t.atEnd()) {
- fputs("\n", stderr);
- evalError(fL1S("Unexpected EOF."));
- return ReturnError;
- }
- ret = split_value_list(QStringRef(&line));
+ fputs(qPrintable(msg), stderr);
+ }
+ QFile qfile;
+ if (qfile.open(stdin, QIODevice::ReadOnly)) {
+ QTextStream t(&qfile);
+ const QString &line = t.readLine();
+ if (t.atEnd()) {
+ fputs("\n", stderr);
+ evalError(fL1S("Unexpected EOF."));
+ return ReturnError;
}
+ ret = split_value_list(QStringRef(&line));
}
- break; }
+ break;
+ }
#endif
- case E_REPLACE:
- if (args.count() != 3 ) {
- evalError(fL1S("replace(var, before, after) requires three arguments."));
- } else {
- const QRegExp before(args.at(1).toQString());
- const QString &after(args.at(2).toQString(m_tmp2));
- const auto vals = values(map(args.at(0)));
- for (const ProString &val : vals) {
- QString rstr = val.toQString(m_tmp1);
- QString copy = rstr; // Force a detach on modify
- rstr.replace(before, after);
- ret << (rstr.isSharedWith(m_tmp1)
- ? val
- : rstr.isSharedWith(m_tmp2)
- ? args.at(2)
- : ProString(rstr).setSource(val));
- }
+ case E_REPLACE: {
+ const QRegExp before(args.at(1).toQString());
+ ProStringRwUser u2(args.at(2), m_tmp2);
+ const QString &after = u2.str();
+ const auto vals = values(map(args.at(0)));
+ for (const ProString &val : vals) {
+ ProStringRwUser u1(val, m_tmp1);
+ QString rstr = u1.str();
+ QString copy = rstr; // Force a detach on modify
+ rstr.replace(before, after);
+ ret << u1.extract(rstr, u2);
}
break;
+ }
case E_SORT_DEPENDS:
- case E_RESOLVE_DEPENDS:
- if (args.count() < 1 || args.count() > 4) {
- evalError(fL1S("%1(var, [prefix, [suffixes, [prio-suffix]]]) requires one to four arguments.")
- .arg(func.toQStringView()));
- } else {
- QHash<ProKey, QSet<ProKey> > dependencies;
- ProValueMap dependees;
- QMultiMap<int, ProString> rootSet;
- ProStringList orgList = values(args.at(0).toKey());
- ProString prefix = args.count() < 2 ? ProString() : args.at(1);
- ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3);
- populateDeps(orgList, prefix,
- args.count() < 3 ? ProStringList(ProString(".depends"))
- : split_value_list(args.at(2).toQStringRef()),
- priosfx, dependencies, dependees, rootSet);
- while (!rootSet.isEmpty()) {
- QMultiMap<int, ProString>::iterator it = rootSet.begin();
- const ProString item = *it;
- rootSet.erase(it);
- if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item))
- ret.prepend(item);
- for (const ProString &dep : qAsConst(dependees[item.toKey()])) {
- QSet<ProKey> &dset = dependencies[dep.toKey()];
- dset.remove(item.toKey());
- if (dset.isEmpty())
- rootSet.insert(first(ProKey(prefix + dep + priosfx)).toInt(), dep);
- }
+ case E_RESOLVE_DEPENDS: {
+ QHash<ProKey, QSet<ProKey> > dependencies;
+ ProValueMap dependees;
+ QMultiMap<int, ProString> rootSet;
+ ProStringList orgList = values(args.at(0).toKey());
+ ProString prefix = args.count() < 2 ? ProString() : args.at(1);
+ ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3);
+ populateDeps(orgList, prefix,
+ args.count() < 3 ? ProStringList(ProString(".depends"))
+ : split_value_list(args.at(2).toQStringRef()),
+ priosfx, dependencies, dependees, rootSet);
+ while (!rootSet.isEmpty()) {
+ QMultiMap<int, ProString>::iterator it = rootSet.begin();
+ const ProString item = *it;
+ rootSet.erase(it);
+ if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item))
+ ret.prepend(item);
+ for (const ProString &dep : qAsConst(dependees[item.toKey()])) {
+ QSet<ProKey> &dset = dependencies[dep.toKey()];
+ dset.remove(item.toKey());
+ if (dset.isEmpty())
+ rootSet.insert(first(ProKey(prefix + dep + priosfx)).toInt(), dep);
}
}
break;
+ }
case E_ENUMERATE_VARS: {
QSet<ProString> keys;
for (const ProValueMap &vmap : qAsConst(m_valuemapStack))
@@ -1167,120 +1132,94 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
for (const ProString &key : qAsConst(keys))
ret << key;
break; }
- case E_SHADOWED:
- if (args.count() != 1) {
- evalError(fL1S("shadowed(path) requires one argument."));
- } else {
- QString rstr = m_option->shadowedPath(resolvePath(args.at(0).toQString(m_tmp1)));
- if (rstr.isEmpty())
- break;
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ case E_SHADOWED: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ QString rstr = m_option->shadowedPath(resolvePath(u1.str()));
+ if (!rstr.isEmpty())
+ ret << u1.extract(rstr);
break;
- case E_ABSOLUTE_PATH:
- if (args.count() > 2) {
- evalError(fL1S("absolute_path(path[, base]) requires one or two arguments."));
- } else {
- QString arg = args.at(0).toQString(m_tmp1);
- QString baseDir = args.count() > 1
- ? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
- : currentDirectory();
- QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
- ret << (rstr.isSharedWith(m_tmp1)
- ? args.at(0)
- : args.count() > 1 && rstr.isSharedWith(m_tmp2)
- ? args.at(1)
- : ProString(rstr).setSource(args.at(0)));
- }
+ }
+ case E_ABSOLUTE_PATH: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ ProStringRwUser u2(m_tmp2);
+ QString baseDir = args.count() > 1
+ ? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
+ : currentDirectory();
+ QString rstr = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
+ ret << u1.extract(rstr, u2);
break;
- case E_RELATIVE_PATH:
- if (args.count() > 2) {
- evalError(fL1S("relative_path(path[, base]) requires one or two arguments."));
- } else {
- QString arg = args.at(0).toQString(m_tmp1);
- QString baseDir = args.count() > 1
- ? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
- : currentDirectory();
- QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
- QString rstr = QDir(baseDir).relativeFilePath(absArg);
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ }
+ case E_RELATIVE_PATH: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ ProStringRoUser u2(m_tmp2);
+ QString baseDir = args.count() > 1
+ ? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
+ : currentDirectory();
+ QString absArg = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
+ QString rstr = QDir(baseDir).relativeFilePath(absArg);
+ ret << u1.extract(rstr);
break;
- case E_CLEAN_PATH:
- if (args.count() != 1) {
- evalError(fL1S("clean_path(path) requires one argument."));
- } else {
- QString rstr = QDir::cleanPath(args.at(0).toQString(m_tmp1));
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ }
+ case E_CLEAN_PATH: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ ret << u1.extract(QDir::cleanPath(u1.str()));
break;
- case E_SYSTEM_PATH:
- if (args.count() != 1) {
- evalError(fL1S("system_path(path) requires one argument."));
- } else {
- QString rstr = args.at(0).toQString(m_tmp1);
+ }
+ case E_SYSTEM_PATH: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ QString rstr = u1.str();
#ifdef Q_OS_WIN
- rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
#else
- rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
#endif
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ ret << u1.extract(rstr);
break;
- case E_SHELL_PATH:
- if (args.count() != 1) {
- evalError(fL1S("shell_path(path) requires one argument."));
+ }
+ case E_SHELL_PATH: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ QString rstr = u1.str();
+ if (m_dirSep.startsWith(QLatin1Char('\\'))) {
+ rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
} else {
- QString rstr = args.at(0).toQString(m_tmp1);
- if (m_dirSep.startsWith(QLatin1Char('\\'))) {
- rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
- } else {
- rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
#ifdef Q_OS_WIN
- // Convert d:/foo/bar to msys-style /d/foo/bar.
- if (rstr.length() > 2 && rstr.at(1) == QLatin1Char(':') && rstr.at(2) == QLatin1Char('/')) {
- rstr[1] = rstr.at(0);
- rstr[0] = QLatin1Char('/');
- }
-#endif
+ // Convert d:/foo/bar to msys-style /d/foo/bar.
+ if (rstr.length() > 2 && rstr.at(1) == QLatin1Char(':') && rstr.at(2) == QLatin1Char('/')) {
+ rstr[1] = rstr.at(0);
+ rstr[0] = QLatin1Char('/');
}
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
+#endif
}
+ ret << u1.extract(rstr);
break;
- case E_SYSTEM_QUOTE:
- if (args.count() != 1) {
- evalError(fL1S("system_quote(arg) requires one argument."));
- } else {
- QString rstr = IoUtils::shellQuote(args.at(0).toQString(m_tmp1));
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ }
+ case E_SYSTEM_QUOTE: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ ret << u1.extract(IoUtils::shellQuote(u1.str()));
break;
- case E_SHELL_QUOTE:
- if (args.count() != 1) {
- evalError(fL1S("shell_quote(arg) requires one argument."));
- } else {
- QString rstr = args.at(0).toQString(m_tmp1);
- if (m_dirSep.startsWith(QLatin1Char('\\')))
- rstr = IoUtils::shellQuoteWin(rstr);
- else
- rstr = IoUtils::shellQuoteUnix(rstr);
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
- }
+ }
+ case E_SHELL_QUOTE: {
+ ProStringRwUser u1(args.at(0), m_tmp1);
+ QString rstr = u1.str();
+ if (m_dirSep.startsWith(QLatin1Char('\\')))
+ rstr = IoUtils::shellQuoteWin(rstr);
+ else
+ rstr = IoUtils::shellQuoteUnix(rstr);
+ ret << u1.extract(rstr);
break;
- case E_GETENV:
- if (args.count() != 1) {
- evalError(fL1S("getenv(arg) requires one argument."));
- } else {
- const ProString &var = args.at(0);
- const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1)));
- ret << val;
- }
+ }
+ case E_GETENV: {
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ ret << ProString(m_option->getEnv(u1.str()));
break;
+ }
default:
evalError(fL1S("Function '%1' is not implemented.").arg(func.toQStringView()));
break;
}
+ allfail:
return ReturnTrue;
}
@@ -1306,7 +1245,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::testFunc_cache(const ProStringList &
} else if (opt == QLatin1String("sub")) {
mode = CacheSub;
} else {
- evalError(fL1S("cache(): invalid flag %1.").arg(opt.toQString(m_tmp3)));
+ evalError(fL1S("cache(): invalid flag %1.").arg(opt.toQStringView()));
return ReturnFalse;
}
}
@@ -1450,17 +1389,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::testFunc_cache(const ProStringList &
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
- int func_t, const ProKey &function, const ProStringList &args)
+ const QMakeInternal::QMakeBuiltin &adef, const ProKey &function, const ProStringList &args)
{
traceMsg("calling built-in %s(%s)", dbgKey(function), dbgSepStrList(args));
+ int asz = args.size() > 1 ? args.size() : args.at(0).isEmpty() ? 0 : 1;
+ if (asz < adef.minArgs || asz > adef.maxArgs) {
+ evalError(adef.usage);
+ return ReturnFalse;
+ }
+ int func_t = adef.index;
switch (func_t) {
case T_DEFINED: {
- if (args.count() < 1 || args.count() > 2) {
- evalError(fL1S("defined(function, [\"test\"|\"replace\"|\"var\"])"
- " requires one or two arguments."));
- return ReturnFalse;
- }
const ProKey &var = args.at(0).toKey();
if (args.count() > 1) {
if (args[1] == QLatin1String("test")) {
@@ -1479,10 +1419,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|| m_functionDefs.testFunctions.contains(var));
}
case T_EXPORT: {
- if (args.count() != 1) {
- evalError(fL1S("export(variable) requires one argument."));
- return ReturnFalse;
- }
const ProKey &var = map(args.at(0));
for (ProValueMapStack::Iterator vmi = m_valuemapStack.end();
--vmi != m_valuemapStack.begin(); ) {
@@ -1503,15 +1439,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnTrue;
}
case T_DISCARD_FROM: {
- if (args.count() != 1 || args.at(0).isEmpty()) {
- evalError(fL1S("discard_from(file) requires one argument."));
- return ReturnFalse;
- }
if (m_valuemapStack.count() != 1) {
evalError(fL1S("discard_from() cannot be called from functions."));
return ReturnFalse;
}
- QString fn = resolvePath(args.at(0).toQString(m_tmp1));
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ QString fn = resolvePath(u1.str());
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
if (!pro)
@@ -1550,32 +1483,34 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
iif.removeAt(idx);
return ReturnTrue;
}
- case T_INFILE:
- if (args.count() < 2 || args.count() > 3) {
- evalError(fL1S("infile(file, var, [values]) requires two or three arguments."));
- } else {
- ProValueMap vars;
- QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
- fn.detach();
- VisitReturn ok = evaluateFileInto(fn, &vars, LoadProOnly);
- if (ok != ReturnTrue)
- return ok;
- if (args.count() == 2)
- return returnBool(vars.contains(map(args.at(1))));
- QRegExp regx;
- const QString &qry = args.at(2).toQString(m_tmp1);
- if (qry != QRegExp::escape(qry)) {
- QString copy = qry;
- copy.detach();
- regx.setPattern(copy);
- }
- const auto strings = vars.value(map(args.at(1)));
- for (const ProString &s : strings) {
- if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[m_toggle ^= 1]))) || s == qry)
+ case T_INFILE: {
+ ProValueMap vars;
+ QString fn = filePathEnvArg0(args);
+ VisitReturn ok = evaluateFileInto(fn, &vars, LoadProOnly);
+ if (ok != ReturnTrue)
+ return ok;
+ if (args.count() == 2)
+ return returnBool(vars.contains(map(args.at(1))));
+ QRegExp regx;
+ ProStringRoUser u1(args.at(2), m_tmp1);
+ const QString &qry = u1.str();
+ if (qry != QRegExp::escape(qry)) {
+ QString copy = qry;
+ copy.detach();
+ regx.setPattern(copy);
+ }
+ const auto strings = vars.value(map(args.at(1)));
+ for (const ProString &s : strings) {
+ if (s == qry)
+ return ReturnTrue;
+ if (!regx.isEmpty()) {
+ ProStringRoUser u2(s, m_tmp[m_toggle ^= 1]);
+ if (regx.exactMatch(u2.str()))
return ReturnTrue;
}
}
return ReturnFalse;
+ }
case T_REQUIRES:
#ifdef PROEVALUATOR_FULL
if (checkRequirements(args) == ReturnError)
@@ -1583,32 +1518,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
#endif
return ReturnFalse; // Another qmake breakage
case T_EVAL: {
- VisitReturn ret = ReturnFalse;
- QString contents = args.join(statics.field_sep);
- ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents),
- 0, m_current.pro->fileName(), m_current.line);
- if (m_cumulative || pro->isOk()) {
- m_locationStack.push(m_current);
- visitProBlock(pro, pro->tokPtr());
- ret = ReturnTrue; // This return value is not too useful, but that's qmake
- m_current = m_locationStack.pop();
- }
- pro->deref();
- return ret;
- }
+ VisitReturn ret = ReturnFalse;
+ QString contents = args.join(statics.field_sep);
+ ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents),
+ 0, m_current.pro->fileName(), m_current.line);
+ if (m_cumulative || pro->isOk()) {
+ m_locationStack.push(m_current);
+ visitProBlock(pro, pro->tokPtr());
+ ret = ReturnTrue; // This return value is not too useful, but that's qmake
+ m_current = m_locationStack.pop();
+ }
+ pro->deref();
+ return ret;
+ }
case T_IF: {
- if (args.count() != 1) {
- evalError(fL1S("if(condition) requires one argument."));
- return ReturnFalse;
- }
return evaluateConditional(args.at(0).toQStringRef(),
m_current.pro->fileName(), m_current.line);
}
case T_CONFIG: {
- if (args.count() < 1 || args.count() > 2) {
- evalError(fL1S("CONFIG(config) requires one or two arguments."));
- return ReturnFalse;
- }
if (args.count() == 1)
return returnBool(isActiveConfig(args.at(0).toQStringRef()));
const auto mutuals = args.at(1).toQStringRef().split(QLatin1Char('|'),
@@ -1624,12 +1551,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
}
case T_CONTAINS: {
- if (args.count() < 2 || args.count() > 3) {
- evalError(fL1S("contains(var, val) requires two or three arguments."));
- return ReturnFalse;
- }
-
- const QString &qry = args.at(1).toQString(m_tmp1);
+ ProStringRoUser u1(args.at(1), m_tmp1);
+ const QString &qry = u1.str();
QRegExp regx;
if (qry != QRegExp::escape(qry)) {
QString copy = qry;
@@ -1640,19 +1563,29 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (args.count() == 2) {
for (int i = 0; i < l.size(); ++i) {
const ProString &val = l[i];
- if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1]))) || val == qry)
+ if (val == qry)
return ReturnTrue;
+ if (!regx.isEmpty()) {
+ ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]);
+ if (regx.exactMatch(u2.str()))
+ return ReturnTrue;
+ }
}
} else {
const auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|'),
QString::SkipEmptyParts);
for (int i = l.size() - 1; i >= 0; i--) {
- const ProString val = l[i];
+ const ProString &val = l[i];
for (int mut = 0; mut < mutuals.count(); mut++) {
if (val.toQStringRef() == mutuals[mut].trimmed()) {
- return returnBool((!regx.isEmpty()
- && regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1])))
- || val == qry);
+ if (val == qry)
+ return ReturnTrue;
+ if (!regx.isEmpty()) {
+ ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]);
+ if (regx.exactMatch(u2.str()))
+ return ReturnTrue;
+ }
+ return ReturnFalse;
}
}
}
@@ -1660,10 +1593,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
}
case T_COUNT: {
- if (args.count() != 2 && args.count() != 3) {
- evalError(fL1S("count(var, count, op=\"equals\") requires two or three arguments."));
- return ReturnFalse;
- }
int cnt = values(map(args.at(0))).count();
int val = args.at(1).toInt();
if (args.count() == 3) {
@@ -1688,11 +1617,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
case T_GREATERTHAN:
case T_LESSTHAN: {
- if (args.count() != 2) {
- evalError(fL1S("%1(variable, value) requires two arguments.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
const ProString &rhs = args.at(1);
const QString &lhs = values(map(args.at(0))).join(statics.field_sep);
bool ok;
@@ -1710,20 +1634,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return returnBool(lhs < rhs.toQStringRef());
}
case T_EQUALS:
- if (args.count() != 2) {
- evalError(fL1S("%1(variable, value) requires two arguments.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
return returnBool(values(map(args.at(0))).join(statics.field_sep)
== args.at(1).toQStringView());
case T_VERSION_AT_LEAST:
case T_VERSION_AT_MOST: {
- if (args.count() != 2) {
- evalError(fL1S("%1(variable, versionNumber) requires two arguments.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
const QVersionNumber lvn = QVersionNumber::fromString(values(args.at(0).toKey()).join('.'));
const QVersionNumber rvn = QVersionNumber::fromString(args.at(1).toQStringView());
if (func_t == T_VERSION_AT_LEAST)
@@ -1731,11 +1645,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return returnBool(lvn <= rvn);
}
case T_CLEAR: {
- if (args.count() != 1) {
- evalError(fL1S("%1(variable) requires one argument.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
ProValueMap *hsh;
ProValueMap::Iterator it;
const ProKey &var = map(args.at(0));
@@ -1748,11 +1657,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnTrue;
}
case T_UNSET: {
- if (args.count() != 1) {
- evalError(fL1S("%1(variable) requires one argument.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
ProValueMap *hsh;
ProValueMap::Iterator it;
const ProKey &var = map(args.at(0));
@@ -1768,21 +1672,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
case T_PARSE_JSON: {
- if (args.count() != 2) {
- evalError(fL1S("parseJson(variable, into) requires two arguments."));
- return ReturnFalse;
- }
-
QByteArray json = values(args.at(0).toKey()).join(QLatin1Char(' ')).toUtf8();
- QString parseInto = args.at(1).toQString(m_tmp2);
+ ProStringRoUser u1(args.at(1), m_tmp2);
+ QString parseInto = u1.str();
return parseJsonInto(json, parseInto, &m_valuemapStack.top());
}
#endif
case T_INCLUDE: {
- if (args.count() < 1 || args.count() > 3) {
- evalError(fL1S("include(file, [into, [silent]]) requires one, two or three arguments."));
- return ReturnFalse;
- }
QString parseInto;
LoadFlags flags = 0;
if (m_cumulative)
@@ -1793,8 +1689,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (args.count() >= 3 && isTrue(args.at(2)))
flags = LoadSilent;
}
- QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
- fn.detach();
+ QString fn = filePathEnvArg0(args);
VisitReturn ok;
if (parseInto.isEmpty()) {
ok = evaluateFileChecked(fn, QMakeHandler::EvalIncludeFile, LoadProOnly | flags);
@@ -1812,9 +1707,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
for (ProValueMap::ConstIterator it = symbols.constBegin();
it != symbols.constEnd(); ++it) {
- const QString &ky = it.key().toQString(m_tmp1);
- if (!ky.startsWith(QLatin1Char('.')))
- newMap.insert(ProKey(parseInto + ky), it.value());
+ if (!it.key().startsWith(QLatin1Char('.')))
+ newMap.insert(ProKey(parseInto + it.key()), it.value());
}
m_valuemapStack.top() = newMap;
}
@@ -1824,13 +1718,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ok;
}
case T_LOAD: {
- bool ignore_error = false;
- if (args.count() == 2) {
- ignore_error = isTrue(args.at(1));
- } else if (args.count() != 1) {
- evalError(fL1S("load(feature) requires one or two arguments."));
- return ReturnFalse;
- }
+ bool ignore_error = (args.count() == 2 && isTrue(args.at(1)));
VisitReturn ok = evaluateFeatureFile(m_option->expandEnvVars(args.at(0).toQString()),
ignore_error);
if (ok == ReturnFalse && ignore_error)
@@ -1839,13 +1727,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
case T_DEBUG: {
#ifdef PROEVALUATOR_DEBUG
- if (args.count() != 2) {
- evalError(fL1S("debug(level, message) requires two arguments."));
- return ReturnFalse;
- }
int level = args.at(0).toInt();
if (level <= m_debugLevel) {
- const QString &msg = m_option->expandEnvVars(args.at(1).toQString(m_tmp2));
+ ProStringRoUser u1(args.at(1), m_tmp1);
+ const QString &msg = m_option->expandEnvVars(u1.str());
debugMsg(level, "Project DEBUG: %s", qPrintable(msg));
}
#endif
@@ -1855,33 +1740,26 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
case T_ERROR:
case T_WARNING:
case T_MESSAGE: {
- if (args.count() != 1) {
- evalError(fL1S("%1(message) requires one argument.")
- .arg(function.toQStringView()));
- return ReturnFalse;
- }
- const QString &msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp2));
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ const QString &msg = m_option->expandEnvVars(u1.str());
if (!m_skipLevel) {
if (func_t == T_LOG) {
#ifdef PROEVALUATOR_FULL
fputs(msg.toLatin1().constData(), stderr);
#endif
} else if (!msg.isEmpty() || func_t != T_ERROR) {
+ ProStringRoUser u2(function, m_tmp2);
m_handler->fileMessage(
(func_t == T_ERROR ? QMakeHandler::ErrorMessage :
func_t == T_WARNING ? QMakeHandler::WarningMessage :
QMakeHandler::InfoMessage)
| (m_cumulative ? QMakeHandler::CumulativeEvalMessage : 0),
- fL1S("Project %1: %2").arg(function.toQString(m_tmp1).toUpper(), msg));
+ fL1S("Project %1: %2").arg(u2.str().toUpper(), msg));
}
}
return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue;
}
case T_SYSTEM: {
- if (args.count() != 1) {
- evalError(fL1S("system(exec) requires one argument."));
- return ReturnFalse;
- }
#ifdef PROEVALUATOR_FULL
if (m_cumulative) // Anything else would be insanity
return ReturnFalse;
@@ -1905,19 +1783,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
#endif
}
case T_ISEMPTY: {
- if (args.count() != 1) {
- evalError(fL1S("isEmpty(var) requires one argument."));
- return ReturnFalse;
- }
return returnBool(values(map(args.at(0))).isEmpty());
}
case T_EXISTS: {
- if (args.count() != 1) {
- evalError(fL1S("exists(file) requires one argument."));
- return ReturnFalse;
- }
- const QString &file = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
-
+ QString file = filePathEnvArg0(args);
// Don't use VFS here:
// - it supports neither listing nor even directories
// - it's unlikely that somebody would test for files they created themselves
@@ -1925,7 +1794,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnTrue;
int slsh = file.lastIndexOf(QLatin1Char('/'));
QString fn = file.mid(slsh+1);
- fn.detach();
if (fn.contains(QLatin1Char('*')) || fn.contains(QLatin1Char('?'))) {
QString dirstr = file.left(slsh+1);
dirstr.detach();
@@ -1936,13 +1804,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
}
case T_MKPATH: {
- if (args.count() != 1) {
- evalError(fL1S("mkpath(file) requires one argument."));
- return ReturnFalse;
- }
#ifdef PROEVALUATOR_FULL
- QString fn = resolvePath(args.at(0).toQString(m_tmp1));
- fn.detach();
+ QString fn = filePathArg0(args);
if (!QDir::current().mkpath(fn)) {
evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn)));
return ReturnFalse;
@@ -1951,10 +1814,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnTrue;
}
case T_WRITE_FILE: {
- if (args.count() > 3) {
- evalError(fL1S("write_file(name, [content var, [append] [exe]]) requires one to three arguments."));
- return ReturnFalse;
- }
QIODevice::OpenMode mode = QIODevice::Truncate;
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
QString contents;
@@ -1970,24 +1829,21 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} else if (opt == QLatin1String("exe")) {
flags |= QMakeVfs::VfsExecutable;
} else {
- evalError(fL1S("write_file(): invalid flag %1.").arg(opt.toQString(m_tmp3)));
+ evalError(fL1S("write_file(): invalid flag %1.").arg(opt.toQStringView()));
return ReturnFalse;
}
}
}
}
- QString path = resolvePath(args.at(0).toQString(m_tmp1));
- path.detach(); // make sure to not leak m_tmp1 into the map of written files.
+ QString path = filePathArg0(args);
return writeFile(QString(), path, mode, flags, contents);
}
case T_TOUCH: {
- if (args.count() != 2) {
- evalError(fL1S("touch(file, reffile) requires two arguments."));
- return ReturnFalse;
- }
#ifdef PROEVALUATOR_FULL
- const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1));
- const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2));
+ ProStringRoUser u1(args.at(0), m_tmp1);
+ ProStringRoUser u2(args.at(1), m_tmp2);
+ const QString &tfn = resolvePath(u1.str());
+ const QString &rfn = resolvePath(u2.str());
QString error;
if (!IoUtils::touchFile(tfn, rfn, &error)) {
evalError(error);
@@ -1997,10 +1853,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnTrue;
}
case T_CACHE:
- if (args.count() > 3) {
- evalError(fL1S("cache(var, [set|add|sub] [transient] [super|stash], [srcvar]) requires one to three arguments."));
- return ReturnFalse;
- }
return testFunc_cache(args);
case T_RELOAD_PROPERTIES:
#ifdef QT_BUILD_QMAKE
diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp
index 6b23412327..ea2233f201 100644
--- a/qmake/library/qmakeevaluator.cpp
+++ b/qmake/library/qmakeevaluator.cpp
@@ -337,7 +337,8 @@ static void replaceInList(ProStringList *varlist,
const QRegExp &regexp, const QString &replace, bool global, QString &tmp)
{
for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
- QString val = varit->toQString(tmp);
+ ProStringRoUser u1(*varit, tmp);
+ QString val = u1.str();
QString copy = val; // Force detach and have a reference value
val.replace(regexp, replace);
if (!val.isSharedWith(copy) && val != copy) {
@@ -1336,7 +1337,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConfigFeatures()
bool finished = true;
ProStringList configs = values(statics.strCONFIG);
for (int i = configs.size() - 1; i >= 0; --i) {
- QString config = configs.at(i).toQString(m_tmp1).toLower();
+ ProStringRoUser u1(configs.at(i), m_tmp1);
+ QString config = u1.str().toLower();
if (!processed.contains(config)) {
config.detach();
processed.insert(config);
@@ -1640,7 +1642,8 @@ bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex)
// CONFIG variable
const auto configValues = values(statics.strCONFIG);
for (const ProString &configValue : configValues) {
- if (re.exactMatch(configValue.toQString(m_tmp[m_toggle ^= 1])))
+ ProStringRoUser u1(configValue, m_tmp[m_toggle ^= 1]);
+ if (re.exactMatch(u1.str()))
return true;
}
} else {
@@ -1749,9 +1752,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
if (val)
return ReturnTrue;
} else {
+ ProStringRoUser u1(function, m_tmp1);
evalError(fL1S("Unexpected return value from test '%1': %2.")
- .arg(function.toQString(m_tmp1))
- .arg(ret.join(QLatin1String(" :: "))));
+ .arg(u1.str(), ret.join(QLatin1String(" :: "))));
}
}
return ReturnFalse;
@@ -1762,12 +1765,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
const ProKey &func, const ushort *&tokPtr)
{
- if (int func_t = statics.functions.value(func)) {
+ auto adef = statics.functions.constFind(func);
+ if (adef != statics.functions.constEnd()) {
//why don't the builtin functions just use args_list? --Sam
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
- return evaluateBuiltinConditional(func_t, func, args);
+ return evaluateBuiltinConditional(*adef, func, args);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
@@ -1788,12 +1792,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction(
const ProKey &func, const ushort *&tokPtr, ProStringList *ret)
{
- if (int func_t = statics.expands.value(func)) {
+ auto adef = statics.expands.constFind(func);
+ if (adef != statics.expands.constEnd()) {
//why don't the builtin functions just use args_list? --Sam
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
- return evaluateBuiltinExpand(func_t, func, args, *ret);
+ return evaluateBuiltinExpand(*adef, func, args, *ret);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h
index dc35e1ddab..b87aaa0eec 100644
--- a/qmake/library/qmakeevaluator.h
+++ b/qmake/library/qmakeevaluator.h
@@ -105,6 +105,8 @@ public:
const ProValueMap &top() const { return last(); }
};
+namespace QMakeInternal { struct QMakeBuiltin; }
+
class QMAKE_EXPORT QMakeEvaluator
{
public:
@@ -186,6 +188,8 @@ public:
int currentFileId() const;
QString resolvePath(const QString &fileName) const
{ return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); }
+ QString filePathArg0(const ProStringList &args);
+ QString filePathEnvArg0(const ProStringList &args);
VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
LoadFlags flags);
@@ -214,8 +218,10 @@ public:
VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
- VisitReturn evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args, ProStringList &ret);
- VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
+ VisitReturn evaluateBuiltinExpand(const QMakeInternal::QMakeBuiltin &adef,
+ const ProKey &function, const ProStringList &args, ProStringList &ret);
+ VisitReturn evaluateBuiltinConditional(const QMakeInternal::QMakeBuiltin &adef,
+ const ProKey &function, const ProStringList &args);
VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL
diff --git a/qmake/library/qmakeevaluator_p.h b/qmake/library/qmakeevaluator_p.h
index f386a49108..f888bc5765 100644
--- a/qmake/library/qmakeevaluator_p.h
+++ b/qmake/library/qmakeevaluator_p.h
@@ -64,6 +64,22 @@ QT_BEGIN_NAMESPACE
namespace QMakeInternal {
+struct QMakeBuiltinInit
+{
+ const char *name;
+ int func;
+ enum { VarArgs = 1000 };
+ int min_args, max_args;
+ const char *args;
+};
+
+struct QMakeBuiltin
+{
+ QMakeBuiltin(const QMakeBuiltinInit &data);
+ QString usage;
+ int index, minArgs, maxArgs;
+};
+
struct QMakeStatics {
QString field_sep;
QString strtrue;
@@ -83,8 +99,8 @@ struct QMakeStatics {
#ifdef PROEVALUATOR_FULL
ProKey strREQUIRES;
#endif
- QHash<ProKey, int> expands;
- QHash<ProKey, int> functions;
+ QHash<ProKey, QMakeBuiltin> expands;
+ QHash<ProKey, QMakeBuiltin> functions;
QHash<ProKey, ProKey> varMap;
ProStringList fakeValue;
};
@@ -93,6 +109,8 @@ extern QMakeStatics statics;
}
+Q_DECLARE_TYPEINFO(QMakeInternal::QMakeBuiltin, Q_MOVABLE_TYPE);
+
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_P_H
diff --git a/qmake/main.cpp b/qmake/main.cpp
index 85709dc9bf..316e4b494f 100644
--- a/qmake/main.cpp
+++ b/qmake/main.cpp
@@ -455,28 +455,22 @@ int runQMake(int argc, char **argv)
QString oldpwd = qmake_getpwd();
Option::output_dir = oldpwd; //for now this is the output dir
- if(Option::output.fileName() != "-") {
+ if (!Option::output.fileName().isEmpty() && Option::output.fileName() != "-") {
+ // The output 'filename', as given by the -o option, might include one
+ // or more directories, so we may need to rebase the output directory.
QFileInfo fi(Option::output);
- QString dir;
- if(fi.isDir()) {
- dir = fi.filePath();
- } else {
- QString tmp_dir = fi.path();
- if(!tmp_dir.isEmpty() && QFile::exists(tmp_dir))
- dir = tmp_dir;
- }
-#ifdef Q_OS_MAC
- if (fi.fileName().endsWith(QLatin1String(".pbxproj"))
- && dir.endsWith(QLatin1String(".xcodeproj")))
- dir += QStringLiteral("/..");
-#endif
- if(!dir.isNull() && dir != ".")
- Option::output_dir = dir;
- if (QDir::isRelativePath(Option::output_dir)) {
- Option::output.setFileName(fi.fileName());
- Option::output_dir.prepend(oldpwd + QLatin1Char('/'));
+
+ QDir dir(QDir::cleanPath(fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath()));
+
+ // Don't treat Xcode project directory as part of OUT_PWD
+ if (dir.dirName().endsWith(QLatin1String(".xcodeproj"))) {
+ // Note: we're intentionally not using cdUp(), as the dir may not exist
+ dir.setPath(QDir::cleanPath(dir.filePath("..")));
}
- Option::output_dir = QDir::cleanPath(Option::output_dir);
+
+ Option::output_dir = dir.path();
+ QString absoluteFilePath = QDir::cleanPath(fi.absoluteFilePath());
+ Option::output.setFileName(absoluteFilePath.mid(Option::output_dir.length() + 1));
}
QMakeProperty prop;
diff --git a/qmake/meta.cpp b/qmake/meta.cpp
index b47645b07f..2e8759b8ba 100644
--- a/qmake/meta.cpp
+++ b/qmake/meta.cpp
@@ -50,49 +50,19 @@ QMakeMetaInfo::readLib(const QString &meta_file)
return true;
}
- bool ret = false;
- if(!meta_file.isNull()) {
- if(meta_file.endsWith(Option::pkgcfg_ext)) {
- if((ret=readPkgCfgFile(meta_file)))
- meta_type = "pkgcfg";
- } else if(meta_file.endsWith(Option::libtool_ext)) {
- if((ret=readLibtoolFile(meta_file)))
- meta_type = "libtool";
- } else if(meta_file.endsWith(Option::prl_ext)) {
- QMakeProject proj;
- if (!proj.read(Option::normalizePath(meta_file), QMakeEvaluator::LoadProOnly))
- return false;
- meta_type = "qmake";
- vars = proj.variables();
- ret = true;
- } else {
- warn_msg(WarnLogic, "QMakeMetaInfo: unknown file format for %s",
- QDir::toNativeSeparators(meta_file).toLatin1().constData());
- }
- }
- if(ret)
- cache_vars.insert(meta_file, vars);
- return ret;
+ QMakeProject proj;
+ if (!proj.read(Option::normalizePath(meta_file), QMakeEvaluator::LoadProOnly))
+ return false;
+ vars = proj.variables();
+ cache_vars.insert(meta_file, vars);
+ return true;
}
QString
-QMakeMetaInfo::findLib(const QString &lib)
+QMakeMetaInfo::checkLib(const QString &lib)
{
- QString ret;
- QString extns[] = { Option::prl_ext, /*Option::pkgcfg_ext, Option::libtool_ext,*/ QString() };
- for(int extn = 0; !extns[extn].isNull(); extn++) {
- if(lib.endsWith(extns[extn]))
- ret = QFile::exists(lib) ? lib : QString();
- }
- if(ret.isNull()) {
- for(int extn = 0; !extns[extn].isNull(); extn++) {
- if(QFile::exists(lib + extns[extn])) {
- ret = lib + extns[extn];
- break;
- }
- }
- }
+ QString ret = QFile::exists(lib) ? lib : QString();
if(ret.isNull()) {
debug_msg(2, "QMakeMetaInfo: Cannot find info file for %s", lib.toLatin1().constData());
} else {
@@ -101,79 +71,4 @@ QMakeMetaInfo::findLib(const QString &lib)
return ret;
}
-
-bool
-QMakeMetaInfo::readLibtoolFile(const QString &f)
-{
- /* I can just run the .la through the .pro parser since they are compatible.. */
- QMakeProject proj;
- QString nf = Option::normalizePath(f);
- if (!proj.read(nf, QMakeEvaluator::LoadProOnly))
- return false;
- QString dirf = nf.section(QLatin1Char('/'), 0, -2);
- if(dirf == nf)
- dirf = "";
- else if(!dirf.isEmpty() && !dirf.endsWith(Option::output_dir))
- dirf += QLatin1Char('/');
- const ProValueMap &v = proj.variables();
- for (ProValueMap::ConstIterator it = v.begin(); it != v.end(); ++it) {
- ProStringList lst = it.value();
- if(lst.count() == 1 && (lst.first().startsWith("'") || lst.first().startsWith("\"")) &&
- lst.first().endsWith(QString(lst.first().at(0))))
- lst = ProStringList(lst.first().mid(1, lst.first().length() - 2));
- if(!vars.contains("QMAKE_PRL_TARGET") &&
- (it.key() == "dlname" || it.key() == "library_names" || it.key() == "old_library")) {
- ProString dir = v["libdir"].first();
- if ((dir.startsWith('\'') || dir.startsWith('"')) && dir.endsWith(dir.at(0)))
- dir = dir.mid(1, dir.length() - 2);
- dir = dir.trimmed();
- if(!dir.isEmpty() && !dir.endsWith(QLatin1Char('/')))
- dir += QLatin1Char('/');
- if(lst.count() == 1)
- lst = ProStringList(lst.first().toQString().split(" "));
- for (ProStringList::Iterator lst_it = lst.begin(); lst_it != lst.end(); ++lst_it) {
- bool found = false;
- QString dirs[] = { "", dir.toQString(), dirf, dirf + ".libs/", "(term)" };
- for(int i = 0; !found && dirs[i] != "(term)"; i++) {
- if(QFile::exists(dirs[i] + (*lst_it))) {
- QString targ = dirs[i] + (*lst_it);
- if(QDir::isRelativePath(targ))
- targ.prepend(qmake_getpwd() + QLatin1Char('/'));
- vars["QMAKE_PRL_TARGET"] << targ;
- found = true;
- }
- }
- if(found)
- break;
- }
- } else if(it.key() == "dependency_libs") {
- if(lst.count() == 1) {
- ProString dep = lst.first();
- if ((dep.startsWith('\'') || dep.startsWith('"')) && dep.endsWith(dep.at(0)))
- dep = dep.mid(1, dep.length() - 2);
- lst = ProStringList(dep.trimmed().toQString().split(" "));
- }
- for (ProStringList::Iterator lit = lst.begin(); lit != lst.end(); ++lit) {
- if((*lit).startsWith("-R")) {
- if(!conf->isEmpty("QMAKE_LFLAGS_RPATH"))
- (*lit) = conf->first("QMAKE_LFLAGS_RPATH") + (*lit).mid(2);
- }
- }
- ProStringList &prlLibs = vars["QMAKE_PRL_LIBS"];
- for (const ProString &s : qAsConst(lst)) {
- prlLibs.removeAll(s);
- prlLibs.append(s);
- }
- }
- }
- return true;
-}
-
-bool
-QMakeMetaInfo::readPkgCfgFile(const QString &f)
-{
- fprintf(stderr, "Must implement reading in pkg-config files (%s)!!!\n", f.toLatin1().constData());
- return false;
-}
-
QT_END_NAMESPACE
diff --git a/qmake/meta.h b/qmake/meta.h
index dd53cdc7a3..4721085fd2 100644
--- a/qmake/meta.h
+++ b/qmake/meta.h
@@ -41,20 +41,16 @@ class QMakeProject;
class QMakeMetaInfo
{
- bool readLibtoolFile(const QString &f);
- bool readPkgCfgFile(const QString &f);
QMakeProject *conf;
ProValueMap vars;
- QString meta_type;
static QHash<QString, ProValueMap> cache_vars;
public:
QMakeMetaInfo(QMakeProject *_conf);
// These functions expect the path to be normalized
- static QString findLib(const QString &lib);
+ static QString checkLib(const QString &lib);
bool readLib(const QString &meta_file);
- QString type() const;
bool isEmpty(const ProKey &v);
ProStringList &values(const ProKey &v);
ProString first(const ProKey &v);
@@ -64,9 +60,6 @@ public:
inline bool QMakeMetaInfo::isEmpty(const ProKey &v)
{ return !vars.contains(v) || vars[v].isEmpty(); }
-inline QString QMakeMetaInfo::type() const
-{ return meta_type; }
-
inline ProStringList &QMakeMetaInfo::values(const ProKey &v)
{ return vars[v]; }
diff --git a/qmake/project.cpp b/qmake/project.cpp
index e6bdb04bfb..1bc9b352b5 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -82,8 +82,9 @@ bool QMakeProject::test(const ProKey &func, const QList<ProStringList> &args)
{
m_current.clear();
- if (int func_t = statics.functions.value(func))
- return boolRet(evaluateBuiltinConditional(func_t, func, prepareBuiltinArgs(args)));
+ auto adef = statics.functions.constFind(func);
+ if (adef != statics.functions.constEnd())
+ return boolRet(evaluateBuiltinConditional(*adef, func, prepareBuiltinArgs(args)));
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.testFunctions.constFind(func);
@@ -99,9 +100,10 @@ QStringList QMakeProject::expand(const ProKey &func, const QList<ProStringList>
{
m_current.clear();
- if (int func_t = statics.expands.value(func)) {
+ auto adef = statics.expands.constFind(func);
+ if (adef != statics.expands.constEnd()) {
ProStringList ret;
- if (evaluateBuiltinExpand(func_t, func, prepareBuiltinArgs(args), ret) == ReturnError)
+ if (evaluateBuiltinExpand(*adef, func, prepareBuiltinArgs(args), ret) == ReturnError)
exit(3);
return ret.toQStringList();
}