/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "configureapp.h" #include "environment.h" #ifdef COMMERCIAL_VERSION # include "tools.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE enum Platforms { WINDOWS, WINDOWS_CE, QNX, BLACKBERRY }; std::ostream &operator<<(std::ostream &s, const QString &val) { s << val.toLocal8Bit().data(); return s; } using namespace std; // Macros to simplify options marking #define MARK_OPTION(x,y) ( dictionary[ #x ] == #y ? "*" : " " ) bool writeToFile(const char* text, const QString &filename) { QByteArray symFile(text); QFile file(filename); QDir dir(QFileInfo(file).absoluteDir()); if (!dir.exists()) dir.mkpath(dir.absolutePath()); if (!file.open(QFile::WriteOnly | QFile::Text)) { cout << "Couldn't write to " << qPrintable(filename) << ": " << qPrintable(file.errorString()) << endl; return false; } file.write(symFile); return true; } Configure::Configure(int& argc, char** argv) { useUnixSeparators = false; // Default values for indentation optionIndent = 4; descIndent = 25; outputWidth = 0; // Get console buffer output width CONSOLE_SCREEN_BUFFER_INFO info; HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (GetConsoleScreenBufferInfo(hStdout, &info)) outputWidth = info.dwSize.X - 1; outputWidth = qMin(outputWidth, 79); // Anything wider gets unreadable if (outputWidth < 35) // Insanely small, just use 79 outputWidth = 79; int i; /* ** Set up the initial state, the default */ dictionary[ "CONFIGCMD" ] = argv[ 0 ]; for (i = 1; i < argc; i++) configCmdLine += argv[ i ]; if (configCmdLine.size() >= 2 && configCmdLine.at(0) == "-srcdir") { sourcePath = QDir::cleanPath(configCmdLine.at(1)); sourceDir = QDir(sourcePath); configCmdLine.erase(configCmdLine.begin(), configCmdLine.begin() + 2); } else { // Get the path to the executable wchar_t module_name[MAX_PATH]; GetModuleFileName(0, module_name, sizeof(module_name) / sizeof(wchar_t)); QFileInfo sourcePathInfo = QString::fromWCharArray(module_name); sourcePath = sourcePathInfo.absolutePath(); sourceDir = sourcePathInfo.dir(); } buildPath = QDir::currentPath(); #if 0 const QString installPath = QString("C:\\Qt\\%1").arg(QT_VERSION_STR); #else const QString installPath = buildPath; #endif if (sourceDir != buildDir) { //shadow builds! if (!findFile("perl") && !findFile("perl.exe")) { cout << "Error: Creating a shadow build of Qt requires" << endl << "perl to be in the PATH environment"; exit(0); // Exit cleanly for Ctrl+C } cout << "Preparing build tree..." << endl; QDir(buildPath).mkpath("bin"); { //make a syncqt script(s) that can be used in the shadow QFile syncqt(buildPath + "/bin/syncqt"); // no QFile::Text, just in case the perl interpreter can't cope with them (unlikely) if (syncqt.open(QFile::WriteOnly)) { QTextStream stream(&syncqt); stream << "#!/usr/bin/perl -w" << endl << "require \"" << sourcePath + "/bin/syncqt\";" << endl; } QFile syncqt_bat(buildPath + "/bin/syncqt.bat"); if (syncqt_bat.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&syncqt_bat); stream << "@echo off" << endl << "call " << fixSeparators(sourcePath) << fixSeparators("/bin/syncqt.bat -qtdir \"") << fixSeparators(buildPath) << "\" %*" << endl; syncqt_bat.close(); } } QFile configtests(buildPath + "/bin/qtmodule-configtests"); // no QFile::Text, just in case the perl interpreter can't cope with them (unlikely) if (configtests.open(QFile::WriteOnly)) { QTextStream stream(&configtests); stream << "#!/usr/bin/perl -w" << endl << "require \"" << sourcePath + "/bin/qtmodule-configtests\";" << endl; } // For Windows CE and shadow builds we need to copy these to the // build directory. QFile::copy(sourcePath + "/bin/setcepaths.bat" , buildPath + "/bin/setcepaths.bat"); //copy the mkspecs buildDir.mkpath("mkspecs"); if (!Environment::cpdir(sourcePath + "/mkspecs", buildPath + "/mkspecs")){ cout << "Couldn't copy mkspecs!" << sourcePath << " " << buildPath << endl; dictionary["DONE"] = "error"; return; } } defaultBuildParts << QStringLiteral("libs") << QStringLiteral("examples"); dictionary[ "QT_SOURCE_TREE" ] = fixSeparators(sourcePath); dictionary[ "QT_BUILD_TREE" ] = fixSeparators(buildPath); dictionary[ "QT_INSTALL_PREFIX" ] = fixSeparators(installPath); dictionary[ "QMAKESPEC" ] = getenv("QMAKESPEC"); if (dictionary[ "QMAKESPEC" ].size() == 0) { dictionary[ "QMAKESPEC" ] = Environment::detectQMakeSpec(); dictionary[ "QMAKESPEC_FROM" ] = "detected"; } else { dictionary[ "QMAKESPEC_FROM" ] = "env"; } dictionary[ "QCONFIG" ] = "full"; dictionary[ "EMBEDDED" ] = "no"; dictionary[ "BUILD_QMAKE" ] = "yes"; dictionary[ "DSPFILES" ] = "yes"; dictionary[ "VCPROJFILES" ] = "yes"; dictionary[ "QMAKE_INTERNAL" ] = "no"; dictionary[ "FAST" ] = "no"; dictionary[ "NOPROCESS" ] = "no"; dictionary[ "WIDGETS" ] = "yes"; dictionary[ "RTTI" ] = "yes"; dictionary[ "SSE2" ] = "auto"; dictionary[ "SSE3" ] = "auto"; dictionary[ "SSSE3" ] = "auto"; dictionary[ "SSE4_1" ] = "auto"; dictionary[ "SSE4_2" ] = "auto"; dictionary[ "AVX" ] = "auto"; dictionary[ "AVX2" ] = "auto"; dictionary[ "IWMMXT" ] = "auto"; dictionary[ "SYNCQT" ] = "auto"; dictionary[ "CE_CRT" ] = "no"; dictionary[ "CETEST" ] = "auto"; dictionary[ "CE_SIGNATURE" ] = "no"; dictionary[ "PHONON_BACKEND" ] = "yes"; dictionary[ "AUDIO_BACKEND" ] = "auto"; dictionary[ "WMSDK" ] = "auto"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "V8SNAPSHOT" ] = "auto"; dictionary[ "QML_DEBUG" ] = "yes"; dictionary[ "PLUGIN_MANIFESTS" ] = "yes"; dictionary[ "DIRECTWRITE" ] = "no"; QString version; QFile qglobal_h(sourcePath + "/src/corelib/global/qglobal.h"); if (qglobal_h.open(QFile::ReadOnly)) { QTextStream read(&qglobal_h); QRegExp version_regexp("^# *define *QT_VERSION_STR *\"([^\"]*)\""); QString line; while (!read.atEnd()) { line = read.readLine(); if (version_regexp.exactMatch(line)) { version = version_regexp.cap(1).trimmed(); if (!version.isEmpty()) break; } } qglobal_h.close(); } if (version.isEmpty()) version = QString("%1.%2.%3").arg(QT_VERSION>>16).arg(((QT_VERSION>>8)&0xff)).arg(QT_VERSION&0xff); dictionary[ "VERSION" ] = version; { QRegExp version_re("([0-9]*)\\.([0-9]*)\\.([0-9]*)(|-.*)"); if (version_re.exactMatch(version)) { dictionary[ "VERSION_MAJOR" ] = version_re.cap(1); dictionary[ "VERSION_MINOR" ] = version_re.cap(2); dictionary[ "VERSION_PATCH" ] = version_re.cap(3); } } dictionary[ "REDO" ] = "no"; dictionary[ "DEPENDENCIES" ] = "no"; dictionary[ "BUILD" ] = "debug"; dictionary[ "BUILDALL" ] = "auto"; // Means yes, but not explicitly dictionary[ "BUILDTYPE" ] = "none"; dictionary[ "BUILDDEV" ] = "no"; dictionary[ "SHARED" ] = "yes"; dictionary[ "ZLIB" ] = "auto"; dictionary[ "PCRE" ] = "auto"; dictionary[ "ICU" ] = "auto"; dictionary[ "GIF" ] = "auto"; dictionary[ "JPEG" ] = "auto"; dictionary[ "PNG" ] = "auto"; dictionary[ "LIBJPEG" ] = "auto"; dictionary[ "LIBPNG" ] = "auto"; dictionary[ "FREETYPE" ] = "yes"; dictionary[ "ACCESSIBILITY" ] = "yes"; dictionary[ "OPENGL" ] = "yes"; dictionary[ "OPENVG" ] = "no"; dictionary[ "OPENSSL" ] = "auto"; dictionary[ "DBUS" ] = "auto"; dictionary[ "STYLE_WINDOWS" ] = "yes"; dictionary[ "STYLE_WINDOWSXP" ] = "auto"; dictionary[ "STYLE_WINDOWSVISTA" ] = "auto"; dictionary[ "STYLE_PLASTIQUE" ] = "yes"; dictionary[ "STYLE_CLEANLOOKS" ]= "yes"; dictionary[ "STYLE_WINDOWSCE" ] = "no"; dictionary[ "STYLE_WINDOWSMOBILE" ] = "no"; dictionary[ "STYLE_MOTIF" ] = "yes"; dictionary[ "STYLE_CDE" ] = "yes"; dictionary[ "STYLE_GTK" ] = "no"; dictionary[ "SQL_MYSQL" ] = "no"; dictionary[ "SQL_ODBC" ] = "no"; dictionary[ "SQL_OCI" ] = "no"; dictionary[ "SQL_PSQL" ] = "no"; dictionary[ "SQL_TDS" ] = "no"; dictionary[ "SQL_DB2" ] = "no"; dictionary[ "SQL_SQLITE" ] = "auto"; dictionary[ "SQL_SQLITE_LIB" ] = "qt"; dictionary[ "SQL_SQLITE2" ] = "no"; dictionary[ "SQL_IBASE" ] = "no"; QString tmp = dictionary[ "QMAKESPEC" ]; if (tmp.contains("\\")) { tmp = tmp.mid(tmp.lastIndexOf("\\") + 1); } else { tmp = tmp.mid(tmp.lastIndexOf("/") + 1); } dictionary[ "QMAKESPEC" ] = tmp; dictionary[ "INCREDIBUILD_XGE" ] = "auto"; dictionary[ "LTCG" ] = "no"; dictionary[ "NATIVE_GESTURES" ] = "yes"; dictionary[ "MSVC_MP" ] = "no"; } Configure::~Configure() { for (int i=0; i<3; ++i) { QList items = makeList[i]; for (int j=0; jremove("qconfig-").remove(".h"); allConfigs << "full"; // Try internal configurations first. QStringList possible_configs = QStringList() << "minimal" << "small" << "medium" << "large" << "full"; int index = possible_configs.indexOf(dictionary["QCONFIG"]); if (index >= 0) { for (int c = 0; c <= index; c++) { qmakeConfig += possible_configs[c] + "-config"; } return; } // If the internal configurations failed, try others. QStringList::Iterator config; for (config = allConfigs.begin(); config != allConfigs.end(); ++config) { if ((*config) == dictionary[ "QCONFIG" ]) break; } if (config == allConfigs.end()) { dictionary[ "HELP" ] = "yes"; cout << "No such configuration \"" << qPrintable(dictionary[ "QCONFIG" ]) << "\"" << endl ; } else qmakeConfig += (*config) + "-config"; } #endif // Output helper functions --------------------------------[ Start ]- /*! Determines the length of a string token. */ static int tokenLength(const char *str) { if (*str == 0) return 0; const char *nextToken = strpbrk(str, " _/\n\r"); if (nextToken == str || !nextToken) return 1; return int(nextToken - str); } /*! Prints out a string which starts at position \a startingAt, and indents each wrapped line with \a wrapIndent characters. The wrap point is set to the console width, unless that width cannot be determined, or is too small. */ void Configure::desc(const char *description, int startingAt, int wrapIndent) { int linePos = startingAt; bool firstLine = true; const char *nextToken = description; while (*nextToken) { int nextTokenLen = tokenLength(nextToken); if (*nextToken == '\n' // Wrap on newline, duh || (linePos + nextTokenLen > outputWidth)) // Wrap at outputWidth { printf("\n"); linePos = 0; firstLine = false; if (*nextToken == '\n') ++nextToken; continue; } if (!firstLine && linePos < wrapIndent) { // Indent to wrapIndent printf("%*s", wrapIndent , ""); linePos = wrapIndent; if (*nextToken == ' ') { ++nextToken; continue; } } printf("%.*s", nextTokenLen, nextToken); linePos += nextTokenLen; nextToken += nextTokenLen; } } /*! Prints out an option with its description wrapped at the description starting point. If \a skipIndent is true, the indentation to the option is not outputted (used by marked option version of desc()). Extra spaces between option and its description is filled with\a fillChar, if there's available space. */ void Configure::desc(const char *option, const char *description, bool skipIndent, char fillChar) { if (!skipIndent) printf("%*s", optionIndent, ""); int remaining = descIndent - optionIndent - strlen(option); int wrapIndent = descIndent + qMax(0, 1 - remaining); printf("%s", option); if (remaining > 2) { printf(" "); // Space in front for (int i = remaining; i > 2; --i) printf("%c", fillChar); // Fill, if available space } printf(" "); // Space between option and description desc(description, wrapIndent, wrapIndent); printf("\n"); } /*! Same as above, except it also marks an option with an '*', if the option is default action. */ void Configure::desc(const char *mark_option, const char *mark, const char *option, const char *description, char fillChar) { const QString markedAs = dictionary.value(mark_option); if (markedAs == "auto" && markedAs == mark) // both "auto", always => + printf(" + "); else if (markedAs == "auto") // setting marked as "auto" and option is default => + printf(" %c " , (defaultTo(mark_option) == QLatin1String(mark))? '+' : ' '); else if (QLatin1String(mark) == "auto" && markedAs != "no") // description marked as "auto" and option is available => + printf(" %c " , checkAvailability(mark_option) ? '+' : ' '); else // None are "auto", (markedAs == mark) => * printf(" %c " , markedAs == QLatin1String(mark) ? '*' : ' '); desc(option, description, true, fillChar); } /*! Modifies the default configuration based on given -platform option. Eg. switches to different default styles for Windows CE. */ void Configure::applySpecSpecifics() { if (dictionary[ "XQMAKESPEC" ].startsWith("wince")) { dictionary[ "STYLE_WINDOWSXP" ] = "no"; dictionary[ "STYLE_WINDOWSVISTA" ] = "no"; dictionary[ "STYLE_PLASTIQUE" ] = "no"; dictionary[ "STYLE_CLEANLOOKS" ] = "no"; dictionary[ "STYLE_WINDOWSCE" ] = "yes"; dictionary[ "STYLE_WINDOWSMOBILE" ] = "yes"; dictionary[ "STYLE_MOTIF" ] = "no"; dictionary[ "STYLE_CDE" ] = "no"; dictionary[ "FREETYPE" ] = "no"; dictionary[ "OPENGL" ] = "no"; dictionary[ "OPENSSL" ] = "no"; dictionary[ "RTTI" ] = "no"; dictionary[ "SSE2" ] = "no"; dictionary[ "SSE3" ] = "no"; dictionary[ "SSSE3" ] = "no"; dictionary[ "SSE4_1" ] = "no"; dictionary[ "SSE4_2" ] = "no"; dictionary[ "AVX" ] = "no"; dictionary[ "AVX2" ] = "no"; dictionary[ "IWMMXT" ] = "no"; dictionary[ "CE_CRT" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; // We only apply MMX/IWMMXT for mkspecs we know they work if (dictionary[ "XQMAKESPEC" ].startsWith("wincewm")) { dictionary[ "MMX" ] = "yes"; dictionary[ "IWMMXT" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "yes"; } dictionary[ "QT_HOST_PREFIX" ] = dictionary[ "QT_INSTALL_PREFIX" ]; dictionary[ "QT_INSTALL_PREFIX" ] = ""; } else if (dictionary[ "XQMAKESPEC" ].startsWith("linux")) { //TODO actually wrong. //TODO dictionary[ "STYLE_WINDOWSXP" ] = "no"; dictionary[ "STYLE_WINDOWSVISTA" ] = "no"; dictionary[ "KBD_DRIVERS" ] = "tty"; dictionary[ "GFX_DRIVERS" ] = "linuxfb"; dictionary[ "MOUSE_DRIVERS" ] = "pc linuxtp"; dictionary[ "OPENGL" ] = "no"; dictionary[ "DBUS"] = "no"; dictionary[ "QT_QWS_DEPTH" ] = "4 8 16 24 32"; dictionary[ "QT_SXE" ] = "no"; dictionary[ "QT_INOTIFY" ] = "no"; dictionary[ "QT_CUPS" ] = "no"; dictionary[ "QT_GLIB" ] = "no"; dictionary[ "QT_ICONV" ] = "no"; dictionary["DECORATIONS"] = "default windows styled"; } } 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 ]- bool Configure::displayHelp() { if (dictionary[ "HELP" ] == "yes") { desc("Usage: configure\n" "[-release] [-debug] [-debug-and-release] [-shared] [-static]\n" "[-no-fast] [-fast] \n" "[-no-accessibility] [-accessibility] [-no-rtti] [-rtti]\n" "[-no-sql-] [-qt-sql-]\n" "[-plugin-sql-] [-system-sqlite]\n" "[-D ] [-I ] [-L ]\n" "[-help] [-no-dsp] [-dsp] [-no-vcproj] [-vcproj]\n" "[-no-qmake] [-qmake] [-dont-process] [-process]\n" "[-no-style-