From fc8f2a77531879f1302388ad3fc6ff820885dfd8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 10 Sep 2010 14:20:25 +0300 Subject: Provide a way to compile with RVCT 4.0 using generated Makefile. QT_RVCT_VERSION environment variable can be used to specify the desired RVCT version for symbian-sbsv2 Makefiles: E.g. QT_RVCT_VERSION=4.0, release-armv6 -> sbs -c arm.v6.urel.rvct4_0 If no version is specified, generic sbsv2 rvct aliases are used just like before: E.g. release-armv6 -> sbs -c armv6_urel Version specific make targets are also generated for each detected compiler: E.g. release-armv6-rvct4.0 -> sbs -c arm.v6.urel.rvct4_0 Also optimized finding the installed compiler versions. Task-number: QTBUG-13499 Reviewed-by: axis --- qmake/generators/symbian/symmake_sbsv2.cpp | 351 +++++++++++++++++++---------- qmake/generators/symbian/symmake_sbsv2.h | 15 +- 2 files changed, 240 insertions(+), 126 deletions(-) diff --git a/qmake/generators/symbian/symmake_sbsv2.cpp b/qmake/generators/symbian/symmake_sbsv2.cpp index c66c1b8..32c31ee 100644 --- a/qmake/generators/symbian/symmake_sbsv2.cpp +++ b/qmake/generators/symbian/symmake_sbsv2.cpp @@ -56,12 +56,21 @@ SymbianSbsv2MakefileGenerator::~SymbianSbsv2MakefileGenerator() { } #define FLM_DEST_DIR "epoc32/tools/makefile_templates/qt" #define FLM_SOURCE_DIR "/mkspecs/symbian-sbsv2/flm/qt" -#define UNDETECTED_GCCE_VERSION "0" #define PLATFORM_GCCE "gcce" #define PLATFORM_WINSCW "winscw" -#define PLATFORM_ARMV5 "armv5" +#define PLATFORM_ARM_PREFIX "arm" #define BUILD_DEBUG "udeb" #define BUILD_RELEASE "urel" +#define SBS_RVCT_PREFIX "rvct" + +static QString winscwPlatform; +static QString armPlatformPrefix; +static QString gccePlatform; +static QString sbsRvctPrefix; + +#if defined(Q_OS_UNIX) + extern char **environ; +#endif // Copies Qt FLMs to correct location under epocroot. // This is not done by configure as it is possible to change epocroot after configure. @@ -96,64 +105,95 @@ void SymbianSbsv2MakefileGenerator::exportFlm() } } -QString SymbianSbsv2MakefileGenerator::gcceVersion() +void SymbianSbsv2MakefileGenerator::findInstalledCompilerVersions(const QString &matchExpression, + const QString &versionPrefix, + QStringList *versionList) { - static QString gcceVersionStr; - - if (gcceVersionStr.isEmpty()) { - // First check if QT_GCCE_VERSION has been set, and use that if it is - QByteArray qtGcceVersion = qgetenv("QT_GCCE_VERSION"); - if (!qtGcceVersion.isEmpty()) { - // Check that QT_GCCE_VERSION is in proper format - QString check(qtGcceVersion); - check.replace(QRegExp("^\\d+\\.\\d+\\.\\d+$"),QString()); - if (check.isEmpty()) { - gcceVersionStr = PLATFORM_GCCE + QString(qtGcceVersion).replace(".","_"); - return gcceVersionStr; - } else { - fprintf(stderr, "Warning: Environment variable QT_GCCE_VERSION ('%s') is in incorrect " - "format, expected format is: '1.2.3'. Attempting to autodetect GCCE version.", - qtGcceVersion.constData()); + // No need to be able to find env variables on other operating systems, + // as only linux and windows have support for symbian-sbsv2 toolchain +#if defined(Q_OS_UNIX) || defined(Q_OS_WIN) + char *entry = 0; + int count = 0; + QRegExp matcher(matchExpression); + while ((entry = environ[count++])) { + if (matcher.exactMatch(QString::fromLocal8Bit(entry)) + && fileInfo(matcher.cap(matcher.captureCount())).exists()) { + // First capture (index 0) is the whole match, which is skipped. + // Next n captures are version numbers, which are interesting. + // Final capture is the env var value, which we alrady used, so that is skipped, too. + int capture = 1; + int finalCapture = matcher.captureCount() - 1; + QString version = versionPrefix; + while (capture <= finalCapture) { + version.append(matcher.cap(capture)); + if (capture != finalCapture) + version.append(QLatin1Char('.')); + capture++; } + *versionList << version; } - // Sbsv2 has separate env variable defined for each gcce version, so try to determine - // which user is likely to want to use by checking version 4.0.0 to 9.9.9 and taking - // the highest found version that actually points to a valid path. - // This is kind of a kludge, but since qmake doesn't bootstrap QProcess, there - // is no Qt API available to get all environment variables. - for (int i = 9; i >= 4; i--) { - for (int j = 9; j >= 0; j--) { - for (int k = 9; k >= 0; k--) { - QByteArray gcceVar = qgetenv(qPrintable(QString("SBS_GCCE%1%2%3BIN").arg(i).arg(j).arg(k))); - if (!gcceVar.isEmpty() && fileInfo(QString::fromLocal8Bit(gcceVar.constData())).exists()) { - gcceVersionStr = QString(PLATFORM_GCCE "%1_%2_%3").arg(i).arg(j).arg(k); - return gcceVersionStr; - } - } - } + } +#endif +} + +void SymbianSbsv2MakefileGenerator::findGcceVersions(QStringList *gcceVersionList, + QString *defaultVersion) +{ + QString matchStr = QLatin1String("SBS_GCCE(\\d)(\\d)(\\d)BIN=(.*)"); + findInstalledCompilerVersions(matchStr, gccePlatform, gcceVersionList); + + QString qtGcceVersion = QString::fromLocal8Bit(qgetenv("QT_GCCE_VERSION")); + + if (!qtGcceVersion.isEmpty()) { + if (QRegExp("\\d+\\.\\d+\\.\\d+").exactMatch(qtGcceVersion)) { + *defaultVersion = gccePlatform + qtGcceVersion; + } else { + fprintf(stderr, "Warning: Variable QT_GCCE_VERSION ('%s') is in incorrect " + "format, expected format is: 'x.y.z'. Attempting to autodetect GCCE version.\n", + qPrintable(qtGcceVersion)); } } - // Indicate undetected version to avoid rechecking multiple times - if (gcceVersionStr.isEmpty()) - gcceVersionStr = UNDETECTED_GCCE_VERSION; + if (defaultVersion->isEmpty() && gcceVersionList->size()) { + gcceVersionList->sort(); + *defaultVersion = gcceVersionList->last(); + } +} + +void SymbianSbsv2MakefileGenerator::findRvctVersions(QStringList *rvctVersionList, + QString *defaultVersion) +{ + QString matchStr = QLatin1String("RVCT(\\d)(\\d)BIN=(.*)"); + findInstalledCompilerVersions(matchStr, sbsRvctPrefix, rvctVersionList); + + QString qtRvctVersion = QString::fromLocal8Bit(qgetenv("QT_RVCT_VERSION")); - return gcceVersionStr; + if (!qtRvctVersion.isEmpty()) { + if (QRegExp("\\d+\\.\\d+").exactMatch(qtRvctVersion)) { + *defaultVersion = sbsRvctPrefix + qtRvctVersion; + } else { + fprintf(stderr, "Warning: Variable QT_RVCT_VERSION ('%s') is in incorrect " + "format, expected format is: 'x.y'.\n", + qPrintable(qtRvctVersion)); + } + } } -QString SymbianSbsv2MakefileGenerator::configClause(QString &platform, - QString &build, - QString &winscwClauseTemplate, - QString &gcceClauseTemplate, - QString &genericClauseTemplate) +QString SymbianSbsv2MakefileGenerator::configClause(const QString &platform, + const QString &build, + const QString &compilerVersion, + const QString &clauseTemplate) { QString retval; - if (QString::compare(platform, PLATFORM_WINSCW) == 0) - retval = winscwClauseTemplate.arg(build); - else if (QString::compare(platform, PLATFORM_GCCE) == 0) - retval = gcceClauseTemplate.arg(build); - else - retval = genericClauseTemplate.arg(platform).arg(build); + if (QString::compare(platform, winscwPlatform) == 0) { + retval = clauseTemplate.arg(build); + } else if (platform.startsWith(armPlatformPrefix)) { + QString fixedCompilerVersion = compilerVersion; + fixedCompilerVersion.replace(".","_"); + retval = clauseTemplate.arg(platform.mid(sizeof(PLATFORM_ARM_PREFIX)-1)) + .arg(build) + .arg(fixedCompilerVersion); + } // else - Unsupported platform for makefile target, return empty clause return retval; } @@ -185,52 +225,101 @@ void SymbianSbsv2MakefileGenerator::writeMkFile(const QString& wrapperFileName, void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile) { - static QString debugBuild(BUILD_DEBUG); - static QString releaseBuild(BUILD_RELEASE); + static QString debugBuild; + static QString releaseBuild; + static QString defaultGcceCompilerVersion; + static QString defaultRvctCompilerVersion; + static QStringList rvctVersions; + static QStringList gcceVersions; + static QStringList allArmCompilerVersions; + + // Initialize static variables used in makefile creation + if (debugBuild.isEmpty()) { + debugBuild.append(QLatin1String(BUILD_DEBUG)); + releaseBuild.append(QLatin1String(BUILD_RELEASE)); + winscwPlatform.append(QLatin1String(PLATFORM_WINSCW)); + gccePlatform.append(QLatin1String(PLATFORM_GCCE)); + armPlatformPrefix.append(QLatin1String(PLATFORM_ARM_PREFIX)); + sbsRvctPrefix.append(QLatin1String(SBS_RVCT_PREFIX)); + + findGcceVersions(&gcceVersions, &defaultGcceCompilerVersion); + findRvctVersions(&rvctVersions, &defaultRvctCompilerVersion); + + allArmCompilerVersions << rvctVersions << gcceVersions; + + if (!allArmCompilerVersions.size()) { + fprintf(stderr, "Warning: No HW compilers detected. " + "Please install either GCCE or RVCT compiler to enable release builds.\n"); + } + } QStringList allPlatforms; foreach(QString platform, project->values("SYMBIAN_PLATFORMS")) { allPlatforms << platform.toLower(); } + if (!gcceVersions.size()) + allPlatforms.removeAll(gccePlatform); + QString testClause; if (project->isActiveConfig(SYMBIAN_TEST_CONFIG)) testClause = QLatin1String(".test"); else testClause = QLatin1String(""); - QString genericClause = " -c %1_%2" + testClause; - QString winscwClause = " -c winscw_%1.mwccinc" + testClause; - QString gcceClause; - bool stripArmv5 = false; + // Note: armClause is used for gcce, too, which has a side effect + // of requiring armv* platform(s) in SYMBIAN_PLATFORMS in order + // to get any compiler version specific targets. + QString armClause = " -c " PLATFORM_ARM_PREFIX ".%1.%2.%3" + testClause; + QString genericArmClause; + if (defaultRvctCompilerVersion.isEmpty()) { + // Note: Argument %3 needs to be empty string in this version of clause + genericArmClause = " -c " PLATFORM_ARM_PREFIX "%1_%2%3" + testClause; + } else { + // If defaultRvctCompilerVersion is defined, use specific sbs clause for "generic" clause + genericArmClause = armClause; + } + QString winscwClause = " -c " PLATFORM_WINSCW "_%1.mwccinc" + testClause;; - if (allPlatforms.contains(PLATFORM_GCCE)) { - if (QString::compare(gcceVersion(), UNDETECTED_GCCE_VERSION) == 0) { - allPlatforms.removeAll(PLATFORM_GCCE); - } else { - gcceClause = " -c arm.v5.%1." + gcceVersion() + testClause; - // Since gcce building is enabled, do not add armv5 for any sbs command - // that also contains gcce, because those will build same targets. - stripArmv5 = true; + QStringList armPlatforms = allPlatforms.filter(QRegExp("^" PLATFORM_ARM_PREFIX)); + + if (!allArmCompilerVersions.size()) { + foreach (QString item, armPlatforms) { + allPlatforms.removeAll(item); } + armPlatforms.clear(); } QStringList allClauses; QStringList debugClauses; QStringList releaseClauses; + // Only winscw and arm platforms are supported QStringList debugPlatforms = allPlatforms; QStringList releasePlatforms = allPlatforms; - releasePlatforms.removeAll(PLATFORM_WINSCW); // No release for emulator + releasePlatforms.removeAll(winscwPlatform); // No release for emulator - foreach(QString item, debugPlatforms) { - if (item != PLATFORM_ARMV5 || !stripArmv5) - debugClauses << configClause(item, debugBuild, winscwClause, gcceClause, genericClause); + if (!releasePlatforms.size()) { + fprintf(stderr, "Warning: No valid release platforms in SYMBIAN_PLATFORMS (%s)\n" + "Most likely required compiler(s) are not properly installed.\n", + qPrintable(project->values("SYMBIAN_PLATFORMS").join(" "))); } - foreach(QString item, releasePlatforms) { - if (item != PLATFORM_ARMV5 || !stripArmv5) - releaseClauses << configClause(item, releaseBuild, winscwClause, gcceClause, genericClause); + + if (debugPlatforms.contains(winscwPlatform)) + debugClauses << configClause(winscwPlatform, debugBuild, QString(), winscwClause); + + foreach(QString item, armPlatforms) { + // Only use single clause per arm platform even if multiple compiler versions were found, + // otherwise we get makefile target collisions from sbsv2 toolchain. + if (rvctVersions.size()) { + debugClauses << configClause(item, debugBuild, defaultRvctCompilerVersion, genericArmClause); + releaseClauses << configClause(item, releaseBuild, defaultRvctCompilerVersion, genericArmClause); + } else { + debugClauses << configClause(item, debugBuild, defaultGcceCompilerVersion, armClause); + releaseClauses << configClause(item, releaseBuild, defaultGcceCompilerVersion, armClause); + } } + allClauses << debugClauses << releaseClauses; QTextStream t(&wrapperFile); @@ -270,22 +359,20 @@ void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, boo t << " -I\"" << values.at(i) << "\" "; } } - t << endl; - t << "first: default" << endl; - if (debugPlatforms.contains(PLATFORM_WINSCW)) - t << "default: debug-winscw"; - else if (debugPlatforms.contains(PLATFORM_ARMV5)) - t << "default: debug-armv5"; - else if (debugPlatforms.size()) - t << "default: debug-" << debugPlatforms.first(); - else - t << "default: all"; t << endl; + t << "first: default" << endl << endl; if (!isPrimaryMakefile) { - t << "all:" << endl; + t << "all:" << endl << endl; + t << "default: all" << endl << endl; } else { - t << "all: debug release" << endl; + t << "all: debug release" << endl << endl; + if (debugPlatforms.contains(winscwPlatform)) + t << "default: debug-winscw"; + else if (debugPlatforms.size()) + t << "default: debug-" << debugPlatforms.first(); + else + t << "default: all"; t << endl; QString qmakeCmd = "\t$(QMAKE) \"" + project->projectFile() + "\" " + buildArgs(); @@ -302,30 +389,80 @@ void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, boo t << "debug: " << BLD_INF_FILENAME << endl; t << "\t$(SBS)"; - foreach(QString item, debugClauses) { - t << item; + foreach(QString clause, debugClauses) { + t << clause; + } + t << endl; + t << "clean-debug: " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean"; + foreach(QString clause, debugClauses) { + t << clause; } t << endl; t << "release: " << BLD_INF_FILENAME << endl; t << "\t$(SBS)"; - foreach(QString item, releaseClauses) { - t << item; + foreach(QString clause, releaseClauses) { + t << clause; } t << endl; + t << "clean-release: " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean"; + foreach(QString clause, releaseClauses) { + t << clause; + } + t << endl << endl; + + QString defaultGcceArmVersion; + if (armPlatforms.size()) { + defaultGcceArmVersion = armPlatforms.first(); + } else { + defaultGcceArmVersion = QLatin1String("armv5"); + } - // For more specific builds, targets are in this form: build-platform, e.g. release-armv5 + // For more specific builds, targets are in this form: + // release-armv5 - generic target, compiler version determined by toolchain or autodetection + // release-armv5-rvct4.0 - compiler version specific target foreach(QString item, debugPlatforms) { + QString clause; + if (item.compare(winscwPlatform) == 0) + clause = configClause(item, debugBuild, QString(), winscwClause); + else if (item.compare(gccePlatform) == 0 ) + clause = configClause(defaultGcceArmVersion, debugBuild, defaultGcceCompilerVersion, armClause); + else // use generic arm clause + clause = configClause(item, debugBuild, defaultRvctCompilerVersion, genericArmClause); + t << "debug-" << item << ": " << BLD_INF_FILENAME << endl; - t << "\t$(SBS)"; - t << configClause(item, debugBuild, winscwClause, gcceClause, genericClause); - t << endl; + t << "\t$(SBS)" << clause << endl; + t << "clean-debug-" << item << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean" << clause << endl; } foreach(QString item, releasePlatforms) { + QString clause; + if (item.compare(gccePlatform) == 0 ) + clause = configClause(defaultGcceArmVersion, releaseBuild, defaultGcceCompilerVersion, armClause); + else // use generic arm clause + clause = configClause(item, releaseBuild, defaultRvctCompilerVersion, genericArmClause); + t << "release-" << item << ": " << BLD_INF_FILENAME << endl; - t << "\t$(SBS)"; - t << configClause(item, releaseBuild, winscwClause, gcceClause, genericClause); - t << endl; + t << "\t$(SBS)" << clause << endl; + t << "clean-release-" << item << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean" << clause << endl; + } + + foreach(QString item, armPlatforms) { + foreach(QString compilerVersion, allArmCompilerVersions) { + QString debugClause = configClause(item, debugBuild, compilerVersion, armClause); + QString releaseClause = configClause(item, releaseBuild, compilerVersion, armClause); + t << "debug-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS)" << debugClause << endl; + t << "clean-debug-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean" << debugClause << endl; + t << "release-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS)" << releaseClause << endl; + t << "clean-release-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl; + t << "\t$(SBS) reallyclean" << releaseClause << endl; + } } t << endl; @@ -344,7 +481,7 @@ void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, boo t << endl << endl; } - // Add all extra targets including extra compiler targest also to wrapper makefile, + // Add all extra targets including extra compiler targets also to wrapper makefile, // even though many of them may have already been added to bld.inf as FLMs. // This is to enable use of targets like 'mocables', which call targets generated by extra compilers. if (targetType != TypeSubdirs) { @@ -365,32 +502,6 @@ void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, boo } t << endl << endl; - t << "clean-debug: " << BLD_INF_FILENAME << endl; - t << "\t$(SBS) reallyclean"; - foreach(QString clause, debugClauses) { - t << clause; - } - t << endl << endl; - t << "clean-release: " << BLD_INF_FILENAME << endl; - t << "\t$(SBS) reallyclean"; - foreach(QString clause, releaseClauses) { - t << clause; - } - t << endl << endl; - - // For more specific builds, targets are in this form: clean-build-platform, e.g. clean-release-armv5 - foreach(QString item, debugPlatforms) { - t << "clean-debug-" << item << ": " << BLD_INF_FILENAME << endl; - t << "\t$(SBS) reallyclean"; - t << configClause(item, debugBuild, winscwClause, gcceClause, genericClause); - t << endl; - } - foreach(QString item, releasePlatforms) { - t << "clean-release-" << item << ": " << BLD_INF_FILENAME << endl; - t << "\t$(SBS) reallyclean"; - t << configClause(item, releaseBuild, winscwClause, gcceClause, genericClause); - t << endl; - } t << endl; } diff --git a/qmake/generators/symbian/symmake_sbsv2.h b/qmake/generators/symbian/symmake_sbsv2.h index 6644a03..557e3dd 100644 --- a/qmake/generators/symbian/symmake_sbsv2.h +++ b/qmake/generators/symbian/symmake_sbsv2.h @@ -65,12 +65,15 @@ public: private: void exportFlm(); - QString gcceVersion(); - QString configClause(QString &platform, - QString &build, - QString &winscwClauseTemplate, - QString &gcceClauseTemplate, - QString &genericClauseTemplate); + void findGcceVersions(QStringList *gcceVersionList, QString *defaultVersion); + void findRvctVersions(QStringList *rvctVersionList, QString *defaultVersion); + void findInstalledCompilerVersions(const QString &matchExpression, + const QString &versionPrefix, + QStringList *versionList); + QString configClause(const QString &platform, + const QString &build, + const QString &compilerVersion, + const QString &clauseTemplate); void writeSbsDeploymentList(const DeploymentList& depList, QTextStream& t); -- cgit v0.12