/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, 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.0, 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. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** $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 QT_BEGIN_NAMESPACE 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)) { 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 ]; // Get the path to the executable QFileInfo sourcePathInfo; QT_WA({ unsigned short module_name[256]; GetModuleFileNameW(0, reinterpret_cast(module_name), sizeof(module_name)); sourcePathInfo = QString::fromUtf16(module_name); }, { char module_name[256]; GetModuleFileNameA(0, module_name, sizeof(module_name)); sourcePathInfo = QString::fromLocal8Bit(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"); { //duplicate qmake QStack qmake_dirs; qmake_dirs.push("qmake"); while(!qmake_dirs.isEmpty()) { QString dir = qmake_dirs.pop(); QString od(buildPath + "/" + dir); QString id(sourcePath + "/" + dir); QFileInfoList entries = QDir(id).entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries); for(int i = 0; i < entries.size(); ++i) { QFileInfo fi(entries.at(i)); if(fi.isDir()) { qmake_dirs.push(dir + "/" + fi.fileName()); QDir().mkpath(od + "/" + fi.fileName()); } else { QDir().mkpath(od ); bool justCopy = true; const QString fname = fi.fileName(); const QString outFile(od + "/" + fname), inFile(id + "/" + fname); if(fi.fileName() == "Makefile") { //ignore } else if(fi.suffix() == "h" || fi.suffix() == "cpp") { QTemporaryFile tmpFile; if(tmpFile.open()) { QTextStream stream(&tmpFile); stream << "#include \"" << inFile << "\"" << endl; justCopy = false; stream.flush(); tmpFile.flush(); if(filesDiffer(tmpFile.fileName(), outFile)) { QFile::remove(outFile); tmpFile.copy(outFile); } } } if(justCopy && filesDiffer(inFile, outFile)) QFile::copy(inFile, outFile); } } } } { //make a syncqt script(s) that can be used in the shadow QFile syncqt(buildPath + "/bin/syncqt"); 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)) { QTextStream stream(&syncqt_bat); stream << "@echo off" << endl << "set QTDIR=" << QDir::toNativeSeparators(sourcePath) << endl << "call " << fixSeparators(sourcePath) << fixSeparators("/bin/syncqt.bat -outdir \"") << fixSeparators(buildPath) << "\"" << endl << "set QTDIR=" << QDir::toNativeSeparators(buildPath) << endl; syncqt_bat.close(); } } // 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; } } 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[ "ARCHITECTURE" ] = "windows"; 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[ "STL" ] = "yes"; dictionary[ "EXCEPTIONS" ] = "yes"; dictionary[ "RTTI" ] = "yes"; dictionary[ "MMX" ] = "auto"; dictionary[ "3DNOW" ] = "auto"; dictionary[ "SSE" ] = "auto"; dictionary[ "SSE2" ] = "auto"; dictionary[ "IWMMXT" ] = "auto"; dictionary[ "SYNCQT" ] = "auto"; dictionary[ "CE_CRT" ] = "no"; dictionary[ "CETEST" ] = "auto"; dictionary[ "CE_SIGNATURE" ] = "no"; dictionary[ "SCRIPTTOOLS" ] = "yes"; dictionary[ "XMLPATTERNS" ] = "auto"; dictionary[ "PHONON" ] = "auto"; dictionary[ "PHONON_BACKEND" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "WEBKIT" ] = "auto"; dictionary[ "PLUGIN_MANIFESTS" ] = "yes"; 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[ "BUILDNOKIA" ] = "no"; dictionary[ "SHARED" ] = "yes"; dictionary[ "ZLIB" ] = "auto"; dictionary[ "GIF" ] = "auto"; dictionary[ "TIFF" ] = "auto"; dictionary[ "JPEG" ] = "auto"; dictionary[ "PNG" ] = "auto"; dictionary[ "MNG" ] = "auto"; dictionary[ "LIBTIFF" ] = "auto"; dictionary[ "LIBJPEG" ] = "auto"; dictionary[ "LIBPNG" ] = "auto"; dictionary[ "LIBMNG" ] = "auto"; dictionary[ "QT3SUPPORT" ] = "yes"; dictionary[ "ACCESSIBILITY" ] = "yes"; dictionary[ "OPENGL" ] = "yes"; dictionary[ "DIRECT3D" ] = "auto"; dictionary[ "IPV6" ] = "yes"; // Always, dynamicly loaded 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"; dictionary[ "GRAPHICS_SYSTEM" ] = "raster"; 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"; } Configure::~Configure() { for (int i=0; i<3; ++i) { QList items = makeList[i]; for (int j=0; jremove("qconfig-").remove(".h"); allConfigs << "full"; QStringList::Iterator config; for( config = allConfigs.begin(); config != allConfigs.end(); ++config ) { configs += (*config) + "-config"; if( (*config) == dictionary[ "QCONFIG" ] ) break; } if( config == allConfigs.end() ) { dictionary[ "HELP" ] = "yes"; cout << "No such configuration \"" << qPrintable(dictionary[ "QCONFIG" ]) << "\"" << endl ; } else qmakeConfig += configs; } #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[ "QT3SUPPORT" ] = "no"; dictionary[ "OPENGL" ] = "no"; dictionary[ "OPENSSL" ] = "no"; dictionary[ "STL" ] = "no"; dictionary[ "EXCEPTIONS" ] = "no"; dictionary[ "RTTI" ] = "no"; dictionary[ "ARCHITECTURE" ] = "windowsce"; dictionary[ "3DNOW" ] = "no"; dictionary[ "SSE" ] = "no"; dictionary[ "SSE2" ] = "no"; dictionary[ "MMX" ] = "no"; dictionary[ "IWMMXT" ] = "no"; dictionary[ "CE_CRT" ] = "yes"; dictionary[ "DIRECT3D" ] = "no"; dictionary[ "WEBKIT" ] = "no"; dictionary[ "PHONON" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "LTCG" ] = "yes"; // 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 vnc"; dictionary[ "MOUSE_DRIVERS" ] = "pc linuxtp"; dictionary[ "QT3SUPPORT" ] = "no"; dictionary[ "OPENGL" ] = "no"; dictionary[ "EXCEPTIONS" ] = "no"; dictionary[ "DBUS"] = "no"; dictionary[ "QT_QWS_DEPTH" ] = "4 8 16 24 32"; dictionary[ "QT_SXE" ] = "no"; dictionary[ "QT_INOTIFY" ] = "no"; dictionary[ "QT_LPR" ] = "no"; dictionary[ "QT_CUPS" ] = "no"; dictionary[ "QT_GLIB" ] = "no"; dictionary[ "QT_ICONV" ] = "no"; dictionary["DECORATIONS"] = "default windows styled"; dictionary[ "QMAKEADDITIONALARGS" ] = "-unix"; } } 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 [-buildkey ]\n" // desc("Usage: configure [-prefix dir] [-bindir ] [-libdir ]\n" // "[-docdir ] [-headerdir ] [-plugindir ]\n" // "[-datadir ] [-translationdir ]\n" // "[-examplesdir ] [-demosdir ][-buildkey ]\n" "[-release] [-debug] [-debug-and-release] [-shared] [-static]\n" "[-no-fast] [-fast] [-no-exceptions] [-exceptions]\n" "[-no-accessibility] [-accessibility] [-no-rtti] [-rtti]\n" "[-no-stl] [-stl] [-no-sql-] [-qt-sql-]\n" "[-plugin-sql-] [-system-sqlite] [-arch ]\n" "[-D ] [-I ] [-L ]\n" "[-help] [-no-dsp] [-dsp] [-no-vcproj] [-vcproj]\n" "[-no-qmake] [-qmake] [-dont-process] [-process]\n" "[-no-style-