diff options
Diffstat (limited to 'qmake')
44 files changed, 1265 insertions, 1320 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..72daa97fe4 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(); @@ -825,7 +829,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"), &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH"); - static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; + static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; libs[i]; i++) { tmp = project->values(libs[i]); for(int x = 0; x < tmp.count();) { @@ -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)) { @@ -1417,7 +1422,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) testHost.append("Contents/MacOS/"); testHost.append(targetName); - static const char * const configs[] = { "Debug", "Release", 0 }; + static const char * const configs[] = { "Debug", "Release", nullptr }; for (int i = 0; configs[i]; i++) { QString testBundleBuildConfig = keyFor(pbx_dir + "QMAKE_PBX_TEST_BUNDLE_BUILDCONFIG_" + configs[i]); t << "\t\t" << testBundleBuildConfig << " = {\n" @@ -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..f15c814cb4 100644 --- a/qmake/generators/mac/pbuilder_pbx.h +++ b/qmake/generators/mac/pbuilder_pbx.h @@ -36,11 +36,11 @@ 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 &); - bool writeMakefile(QTextStream &); + bool writeMakefile(QTextStream &) override; QString pbxbuild(); QHash<QString, QString> keys; @@ -64,11 +64,11 @@ public: ProjectBuilderMakefileGenerator(); ~ProjectBuilderMakefileGenerator(); - virtual bool supportsMetaBuild() { return false; } - virtual bool openOutput(QFile &, const QString &) const; + bool supportsMetaBuild() override { return false; } + bool openOutput(QFile &, const QString &) const override; protected: - bool doPrecompiledHeaders() const { return false; } - virtual bool doDepends() const { return writingUnixMakefileGenerator && UnixMakefileGenerator::doDepends(); } + bool doPrecompiledHeaders() const override { return false; } + bool doDepends() const override { return writingUnixMakefileGenerator && UnixMakefileGenerator::doDepends(); } }; inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator() diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 73e09a1025..cae179cc93 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -96,7 +96,7 @@ bool MakefileGenerator::mkdir(const QString &in_path) const // ** base makefile generator MakefileGenerator::MakefileGenerator() : - no_io(false), project(0) + no_io(false), project(nullptr) { } @@ -164,7 +164,7 @@ MakefileGenerator::initOutPaths() v["PRECOMPILED_DIR"] = v["OBJECTS_DIR"]; static const char * const dirs[] = { "OBJECTS_DIR", "DESTDIR", "SUBLIBS_DIR", "DLLDESTDIR", - "PRECOMPILED_DIR", 0 }; + "PRECOMPILED_DIR", nullptr }; for (int x = 0; dirs[x]; x++) { const ProKey dkey(dirs[x]); if (v[dkey].isEmpty()) @@ -424,7 +424,7 @@ MakefileGenerator::init() } incs.append(project->specDir()); - const char * const cacheKeys[] = { "_QMAKE_STASH_", "_QMAKE_SUPER_CACHE_", 0 }; + const char * const cacheKeys[] = { "_QMAKE_STASH_", "_QMAKE_SUPER_CACHE_", nullptr }; for (int i = 0; cacheKeys[i]; ++i) { if (v[cacheKeys[i]].isEmpty()) continue; @@ -614,7 +614,7 @@ MakefileGenerator::init() //build up a list of compilers QVector<Compiler> compilers; { - const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", 0 }; + const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", nullptr }; for(x = 0; builtins[x]; ++x) { Compiler compiler; compiler.variable_in = builtins[x]; @@ -829,7 +829,7 @@ MakefileGenerator::init() } //fix up the target deps - static const char * const fixpaths[] = { "PRE_TARGETDEPS", "POST_TARGETDEPS", 0 }; + static const char * const fixpaths[] = { "PRE_TARGETDEPS", "POST_TARGETDEPS", nullptr }; for (int path = 0; fixpaths[path]; path++) { ProStringList &l = v[fixpaths[path]]; for (ProStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { @@ -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()) @@ -2746,7 +2790,7 @@ MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll) QFileInfo MakefileGenerator::fileInfo(QString file) const { - static QHash<FileInfoCacheKey, QFileInfo> *cache = 0; + static QHash<FileInfoCacheKey, QFileInfo> *cache = nullptr; static QFileInfo noInfo = QFileInfo(); if(!cache) { cache = new QHash<FileInfoCacheKey, QFileInfo>; @@ -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..b5c150e1cb 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -124,9 +124,9 @@ protected: { return replaceExtraCompilerVariables(val, QStringList(in), QStringList(out), forShell); } //interface to the source file info - QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool); - QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &); - QFileInfo findFileInfo(const QMakeLocalFileName &); + QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool) override; + QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &) override; + QFileInfo findFileInfo(const QMakeLocalFileName &) override; QMakeProject *project; //escape @@ -172,7 +172,7 @@ protected: { int ret; canExecute(cmdline, &ret); return ret; } bool canExecute(const QStringList &cmdline, int *argv0) const; inline bool canExecute(const QString &cmdline) const - { return canExecute(cmdline.split(' '), 0); } + { return canExecute(cmdline.split(' '), nullptr); } bool mkdir(const QString &dir) const; QString mkdir_p_asstring(const QString &dir, bool escape=true) const; @@ -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,9 +246,14 @@ 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(); + ~MakefileGenerator(); QMakeProject *projectFile() const; void setProjectFile(QMakeProject *p); diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index ffccdefbe1..decc1d980c 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -81,7 +81,7 @@ const QString struct SourceDependChildren; struct SourceFile { - SourceFile() : deps(0), type(QMakeSourceFileInfo::TYPE_UNKNOWN), + SourceFile() : deps(nullptr), type(QMakeSourceFileInfo::TYPE_UNKNOWN), mocable(0), traversed(0), exists(1), moc_checked(0), dep_checked(0), included_count(0) { } ~SourceFile(); @@ -95,8 +95,8 @@ struct SourceFile { struct SourceDependChildren { SourceFile **children; int num_nodes, used_nodes; - SourceDependChildren() : children(0), num_nodes(0), used_nodes(0) { } - ~SourceDependChildren() { if(children) free(children); children = 0; } + SourceDependChildren() : children(nullptr), num_nodes(0), used_nodes(0) { } + ~SourceDependChildren() { if (children) free(children); children = nullptr; } void addChild(SourceFile *s) { if(num_nodes <= used_nodes) { num_nodes += 200; @@ -115,10 +115,10 @@ public: SourceFile *lookupFile(const char *); inline SourceFile *lookupFile(const QString &f) { return lookupFile(f.toLatin1().constData()); } inline SourceFile *lookupFile(const QMakeLocalFileName &f) { return lookupFile(f.local().toLatin1().constData()); } - void addFile(SourceFile *, const char *k=0, bool own=true); + void addFile(SourceFile *, const char *k = nullptr, bool own = true); struct SourceFileNode { - SourceFileNode() : key(0), next(0), file(0), own_file(1) { } + SourceFileNode() : key(nullptr), next(nullptr), file(nullptr), own_file(1) { } ~SourceFileNode() { delete [] key; if(own_file) @@ -135,7 +135,7 @@ SourceFiles::SourceFiles() { nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); for(int n = 0; n < num_nodes; n++) - nodes[n] = 0; + nodes[n] = nullptr; } SourceFiles::~SourceFiles() @@ -170,7 +170,7 @@ SourceFile *SourceFiles::lookupFile(const char *file) if(!strcmp(p->key, file)) return p->file; } - return 0; + return nullptr; } void SourceFiles::addFile(SourceFile *p, const char *k, bool own_file) @@ -259,11 +259,11 @@ QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf) dep_mode = Recursive; //quick project lookups - includes = files = 0; + includes = files = nullptr; files_changed = false; //buffer - spare_buffer = 0; + spare_buffer = nullptr; spare_buffer_size = 0; //cache @@ -281,7 +281,7 @@ QMakeSourceFileInfo::~QMakeSourceFileInfo() //buffer if(spare_buffer) { free(spare_buffer); - spare_buffer = 0; + spare_buffer = nullptr; spare_buffer_size = 0; } @@ -538,7 +538,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) const QMakeLocalFileName sourceFile = fixPathForFile(file->file, true); struct stat fst; - char *buffer = 0; + char *buffer = nullptr; int buffer_len = 0; { int fd; @@ -588,7 +588,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) } for (; x < buffer_len; ++x) { bool try_local = true; - char *inc = 0; + char *inc = nullptr; if(file->type == QMakeSourceFileInfo::TYPE_UI) { // skip whitespaces while (x < buffer_len && (buffer[x] == ' ' || buffer[x] == '\t')) @@ -802,7 +802,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) if (cpp_state == WantName) buffer[clean] = '\0'; else // i.e. malformed - inc = 0; + inc = nullptr; cpp_state = InCode; // hereafter break; @@ -915,7 +915,7 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) file->moc_checked = true; int buffer_len = 0; - char *buffer = 0; + char *buffer = nullptr; { struct stat fst; int fd; diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp index 874b4286bc..8ebd0c61ce 100644 --- a/qmake/generators/metamakefile.cpp +++ b/qmake/generators/metamakefile.cpp @@ -62,11 +62,11 @@ private: public: BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { } - virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); } + ~BuildsMetaMakefileGenerator() { clearBuilds(); } - virtual bool init(); - virtual int type() const { return BUILDSMETATYPE; } - virtual bool write(); + bool init() override; + int type() const override { return BUILDSMETATYPE; } + bool write() override; }; void @@ -138,7 +138,7 @@ BuildsMetaMakefileGenerator::init() bool BuildsMetaMakefileGenerator::write() { - Build *glue = 0; + Build *glue = nullptr; if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) { glue = new Build; glue->name = name; @@ -228,7 +228,7 @@ MakefileGenerator if (build_proj->read(project->projectFile())) return createMakefileGenerator(build_proj); } - return 0; + return nullptr; } class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator @@ -236,7 +236,7 @@ class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator protected: bool init_flag; struct Subdir { - Subdir() : makefile(0), indent(0) { } + Subdir() : makefile(nullptr), indent(0) { } ~Subdir() { delete makefile; } QString input_dir; QString output_dir, output_file; @@ -248,11 +248,11 @@ protected: public: SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { } - virtual ~SubdirsMetaMakefileGenerator(); + ~SubdirsMetaMakefileGenerator(); - virtual bool init(); - virtual int type() const { return SUBDIRSMETATYPE; } - virtual bool write(); + bool init() override; + int type() const override { return SUBDIRSMETATYPE; } + bool write() override; }; bool @@ -336,7 +336,7 @@ SubdirsMetaMakefileGenerator::init() hasError |= !sub->makefile->write(); delete sub; qmakeClearCaches(); - sub = 0; + sub = nullptr; Option::output.setFileName(output_name); } Option::output_dir = old_output_dir; @@ -412,7 +412,7 @@ MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO) { Option::postProcessProject(proj); - MakefileGenerator *mkfile = NULL; + MakefileGenerator *mkfile = nullptr; if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { mkfile = new ProjectGenerator; mkfile->setProjectFile(proj); @@ -459,7 +459,7 @@ MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &na { Option::postProcessProject(proj); - MetaMakefileGenerator *ret = 0; + MetaMakefileGenerator *ret = nullptr; if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) { if (proj->first("TEMPLATE").endsWith("subdirs")) diff --git a/qmake/generators/metamakefile.h b/qmake/generators/metamakefile.h index 706bca3363..9337130143 100644 --- a/qmake/generators/metamakefile.h +++ b/qmake/generators/metamakefile.h @@ -49,7 +49,7 @@ public: virtual ~MetaMakefileGenerator(); - static MetaMakefileGenerator *createMetaGenerator(QMakeProject *proj, const QString &name, bool op=true, bool *success = 0); + static MetaMakefileGenerator *createMetaGenerator(QMakeProject *proj, const QString &name, bool op=true, bool *success = nullptr); static MakefileGenerator *createMakefileGenerator(QMakeProject *proj, bool noIO = false); inline QMakeProject *projectFile() const { return project; } diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp index 073d315aab..f45a90b851 100644 --- a/qmake/generators/projectgenerator.cpp +++ b/qmake/generators/projectgenerator.cpp @@ -229,7 +229,7 @@ ProjectGenerator::init() ProStringList &h = v["HEADERS"]; bool no_qt_files = true; - static const char *srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "FORMS", 0 }; + static const char *srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "FORMS", nullptr }; for (int i = 0; srcs[i]; i++) { const ProStringList &l = v[srcs[i]]; QMakeSourceFileInfo::SourceFileType type = QMakeSourceFileInfo::TYPE_C; @@ -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/projectgenerator.h b/qmake/generators/projectgenerator.h index 89c66f1ec8..cbc9f371ab 100644 --- a/qmake/generators/projectgenerator.h +++ b/qmake/generators/projectgenerator.h @@ -40,16 +40,16 @@ class ProjectGenerator : public MakefileGenerator QString getWritableVar(const char *, bool fixPath=true); QString fixPathToQmake(const QString &file); protected: - virtual void init(); - virtual bool writeMakefile(QTextStream &); + void init() override; + bool writeMakefile(QTextStream &) override; - virtual QString escapeFilePath(const QString &path) const { Q_ASSERT(false); return QString(); } + QString escapeFilePath(const QString &path) const override { Q_ASSERT(false); return QString(); } public: ProjectGenerator(); ~ProjectGenerator(); - virtual bool supportsMetaBuild() { return false; } - virtual bool openOutput(QFile &, const QString &) const; + bool supportsMetaBuild() override { return false; } + bool openOutput(QFile &, const QString &) const override; }; inline ProjectGenerator::~ProjectGenerator() diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 894020d2bd..4fe1a54501 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -420,7 +420,7 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) libdirs.append(QMakeLocalFileName(dlib.toQString())); frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks")); frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks")); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; + static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end(); ) { @@ -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/unixmake.h b/qmake/generators/unix/unixmake.h index da5cdb320c..c5e42aa1ae 100644 --- a/qmake/generators/unix/unixmake.h +++ b/qmake/generators/unix/unixmake.h @@ -38,7 +38,7 @@ class UnixMakefileGenerator : public MakefileGenerator bool include_deps; QString libtoolFileName(bool fixify=true); void writeLibtoolFile(); // for libtool - void writePrlFile(QTextStream &); + void writePrlFile(QTextStream &) override; public: UnixMakefileGenerator(); @@ -46,23 +46,23 @@ public: protected: virtual bool doPrecompiledHeaders() const { return project->isActiveConfig("precompile_header"); } - virtual bool doDepends() const { return !Option::mkfile::do_stub_makefile && MakefileGenerator::doDepends(); } + bool doDepends() const override { return !Option::mkfile::do_stub_makefile && MakefileGenerator::doDepends(); } #ifdef Q_OS_WIN // MinGW x-compiling for QNX - virtual QString installRoot() const; + QString installRoot() const override; #endif - virtual QString defaultInstall(const QString &); - virtual ProString fixLibFlag(const ProString &lib); + QString defaultInstall(const QString &) override; + ProString fixLibFlag(const ProString &lib) override; - virtual bool findLibraries(bool linkPrl, bool mergeLflags); - virtual QString escapeFilePath(const QString &path) const; + bool findLibraries(bool linkPrl, bool mergeLflags) override; + QString escapeFilePath(const QString &path) const override; ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); } - virtual QStringList &findDependencies(const QString &); - virtual void init(); + QStringList &findDependencies(const QString &) override; + void init() override; - virtual void writeDefaultVariables(QTextStream &t); - virtual void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags); + void writeDefaultVariables(QTextStream &t) override; + void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags) override; void writeMakeParts(QTextStream &); - bool writeMakefile(QTextStream &); + bool writeMakefile(QTextStream &) override; private: void init2(); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index ecb0de3b52..2ed1866584 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; @@ -346,7 +346,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) t << mkdir_p_asstring("$(@D)", false) << "\n\t" << "@$(CC) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@\n\n"; - static const char * const src[] = { "SOURCES", "GENERATED_SOURCES", 0 }; + static const char * const src[] = { "SOURCES", "GENERATED_SOURCES", nullptr }; for (int x = 0; src[x]; x++) { const ProStringList &l = project->values(src[x]); for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { @@ -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..5da5b24088 100644 --- a/qmake/generators/win32/mingw_make.h +++ b/qmake/generators/win32/mingw_make.h @@ -40,25 +40,27 @@ public: ~MingwMakefileGenerator(); protected: using MakefileGenerator::escapeDependencyPath; - virtual QString escapeDependencyPath(const QString &path) const; - virtual ProString fixLibFlag(const ProString &lib); - virtual QString getManifestFileForRcFile() const; - bool writeMakefile(QTextStream &); - void init(); - virtual QString installRoot() const; + QString escapeDependencyPath(const QString &path) const override; + ProString fixLibFlag(const ProString &lib) override; + bool processPrlFileBase(QString &origFile, const QStringRef &origName, + const QStringRef &fixedBase, int slashOff) override; + QString getManifestFileForRcFile() const override; + bool writeMakefile(QTextStream &) override; + void init() override; + QString installRoot() const override; private: void writeMingwParts(QTextStream &); - void writeIncPart(QTextStream &t); - void writeLibsPart(QTextStream &t); - void writeObjectsPart(QTextStream &t); - void writeBuildRulesPart(QTextStream &t); - void writeRcFilePart(QTextStream &t); + void writeIncPart(QTextStream &t) override; + void writeLibsPart(QTextStream &t) override; + void writeObjectsPart(QTextStream &t) override; + void writeBuildRulesPart(QTextStream &t) override; + void writeRcFilePart(QTextStream &t) override; - QStringList &findDependencies(const QString &file); + QStringList &findDependencies(const QString &file) override; QString preCompHeaderOut; - virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg); + LibFlagType parseLibFlag(const ProString &flag, ProString *arg) override; QString objectsLinkLine; }; diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 082f357d32..ad2976aa01 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -1207,7 +1207,7 @@ static inline QString toString(midlCharOption option) static inline QString toString(midlErrorCheckOption option) { switch (option) { - case midlAlignNotSet: + case midlEnableCustom: break; case midlDisableAll: return "None"; diff --git a/qmake/generators/win32/msbuild_objectmodel.h b/qmake/generators/win32/msbuild_objectmodel.h index 2e77537916..ce5711f2da 100644 --- a/qmake/generators/win32/msbuild_objectmodel.h +++ b/qmake/generators/win32/msbuild_objectmodel.h @@ -72,7 +72,7 @@ public: return Uindex; } - void addElement(const QString &filepath, const VCFilterFile &allInfo){ + void addElement(const QString &filepath, const VCFilterFile &allInfo) override { QString newNodeName(filepath); int index = pathIndex(filepath); @@ -89,7 +89,7 @@ public: n->addElement(filepath.mid(index+1), allInfo); } - void removeElements() { + void removeElements() override { ChildrenMap::ConstIterator it = children.constBegin(); ChildrenMap::ConstIterator end = children.constEnd(); for( ; it != end; it++) { @@ -100,8 +100,8 @@ public: } void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &tool, - const QString &filter); - bool hasElements() { + const QString &filter) override; + bool hasElements() override { return children.size() != 0; } }; @@ -124,7 +124,7 @@ public: return Uindex; } - void addElement(const QString &filepath, const VCFilterFile &allInfo){ + void addElement(const QString &filepath, const VCFilterFile &allInfo) override { QString newKey(filepath); int index = pathIndex(filepath); @@ -136,13 +136,13 @@ public: children.insert(newKey + "\0" + allInfo.file, allInfo); } - void removeElements() { + void removeElements() override { children.clear(); } void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &proj, - const QString &filter); - bool hasElements() { + const QString &filter) override; + bool hasElements() override { return children.size() != 0; } }; @@ -150,20 +150,20 @@ public: class VCXProjectWriter : public VCProjectWriter { public: - void write(XmlOutput &, VCProjectSingleConfig &); - void write(XmlOutput &, VCProject &); - - void write(XmlOutput &, const VCCLCompilerTool &); - void write(XmlOutput &, const VCLinkerTool &); - void write(XmlOutput &, const VCMIDLTool &); - void write(XmlOutput &, const VCCustomBuildTool &); - void write(XmlOutput &, const VCLibrarianTool &); - void write(XmlOutput &, const VCResourceCompilerTool &); - void write(XmlOutput &, const VCEventTool &); - void write(XmlOutput &, const VCDeploymentTool &); - void write(XmlOutput &, const VCWinDeployQtTool &); - void write(XmlOutput &, const VCConfiguration &); - void write(XmlOutput &, VCFilter &); + void write(XmlOutput &, VCProjectSingleConfig &) override; + void write(XmlOutput &, VCProject &) override; + + void write(XmlOutput &, const VCCLCompilerTool &) override; + void write(XmlOutput &, const VCLinkerTool &) override; + void write(XmlOutput &, const VCMIDLTool &) override; + void write(XmlOutput &, const VCCustomBuildTool &) override; + void write(XmlOutput &, const VCLibrarianTool &) override; + void write(XmlOutput &, const VCResourceCompilerTool &) override; + void write(XmlOutput &, const VCEventTool &) override; + void write(XmlOutput &, const VCDeploymentTool &) override; + void write(XmlOutput &, const VCWinDeployQtTool &) override; + void write(XmlOutput &, const VCConfiguration &) override; + void write(XmlOutput &, VCFilter &) override; private: struct OutputFilterData diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 92b4eb5054..fa7ee1b98a 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -499,7 +499,7 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t) QSet<QString> source_directories; if (useInferenceRules) { source_directories.insert("."); - static const char * const directories[] = { "UI_SOURCES_DIR", "UI_DIR", 0 }; + static const char * const directories[] = { "UI_SOURCES_DIR", "UI_DIR", nullptr }; for (int y = 0; directories[y]; y++) { QString dirTemp = project->first(directories[y]).toQString(); if (dirTemp.endsWith("\\")) @@ -507,7 +507,7 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t) if(!dirTemp.isEmpty()) source_directories.insert(dirTemp); } - static const char * const srcs[] = { "SOURCES", "GENERATED_SOURCES", 0 }; + static const char * const srcs[] = { "SOURCES", "GENERATED_SOURCES", nullptr }; for (int x = 0; srcs[x]; x++) { const ProStringList &l = project->values(srcs[x]); for (ProStringList::ConstIterator sit = l.begin(); sit != l.end(); ++sit) { @@ -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_nmake.h b/qmake/generators/win32/msvc_nmake.h index 67b609d0a6..67a56c7813 100644 --- a/qmake/generators/win32/msvc_nmake.h +++ b/qmake/generators/win32/msvc_nmake.h @@ -36,21 +36,21 @@ QT_BEGIN_NAMESPACE class NmakeMakefileGenerator : public Win32MakefileGenerator { void writeNmakeParts(QTextStream &); - bool writeMakefile(QTextStream &); - void writeImplicitRulesPart(QTextStream &t); - void writeBuildRulesPart(QTextStream &t); + bool writeMakefile(QTextStream &) override; + void writeImplicitRulesPart(QTextStream &t) override; + void writeBuildRulesPart(QTextStream &t) override; void writeLinkCommand(QTextStream &t, const QString &extraFlags = QString(), const QString &extraInlineFileContent = QString()); void writeResponseFileFiles(QTextStream &t, const ProStringList &files); int msvcVersion() const; - void init(); + void init() override; static QStringList sourceFilesForImplicitRulesFilter(); protected: - virtual void writeSubMakeCall(QTextStream &t, const QString &callPrefix, - const QString &makeArguments); - virtual QString defaultInstall(const QString &t); - virtual QStringList &findDependencies(const QString &file); - QString var(const ProKey &value) const; + void writeSubMakeCall(QTextStream &t, const QString &callPrefix, + const QString &makeArguments) override; + QString defaultInstall(const QString &t) override; + QStringList &findDependencies(const QString &file) override; + QString var(const ProKey &value) const override; QString precompH, precompObj, precompPch; QString precompObjC, precompPchC; bool usePCH, usePCHC; diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 300792c5af..0406da584b 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2185,7 +2185,7 @@ VCConfiguration::VCConfiguration() // VCFilter --------------------------------------------------------- VCFilter::VCFilter() : ParseFiles(unset), - Config(0) + Config(nullptr) { useCustomBuildTool = false; useCompilerTool = false; diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 10d44970ff..9d1a170489 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -484,7 +484,7 @@ public: // Functions VCCLCompilerTool(); - bool parseOption(const char* option); + bool parseOption(const char* option) override; // Variables QStringList AdditionalIncludeDirectories; @@ -581,7 +581,7 @@ public: // Functions VCLinkerTool(); - bool parseOption(const char* option); + bool parseOption(const char* option) override; // Variables QStringList AdditionalDependencies; @@ -676,7 +676,7 @@ class VCManifestTool : public VCToolBase public: VCManifestTool(); - bool parseOption(const char* option); + bool parseOption(const char* option) override; triState EmbedManifest; }; @@ -687,7 +687,7 @@ public: // Functions VCMIDLTool(); - bool parseOption(const char* option); + bool parseOption(const char* option) override; // Variables QStringList AdditionalIncludeDirectories; @@ -741,7 +741,7 @@ public: // Functions VCLibrarianTool(); - bool parseOption(const char*){ return false; } + bool parseOption(const char*) override { return false; } // Variables QStringList AdditionalDependencies; @@ -762,7 +762,7 @@ public: // Functions VCCustomBuildTool(); - bool parseOption(const char*){ return false; } + bool parseOption(const char*) override { return false; } // Variables QStringList AdditionalDependencies; @@ -781,7 +781,7 @@ public: // Functions VCResourceCompilerTool(); - bool parseOption(const char*){ return false; } + bool parseOption(const char*) override { return false; } // Variables QStringList AdditionalIncludeDirectories; @@ -815,7 +815,7 @@ protected: // Functions VCEventTool(const QString &eventName); - bool parseOption(const char*){ return false; } + bool parseOption(const char*) override { return false; } public: // Variables @@ -851,7 +851,7 @@ public: VCWinDeployQtTool() {} protected: - bool parseOption(const char *) { return false; } + bool parseOption(const char *) override { return false; } public: // Variables @@ -1037,7 +1037,7 @@ public: return Uindex; } - void addElement(const QString &filepath, const VCFilterFile &allInfo){ + void addElement(const QString &filepath, const VCFilterFile &allInfo) override { QString newNodeName(filepath); int index = pathIndex(filepath); @@ -1054,7 +1054,7 @@ public: n->addElement(filepath.mid(index+1), allInfo); } - void removeElements() { + void removeElements() override { ChildrenMap::ConstIterator it = children.constBegin(); ChildrenMap::ConstIterator end = children.constEnd(); for( ; it != end; it++) { @@ -1064,8 +1064,8 @@ public: children.clear(); } - void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter); - bool hasElements() { + void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter) override; + bool hasElements() override { return children.size() != 0; } }; @@ -1088,7 +1088,7 @@ public: return Uindex; } - void addElement(const QString &filepath, const VCFilterFile &allInfo){ + void addElement(const QString &filepath, const VCFilterFile &allInfo) override { QString newKey(filepath); int index = pathIndex(filepath); @@ -1100,12 +1100,12 @@ public: children.insert(newKey + "\0" + allInfo.file, allInfo); } - void removeElements() { + void removeElements() override { children.clear(); } - void generateXML(XmlOutput &xml, const QString &tagName, VCProject &proj, const QString &filter); - bool hasElements() { + void generateXML(XmlOutput &xml, const QString &tagName, VCProject &proj, const QString &filter) override; + bool hasElements() override { return children.size() != 0; } }; diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 24d1657552..b453873344 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -112,7 +112,7 @@ VcprojGenerator::VcprojGenerator() : Win32MakefileGenerator(), is64Bit(false), customBuildToolFilterFileSuffix(QStringLiteral(".cbt")), - projectWriter(0) + projectWriter(nullptr) { } @@ -1100,7 +1100,7 @@ void VcprojGenerator::initLinkerTool() if (!project->values("DEF_FILE").isEmpty()) conf.linker.ModuleDefinitionFile = project->first("DEF_FILE").toQString(); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; + static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { const auto libs = fixLibFlags(lflags[i]); for (const ProString &lib : libs) { @@ -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/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index 4882296b46..6af5ec7007 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -47,10 +47,10 @@ class VcprojGenerator : public Win32MakefileGenerator bool is64Bit; bool writeVcprojParts(QTextStream &); - bool writeMakefile(QTextStream &); - bool writeProjectMakefile(); + bool writeMakefile(QTextStream &) override; + bool writeProjectMakefile() override; - void init(); + void init() override; public: VcprojGenerator(); @@ -70,14 +70,14 @@ public: protected: virtual VCProjectWriter *createProjectWriter(); - virtual bool doDepends() const { return false; } //never necesary + bool doDepends() const override { return false; } // Never necessary using Win32MakefileGenerator::replaceExtraCompilerVariables; - virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor); - virtual bool supportsMetaBuild() { return true; } - virtual bool supportsMergedBuilds() { return true; } - virtual bool mergeBuildProject(MakefileGenerator *other); + QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor) override; + bool supportsMetaBuild() override { return true; } + bool supportsMergedBuilds() override { return true; } + bool mergeBuildProject(MakefileGenerator *other) override; - virtual bool openOutput(QFile &file, const QString &build) const; + bool openOutput(QFile &file, const QString &build) const override; virtual void initProject(); void initConfiguration(); diff --git a/qmake/generators/win32/msvc_vcxproj.h b/qmake/generators/win32/msvc_vcxproj.h index 8f68348693..7e02b6c32f 100644 --- a/qmake/generators/win32/msvc_vcxproj.h +++ b/qmake/generators/win32/msvc_vcxproj.h @@ -39,7 +39,7 @@ public: VcxprojGenerator(); protected: - virtual VCProjectWriter *createProjectWriter(); + VCProjectWriter *createProjectWriter() override; }; QT_END_NAMESPACE diff --git a/qmake/generators/win32/registry.cpp b/qmake/generators/win32/registry.cpp index 7320cb0551..3391ab9512 100644 --- a/qmake/generators/win32/registry.cpp +++ b/qmake/generators/win32/registry.cpp @@ -77,7 +77,7 @@ QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned l QString rSubkeyName = keyName(rSubkey); QString rSubkeyPath = keyPath(rSubkey); - HKEY handle = 0; + HKEY handle = nullptr; LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, KEY_READ | options, &handle); @@ -87,7 +87,7 @@ QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned l // get the size and type of the value DWORD dataType; DWORD dataSize; - res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, &dataType, 0, &dataSize); + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, &dataType, nullptr, &dataSize); if (res != ERROR_SUCCESS) { RegCloseKey(handle); return QString(); @@ -95,7 +95,7 @@ QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned l // get the value QByteArray data(dataSize, 0); - res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, 0, + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, nullptr, reinterpret_cast<unsigned char*>(data.data()), &dataSize); if (res != ERROR_SUCCESS) { RegCloseKey(handle); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index bca27b7044..3c730299be 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -84,7 +84,7 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) if (impexts.isEmpty()) impexts = project->values("QMAKE_EXTENSION_STATICLIB"); QList<QMakeLocalFileName> dirs; - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; + static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end();) { @@ -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")) @@ -422,7 +439,7 @@ void Win32MakefileGenerator::writeCleanParts(QTextStream &t) { t << "clean: compiler_clean " << depVar("CLEAN_DEPS"); { - const char *clean_targets[] = { "OBJECTS", "QMAKE_CLEAN", "CLEAN_FILES", 0 }; + const char *clean_targets[] = { "OBJECTS", "QMAKE_CLEAN", "CLEAN_FILES", nullptr }; for(int i = 0; clean_targets[i]; ++i) { const ProStringList &list = project->values(clean_targets[i]); const QString del_statement("-$(DEL_FILE)"); @@ -451,7 +468,7 @@ void Win32MakefileGenerator::writeCleanParts(QTextStream &t) t << "distclean: clean " << depVar("DISTCLEAN_DEPS"); { - const char *clean_targets[] = { "QMAKE_DISTCLEAN", 0 }; + const char *clean_targets[] = { "QMAKE_DISTCLEAN", nullptr }; for(int i = 0; clean_targets[i]; ++i) { const ProStringList &list = project->values(clean_targets[i]); const QString del_statement("-$(DEL_FILE)"); @@ -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..4416951a09 100644 --- a/qmake/generators/win32/winmakefile.h +++ b/qmake/generators/win32/winmakefile.h @@ -39,7 +39,7 @@ public: Win32MakefileGenerator(); ~Win32MakefileGenerator(); protected: - virtual QString defaultInstall(const QString &); + QString defaultInstall(const QString &) override; virtual void writeCleanParts(QTextStream &t); virtual void writeStandardParts(QTextStream &t); virtual void writeIncPart(QTextStream &t); @@ -48,16 +48,18 @@ protected: virtual void writeImplicitRulesPart(QTextStream &t); virtual void writeBuildRulesPart(QTextStream &); using MakefileGenerator::escapeFilePath; - virtual QString escapeFilePath(const QString &path) const; + QString escapeFilePath(const QString &path) const override; using MakefileGenerator::escapeDependencyPath; - virtual QString escapeDependencyPath(const QString &path) const; + QString escapeDependencyPath(const QString &path) const override; virtual void writeRcFilePart(QTextStream &t); - virtual bool findLibraries(bool linkPrl, bool mergeLflags); + bool findLibraries(bool linkPrl, bool mergeLflags) override; - virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg); - virtual ProString fixLibFlag(const ProString &lib); + LibFlagType parseLibFlag(const ProString &flag, ProString *arg) override; + ProString fixLibFlag(const ProString &lib) override; + bool processPrlFileBase(QString &origFile, const QStringRef &origName, + const QStringRef &fixedBase, int slashOff) override; void processVars(); void fixTargetExt(); diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp index fd84dff59d..2b2c6d0078 100644 --- a/qmake/library/ioutils.cpp +++ b/qmake/library/ioutils.cpp @@ -200,7 +200,7 @@ QString IoUtils::shellQuoteWin(const QString &arg) # if defined(Q_OS_WIN) static QString windowsErrorCode() { - wchar_t *string = 0; + wchar_t *string = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), @@ -244,7 +244,7 @@ bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceF return false; } FILETIME ft; - GetFileTime(rHand, 0, 0, &ft); + GetFileTime(rHand, NULL, NULL, &ft); CloseHandle(rHand); HANDLE wHand = CreateFile((wchar_t*)targetFileName.utf16(), GENERIC_WRITE, FILE_SHARE_READ, @@ -253,7 +253,7 @@ bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceF *errorString = fL1S("Cannot open %1: %2").arg(targetFileName, windowsErrorCode()); return false; } - SetFileTime(wHand, 0, 0, &ft); + SetFileTime(wHand, NULL, NULL, &ft); CloseHandle(wHand); # endif return true; diff --git a/qmake/library/proitems.h b/qmake/library/proitems.h index 1d7ebed3aa..2b09fc2074 100644 --- a/qmake/library/proitems.h +++ b/qmake/library/proitems.h @@ -78,12 +78,12 @@ public: int sourceFile() const { return m_file; } ProString &prepend(const ProString &other); - ProString &append(const ProString &other, bool *pending = 0); + ProString &append(const ProString &other, bool *pending = nullptr); ProString &append(const QString &other) { return append(ProString(other)); } ProString &append(const QLatin1String other); ProString &append(const char *other) { return append(QLatin1String(other)); } ProString &append(QChar other); - ProString &append(const ProStringList &other, bool *pending = 0, bool skipEmpty1st = false); + ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false); ProString &operator+=(const ProString &other) { return append(other); } ProString &operator+=(const QString &other) { return append(other); } ProString &operator+=(const QLatin1String other) { return append(other); } @@ -133,9 +133,9 @@ public: bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } - int toLongLong(bool *ok = 0, int base = 10) const { return toQStringRef().toLongLong(ok, base); } - int toInt(bool *ok = 0, int base = 10) const { return toQStringRef().toInt(ok, base); } - short toShort(bool *ok = 0, int base = 10) const { return toQStringRef().toShort(ok, base); } + int toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringRef().toLongLong(ok, base); } + int toInt(bool *ok = nullptr, int base = 10) const { return toQStringRef().toInt(ok, base); } + short toShort(bool *ok = nullptr, int base = 10) const { return toQStringRef().toShort(ok, base); } uint hash() const { return m_hash; } static uint hash(const QChar *p, int n); @@ -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(nullptr) {} + 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..f81bec158b 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,23 +1672,15 @@ 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; + LoadFlags flags; if (m_cumulative) flags = LoadSilent; if (args.count() >= 2) { @@ -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..432339d48e 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -118,7 +118,7 @@ bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two) } QMakeBaseEnv::QMakeBaseEnv() - : evaluator(0) + : evaluator(nullptr) { #ifdef PROEVALUATOR_THREAD_SAFE inProgress = false; @@ -215,7 +215,7 @@ QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeV initStatics(); // Configuration, more or less - m_caller = 0; + m_caller = nullptr; #ifdef PROEVALUATOR_CUMULATIVE m_cumulative = false; #endif @@ -337,7 +337,8 @@ static void replaceInList(ProStringList *varlist, const QRegExp ®exp, 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) { @@ -940,7 +941,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( if (varName == statics.strTEMPLATE) setTemplate(); else if (varName == statics.strQMAKE_PLATFORM) - m_featureRoots = 0; + m_featureRoots = nullptr; else if (varName == statics.strQMAKE_DIR_SEP) m_dirSep = first(varName); else if (varName == statics.strQMAKESPEC) { @@ -949,7 +950,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( if (IoUtils::isAbsolutePath(spec)) { m_qmakespec = spec; m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); - m_featureRoots = 0; + m_featureRoots = nullptr; } } } @@ -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); @@ -1592,7 +1594,7 @@ ProFile *QMakeEvaluator::currentProFile() const { if (m_profileStack.count() > 0) return m_profileStack.top(); - return 0; + return nullptr; } int QMakeEvaluator::currentFileId() const @@ -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 = @@ -1869,7 +1874,7 @@ ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap: if (first && isFunctParam(variableName)) break; } - return 0; + return nullptr; } ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName) diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h index dc35e1ddab..f617681cbb 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 @@ -276,9 +282,9 @@ public: #endif struct Location { - Location() : pro(0), line(0) {} + Location() : pro(nullptr), line(0) {} Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {} - void clear() { pro = 0; line = 0; } + void clear() { pro = nullptr; line = 0; } ProFile *pro; ushort line; }; 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/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp index 37608c7a15..131ec6db6a 100644 --- a/qmake/library/qmakeparser.cpp +++ b/qmake/library/qmakeparser.cpp @@ -215,7 +215,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) pro->itemsRef()->squeeze(); pro->ref(); } else { - pro = 0; + pro = nullptr; } ent->pro = pro; #ifdef PROPARSER_THREAD_SAFE @@ -234,7 +234,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) if (readFile(id, flags, &contents)) pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); else - pro = 0; + pro = nullptr; } return pro; } @@ -437,7 +437,7 @@ void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar if (context == CtxPureValue) { end = inend; - cptr = 0; + cptr = nullptr; lineCont = false; indent = 0; // just gcc being stupid goto nextChr; @@ -449,7 +449,7 @@ void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar // First, skip leading whitespace for (indent = 0; ; ++cur, ++indent) { if (cur == inend) { - cur = 0; + cur = nullptr; goto flushLine; } c = *cur; @@ -1112,7 +1112,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg if (uc == ptr) { // for(literal) (only "ever" would be legal if qmake was sane) putTok(tokPtr, TokForLoop); - putHashStr(tokPtr, (ushort *)0, (uint)0); + putHashStr(tokPtr, nullptr, (uint)0); putBlockLen(tokPtr, 1 + 3 + nlen + 1); putTok(tokPtr, TokHashLiteral); putHashStr(tokPtr, uce + 2, nlen); @@ -1135,7 +1135,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg } else if (argc == 1) { // for(non-literal) (this wouldn't be here if qmake was sane) putTok(tokPtr, TokForLoop); - putHashStr(tokPtr, (ushort *)0, (uint)0); + putHashStr(tokPtr, nullptr, (uint)0); uc = uce; goto doFor; } diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h index 3ae30dcf74..e9529f8bf6 100644 --- a/qmake/library/qmakeparser.h +++ b/qmake/library/qmakeparser.h @@ -110,7 +110,7 @@ private: }; struct BlockScope { - BlockScope() : start(0), braceLevel(0), special(false), inBranch(false), nest(NestNone) {} + BlockScope() : start(nullptr), braceLevel(0), special(false), inBranch(false), nest(NestNone) {} BlockScope(const BlockScope &other) { *this = other; } ushort *start; // Where this block started; store length here int braceLevel; // Nesting of braces in scope diff --git a/qmake/main.cpp b/qmake/main.cpp index 85709dc9bf..a4ef79227b 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; @@ -552,7 +546,7 @@ int runQMake(int argc, char **argv) exit_val = 5; } delete mkfile; - mkfile = NULL; + mkfile = nullptr; } qmakeClearCaches(); return exit_val; 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/option.cpp b/qmake/option.cpp index baad644280..dcebeadcb8 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -507,7 +507,7 @@ QString Option::fixString(QString string, uchar flags) { //const QString orig_string = string; - static QHash<FixStringCacheKey, QString> *cache = 0; + static QHash<FixStringCacheKey, QString> *cache = nullptr; if(!cache) { cache = new QHash<FixStringCacheKey, QString>; qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache); @@ -635,7 +635,7 @@ public: QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { } ~QMakeCacheClearItem() { (*func)(*data); - *data = 0; + *data = nullptr; } }; static QList<QMakeCacheClearItem*> cache_items; diff --git a/qmake/option.h b/qmake/option.h index eaa3706b24..25b2d64aaa 100644 --- a/qmake/option.h +++ b/qmake/option.h @@ -60,12 +60,12 @@ class QMakeProject; class EvalHandler : public QMakeHandler { public: - void message(int type, const QString &msg, const QString &fileName, int lineNo); + void message(int type, const QString &msg, const QString &fileName, int lineNo) override; - void fileMessage(int type, const QString &msg); + void fileMessage(int type, const QString &msg) override; - void aboutToEval(ProFile *, ProFile *, EvalFileType); - void doneWithEval(ProFile *); + void aboutToEval(ProFile *, ProFile *, EvalFileType) override; + void doneWithEval(ProFile *) override; }; struct Option @@ -108,7 +108,7 @@ struct Option }; //both of these must be called.. - static int init(int argc=0, char **argv=0); //parse cmdline + static int init(int argc = 0, char **argv = nullptr); //parse cmdline static void prepareProject(const QString &pfile); static bool postProcessProject(QMakeProject *); 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(); } diff --git a/qmake/property.cpp b/qmake/property.cpp index 9a8db8904d..c0a3ec0dab 100644 --- a/qmake/property.cpp +++ b/qmake/property.cpp @@ -68,7 +68,7 @@ static const struct { { "QMAKE_XSPEC", QLibraryInfo::TargetSpecPath, true, true }, }; -QMakeProperty::QMakeProperty() : settings(0) +QMakeProperty::QMakeProperty() : settings(nullptr) { reload(); } @@ -99,7 +99,7 @@ void QMakeProperty::reload() QMakeProperty::~QMakeProperty() { delete settings; - settings = 0; + settings = nullptr; } void QMakeProperty::initSettings() |