From 9c2ec72b95c13991f3c62b762783373c3d691337 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 1 Nov 2012 14:31:16 +0100 Subject: Improve path search in configure. - Remove duplicated code locateFile/locateFileInPaths. - Move basic path search functionality to Environment. - Add functions for headerPaths/libraryPaths to Environment. - Use QStandardPaths::findExecutable(). - Replace Environment::detectExecutable by QStandardPaths::findExecutable(). - Introduce static path lists in findFile() to avoid repeated directory scans Change-Id: I9b93066a3de65f40527780d6ddf7989bca35cd04 Reviewed-by: Oswald Buddenhagen --- tools/configure/Makefile.mingw | 2 + tools/configure/Makefile.win32 | 4 + tools/configure/configure.pro | 3 + tools/configure/configureapp.cpp | 127 +++++------------------------ tools/configure/configureapp.h | 7 +- tools/configure/environment.cpp | 171 ++++++++++++++++++++++++++++++++------- tools/configure/environment.h | 12 ++- 7 files changed, 183 insertions(+), 143 deletions(-) (limited to 'tools') diff --git a/tools/configure/Makefile.mingw b/tools/configure/Makefile.mingw index d6fe5b1f22..7212b0d3a7 100644 --- a/tools/configure/Makefile.mingw +++ b/tools/configure/Makefile.mingw @@ -52,6 +52,8 @@ OBJECTS = \ qtextstream.o \ qlogging.o \ qtemporaryfile.o \ + qstandardpaths.o \ + qstandardpaths_win.o \ qsystemlibrary.o \ qbitarray.o \ qdatetime.o \ diff --git a/tools/configure/Makefile.win32 b/tools/configure/Makefile.win32 index 5a917b1605..5b0a21a669 100644 --- a/tools/configure/Makefile.win32 +++ b/tools/configure/Makefile.win32 @@ -50,6 +50,8 @@ OBJECTS = \ qtextstream.obj \ qlogging.obj \ qtemporaryfile.obj \ + qstandardpaths.obj \ + qstandardpaths_win.obj \ qsystemlibrary.obj \ qbitarray.obj \ qdatetime.obj \ @@ -119,6 +121,8 @@ qfsfileengine_iterator.obj: $(CORESRC)\io\qfsfileengine_iterator.cpp $(PCH) qiodevice.obj: $(CORESRC)\io\qiodevice.cpp $(PCH) qtextstream.obj: $(CORESRC)\io\qtextstream.cpp $(PCH) qtemporaryfile.obj: $(CORESRC)\io\qtemporaryfile.cpp $(PCH) +qstandardpaths.obj: $(CORESRC)\io\qstandardpaths.cpp $(PCH) +qstandardpaths_win.obj: $(CORESRC)\io\qstandardpaths_win.cpp $(PCH) qsystemlibrary.obj: $(CORESRC)\plugin\qsystemlibrary.cpp $(PCH) qbitarray.obj: $(CORESRC)\tools\qbitarray.cpp $(PCH) qdatetime.obj: $(CORESRC)\tools\qdatetime.cpp $(PCH) diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index c970880d8c..2163e37a58 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -63,6 +63,7 @@ HEADERS = configureapp.h environment.h tools.h\ $$QT_SOURCE_TREE/src/corelib/io/qiodevice.h \ $$QT_SOURCE_TREE/src/corelib/io/qtextstream.h \ $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.h \ + $$QT_SOURCE_TREE/src/corelib/io/qstandardpaths.h \ $$QT_SOURCE_TREE/src/corelib/tools/qbitarray.h \ $$QT_SOURCE_TREE/src/corelib/tools/qdatetime.h \ $$QT_SOURCE_TREE/src/corelib/tools/qmap.h \ @@ -110,6 +111,8 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qiodevice.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qtextstream.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qstandardpaths.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qstandardpaths_win.cpp \ $$QT_SOURCE_TREE/src/corelib/plugin/qsystemlibrary.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qbitarray.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qdatetime.cpp \ diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index cb7a3f4d6f..3a352f459c 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -142,7 +143,7 @@ Configure::Configure(int& argc, char** argv) const QString installPath = buildPath; #endif if (sourceDir != buildDir) { //shadow builds! - if (!findFile("perl") && !findFile("perl.exe")) { + if (QStandardPaths::findExecutable(QStringLiteral("perl.exe")).isEmpty()) { cout << "Error: Creating a shadow build of Qt requires" << endl << "perl to be in the PATH environment"; exit(0); // Exit cleanly for Ctrl+C @@ -1521,42 +1522,6 @@ void Configure::applySpecSpecifics() } } -QString Configure::locateFileInPaths(const QString &fileName, const QStringList &paths) -{ - QDir d; - for (QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it) { - // Remove any leading or trailing ", this is commonly used in the environment - // variables - QString path = (*it); - if (path.startsWith("\"")) - path = path.right(path.length() - 1); - if (path.endsWith("\"")) - path = path.left(path.length() - 1); - if (d.exists(path + QDir::separator() + fileName)) { - return (path); - } - } - return QString(); -} - -QString Configure::locateFile(const QString &fileName) -{ - QString file = fileName.toLower(); - QStringList paths; -#if defined(Q_OS_WIN32) - QRegExp splitReg("[;,]"); -#else - QRegExp splitReg("[:]"); -#endif - if (file.endsWith(".h")) - paths = QString::fromLocal8Bit(getenv("INCLUDE")).split(splitReg, QString::SkipEmptyParts); - else if (file.endsWith(".lib")) - paths = QString::fromLocal8Bit(getenv("LIB")).split(splitReg, QString::SkipEmptyParts); - else - paths = QString::fromLocal8Bit(getenv("PATH")).split(splitReg, QString::SkipEmptyParts); - return locateFileInPaths(file, paths); -} - // Output helper functions ---------------------------------[ Stop ]- @@ -1830,80 +1795,25 @@ bool Configure::displayHelp() return false; } -QString Configure::findFileInPaths(const QString &fileName, const QString &paths) -{ -#if defined(Q_OS_WIN32) - QRegExp splitReg("[;,]"); -#else - QRegExp splitReg("[:]"); -#endif - QStringList pathList = paths.split(splitReg, QString::SkipEmptyParts); - QDir d; - for (QStringList::ConstIterator it = pathList.begin(); it != pathList.end(); ++it) { - // Remove any leading or trailing ", this is commonly used in the environment - // variables - QString path = (*it); - if (path.startsWith('\"')) - path = path.right(path.length() - 1); - if (path.endsWith('\"')) - path = path.left(path.length() - 1); - if (d.exists(path + QDir::separator() + fileName)) - return path; - } - return QString(); -} - -static QString mingwPaths(const QString &mingwPath, const QString &pathName) -{ - QString ret; - QDir mingwDir = QFileInfo(mingwPath).dir(); - const QFileInfoList subdirs = mingwDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (int i = 0 ;i < subdirs.length(); ++i) { - const QFileInfo &fi = subdirs.at(i); - const QString name = fi.fileName(); - if (name == pathName) - ret += fi.absoluteFilePath() + ';'; - else if (name.contains("mingw")) - ret += fi.absoluteFilePath() + QDir::separator() + pathName + ';'; - } - return ret; -} - -bool Configure::findFile(const QString &fileName) +// Locate a file and return its containing directory. +QString Configure::locateFile(const QString &fileName) const { const QString file = fileName.toLower(); - const QString pathEnvVar = QString::fromLocal8Bit(getenv("PATH")); - const QString mingwPath = dictionary["QMAKESPEC"].endsWith("-g++") ? - findFileInPaths("g++.exe", pathEnvVar) : QString(); - - QString paths; + QStringList pathList; if (file.endsWith(".h")) { - if (!mingwPath.isNull()) { - if (!findFileInPaths(file, mingwPaths(mingwPath, "include")).isNull()) - return true; - //now let's try the additional compiler path - - const QFileInfoList mingwConfigs = QDir(mingwPath + QLatin1String("/../lib/gcc")).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (int i = 0; i < mingwConfigs.length(); ++i) { - const QDir mingwLibDir = mingwConfigs.at(i).absoluteFilePath(); - foreach(const QFileInfo &version, mingwLibDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { - if (!findFileInPaths(file, version.absoluteFilePath() + QLatin1String("/include")).isNull()) - return true; - } - } - } - paths = QString::fromLocal8Bit(getenv("INCLUDE")); - const QByteArray directXSdk = qgetenv("DXSDK_DIR"); - if (!directXSdk.isEmpty()) // Add Direct X SDK for ANGLE - paths += QLatin1Char(';') + QString::fromLocal8Bit(directXSdk) + QLatin1String("/include"); + static const QStringList headerPaths = + Environment::headerPaths(Environment::compilerFromQMakeSpec(dictionary[QStringLiteral("QMAKESPEC")])); + pathList = headerPaths; } else if (file.endsWith(".lib") || file.endsWith(".a")) { - if (!mingwPath.isNull() && !findFileInPaths(file, mingwPaths(mingwPath, "lib")).isNull()) - return true; - paths = QString::fromLocal8Bit(getenv("LIB")); + static const QStringList libPaths = + Environment::libraryPaths(Environment::compilerFromQMakeSpec(dictionary[QStringLiteral("QMAKESPEC")])); + pathList = libPaths; } else { - paths = pathEnvVar; + // Fallback for .exe and .dll (latter are not covered by QStandardPaths). + static const QStringList exePaths = Environment::path(); + pathList = exePaths; } - return !findFileInPaths(file, paths).isNull(); + return Environment::findFileInPaths(file, pathList); } /*! @@ -2058,7 +1968,8 @@ bool Configure::checkAvailability(const QString &part) dictionary[ "DONE" ] = "error"; } } else if (part == "INCREDIBUILD_XGE") { - available = findFile("BuildConsole.exe") && findFile("xgConsole.exe"); + available = !QStandardPaths::findExecutable(QStringLiteral("BuildConsole.exe")).isEmpty() + && !QStandardPaths::findExecutable(QStringLiteral("xgConsole.exe")).isEmpty(); } else if (part == "WMSDK") { available = findFile("wmsdk.h"); } else if (part == "V8SNAPSHOT") { @@ -2673,7 +2584,7 @@ void Configure::generateOutputVars() if (dictionary["QMAKESPEC"].endsWith("-g++")) { QString includepath = qgetenv("INCLUDE"); - bool hasSh = Environment::detectExecutable("sh.exe"); + const bool hasSh = !QStandardPaths::findExecutable(QStringLiteral("sh.exe")).isEmpty(); QChar separator = (!includepath.contains(":\\") && hasSh ? QChar(':') : QChar(';')); qmakeVars += QString("TMPPATH = $$quote($$(INCLUDE))"); qmakeVars += QString("QMAKE_INCDIR_POST += $$split(TMPPATH,\"%1\")").arg(separator); @@ -3461,7 +3372,7 @@ void Configure::generateHeaders() dictionary["SYNCQT"] = defaultTo("SYNCQT"); if (dictionary["SYNCQT"] == "yes") { - if (findFile("perl.exe")) { + if (!QStandardPaths::findExecutable(QStringLiteral("perl.exe")).isEmpty()) { cout << "Running syncqt..." << endl; QStringList args; args += buildPath + "/bin/syncqt.bat"; diff --git a/tools/configure/configureapp.h b/tools/configure/configureapp.h index bfec520c39..24f4858adf 100644 --- a/tools/configure/configureapp.h +++ b/tools/configure/configureapp.h @@ -167,8 +167,9 @@ private: QString formatPaths(const QStringList &paths); bool filesDiffer(const QString &file1, const QString &file2); - bool findFile(const QString &fileName); - static QString findFileInPaths(const QString &fileName, const QString &paths); + QString locateFile(const QString &fileName) const; + bool findFile(const QString &fileName) const { return !locateFile(fileName).isEmpty(); } + static QString findFileInPaths(const QString &fileName, const QStringList &paths); #if !defined(EVAL) void reloadCmdLine(); void saveCmdLine(); @@ -181,8 +182,6 @@ private: void desc(const char *option, const char *description, bool skipIndent = false, char fillChar = '.'); void desc(const char *mark_option, const char *mark, const char *option, const char *description, char fillChar = '.'); void applySpecSpecifics(); - static QString locateFile(const QString &fileName); - static QString locateFileInPaths(const QString &fileName, const QStringList &paths); }; class MakeItem diff --git a/tools/configure/environment.cpp b/tools/configure/environment.cpp index 50b121e357..9d0194bcbf 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,27 @@ QString Environment::detectQMakeSpec() return spec; } +Compiler Environment::compilerFromQMakeSpec(const QString &qmakeSpec) +{ + if (qmakeSpec == QLatin1String("win32-msvc2012")) + return CC_NET2012; + if (qmakeSpec == QLatin1String("win32-msvc2012")) + return CC_NET2010; + if (qmakeSpec == QLatin1String("win32-msvc2008")) + return CC_NET2008; + if (qmakeSpec == QLatin1String("win32-msvc2005")) + return CC_NET2005; + if (qmakeSpec == QLatin1String("win32-msvc2003")) + return CC_NET2003; + if (qmakeSpec == QLatin1String("win32-icc")) + return CC_INTEL; + if (qmakeSpec == QLatin1String("win32-g++")) + return CC_MINGW; + if (qmakeSpec == QLatin1String("win32-borland")) + return CC_BORLAND; + return CC_UNKNOWN; +} + /*! Returns the enum of the compiler which was detected on the system. The compilers are detected in the order as entered into the @@ -189,7 +211,7 @@ Compiler Environment::detectCompiler() if (!installed) { for(int i = 0; compiler_info[i].compiler; ++i) { QString executable = QString(compiler_info[i].executable).toLower(); - if (executable.length() && Environment::detectExecutable(executable)) { + if (executable.length() && !QStandardPaths::findExecutable(executable).isEmpty()) { if (detectedCompiler != compiler_info[i].compiler) { ++installed; detectedCompiler = compiler_info[i].compiler; @@ -215,33 +237,6 @@ Compiler Environment::detectCompiler() #endif }; -/*! - Returns true if the \a executable could be loaded, else false. - This means that the executable either is in the current directory - or in the PATH. -*/ -bool Environment::detectExecutable(const QString &executable) -{ - PROCESS_INFORMATION procInfo; - memset(&procInfo, 0, sizeof(procInfo)); - - STARTUPINFO startInfo; - memset(&startInfo, 0, sizeof(startInfo)); - startInfo.cb = sizeof(startInfo); - - bool couldExecute = CreateProcess(0, (wchar_t*)executable.utf16(), - 0, 0, false, - CREATE_NO_WINDOW | CREATE_SUSPENDED, - 0, 0, &startInfo, &procInfo); - - if (couldExecute) { - CloseHandle(procInfo.hThread); - TerminateProcess(procInfo.hProcess, 0); - CloseHandle(procInfo.hProcess); - } - return couldExecute; -} - /*! Creates a commandling from \a program and it \a arguments, escaping characters that needs it. @@ -514,4 +509,124 @@ bool Environment::rmdir(const QString &name) return result; } +static QStringList splitPathList(const QString &path) +{ +#if defined(Q_OS_WIN) + QRegExp splitReg(QStringLiteral("[;,]")); +#else + QRegExp splitReg(QStringLiteral("[:]")); +#endif + QStringList result = path.split(splitReg, QString::SkipEmptyParts); + const QChar separator = QDir::separator(); + const QStringList::iterator end = result.end(); + for (QStringList::iterator it = result.begin(); it != end; ++it) { + // Remove any leading or trailing ", this is commonly used in the environment + // variables + if (it->startsWith('"')) + it->remove(0, 1); + if (it->endsWith('"')) + it->chop(1); + if (it->endsWith(separator)) + it->chop(1); + } + return result; +} + +QString Environment::findFileInPaths(const QString &fileName, const QStringList &paths) +{ + if (!paths.isEmpty()) { + QDir d; + const QChar separator = QDir::separator(); + foreach (const QString &path, paths) + if (d.exists(path + separator + fileName)) + return path; + } + return QString(); +} + +QStringList Environment::path() +{ + return splitPathList(QString::fromLocal8Bit(qgetenv("PATH"))); +} + +static QStringList mingwPaths(const QString &mingwPath, const QString &pathName) +{ + QStringList ret; + QDir mingwDir(mingwPath); + const QFileInfoList subdirs = mingwDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (int i = 0 ;i < subdirs.length(); ++i) { + const QFileInfo &fi = subdirs.at(i); + const QString name = fi.fileName(); + if (name == pathName) + ret += fi.absoluteFilePath(); + else if (name.contains(QLatin1String("mingw"))) { + ret += fi.absoluteFilePath() + QLatin1Char('/') + pathName; + } + } + return ret; +} + +// Return MinGW location from "c:\mingw\bin" -> "c:\mingw" +static inline QString detectMinGW() +{ + const QString gcc = QStandardPaths::findExecutable(QLatin1String("g++.exe")); + return gcc.isEmpty() ? + gcc : QFileInfo(QFileInfo(gcc).absolutePath()).absolutePath(); +} + +// Detect Direct X SDK up tp June 2010. Included in Windows Kit 8. +QString Environment::detectDirectXSdk() +{ + const QByteArray directXSdkEnv = qgetenv("DXSDK_DIR"); + if (directXSdkEnv.isEmpty()) + return QString(); + QString directXSdk = QDir::cleanPath(QString::fromLocal8Bit(directXSdkEnv)); + if (directXSdk.endsWith(QLatin1Char('/'))) + directXSdk.truncate(directXSdk.size() - 1); + return directXSdk; +} + +QStringList Environment::headerPaths(Compiler compiler) +{ + QStringList headerPaths; + if (compiler == CC_MINGW) { + const QString mingwPath = detectMinGW(); + headerPaths = mingwPaths(mingwPath, QLatin1String("include")); + // Additional compiler paths + const QFileInfoList mingwConfigs = QDir(mingwPath + QLatin1String("/lib/gcc")).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (int i = 0; i < mingwConfigs.length(); ++i) { + const QDir mingwLibDir = mingwConfigs.at(i).absoluteFilePath(); + foreach (const QFileInfo &version, mingwLibDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) + headerPaths += version.absoluteFilePath() + QLatin1String("/include"); + } + } else { + headerPaths = splitPathList(QString::fromLocal8Bit(getenv("INCLUDE"))); + } + // Add Direct X SDK for ANGLE + const QString directXSdk = detectDirectXSdk(); + if (!directXSdk.isEmpty()) // Add Direct X SDK for ANGLE + headerPaths += directXSdk + QLatin1String("/include"); + return headerPaths; +} + +QStringList Environment::libraryPaths(Compiler compiler) +{ + QStringList libraryPaths; + if (compiler == CC_MINGW) { + libraryPaths = mingwPaths(detectMinGW(), "lib"); + } else { + libraryPaths = splitPathList(QString::fromLocal8Bit(qgetenv("LIB"))); + } + // Add Direct X SDK for ANGLE + const QString directXSdk = detectDirectXSdk(); + if (!directXSdk.isEmpty()) { +#ifdef Q_OS_WIN64 + libraryPaths += directXSdk + QLatin1String("/lib/x64"); +#else + libraryPaths += directXSdk + QLatin1String("/lib/x86"); +#endif + } + return libraryPaths; +} + QT_END_NAMESPACE diff --git a/tools/configure/environment.h b/tools/configure/environment.h index af4bf4b83a..3818d517b6 100644 --- a/tools/configure/environment.h +++ b/tools/configure/environment.h @@ -39,8 +39,7 @@ ** ****************************************************************************/ -#include -#include +#include QT_BEGIN_NAMESPACE @@ -63,13 +62,20 @@ class Environment public: static Compiler detectCompiler(); static QString detectQMakeSpec(); - static bool detectExecutable(const QString &executable); + static Compiler compilerFromQMakeSpec(const QString &qmakeSpec); static int execute(QStringList arguments, const QStringList &additionalEnv, const QStringList &removeEnv); static QString execute(const QString &command, int *returnCode = 0); static bool cpdir(const QString &srcDir, const QString &destDir); static bool rmdir(const QString &name); + static QString findFileInPaths(const QString &fileName, const QStringList &paths); + static QStringList path(); + + static QString detectDirectXSdk(); + static QStringList headerPaths(Compiler compiler); + static QStringList libraryPaths(Compiler compiler); + private: static Compiler detectedCompiler; -- cgit v1.2.3