fix host vs. makefile directory separator mess
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>
Wed, 25 Jul 2012 08:51:44 +0000 (10:51 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 27 Jul 2012 22:09:45 +0000 (00:09 +0200)
the system path separator and shell are bound to the host system
(system() will use cmd even on mingw with sh.exe in path).
the makefiles otoh may depend on what the qmakespec defines.

consequently, add $$system_path() and $$system_quote() (for use with
system() & $$system()). $$native_path() is renamed to $$shell_path() and
should be used with $$shell_quote() to produce command lines in
makefiles.
$$QMAKE_DIR_SEP needs to be applied to Option::dir_sep right after
parsing the spec, so it is available to $$shell_{path,quote}().

Change-Id: If3db4849e7f96068cf03a32348a24f3a72d6292c
Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
mkspecs/features/configure.prf
mkspecs/features/default_post.prf
mkspecs/features/incredibuild_xge.prf
mkspecs/features/qt_functions.prf
mkspecs/features/testcocoon.prf
mkspecs/features/win32/embed_manifest_dll.prf
mkspecs/features/win32/embed_manifest_exe.prf
qmake/option.cpp
qmake/project.cpp
tests/auto/tools/qmake/testdata/functions/functions.pro

index 651f0ad..ff52c6b 100644 (file)
@@ -44,7 +44,7 @@ defineTest(qtCompileTest) {
 
     test_dir = $$QMAKE_CONFIG_TESTS_DIR/$$1
     test_out_dir = $$shadowed($$test_dir)
-    test_cmd_base = "cd $$shell_quote($$native_path($$test_out_dir)) &&"
+    test_cmd_base = "cd $$system_quote($$system_path($$test_out_dir)) &&"
 
     # Disable qmake features which are typically counterproductive for tests
     qmake_configs = "\"CONFIG -= qt debug_and_release app_bundle lib_bundle\""
@@ -54,7 +54,7 @@ defineTest(qtCompileTest) {
 
     mkpath($$test_out_dir)|error("Aborting.")
 
-    qtRunLoggedCommand("$$test_cmd_base $$shell_quote($$native_path($$QMAKE_QMAKE)) $$qmake_configs $$shell_quote($$test_dir)") {
+    qtRunLoggedCommand("$$test_cmd_base $$system_quote($$system_path($$QMAKE_QMAKE)) $$qmake_configs $$shell_quote($$test_dir)") {
         qtRunLoggedCommand("$$test_cmd_base $$QMAKE_MAKE") {
             log("yes$$escape_expand(\\n)")
             msg = "test $$1 succeeded"
index 63daff6..d0a2d61 100644 (file)
@@ -31,8 +31,8 @@ breakpad {
     load(resolve_target)
     win32: QMAKE_CLEAN += $$replace(QMAKE_RESOLVED_TARGET, ...$, pdb)  # for the debug case it is hardcoded in qmake
 
-    DEBUGFILENAME = $$shell_quote($$native_path($$QMAKE_RESOLVED_TARGET))
-    PROJECTPATH = $$shell_quote($$native_path($$OUT_PWD))
+    DEBUGFILENAME = $$shell_quote($$shell_path($$QMAKE_RESOLVED_TARGET))
+    PROJECTPATH = $$shell_quote($$shell_path($$OUT_PWD))
 
     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$QMAKE_POST_LINK$$escape_expand(\\n\\t)
     QMAKE_POST_LINK = $$QMAKE_POST_LINK$$quote($${QT_BREAKPAD_ROOT_PATH}$${QMAKE_DIR_SEP}qtbreakpadsymbols $$DEBUGFILENAME $$PROJECTPATH)
index 28a58ca..028f39d 100644 (file)
@@ -6,6 +6,6 @@ contains(TEMPLATE, "vc.*") {
     win32-msvc2*|wince*msvc*: EOC = $$escape_expand(\\r\\h)
 
     for(xge, INCREDIBUILD_XGE) {
-        $${xge}.commands = Rem IncrediBuild_AllowRemote $$EOC Rem IncrediBuild_OutputFile $$native_path($${xge}.output) $$EOC $$eval($${xge}.commands)
+        $${xge}.commands = Rem IncrediBuild_AllowRemote $$EOC Rem IncrediBuild_OutputFile $$shell_path($${xge}.output) $$EOC $$eval($${xge}.commands)
     }
 }
index 649bea0..b6a3b0a 100644 (file)
@@ -137,12 +137,12 @@ defineTest(qtPrepareTool) {
             }
         }
     }
-    $$1 = $$native_path($$eval($$1))
+    $$1 = $$shell_path($$eval($$1))
 
     deps = $$resolve_depends(QT_TOOL.$${2}.depends, "QT.")
     !isEmpty(deps) {
         for(dep, deps): \
-            deppath += $$native_path($$eval(QT.$${dep}.libs))
+            deppath += $$shell_path($$eval(QT.$${dep}.libs))
         deppath = $$unique(deppath)
         equals(QMAKE_DIR_SEP, /) {
             equals(QMAKE_HOST.os, Windows): \
index bf7e3dd..efa33ec 100644 (file)
@@ -25,7 +25,7 @@ TESTCOCOON_COVERAGE_OPTIONS = \
 # is built directly in target.path and there is no need to move the csmes.
 !isEmpty(DESTDIR):contains(TEMPLATE, lib) {
     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
-    QMAKE_POST_LINK = -$(MOVE) $${TARGET_BASENAME}.csmes $$native_path($${QMAKE_RESOLVED_TARGET}.csmes)$$QMAKE_POST_LINK
+    QMAKE_POST_LINK = -$(MOVE) $${TARGET_BASENAME}.csmes $$shell_path($${QMAKE_RESOLVED_TARGET}.csmes)$$QMAKE_POST_LINK
 }
 
 QMAKE_CLEAN +=  *.csexe *.csmes
index 783dc67..e50783d 100644 (file)
@@ -7,6 +7,6 @@
     NOPATH_TARGET ~= s,^(.*/)+,,    # Remove all paths
     QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\")
     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
-    QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$native_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);2)$$QMAKE_POST_LINK
+    QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$shell_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);2)$$QMAKE_POST_LINK
     QMAKE_CLEAN += $$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest
 }
index c496a53..526fc00 100644 (file)
@@ -7,6 +7,6 @@ if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):equals(TEMPLATE, "app") {
     NOPATH_TARGET ~= s,^(.*/)+,,    # Remove all paths
     QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\")
     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
-    QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$native_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);1)$$QMAKE_POST_LINK
+    QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$shell_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);1)$$QMAKE_POST_LINK
     QMAKE_CLEAN += $$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest
 }
index b01b4ed..3bfec96 100644 (file)
@@ -555,7 +555,6 @@ bool Option::postProcessProject(QMakeProject *project)
     Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
     Option::lex_mod = project->first("QMAKE_MOD_LEX");
     Option::yacc_mod = project->first("QMAKE_MOD_YACC");
-    Option::dir_sep = project->first("QMAKE_DIR_SEP");
 
     if (Option::output_dir.startsWith(project->buildRoot()))
         Option::mkfile::cachefile_depth =
index 26ab0d0..0681697 100644 (file)
@@ -82,8 +82,8 @@ enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST
                   E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
                   E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_REPLACE,
                   E_SIZE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
-                  E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, E_NATIVE_PATH,
-                  E_SHELL_QUOTE };
+                  E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
+                  E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE };
 QHash<QString, ExpandFunc> qmake_expandFunctions()
 {
     static QHash<QString, ExpandFunc> *qmake_expand_functions = 0;
@@ -125,7 +125,9 @@ QHash<QString, ExpandFunc> qmake_expandFunctions()
         qmake_expand_functions->insert("absolute_path", E_ABSOLUTE_PATH);
         qmake_expand_functions->insert("relative_path", E_RELATIVE_PATH);
         qmake_expand_functions->insert("clean_path", E_CLEAN_PATH);
-        qmake_expand_functions->insert("native_path", E_NATIVE_PATH);
+        qmake_expand_functions->insert("system_path", E_SYSTEM_PATH);
+        qmake_expand_functions->insert("shell_path", E_SHELL_PATH);
+        qmake_expand_functions->insert("system_quote", E_SYSTEM_QUOTE);
         qmake_expand_functions->insert("shell_quote", E_SHELL_QUOTE);
     }
     return *qmake_expand_functions;
@@ -1498,6 +1500,8 @@ QMakeProject::read(uchar cmd)
             doProjectInclude("spec_post", IncludeFlagFeature, vars);
             // The spec extends the feature search path, so invalidate the cache.
             invalidateFeatureRoots();
+            // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it
+            Option::dir_sep = first(QLatin1String("QMAKE_DIR_SEP"));
 
             if (!conffile.isEmpty()) {
                 debug_msg(1, "Project config file: reading %s", conffile.toLatin1().constData());
@@ -1895,45 +1899,54 @@ subAll(QStringList *val, const QStringList &diffval)
 }
 
 inline static
-bool isSpecialChar(ushort c)
+bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
+{
+    for (int x = arg.length() - 1; x >= 0; --x) {
+        ushort c = arg.unicode()[x].unicode();
+        if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
+            return true;
+    }
+    return false;
+}
+
+static QString
+shellQuoteUnix(const QString &arg)
 {
     // Chars that should be quoted (TM). This includes:
-#ifdef Q_OS_WIN
-    // - control chars & space
-    // - the shell meta chars "&()<>^|
-    // - the potential separators ,;=
-    static const uchar iqm[] = {
-        0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
-        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
-    };
-#else
     static const uchar iqm[] = {
         0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
         0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
     }; // 0-32 \'"$`<>|;&(){}*?#!~[]
-#endif
 
-    return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
-}
+    if (!arg.length())
+        return QString::fromLatin1("\"\"");
 
-inline static
-bool hasSpecialChars(const QString &arg)
-{
-    for (int x = arg.length() - 1; x >= 0; --x)
-        if (isSpecialChar(arg.unicode()[x].unicode()))
-            return true;
-    return false;
+    QString ret(arg);
+    if (hasSpecialChars(ret, iqm)) {
+        ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+        ret.prepend(QLatin1Char('\''));
+        ret.append(QLatin1Char('\''));
+    }
+    return ret;
 }
 
 static QString
-shellQuote(const QString &arg)
+shellQuoteWin(const QString &arg)
 {
+    // Chars that should be quoted (TM). This includes:
+    // - control chars & space
+    // - the shell meta chars "&()<>^|
+    // - the potential separators ,;=
+    static const uchar iqm[] = {
+        0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
+        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
+    };
+
     if (!arg.length())
         return QString::fromLatin1("\"\"");
 
     QString ret(arg);
-    if (hasSpecialChars(ret)) {
-#ifdef Q_OS_WIN
+    if (hasSpecialChars(ret, iqm)) {
         // Quotes are escaped and their preceding backslashes are doubled.
         // It's impossible to escape anything inside a quoted string on cmd
         // level, so the outer quoting must be "suspended".
@@ -1946,11 +1959,6 @@ shellQuote(const QString &arg)
             --i;
         ret.insert(i, QLatin1Char('"'));
         ret.prepend(QLatin1Char('"'));
-#else // Q_OS_WIN
-        ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
-        ret.prepend(QLatin1Char('\''));
-        ret.append(QLatin1Char('\''));
-#endif // Q_OS_WIN
     }
     return ret;
 }
@@ -2738,19 +2746,39 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
         else
             ret += QDir::cleanPath(args.at(0));
         break;
-    case E_NATIVE_PATH:
+    case E_SYSTEM_PATH:
         if (args.count() != 1)
-            fprintf(stderr, "%s:%d native_path(path) requires one argument.\n",
+            fprintf(stderr, "%s:%d system_path(path) requires one argument.\n",
+                    parser.file.toLatin1().constData(), parser.line_no);
+        else
+            ret += Option::fixPathToLocalOS(args.at(0), false);
+        break;
+    case E_SHELL_PATH:
+        if (args.count() != 1)
+            fprintf(stderr, "%s:%d shell_path(path) requires one argument.\n",
                     parser.file.toLatin1().constData(), parser.line_no);
         else
             ret += Option::fixPathToTargetOS(args.at(0), false);
         break;
+    case E_SYSTEM_QUOTE:
+        if (args.count() != 1)
+            fprintf(stderr, "%s:%d system_quote(args) requires one argument.\n",
+                    parser.file.toLatin1().constData(), parser.line_no);
+        else
+#ifdef Q_OS_WIN
+            ret += shellQuoteWin(args.at(0));
+#else
+            ret += shellQuoteUnix(args.at(0));
+#endif
+        break;
     case E_SHELL_QUOTE:
         if (args.count() != 1)
             fprintf(stderr, "%s:%d shell_quote(args) requires one argument.\n",
                     parser.file.toLatin1().constData(), parser.line_no);
+        else if (Option::dir_sep.at(0) != QLatin1Char('/'))
+            ret += shellQuoteWin(args.at(0));
         else
-            ret += shellQuote(args.at(0));
+            ret += shellQuoteUnix(args.at(0));
         break;
     default: {
         fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
index 884113b..98e12b7 100644 (file)
@@ -131,7 +131,8 @@ testReplace($$format_number(13, width=5 padsign zeropad), " 0013", "zero-padded
 
 testReplace($$clean_path("c:$${DIR_SEPARATOR}crazy//path/../trolls"), "c:/crazy/trolls", "clean_path")
 
-testReplace($$native_path("/crazy/trolls"), "$${DIR_SEPARATOR}crazy$${DIR_SEPARATOR}trolls", "native_path")
+testReplace($$shell_path("/crazy/trolls"), "$${QMAKE_DIR_SEP}crazy$${QMAKE_DIR_SEP}trolls", "shell_path")
+testReplace($$system_path("/crazy/trolls"), "$${DIR_SEPARATOR}crazy$${DIR_SEPARATOR}trolls", "system_path")
 
 testReplace($$absolute_path("crazy/trolls"), "$$PWD/crazy/trolls", "absolute_path")
 testReplace($$absolute_path("crazy/trolls", "/fake/path"), "/fake/path/crazy/trolls", "absolute_path with base")
@@ -142,10 +143,17 @@ testReplace($$relative_path(""), "", "relative_path of empty")
 
 #this test is very rudimentary. the backend function is thoroughly tested in qt creator
 in = "some nasty\" path\\"
-win32: \
-    out = "\"some nasty\"\\^\"\" path\"\\"
+out_cmd = "\"some nasty\"\\^\"\" path\"\\"
+out_sh = "'some nasty\" path\\'"
+equals(QMAKE_HOST.os, Windows): \
+    out = $$out_cmd
 else: \
-    out = "'some nasty\" path\\'"
+    out = $$out_sh
+testReplace($$system_quote($$in), $$out, "system_quote")
+!equals(QMAKE_DIR_SEP, /): \
+    out = $$out_cmd
+else: \
+    out = $$out_sh
 testReplace($$shell_quote($$in), $$out, "shell_quote")
 
 testReplace($$reverse($$list(one two three)), three two one, "reverse")