fix host vs. makefile directory separator mess
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>
This commit is contained in:
parent
d9048bef20
commit
e07372ff50
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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): \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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,10 +1899,41 @@ 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:
|
||||
static const uchar iqm[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
|
||||
0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
|
||||
}; // 0-32 \'"$`<>|;&(){}*?#!~[]
|
||||
|
||||
if (!arg.length())
|
||||
return QString::fromLatin1("\"\"");
|
||||
|
||||
QString ret(arg);
|
||||
if (hasSpecialChars(ret, iqm)) {
|
||||
ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
|
||||
ret.prepend(QLatin1Char('\''));
|
||||
ret.append(QLatin1Char('\''));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QString
|
||||
shellQuoteWin(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 ,;=
|
||||
@ -1906,34 +1941,12 @@ bool isSpecialChar(ushort c)
|
||||
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)));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static QString
|
||||
shellQuote(const QString &arg)
|
||||
{
|
||||
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",
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user