diff options
Diffstat (limited to 'qmake/generators/win32')
-rw-r--r-- | qmake/generators/win32/cesdkhandler.cpp | 266 | ||||
-rw-r--r-- | qmake/generators/win32/cesdkhandler.h | 12 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_nmake.cpp | 20 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_objectmodel.cpp | 2 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_vcproj.cpp | 67 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_vcproj.h | 6 |
6 files changed, 338 insertions, 35 deletions
diff --git a/qmake/generators/win32/cesdkhandler.cpp b/qmake/generators/win32/cesdkhandler.cpp index 3afed2b8c1..cbee1d0dbd 100644 --- a/qmake/generators/win32/cesdkhandler.cpp +++ b/qmake/generators/win32/cesdkhandler.cpp @@ -34,11 +34,22 @@ #include "cesdkhandler.h" #include <qfile.h> +#include <qfileinfo.h> #include <qdebug.h> #include <qxmlstream.h> +#include <qsettings.h> +#include <qtextstream.h> QT_BEGIN_NAMESPACE +struct PropertyContainer +{ + void clear() { name.clear(); value.clear(); properties.clear(); } + QString name; + QString value; + QMap<QString, PropertyContainer> properties; +}; + CeSdkInfo::CeSdkInfo() : m_major(0) , m_minor(0) { } @@ -47,22 +58,255 @@ CeSdkHandler::CeSdkHandler() { } -bool CeSdkHandler::parse() +struct ContainsPathKey +{ + bool operator()(const QString &val) + { + return !(val.endsWith(QStringLiteral("MSBuildToolsPath")) + || val.endsWith(QStringLiteral("MSBuildToolsRoot"))); + } +}; + +struct ValueFromKey +{ + ValueFromKey(const QSettings *settings) : settings(settings){} + QString operator()(const QString &key) + { + return settings->value(key).toString(); + } + + const QSettings *settings; +}; + +bool CeSdkHandler::parseMsBuildFile(QFile *file, CeSdkInfo *info) +{ + bool result = file->open(QFile::ReadOnly | QFile::Text); + const QString IncludePath = QStringLiteral("IncludePath"); + const QString LibraryPath = QStringLiteral("LibraryPath"); + const QString PreprocessorDefinitions = QStringLiteral("PreprocessorDefinitions"); + const QString SdkRootPathString = QStringLiteral("SdkRootPath"); + const QString ExecutablePath = QStringLiteral("ExecutablePath"); + enum ParserState{Not, Include, Lib, Define, BinDir, SdkRootPath}; + QString includePath; + QString libraryPath; + QString defines; + QString binDirs; + QString sdkRootPath; + ParserState state = Not; + if (result) { + QXmlStreamReader xml(file); + while (!xml.atEnd()) { + if (xml.isStartElement()) { + if (xml.name() == IncludePath) + state = Include; + else if (xml.name() == LibraryPath) + state = Lib; + else if (xml.name() == PreprocessorDefinitions) + state = Define; + else if (xml.name() == SdkRootPathString) + state = SdkRootPath; + else if (xml.name() == ExecutablePath) + state = BinDir; + else + state = Not; + } else if (xml.isEndElement()) { + state = Not; + } else if (xml.isCharacters()) { + switch (state) { + case Include: + includePath += xml.text(); + break; + case Lib: + libraryPath += xml.text(); + break; + case Define: + defines += xml.text(); + break; + case SdkRootPath: + sdkRootPath = xml.text().toString(); + break; + case BinDir: + binDirs += xml.text(); + case(Not): + break; + } + } + xml.readNext(); + } + } + file->close(); + const bool success = result && !includePath.isEmpty() && !libraryPath.isEmpty() && + !defines.isEmpty() && !sdkRootPath.isEmpty(); + if (success) { + const QString startPattern = QStringLiteral("$(Registry:"); + const int startIndex = sdkRootPath.indexOf(startPattern); + const int endIndex = sdkRootPath.lastIndexOf(QStringLiteral(")")); + const QString regString = sdkRootPath.mid(startIndex + startPattern.size(), + endIndex - startIndex - startPattern.size()); + QSettings sdkRootPathRegistry(regString, QSettings::NativeFormat); + const QString erg = sdkRootPathRegistry.value(QStringLiteral(".")).toString(); + const QString fullSdkRootPath = erg + sdkRootPath.mid(endIndex + 1); + const QString rootString = QStringLiteral("$(SdkRootPath)"); + + includePath = includePath.replace(rootString, fullSdkRootPath); + libraryPath = libraryPath.replace(rootString, fullSdkRootPath); + binDirs = binDirs.replace(rootString, fullSdkRootPath); + info->m_include = includePath + ";$(INCLUDE)"; + info->m_lib = libraryPath; + info->m_bin = binDirs; + } + return success; +} + +QStringList CeSdkHandler::getMsBuildToolPaths() const +{ + QSettings msbuildEntries("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\MSBuild\\ToolsVersions", + QSettings::NativeFormat); + const QStringList allKeys = msbuildEntries.allKeys(); + QStringList toolVersionKeys; + toolVersionKeys.push_back(QStringLiteral("c:\\Program Files\\MSBuild\\")); + std::remove_copy_if(allKeys.cbegin(), allKeys.cend(), + std::back_inserter(toolVersionKeys), ContainsPathKey()); + QStringList toolVersionValues; + std::transform(toolVersionKeys.constBegin(), toolVersionKeys.constEnd(), + std::back_inserter(toolVersionValues), + ValueFromKey(&msbuildEntries)); + return toolVersionValues; +} + +QStringList CeSdkHandler::filterMsBuildToolPaths(const QStringList &paths) const +{ + QStringList result; + foreach (const QString &path, paths) { + QDir dir(path); + if (path.endsWith(QStringLiteral("bin"))) + dir.cdUp(); + if (dir.cd(QStringLiteral("Microsoft.Cpp\\v4.0\\V110\\Platforms")) + || dir.cd(QStringLiteral("Microsoft.Cpp\\v4.0\\V120\\Platforms"))) { + result << dir.absolutePath(); + } + } + return result; +} + +bool CeSdkHandler::retrieveEnvironment(const QStringList &relativePaths, + const QStringList &toolPaths, + CeSdkInfo *info) +{ + bool result = false; + foreach (const QString &path, toolPaths) { + const QDir dir(path); + foreach (const QString &filePath, relativePaths) { + QFile file(dir.absoluteFilePath(filePath)); + if (file.exists()) + result = parseMsBuildFile(&file, info) || result; + } + } + + return result; +} + +void CeSdkHandler::retrieveWEC2013SDKs() +{ + const QStringList toolPaths = getMsBuildToolPaths(); + const QStringList filteredToolPaths = filterMsBuildToolPaths(toolPaths); + QSettings settings("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows CE Tools\\SDKs", QSettings::NativeFormat); + const QStringList keys = settings.allKeys(); + foreach (const QString &key, keys) { + if (key.contains(QLatin1String("SDKInformation")) || key.contains(QLatin1Char('.'))) { + QFile sdkPropertyFile(settings.value(key).toString()); + if (!sdkPropertyFile.exists()) + continue; + QFileInfo info(sdkPropertyFile); + if (info.isDir()) { + const QDir dir = info.absoluteFilePath(); + QFileInfo fInfo(dir.filePath(QLatin1String("Properties.xml"))); + if (fInfo.exists()) + sdkPropertyFile.setFileName(fInfo.absoluteFilePath()); + } + if (!sdkPropertyFile.open(QFile::ReadOnly)) + continue; + QXmlStreamReader xml(&sdkPropertyFile); + QString currentElement; + QString curName; + PropertyContainer currentProperty; + QVector<PropertyContainer> propStack; + propStack.push_back(currentProperty); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement()) { + currentElement = xml.name().toString(); + if (currentElement == QLatin1String("Property")) { + QXmlStreamAttributes attributes = xml.attributes(); + if (attributes.hasAttribute(QLatin1String("NAME"))) + curName = attributes.value(QLatin1String("NAME")).toString(); + Q_ASSERT(!curName.isEmpty()); + currentProperty.clear(); + currentProperty.name = curName; + propStack.push_back(currentProperty); + } else if (currentElement == QLatin1String("PropertyBag")) { + QXmlStreamAttributes attributes = xml.attributes(); + if (attributes.hasAttribute(QLatin1String("NAME"))) + curName = attributes.value(QLatin1String("NAME")).toString(); + Q_ASSERT(!curName.isEmpty()); + currentProperty.clear(); + currentProperty.name = curName; + propStack.push_back(currentProperty); + } + } else if (xml.isEndElement()) { + currentElement = xml.name().toString(); + PropertyContainer self = propStack.takeLast(); + if (currentElement != QLatin1String("Root")) { + PropertyContainer &last = propStack.last(); + last.properties[self.name] = self; + } else { + currentProperty = self; + } + } else if (xml.isCharacters()) { + PropertyContainer &self = propStack.last(); + self.value = xml.text().toString(); + } + } + + if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { + qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); + return; + } + CeSdkInfo currentSdk; + const PropertyContainer &cpuInfo = currentProperty.properties.value(QLatin1String("CPU info")); + if (cpuInfo.properties.isEmpty()) + continue; + const PropertyContainer &cpuInfoVal = cpuInfo.properties.first().properties.value(QLatin1String("CpuName")); + if (cpuInfoVal.name != QStringLiteral("CpuName")) + continue; + const QString SDKName = QStringLiteral("SDK name"); + currentSdk.m_name = currentProperty.properties.value(SDKName).value+ + QStringLiteral(" (") + cpuInfoVal.value + ")"; + currentSdk.m_major = currentProperty.properties.value(QLatin1String("OSMajor")).value.toInt(); + currentSdk.m_minor = currentProperty.properties.value(QLatin1String("OSMinor")).value.toInt(); + retrieveEnvironment(currentProperty.properties.value(QLatin1String("MSBuild Files110")).value.split(';'), + filteredToolPaths, ¤tSdk); + if (!currentSdk.m_include.isEmpty()) + m_list.append(currentSdk); + } + } +} + +void CeSdkHandler::retrieveWEC6n7SDKs() { // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config // and scan through all installed sdks... - m_list.clear(); m_vcInstallDir = QString::fromLatin1(qgetenv("VCInstallDir")); if (m_vcInstallDir.isEmpty()) - return false; + return; QDir vStudioDir(m_vcInstallDir); if (!vStudioDir.cd(QLatin1String("vcpackages"))) - return false; + return; QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config"))); if (!configFile.open(QIODevice::ReadOnly)) - return false; + return; QString currentElement; CeSdkInfo currentItem; @@ -94,13 +338,19 @@ bool CeSdkHandler::parse() if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); - return false; + return; } +} - return m_list.size() > 0; +bool CeSdkHandler::retrieveAvailableSDKs() +{ + m_list.clear(); + retrieveWEC2013SDKs(); + retrieveWEC6n7SDKs(); + return !m_list.empty(); } -QString CeSdkHandler::fixPaths(QString path) const +QString CeSdkHandler::fixPaths(const QString &path) const { QRegExp searchStr(QLatin1String("(\\$\\(\\w+\\))")); QString fixedString = path; diff --git a/qmake/generators/win32/cesdkhandler.h b/qmake/generators/win32/cesdkhandler.h index 42c0121720..b90c3c6dce 100644 --- a/qmake/generators/win32/cesdkhandler.h +++ b/qmake/generators/win32/cesdkhandler.h @@ -73,10 +73,18 @@ class CeSdkHandler { public: CeSdkHandler(); - bool parse(); + bool retrieveAvailableSDKs(); inline QList<CeSdkInfo> listAll() const { return m_list; } private: - inline QString fixPaths(QString path) const; + void retrieveWEC6n7SDKs(); + void retrieveWEC2013SDKs(); + inline QString fixPaths(const QString &path) const; + QStringList getMsBuildToolPaths() const; + QStringList filterMsBuildToolPaths(const QStringList &paths) const; + bool parseMsBuildFile(QFile *file, CeSdkInfo *info); + bool retrieveEnvironment(const QStringList &relativePaths, + const QStringList &toolPaths, + CeSdkInfo *info); QList<CeSdkInfo> m_list; QString m_vcInstallDir; }; diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 740c8c4d13..eb8ae23384 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -79,7 +79,7 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) const ProValueMap &variables = project->variables(); if (project->isActiveConfig("wince")) { CeSdkHandler sdkhandler; - sdkhandler.parse(); + sdkhandler.retrieveAvailableSDKs(); const QString sdkName = variables["CE_SDK"].join(' ') + " (" + variables["CE_ARCH"].join(' ') + ")"; const QList<CeSdkInfo> sdkList = sdkhandler.listAll(); @@ -354,14 +354,18 @@ void NmakeMakefileGenerator::init() project->values("QMAKE_LFLAGS").append(QString("/DEF:") + escapeFilePath(defFileName)); } - if(!project->values("VERSION").isEmpty()) { - ProString version = project->values("VERSION")[0]; - int firstDot = version.indexOf("."); - QString major = version.left(firstDot).toQString(); - QString minor = version.right(version.length() - firstDot - 1).toQString(); - minor.replace(".", ""); - project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor); + // set /VERSION for EXE/DLL header + ProString major_minor = project->first("VERSION_PE_HEADER"); + if (major_minor.isEmpty()) { + ProString version = project->first("VERSION"); + if (!version.isEmpty()) { + int firstDot = version.indexOf("."); + int secondDot = version.indexOf(".", firstDot + 1); + major_minor = version.left(secondDot); + } } + if (!major_minor.isEmpty()) + project->values("QMAKE_LFLAGS").append("/VERSION:" + major_minor); if (project->isEmpty("QMAKE_LINK_O_FLAG")) project->values("QMAKE_LINK_O_FLAG").append("/OUT:"); diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 917f4467a0..aa7320bc27 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2337,7 +2337,7 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) for (int i = 0; i < extradeps.count(); ++i) { QString dd = extradeps.at(i).simplified(); if (!dd.isEmpty()) - deps += Project->fileFixify(dd, QString(), Option::output_dir); + deps += Project->fileFixify(dd, MakefileGenerator::FileFixifyFromOutdir); } } } diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 3222030018..1fa117afda 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -421,6 +421,24 @@ bool VcprojGenerator::isStandardSuffix(const QString &suffix) const return false; } +ProString VcprojGenerator::firstInputFileName(const ProString &extraCompilerName) const +{ + foreach (const ProString &var, project->values(ProKey(extraCompilerName + ".input"))) { + const ProStringList &files = project->values(var.toKey()); + if (!files.isEmpty()) + return files.first(); + } + return ProString(); +} + +QString VcprojGenerator::firstExpandedOutputFileName(const ProString &extraCompilerName) +{ + const ProString firstOutput = project->first(ProKey(extraCompilerName + ".output")); + return replaceExtraCompilerVariables(firstOutput.toQString(), + firstInputFileName(extraCompilerName).toQString(), + QString(), NoShell); +} + ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHash<QString, QString> &projLookup, QHash<QString, QString> &projGuids, QHash<VcsolutionDepend *, QStringList> &extraSubdirs, @@ -787,14 +805,18 @@ void VcprojGenerator::init() processVars(); - if(!project->values("VERSION").isEmpty()) { - QString version = project->values("VERSION")[0].toQString(); - int firstDot = version.indexOf("."); - QString major = version.left(firstDot); - QString minor = version.right(version.length() - firstDot - 1); - minor.replace(QRegExp("\\."), ""); - project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor); + // set /VERSION for EXE/DLL header + ProString major_minor = project->first("VERSION_PE_HEADER"); + if (major_minor.isEmpty()) { + ProString version = project->first("VERSION"); + if (!version.isEmpty()) { + int firstDot = version.indexOf("."); + int secondDot = version.indexOf(".", firstDot + 1); + major_minor = version.left(secondDot); + } } + if (!major_minor.isEmpty()) + project->values("QMAKE_LFLAGS").append("/VERSION:" + major_minor); MakefileGenerator::init(); @@ -1414,9 +1436,29 @@ void VcprojGenerator::initWinDeployQtTool() conf.windeployqt.ExcludedFromBuild = true; if (project->isActiveConfig("windeployqt")) { conf.windeployqt.Record = QStringLiteral("$(TargetName).windeployqt.$(Platform).$(Configuration)"); - conf.windeployqt.CommandLine = - MakefileGenerator::shellQuote(QDir::toNativeSeparators(project->first("QMAKE_WINDEPLOYQT").toQString())) - + QLatin1Char(' ') + project->values("WINDEPLOYQT_OPTIONS").join(QLatin1Char(' ')) + const QString commandLine = MakefileGenerator::shellQuote(QDir::toNativeSeparators(project->first("QMAKE_WINDEPLOYQT").toQString())) + + QLatin1Char(' ') + project->values("WINDEPLOYQT_OPTIONS").join(QLatin1Char(' ')); + + // Visual Studio copies all files to be deployed into the MSIL directory + // and then invokes MDILXapCompile on it, which checks for managed code and + // translates it into native code. The problem is that all entries of the + // package will be copied into the MSIL directly, losing the subdirectory + // structure (for instance for plugins). However, the MDILXapCompile call + // itself contains the original subdirectories as parameters and hence the + // call fails. + // Neither there is a way to disable this behavior for Windows Phone, nor + // to influence the parameters. Hence the only way to get a release build + // done is to recreate the directory structure manually by invoking + // windeployqt a second time, so that the MDILXapCompile call succeeds and + // deployment continues. + if (conf.WinPhone && conf.Name == QStringLiteral("Release|ARM")) { + conf.windeployqt.CommandLine = commandLine + + QStringLiteral(" -list relative -dir \"$(MSBuildProjectDirectory)\\") + + var("OBJECTS_DIR") + + QStringLiteral("MSIL\" \"$(OutDir)\\$(TargetName).exe\" ") + + QLatin1String(" && "); + } + conf.windeployqt.CommandLine += commandLine + QStringLiteral(" -list relative -dir \"$(MSBuildProjectDirectory)\" \"$(OutDir)\\$(TargetName).exe\" > ") + MakefileGenerator::shellQuote(conf.windeployqt.Record); conf.windeployqt.config = &vcProject.Configuration; @@ -1564,7 +1606,7 @@ void VcprojGenerator::initResourceFiles() QT_PCLOSE(proc); if(!indeps.isEmpty()) deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' '), - QString(), Option::output_dir); + FileFixifyFromOutdir); } } } @@ -1618,10 +1660,9 @@ void VcprojGenerator::initExtraCompilerOutputs() extraCompile.Filter = ""; extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it); - // If the extra compiler has a variable_out set the output file // is added to an other file list, and does not need its own.. - bool addOnInput = hasBuiltinCompiler(project->first(ProKey(*it + ".output")).toQString()); + bool addOnInput = hasBuiltinCompiler(firstExpandedOutputFileName(*it)); const ProString &tmp_other_out = project->first(ProKey(*it + ".variable_out")); if (!tmp_other_out.isEmpty() && !addOnInput) continue; diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index 3396ea4986..35dc1e8937 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -76,10 +76,8 @@ protected: virtual VCProjectWriter *createProjectWriter(); virtual bool doDepends() const { return false; } //never necesary virtual void processSources() { filterIncludedFiles("SOURCES"); filterIncludedFiles("GENERATED_SOURCES"); } - using MakefileGenerator::ReplaceFor; + using Win32MakefileGenerator::replaceExtraCompilerVariables; virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor); - inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out, ReplaceFor forShell) - { return MakefileGenerator::replaceExtraCompilerVariables(val, in, out, forShell); } virtual bool supportsMetaBuild() { return true; } virtual bool supportsMergedBuilds() { return true; } virtual bool mergeBuildProject(MakefileGenerator *other); @@ -135,6 +133,8 @@ private: QUuid increaseUUID(const QUuid &id); QString retrievePlatformToolSet() const; bool isStandardSuffix(const QString &suffix) const; + ProString firstInputFileName(const ProString &extraCompilerName) const; + QString firstExpandedOutputFileName(const ProString &extraCompilerName); friend class VCFilter; }; |