summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qmake/library/ioutils.cpp23
-rw-r--r--qmake/library/qmakebuiltins.cpp13
-rw-r--r--qmake/library/qmakeglobals.cpp15
-rw-r--r--tests/auto/tools/qmakelib/evaltest.cpp46
-rw-r--r--tests/auto/tools/qmakelib/tst_qmakelib.cpp97
-rw-r--r--tests/auto/tools/qmakelib/tst_qmakelib.h5
6 files changed, 157 insertions, 42 deletions
diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp
index 684bcb9a37..afd41912fe 100644
--- a/qmake/library/ioutils.cpp
+++ b/qmake/library/ioutils.cpp
@@ -66,21 +66,22 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName)
bool IoUtils::isRelativePath(const QString &path)
{
- if (path.startsWith(QLatin1Char('/')))
- return false;
#ifdef QMAKE_BUILTIN_PRFS
if (path.startsWith(QLatin1String(":/")))
return false;
#endif
#ifdef Q_OS_WIN
- if (path.startsWith(QLatin1Char('\\')))
- return false;
- // Unlike QFileInfo, this won't accept a relative path with a drive letter.
- // Such paths result in a royal mess anyway ...
+ // Unlike QFileInfo, this considers only paths with both a drive prefix and
+ // a subsequent (back-)slash absolute:
if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
- && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\')))
+ && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
return false;
-#endif
+ }
+ // (... unless, of course, they're UNC, which qmake fails on anyway)
+#else
+ if (path.startsWith(QLatin1Char('/')))
+ return false;
+#endif // Q_OS_WIN
return true;
}
@@ -100,6 +101,12 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
return QString();
if (isAbsolutePath(fileName))
return QDir::cleanPath(fileName);
+#ifdef Q_OS_WIN // Add drive to otherwise-absolute path:
+ if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') {
+ Q_ASSERT(isAbsolutePath(baseDir));
+ return QDir::cleanPath(baseDir.left(2) + fileName);
+ }
+#endif // Q_OS_WIN
return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
}
diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp
index 1b98cbd909..e4b00a6cb3 100644
--- a/qmake/library/qmakebuiltins.cpp
+++ b/qmake/library/qmakebuiltins.cpp
@@ -1173,9 +1173,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
if (args.count() > 2) {
evalError(fL1S("absolute_path(path[, base]) requires one or two arguments."));
} else {
- QString rstr = QDir::cleanPath(
- QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory())
- .absoluteFilePath(args.at(0).toQString(m_tmp1)));
+ QString arg = args.at(0).toQString(m_tmp1);
+ QString baseDir = args.count() > 1 ? 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)
@@ -1187,9 +1187,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
if (args.count() > 2) {
evalError(fL1S("relative_path(path[, base]) requires one or two arguments."));
} else {
- QDir baseDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory());
- QString rstr = baseDir.relativeFilePath(baseDir.absoluteFilePath(
- args.at(0).toQString(m_tmp1)));
+ QString arg = args.at(0).toQString(m_tmp1);
+ QString baseDir = args.count() > 1 ? 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)));
}
break;
diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp
index b6dc8b20b6..d733d479cf 100644
--- a/qmake/library/qmakeglobals.cpp
+++ b/qmake/library/qmakeglobals.cpp
@@ -68,6 +68,7 @@
#endif
QT_BEGIN_NAMESPACE
+using namespace QMakeInternal; // for IoUtils
#define fL1S(s) QString::fromLatin1(s)
@@ -96,9 +97,9 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s
{
QString ret = QDir::cleanPath(spec);
if (ret.contains(QLatin1Char('/'))) {
- QString absRet = QDir(state.pwd).absoluteFilePath(ret);
+ QString absRet = IoUtils::resolvePath(state.pwd, ret);
if (QFile::exists(absRet))
- ret = QDir::cleanPath(absRet);
+ ret = absRet;
}
return ret;
}
@@ -126,10 +127,10 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
user_template_prefix = arg;
break;
case ArgCache:
- cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
+ cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
break;
case ArgQtConf:
- qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
+ qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
break;
default:
if (arg.startsWith(QLatin1Char('-'))) {
@@ -259,11 +260,11 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const
{
QStringList ret;
if (!val.isEmpty()) {
- QDir bdir;
+ QString cwd(QDir::currentPath());
const QStringList vals = val.split(dirlist_sep);
ret.reserve(vals.length());
for (const QString &it : vals)
- ret << QDir::cleanPath(bdir.absoluteFilePath(it));
+ ret << IoUtils::resolvePath(cwd, it);
}
return ret;
}
@@ -318,7 +319,7 @@ bool QMakeGlobals::initProperties()
return false;
data = proc.readAll();
#else
- if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation)
+ if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation)
+ QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) {
char buff[1024];
while (!feof(proc))
diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp
index 03fd4753fd..cf69cc4026 100644
--- a/tests/auto/tools/qmakelib/evaltest.cpp
+++ b/tests/auto/tools/qmakelib/evaltest.cpp
@@ -34,6 +34,12 @@
#include <qmakeglobals.h>
#include <qmakeevaluator.h>
+#ifdef Q_OS_WIN
+# define EVAL_DRIVE "R:"
+#else
+# define EVAL_DRIVE
+#endif
+
void tst_qmakelib::addAssignments()
{
QTest::newRow("assignment")
@@ -1599,20 +1605,28 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
<< true;
QTest::newRow("$$absolute_path(): file & path")
- << "VAR = $$absolute_path(dir/file.ext, /root/sub)"
- << "VAR = /root/sub/dir/file.ext"
+ << "VAR = $$absolute_path(dir/file.ext, " EVAL_DRIVE "/root/sub)"
+ << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext"
<< ""
<< true;
+#ifdef Q_OS_WIN
+ QTest::newRow("$$absolute_path(): driveless file & absolute path")
+ << "VAR = $$absolute_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/other)"
+ << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext"
+ << ""
+ << true;
+#endif
+
QTest::newRow("$$absolute_path(): absolute file & path")
- << "VAR = $$absolute_path(/root/sub/dir/file.ext, /other)"
- << "VAR = /root/sub/dir/file.ext"
+ << "VAR = $$absolute_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/other)"
+ << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext"
<< ""
<< true;
QTest::newRow("$$absolute_path(): empty file & path")
- << "VAR = $$absolute_path('', /root/sub)"
- << "VAR = /root/sub"
+ << "VAR = $$absolute_path('', " EVAL_DRIVE "/root/sub)"
+ << "VAR = " EVAL_DRIVE "/root/sub"
<< ""
<< true;
@@ -1634,14 +1648,22 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
<< ""
<< true;
+#ifdef Q_OS_WIN
+ QTest::newRow("$$relative_path(): driveless file & absolute path")
+ << "VAR = $$relative_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)"
+ << "VAR = dir/file.ext"
+ << ""
+ << true;
+#endif
+
QTest::newRow("$$relative_path(): absolute file & path")
- << "VAR = $$relative_path(/root/sub/dir/file.ext, /root/sub)"
+ << "VAR = $$relative_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)"
<< "VAR = dir/file.ext"
<< ""
<< true;
QTest::newRow("$$relative_path(): empty file & path")
- << "VAR = $$relative_path('', /root/sub)"
+ << "VAR = $$relative_path('', " EVAL_DRIVE "/root/sub)"
<< "VAR = ."
<< ""
<< true;
@@ -2555,20 +2577,20 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
<< true;
QTest::newRow("touch(): missing target")
- << "touch(/does/not/exist, files/other.txt): OK = 1"
+ << "touch(" EVAL_DRIVE "/does/not/exist, files/other.txt): OK = 1"
<< "OK = UNDEF"
#ifdef Q_OS_WIN
- << "##:1: Cannot open /does/not/exist: The system cannot find the path specified."
+ << "##:1: Cannot open " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified."
#else
<< "##:1: Cannot touch /does/not/exist: No such file or directory."
#endif
<< true;
QTest::newRow("touch(): missing reference")
- << "touch(" + wpath + ", /does/not/exist): OK = 1"
+ << "touch(" + wpath + ", " EVAL_DRIVE "/does/not/exist): OK = 1"
<< "OK = UNDEF"
#ifdef Q_OS_WIN
- << "##:1: Cannot open reference file /does/not/exist: The system cannot find the path specified."
+ << "##:1: Cannot open reference file " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified."
#else
<< "##:1: Cannot stat() reference file /does/not/exist: No such file or directory."
#endif
diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.cpp b/tests/auto/tools/qmakelib/tst_qmakelib.cpp
index b1250f4f1a..4a4b20fe50 100644
--- a/tests/auto/tools/qmakelib/tst_qmakelib.cpp
+++ b/tests/auto/tools/qmakelib/tst_qmakelib.cpp
@@ -42,6 +42,7 @@ void tst_qmakelib::initTestCase()
#endif
m_prop.insert(ProKey("P1"), ProString("prop val"));
m_prop.insert(ProKey("QT_HOST_DATA/get"), ProString(m_indir));
+ m_prop.insert(ProKey("QT_HOST_DATA/src"), ProString(m_indir));
QVERIFY(!m_indir.isEmpty());
QVERIFY(QDir(m_outdir).removeRecursively());
@@ -224,21 +225,99 @@ void tst_qmakelib::pathUtils()
QVERIFY(IoUtils::isRelativePath(fn0));
QString fn1 = "/a/unix/file/path";
- QVERIFY(IoUtils::isAbsolutePath(fn1));
QCOMPARE(IoUtils::pathName(fn1).toString(), QStringLiteral("/a/unix/file/"));
QCOMPARE(IoUtils::fileName(fn1).toString(), QStringLiteral("path"));
+}
-#ifdef Q_OS_WIN
- QString fn0a = "c:file/path";
- QVERIFY(IoUtils::isRelativePath(fn0a));
+void tst_qmakelib::ioUtilRelativity_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<bool>("relative");
- QString fn1a = "c:\\file\\path";
- QVERIFY(IoUtils::isAbsolutePath(fn1a));
+ static const struct {
+ const char *name;
+ const char *path;
+ bool relative;
+ } rows[] = {
+ { "resource", ":/resource",
+#ifdef QMAKE_BUILTIN_PRFS
+ false
+#else
+ true
#endif
+ },
+#ifdef Q_OS_WIN // all the complications:
+ // (except UNC: unsupported)
+ { "drive-abs", "c:/path/to/file", false },
+ { "drive-abs-bs", "c:\\path\\to\\file", false },
+ { "drive-path", "c:path/to/file.txt", true },
+ { "drive-path-bs", "c:path\\to\\file.txt", true },
+ { "rooted", "/Users/qt/bin/true", true },
+ { "rooted-bs", "\\Users\\qt\\bin\\true", true },
+ { "drive-rel", "c:file.txt", true },
+ { "subdir-bs", "path\\to\\file", true },
+#else
+ { "rooted", "/usr/bin/false", false },
+#endif // Q_OS_WIN
+ { "subdir", "path/to/file", true },
+ { "simple", "file.name", true },
+ { "empty", "", true }
+ };
+
+ for (unsigned int i = sizeof(rows) / sizeof(rows[0]); i-- > 0; )
+ QTest::newRow(rows[i].name) << QString::fromLatin1(rows[i].path)
+ << rows[i].relative;
+}
+
+void tst_qmakelib::ioUtilRelativity()
+{
+ QFETCH(QString, path);
+ QFETCH(bool, relative);
+
+ QCOMPARE(IoUtils::isRelativePath(path), relative);
+}
+
+void tst_qmakelib::ioUtilResolve_data()
+{
+ QTest::addColumn<QString>("base");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("expect");
+
+ static const struct {
+ const char *name;
+ const char *base;
+ const char *path;
+ const char *expect;
+ } data[] = {
+#ifdef Q_OS_WIN // all the complications:
+ { "drive-drive", "a:/ms/dir", "z:/root/file", "z:/root/file" },
+ { "drive-drive-bs", "a:\\ms\\dir", "z:\\root\\file", "z:/root/file" },
+ { "drive-root", "a:/ms/dir", "/root/file", "a:/root/file" },
+ { "drive-root-bs", "a:\\ms\\dir", "\\root\\file", "a:/root/file" },
+ { "drive-sub", "a:/ms/dir", "sub/file", "a:/ms/dir/sub/file" },
+ { "drive-sub-bs", "a:\\ms\\dir", "sub\\file", "a:/ms/dir/sub/file" },
+ { "drive-rel", "a:/ms/dir", "file.txt", "a:/ms/dir/file.txt" },
+ { "drive-rel-bs", "a:\\ms\\dir", "file.txt", "a:/ms/dir/file.txt" },
+#else
+ { "abs-abs", "/a/unix/dir", "/root/file", "/root/file" },
+ { "abs-sub", "/a/unix/dir", "sub/file", "/a/unix/dir/sub/file" },
+ { "abs-rel", "/a/unix/dir", "file.txt", "/a/unix/dir/file.txt" },
+#endif // Q_OS_WIN
+ };
+
+ for (unsigned i = sizeof(data) / sizeof(data[0]); i-- > 0; )
+ QTest::newRow(data[i].name) << QString::fromLatin1(data[i].base)
+ << QString::fromLatin1(data[i].path)
+ << QString::fromLatin1(data[i].expect);
+}
+
+void tst_qmakelib::ioUtilResolve()
+{
+ QFETCH(QString, base);
+ QFETCH(QString, path);
+ QFETCH(QString, expect);
- QString fnbase = "/another/dir";
- QCOMPARE(IoUtils::resolvePath(fnbase, fn0), QStringLiteral("/another/dir/file/path"));
- QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path"));
+ QCOMPARE(IoUtils::resolvePath(base, path), expect);
}
void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg)
diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.h b/tests/auto/tools/qmakelib/tst_qmakelib.h
index e75dedb7ec..acfeb43ecd 100644
--- a/tests/auto/tools/qmakelib/tst_qmakelib.h
+++ b/tests/auto/tools/qmakelib/tst_qmakelib.h
@@ -48,7 +48,12 @@ private slots:
void quoteArgUnix();
void quoteArgWin_data();
void quoteArgWin();
+
void pathUtils();
+ void ioUtilRelativity_data();
+ void ioUtilRelativity();
+ void ioUtilResolve_data();
+ void ioUtilResolve();
void proString();
void proStringList();