qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,326 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "mingw_make.h"
#include "option.h"
#include <proitems.h>
#include <qregularexpression.h>
#include <qdir.h>
#include <stdlib.h>
#include <time.h>
QT_BEGIN_NAMESPACE
QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const
{
QString ret = path;
ret.replace('\\', "/"); // ### this shouldn't be here
return MakefileGenerator::escapeDependencyPath(ret);
}
ProString MingwMakefileGenerator::fixLibFlag(const ProString &lib)
{
if (lib.startsWith("-l")) // Fallback for unresolved -l libs.
return QLatin1String("-l") + escapeFilePath(lib.mid(2));
if (lib.startsWith("-L")) // Lib search path. Needed only by -l above.
return QLatin1String("-L")
+ escapeFilePath(Option::fixPathToTargetOS(lib.mid(2).toQString(), false));
if (lib.startsWith("lib")) // Fallback for unresolved MSVC-style libs.
return QLatin1String("-l") + escapeFilePath(lib.mid(3).toQString());
return escapeFilePath(Option::fixPathToTargetOS(lib.toQString(), false));
}
MakefileGenerator::LibFlagType
MingwMakefileGenerator::parseLibFlag(const ProString &flag, ProString *arg)
{
// Skip MSVC handling from Win32MakefileGenerator
return MakefileGenerator::parseLibFlag(flag, arg);
}
bool MingwMakefileGenerator::processPrlFileBase(QString &origFile, QStringView origName,
QStringView fixedBase, int slashOff)
{
if (origName.startsWith(u"lib")) {
QString newFixedBase = fixedBase.left(slashOff) + fixedBase.mid(slashOff + 3);
if (Win32MakefileGenerator::processPrlFileBase(origFile, origName,
QStringView(newFixedBase), slashOff)) {
return true;
}
}
return Win32MakefileGenerator::processPrlFileBase(origFile, origName, fixedBase, slashOff);
}
bool MingwMakefileGenerator::writeMakefile(QTextStream &t)
{
writeHeader(t);
if (writeDummyMakefile(t))
return true;
if(project->first("TEMPLATE") == "app" ||
project->first("TEMPLATE") == "lib" ||
project->first("TEMPLATE") == "aux") {
if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
writePkgConfigFile();
writeMingwParts(t);
return MakefileGenerator::writeMakefile(t);
}
else if(project->first("TEMPLATE") == "subdirs") {
writeSubDirs(t);
return true;
}
return false;
}
QString MingwMakefileGenerator::installRoot() const
{
/*
We include a magic prefix on the path to bypass mingw-make's "helpful"
intervention in the environment, recognising variables that look like
paths and adding the msys system root as prefix, which we don't want.
Once this hack has smuggled INSTALL_ROOT into make's variable space, we
can trivially strip the magic prefix back off to get the path we meant.
*/
return QStringLiteral("$(INSTALL_ROOT:@msyshack@%=%)");
}
void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
{
writeStandardParts(t);
if (!preCompHeaderOut.isEmpty()) {
QString header = project->first("PRECOMPILED_HEADER").toQString();
QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
<< finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
<< "\n\t" << mkdir_p_asstring(preCompHeaderOut)
<< "\n\t$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << escapeFilePath(cHeader)
<< ' ' << escapeFilePath(header) << Qt::endl << Qt::endl;
QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
<< finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
<< "\n\t" << mkdir_p_asstring(preCompHeaderOut)
<< "\n\t$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << escapeFilePath(cppHeader)
<< ' ' << escapeFilePath(header) << Qt::endl << Qt::endl;
}
}
void MingwMakefileGenerator::init()
{
/* this should probably not be here, but I'm using it to wrap the .t files */
if(project->first("TEMPLATE") == "app")
project->values("QMAKE_APP_FLAG").append("1");
else if(project->first("TEMPLATE") == "lib")
project->values("QMAKE_LIB_FLAG").append("1");
else if(project->first("TEMPLATE") == "subdirs") {
MakefileGenerator::init();
if(project->values("MAKEFILE").isEmpty())
project->values("MAKEFILE").append("Makefile");
return;
}
processVars();
project->values("LIBS") += project->values("RES_FILE");
if (project->isActiveConfig("dll")) {
QString destDir = "";
if(!project->first("DESTDIR").isEmpty())
destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
project->values("MINGW_IMPORT_LIB").prepend(destDir + project->first("LIB_TARGET"));
project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + fileVar("MINGW_IMPORT_LIB"));
}
if (!project->values("DEF_FILE").isEmpty()) {
QString defFileName = fileFixify(project->first("DEF_FILE").toQString());
project->values("QMAKE_LFLAGS").append(QString("-Wl,") + escapeFilePath(defFileName));
}
if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib")
project->values("QMAKE_LFLAGS").append("-static");
MakefileGenerator::init();
// precomp
if (!project->first("PRECOMPILED_HEADER").isEmpty()
&& project->isActiveConfig("precompile_header")) {
QString preCompHeader = var("PRECOMPILED_DIR")
+ QFileInfo(project->first("PRECOMPILED_HEADER").toQString()).fileName();
preCompHeaderOut = preCompHeader + ".gch";
project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
preCompHeader = escapeFilePath(preCompHeader);
project->values("QMAKE_RUN_CC").clear();
project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
" $(CFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$obj $src");
project->values("QMAKE_RUN_CC_IMP").clear();
project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
" $(CFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$@ $<");
project->values("QMAKE_RUN_CXX").clear();
project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
" $(CXXFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$obj $src");
project->values("QMAKE_RUN_CXX_IMP").clear();
project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
" $(CXXFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$@ $<");
}
if(project->isActiveConfig("dll")) {
project->values("QMAKE_DISTCLEAN").append(project->first("MINGW_IMPORT_LIB"));
}
}
void MingwMakefileGenerator::writeIncPart(QTextStream &t)
{
t << "INCPATH = ";
const ProStringList &incs = project->values("INCLUDEPATH");
QFile responseFile;
QTextStream responseStream;
QChar sep(' ');
int totalLength = std::accumulate(incs.constBegin(), incs.constEnd(), 0,
[](int total, const ProString &inc) {
return total + inc.size() + 2;
});
if (totalLength > project->intValue("QMAKE_RESPONSEFILE_THRESHOLD", 8000)) {
const QString fileName = createResponseFile("incpath", incs, "-I");
if (!fileName.isEmpty()) {
t << '@' + fileName;
t << Qt::endl;
return;
}
}
for (const ProString &incit: std::as_const(incs)) {
QString inc = incit.toQString();
inc.replace(QRegularExpression("\\\\$"), "");
inc.replace('\\', '/');
t << "-I" << escapeFilePath(inc) << sep;
}
t << Qt::endl;
}
void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
{
if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
t << "LIB = " << var("QMAKE_LIB") << Qt::endl;
} else {
t << "LINKER = " << var("QMAKE_LINK") << Qt::endl;
t << "LFLAGS = " << var("QMAKE_LFLAGS") << Qt::endl;
t << "LIBS = "
<< fixLibFlags("LIBS").join(' ') << ' '
<< fixLibFlags("LIBS_PRIVATE").join(' ') << ' '
<< fixLibFlags("QMAKE_LIBS").join(' ') << ' '
<< fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << Qt::endl;
}
}
void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
{
linkerResponseFile = maybeCreateLinkerResponseFile();
if (!linkerResponseFile.isValid()) {
objectsLinkLine = "$(OBJECTS)";
} else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
// QMAKE_LIB is used for win32, including mingw, whereas QMAKE_AR is used on Unix.
QString ar_cmd = var("QMAKE_LIB");
if (ar_cmd.isEmpty())
ar_cmd = "ar -rc";
objectsLinkLine = ar_cmd + ' ' + var("DEST_TARGET") + " @"
+ escapeFilePath(linkerResponseFile.filePath);
} else {
objectsLinkLine = "@" + escapeFilePath(linkerResponseFile.filePath);
}
Win32MakefileGenerator::writeObjectsPart(t);
}
void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
{
t << "first: all\n";
t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName()))
<< ' ' << depVar("ALL_DEPS") << ' ' << depVar("DEST_TARGET") << "\n\n";
t << depVar("DEST_TARGET") << ": "
<< depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
if (project->first("TEMPLATE") == "aux") {
t << "\n\n";
return;
}
if(!project->isEmpty("QMAKE_PRE_LINK"))
t << "\n\t" <<var("QMAKE_PRE_LINK");
if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" << var("QMAKE_SHELL_NULL_DEVICE");
const ProString &objmax = project->first("QMAKE_LINK_OBJECT_MAX");
if (objmax.isEmpty() || project->values("OBJECTS").size() < objmax.toInt()) {
t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
} else {
t << "\n\t" << objectsLinkLine << " " ;
}
} else {
t << "\n\t$(LINKER) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(DESTDIR_TARGET) "
<< objectsLinkLine;
if (!linkerResponseFile.isValid() || linkerResponseFile.onlyObjects)
t << " $(LIBS)";
}
if(!project->isEmpty("QMAKE_POST_LINK"))
t << "\n\t" <<var("QMAKE_POST_LINK");
t << Qt::endl;
}
void MingwMakefileGenerator::writeRcFilePart(QTextStream &t)
{
const QString rc_file = fileFixify(project->first("RC_FILE").toQString());
ProStringList rcIncPaths = project->values("RC_INCLUDEPATH");
rcIncPaths.prepend(fileInfo(rc_file).path());
QString incPathStr;
for (int i = 0; i < rcIncPaths.size(); ++i) {
const ProString &path = rcIncPaths.at(i);
if (path.isEmpty())
continue;
incPathStr += QStringLiteral(" --include-dir=");
if (path != "." && QDir::isRelativePath(path.toQString()))
incPathStr += "./";
incPathStr += escapeFilePath(path);
}
if (!rc_file.isEmpty()) {
ProString defines = varGlue("RC_DEFINES", " -D", " -D", "");
if (defines.isEmpty())
defines = ProString(" $(DEFINES)");
addSourceFile(rc_file, QMakeSourceFileInfo::SEEK_DEPS);
const QStringList rcDeps = QStringList(rc_file) << dependencies(rc_file);
t << escapeDependencyPath(var("RES_FILE")) << ": "
<< escapeDependencyPaths(rcDeps).join(' ') << "\n\t"
<< var("QMAKE_RC") << " -i " << escapeFilePath(rc_file) << " -o " << fileVar("RES_FILE")
<< incPathStr << defines << "\n\n";
}
}
QStringList &MingwMakefileGenerator::findDependencies(const QString &file)
{
QStringList &aList = MakefileGenerator::findDependencies(file);
if (preCompHeaderOut.isEmpty())
return aList;
for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
if (file.endsWith(*it)) {
QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
if (!aList.contains(cHeader))
aList += cHeader;
break;
}
}
for (QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
if (file.endsWith(*it)) {
QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
if (!aList.contains(cppHeader))
aList += cppHeader;
break;
}
}
return aList;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,42 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MINGW_MAKE_H
#define MINGW_MAKE_H
#include "winmakefile.h"
QT_BEGIN_NAMESPACE
class MingwMakefileGenerator : public Win32MakefileGenerator
{
protected:
using MakefileGenerator::escapeDependencyPath;
QString escapeDependencyPath(const QString &path) const override;
ProString fixLibFlag(const ProString &lib) override;
bool processPrlFileBase(QString &origFile, QStringView origName,
QStringView fixedBase, int slashOff) override;
bool writeMakefile(QTextStream &) override;
void init() override;
QString installRoot() const override;
private:
void writeMingwParts(QTextStream &);
void writeIncPart(QTextStream &t) override;
void writeLibsPart(QTextStream &t) override;
void writeObjectsPart(QTextStream &t) override;
void writeBuildRulesPart(QTextStream &t) override;
void writeRcFilePart(QTextStream &t) override;
QStringList &findDependencies(const QString &file) override;
QString preCompHeaderOut;
LibFlagType parseLibFlag(const ProString &flag, ProString *arg) override;
QString objectsLinkLine;
LinkerResponseFileInfo linkerResponseFile;
};
QT_END_NAMESPACE
#endif // MINGW_MAKE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MSBUILD_OBJECTMODEL_H
#define MSBUILD_OBJECTMODEL_H
#include "project.h"
#include "xmloutput.h"
#include "msvc_objectmodel.h"
#include <qlist.h>
#include <qstring.h>
#include <qmap.h>
QT_BEGIN_NAMESPACE
// Tree & Flat view of files --------------------------------------------------
class XNode
{
public:
virtual ~XNode() { }
void addElement(const VCFilterFile &file) {
addElement(file.file, file);
}
virtual void addElement(const QString &filepath, const VCFilterFile &allInfo) = 0;
virtual void removeElements()= 0;
virtual void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName,
VCProject &tool, const QString &filter) = 0;
virtual bool hasElements() = 0;
};
class XTreeNode : public XNode
{
typedef QMap<QString, XTreeNode*> ChildrenMap;
VCFilterFile info;
ChildrenMap children;
public:
virtual ~XTreeNode() { removeElements(); }
int pathIndex(const QString &filepath) {
int Windex = filepath.indexOf("\\");
int Uindex = filepath.indexOf("/");
if (Windex != -1 && Uindex != -1)
return qMin(Windex, Uindex);
else if (Windex != -1)
return Windex;
return Uindex;
}
void addElement(const QString &filepath, const VCFilterFile &allInfo) override {
QString newNodeName(filepath);
int index = pathIndex(filepath);
if (index != -1)
newNodeName = filepath.left(index);
XTreeNode *n = children.value(newNodeName);
if (!n) {
n = new XTreeNode;
n->info = allInfo;
children.insert(newNodeName, n);
}
if (index != -1)
n->addElement(filepath.mid(index+1), allInfo);
}
void removeElements() override {
ChildrenMap::ConstIterator it = children.constBegin();
ChildrenMap::ConstIterator end = children.constEnd();
for( ; it != end; it++) {
(*it)->removeElements();
delete it.value();
}
children.clear();
}
void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &tool,
const QString &filter) override;
bool hasElements() override {
return children.size() != 0;
}
};
class XFlatNode : public XNode
{
typedef QMap<QString, VCFilterFile> ChildrenMapFlat;
ChildrenMapFlat children;
public:
virtual ~XFlatNode() { removeElements(); }
int pathIndex(const QString &filepath) {
int Windex = filepath.lastIndexOf("\\");
int Uindex = filepath.lastIndexOf("/");
if (Windex != -1 && Uindex != -1)
return qMax(Windex, Uindex);
else if (Windex != -1)
return Windex;
return Uindex;
}
void addElement(const QString &filepath, const VCFilterFile &allInfo) override {
QString newKey(filepath);
int index = pathIndex(filepath);
if (index != -1)
newKey = filepath.mid(index+1);
// Key designed to sort files with same
// name in different paths correctly
children.insert(newKey + "\0" + allInfo.file, allInfo);
}
void removeElements() override {
children.clear();
}
void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &proj,
const QString &filter) override;
bool hasElements() override {
return children.size() != 0;
}
};
class VCXProjectWriter : public VCProjectWriter
{
public:
void write(XmlOutput &, VCProjectSingleConfig &) override;
void write(XmlOutput &, VCProject &) override;
void write(XmlOutput &, const VCCLCompilerTool &) override;
void write(XmlOutput &, const VCLinkerTool &) override;
void write(XmlOutput &, const VCMIDLTool &) override;
void write(XmlOutput &, const VCCustomBuildTool &) override;
void write(XmlOutput &, const VCLibrarianTool &) override;
void write(XmlOutput &, const VCResourceCompilerTool &) override;
void write(XmlOutput &, const VCEventTool &) override;
void write(XmlOutput &, const VCDeploymentTool &) override;
void write(XmlOutput &, const VCWinDeployQtTool &) override;
void write(XmlOutput &, const VCConfiguration &) override;
void write(XmlOutput &, VCFilter &) override;
private:
struct OutputFilterData
{
VCFilter filter;
VCFilterFile info;
bool inBuild;
};
static void addFilters(VCProject &project, XmlOutput &xmlFilter, const QString &filterName);
static void outputFilter(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter, const QString &filtername);
static void outputFileConfigs(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter,
const VCFilterFile &info, const QString &filtername);
static bool outputFileConfig(OutputFilterData *d, XmlOutput &xml, XmlOutput &xmlFilter,
const QString &filename, const QString &fullFilterName,
bool fileAdded, bool hasCustomBuildStep);
static void outputFileConfig(XmlOutput &xml, XmlOutput &xmlFilter, const QString &fileName, const QString &filterName);
static QString generateCondition(const VCConfiguration &config);
static XmlOutput::xml_output attrTagToolsVersion(const VCConfiguration &config);
friend class XTreeNode;
friend class XFlatNode;
};
QT_END_NAMESPACE
#endif // MSVC_OBJECTMODEL_H

View File

@ -0,0 +1,515 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "msvc_nmake.h"
#include "option.h"
#include <qregularexpression.h>
#include <qdir.h>
#include <qdiriterator.h>
#include <qset.h>
#include <time.h>
QT_BEGIN_NAMESPACE
bool
NmakeMakefileGenerator::writeMakefile(QTextStream &t)
{
writeHeader(t);
if (writeDummyMakefile(t))
return true;
if(project->first("TEMPLATE") == "app" ||
project->first("TEMPLATE") == "lib" ||
project->first("TEMPLATE") == "aux") {
writeNmakeParts(t);
return MakefileGenerator::writeMakefile(t);
}
else if(project->first("TEMPLATE") == "subdirs") {
writeSubDirs(t);
return true;
}
return false;
}
void NmakeMakefileGenerator::writeSubMakeCall(QTextStream &t, const QString &callPrefix,
const QString &makeArguments)
{
// Pass MAKEFLAGS as environment variable to sub-make calls.
// Unlike other make tools nmake doesn't do this automatically.
t << "\n\t@set MAKEFLAGS=$(MAKEFLAGS)";
Win32MakefileGenerator::writeSubMakeCall(t, callPrefix, makeArguments);
}
ProStringList NmakeMakefileGenerator::extraSubTargetDependencies()
{
return { "$(MAKEFILE)" };
}
QString NmakeMakefileGenerator::defaultInstall(const QString &t)
{
QString ret = Win32MakefileGenerator::defaultInstall(t);
if (ret.isEmpty())
return ret;
const QString root = installRoot();
ProStringList &uninst = project->values(ProKey(t + ".uninstall"));
QString targetdir = fileFixify(project->first(ProKey(t + ".path")).toQString(), FileFixifyAbsolute);
if(targetdir.right(1) != Option::dir_sep)
targetdir += Option::dir_sep;
if (project->isActiveConfig("debug_info")) {
if (t == "dlltarget" || project->values(ProKey(t + ".CONFIG")).indexOf("no_dll") == -1) {
const QFileInfo targetFileInfo(project->first("DESTDIR") + project->first("TARGET")
+ project->first("TARGET_EXT"));
const QString pdb_target = targetFileInfo.completeBaseName() + ".pdb";
QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + pdb_target;
QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + pdb_target, FileFixifyAbsolute));
if(!ret.isEmpty())
ret += "\n\t";
ret += QString("-$(INSTALL_FILE) ") + escapeFilePath(src_targ) + ' ' + escapeFilePath(dst_targ);
if(!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + escapeFilePath(dst_targ));
}
}
return ret;
}
QStringList &NmakeMakefileGenerator::findDependencies(const QString &file)
{
QStringList &aList = MakefileGenerator::findDependencies(file);
for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
if(file.endsWith(*it)) {
if(!precompObj.isEmpty() && !aList.contains(precompObj))
aList += precompObj;
break;
}
}
for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
if (file.endsWith(*it)) {
if (!precompObjC.isEmpty() && !aList.contains(precompObjC))
aList += precompObjC;
break;
}
}
return aList;
}
void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t)
{
writeStandardParts(t);
// precompiled header
if(usePCH) {
QString precompRule = QString("-c -Yc -Fp%1 -Fo%2")
.arg(escapeFilePath(precompPch), escapeFilePath(precompObj));
t << escapeDependencyPath(precompObj) << ": " << escapeDependencyPath(precompH) << ' '
<< finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t")
<< "\n\t$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP "
<< escapeFilePath(precompH) << Qt::endl << Qt::endl;
}
if (usePCHC) {
QString precompRuleC = QString("-c -Yc -Fp%1 -Fo%2")
.arg(escapeFilePath(precompPchC), escapeFilePath(precompObjC));
t << escapeDependencyPath(precompObjC) << ": " << escapeDependencyPath(precompH) << ' '
<< finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t")
<< "\n\t$(CC) " + precompRuleC +" $(CFLAGS) $(INCPATH) -TC "
<< escapeFilePath(precompH) << Qt::endl << Qt::endl;
}
}
QString NmakeMakefileGenerator::var(const ProKey &value) const
{
if (usePCH || usePCHC) {
const bool isRunC = (value == "QMAKE_RUN_CC_IMP_BATCH"
|| value == "QMAKE_RUN_CC_IMP"
|| value == "QMAKE_RUN_CC");
const bool isRunCpp = (value == "QMAKE_RUN_CXX_IMP_BATCH"
|| value == "QMAKE_RUN_CXX_IMP"
|| value == "QMAKE_RUN_CXX");
if ((isRunCpp && usePCH) || (isRunC && usePCHC)) {
QString precompH_f = escapeFilePath(fileFixify(precompH, FileFixifyBackwards));
QString precompRule = QString("-c -FI%1 -Yu%2 -Fp%3")
.arg(precompH_f, precompH_f, escapeFilePath(isRunC ? precompPchC : precompPch));
// ### For clang_cl 8 we force inline methods to be compiled here instead
// linking them from a pch.o file. We do this by pretending we are also doing
// the pch.o generation step.
if (project->isActiveConfig("clang_cl"))
precompRule += QString(" -Xclang -building-pch-with-obj");
QString p = MakefileGenerator::var(value);
p.replace(QLatin1String("-c"), precompRule);
return p;
}
}
// Normal val
return MakefileGenerator::var(value);
}
void NmakeMakefileGenerator::suppressBuiltinRules(QTextStream &) const
{
}
void NmakeMakefileGenerator::init()
{
/* this should probably not be here, but I'm using it to wrap the .t files */
if(project->first("TEMPLATE") == "app")
project->values("QMAKE_APP_FLAG").append("1");
else if(project->first("TEMPLATE") == "lib")
project->values("QMAKE_LIB_FLAG").append("1");
else if(project->first("TEMPLATE") == "subdirs") {
MakefileGenerator::init();
if(project->values("MAKEFILE").isEmpty())
project->values("MAKEFILE").append("Makefile");
return;
}
processVars();
project->values("LIBS") += project->values("RES_FILE");
if (!project->values("DEF_FILE").isEmpty()) {
QString defFileName = fileFixify(project->first("DEF_FILE").toQString());
project->values("QMAKE_LFLAGS").append(QString("/DEF:") + escapeFilePath(defFileName));
}
// 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:");
// Base class init!
MakefileGenerator::init();
// Setup PCH variables
precompH = project->first("PRECOMPILED_HEADER").toQString();
usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
usePCHC = !precompH.isEmpty() && project->isActiveConfig("precompile_header_c");
if (usePCH) {
// Created files
precompObj = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch" + Option::obj_ext;
precompPch = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch.pch";
// Add linking of precompObj (required for whole precompiled classes)
// ### For clang_cl we currently let inline methods be generated in the normal objects,
// since the PCH object is buggy (as of clang 8.0.0)
if (!project->isActiveConfig("clang_cl"))
project->values("OBJECTS") += precompObj;
// Add pch file to cleanup
project->values("QMAKE_CLEAN") += precompPch;
// Return to variable pool
project->values("PRECOMPILED_OBJECT") = ProStringList(precompObj);
project->values("PRECOMPILED_PCH") = ProStringList(precompPch);
}
if (usePCHC) {
precompObjC = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch_c" + Option::obj_ext;
precompPchC = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch_c.pch";
if (!project->isActiveConfig("clang_cl"))
project->values("OBJECTS") += precompObjC;
project->values("QMAKE_CLEAN") += precompPchC;
project->values("PRECOMPILED_OBJECT_C") = ProStringList(precompObjC);
project->values("PRECOMPILED_PCH_C") = ProStringList(precompPchC);
}
const QFileInfo targetFileInfo(project->first("DESTDIR") + project->first("TARGET")
+ project->first("TARGET_EXT"));
const ProString targetBase = targetFileInfo.path() + '/' + targetFileInfo.completeBaseName();
if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("shared")) {
project->values("QMAKE_CLEAN").append(targetBase + ".exp");
project->values("QMAKE_DISTCLEAN").append(targetBase + ".lib");
}
if (project->isActiveConfig("debug_info")) {
QString pdbfile;
QString distPdbFile = targetBase + ".pdb";
if (project->isActiveConfig("staticlib")) {
// For static libraries, the compiler's pdb file and the dist pdb file are the same.
pdbfile = distPdbFile;
} else {
// Use $${TARGET}.vc.pdb in the OBJECTS_DIR for the compiler and
// $${TARGET}.pdb (the default) for the linker.
pdbfile = var("OBJECTS_DIR") + project->first("TARGET") + ".vc.pdb";
}
QString escapedPdbFile = escapeFilePath(pdbfile);
project->values("QMAKE_CFLAGS").append("/Fd" + escapedPdbFile);
project->values("QMAKE_CXXFLAGS").append("/Fd" + escapedPdbFile);
project->values("QMAKE_CLEAN").append(pdbfile);
project->values("QMAKE_DISTCLEAN").append(distPdbFile);
}
if (project->isActiveConfig("debug")) {
project->values("QMAKE_CLEAN").append(targetBase + ".ilk");
project->values("QMAKE_CLEAN").append(targetBase + ".idb");
}
if (project->values("QMAKE_APP_FLAG").isEmpty() && project->isActiveConfig("dll")) {
ProStringList &defines = project->values("DEFINES");
if (!defines.contains("_WINDLL"))
defines.append("_WINDLL");
}
}
QStringList NmakeMakefileGenerator::sourceFilesForImplicitRulesFilter()
{
QStringList filter;
const QChar wildcard = QLatin1Char('*');
for (const QString &ext : std::as_const(Option::c_ext))
filter << wildcard + ext;
for (const QString &ext : std::as_const(Option::cpp_ext))
filter << wildcard + ext;
return filter;
}
void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
{
t << "####### Implicit rules\n\n";
t << ".SUFFIXES:";
for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
t << " " << (*cit);
for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
t << " " << (*cppit);
t << Qt::endl << Qt::endl;
bool useInferenceRules = !project->isActiveConfig("no_batch");
QSet<QString> source_directories;
if (useInferenceRules) {
source_directories.insert(".");
static const char * const directories[] = { "UI_SOURCES_DIR", "UI_DIR", nullptr };
for (int y = 0; directories[y]; y++) {
QString dirTemp = project->first(directories[y]).toQString();
if (dirTemp.endsWith("\\"))
dirTemp.truncate(dirTemp.size()-1);
if(!dirTemp.isEmpty())
source_directories.insert(dirTemp);
}
static const char * const srcs[] = { "SOURCES", "GENERATED_SOURCES", nullptr };
for (int x = 0; srcs[x]; x++) {
const ProStringList &l = project->values(srcs[x]);
for (ProStringList::ConstIterator sit = l.begin(); sit != l.end(); ++sit) {
QString sep = "\\";
if((*sit).indexOf(sep) == -1)
sep = "/";
QString dir = (*sit).toQString().section(sep, 0, -2);
if (!dir.isEmpty())
source_directories.insert(dir);
}
}
// nmake's inference rules might pick up the wrong files when encountering source files with
// the same name in different directories. In this situation, turn inference rules off.
QHash<QString, QString> fileNames;
bool duplicatesFound = false;
const QStringList sourceFilesFilter = sourceFilesForImplicitRulesFilter();
QStringList fixifiedSourceDirs = fileFixify(QList<QString>(source_directories.constBegin(), source_directories.constEnd()), FileFixifyAbsolute);
fixifiedSourceDirs.removeDuplicates();
for (const QString &sourceDir : std::as_const(fixifiedSourceDirs)) {
QDirIterator dit(sourceDir, sourceFilesFilter, QDir::Files | QDir::NoDotAndDotDot);
while (dit.hasNext()) {
const QFileInfo fi = dit.nextFileInfo();
QString &duplicate = fileNames[fi.completeBaseName()];
if (duplicate.isNull()) {
duplicate = fi.filePath();
} else {
warn_msg(WarnLogic, "%s conflicts with %s", qPrintable(duplicate),
qPrintable(fi.filePath()));
duplicatesFound = true;
}
}
}
if (duplicatesFound) {
useInferenceRules = false;
warn_msg(WarnLogic, "Automatically turning off nmake's inference rules. (CONFIG += no_batch)");
}
}
if (useInferenceRules) {
// Batchmode doesn't use the non implicit rules QMAKE_RUN_CXX & QMAKE_RUN_CC
project->variables().remove("QMAKE_RUN_CXX");
project->variables().remove("QMAKE_RUN_CC");
for (const QString &sourceDir : std::as_const(source_directories)) {
if (sourceDir.isEmpty())
continue;
QString objDir = var("OBJECTS_DIR");
if (objDir == ".\\")
objDir = "";
for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
t << '{' << escapeDependencyPath(sourceDir) << '}' << (*cppit)
<< '{' << escapeDependencyPath(objDir) << '}' << Option::obj_ext << "::\n\t"
<< var("QMAKE_RUN_CXX_IMP_BATCH").replace(QRegularExpression("\\$@"), fileVar("OBJECTS_DIR"))
<< "\n\t$<\n<<\n\n";
for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
t << '{' << escapeDependencyPath(sourceDir) << '}' << (*cit)
<< '{' << escapeDependencyPath(objDir) << '}' << Option::obj_ext << "::\n\t"
<< var("QMAKE_RUN_CC_IMP_BATCH").replace(QRegularExpression("\\$@"), fileVar("OBJECTS_DIR"))
<< "\n\t$<\n<<\n\n";
}
} else {
for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << Qt::endl << Qt::endl;
for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << Qt::endl << Qt::endl;
}
}
void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
{
const ProString templateName = project->first("TEMPLATE");
t << "first: all\n";
t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName()))
<< ' ' << depVar("ALL_DEPS") << ' ' << depVar("DEST_TARGET") << "\n\n";
t << depVar("DEST_TARGET") << ": "
<< depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
if (templateName == "aux") {
t << "\n\n";
return;
}
if(!project->isEmpty("QMAKE_PRE_LINK"))
t << "\n\t" <<var("QMAKE_PRE_LINK");
if(project->isActiveConfig("staticlib")) {
t << "\n\t$(LIBAPP) $(LIBFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(DESTDIR_TARGET) @<<\n\t ";
writeResponseFileFiles(t, project->values("OBJECTS"));
t << "<<";
} else {
const bool embedManifest = ((templateName == "app" && project->isActiveConfig("embed_manifest_exe"))
|| (templateName == "lib" && project->isActiveConfig("embed_manifest_dll")
&& !(project->isActiveConfig("plugin") && project->isActiveConfig("no_plugin_manifest"))
));
if (embedManifest) {
bool generateManifest = false;
const QString target = var("DEST_TARGET");
QString manifest = project->first("QMAKE_MANIFEST").toQString();
QString extraLFlags;
const bool linkerSupportsEmbedding = (msvcVersion() >= 1200);
if (manifest.isEmpty()) {
generateManifest = true;
if (linkerSupportsEmbedding) {
extraLFlags = "/MANIFEST:embed";
} else {
manifest = target + ".embed.manifest";
extraLFlags += "/MANIFEST /MANIFESTFILE:" + escapeFilePath(manifest);
project->values("QMAKE_CLEAN") << manifest;
}
} else {
manifest = fileFixify(manifest);
if (linkerSupportsEmbedding)
extraLFlags = "/MANIFEST:embed /MANIFESTINPUT:" + escapeFilePath(manifest);
}
const QString resourceId = (templateName == "app") ? "1" : "2";
const bool incrementalLinking = project->values("QMAKE_LFLAGS").toQStringList().filter(QRegularExpression("(/|-)INCREMENTAL:NO")).isEmpty();
if (incrementalLinking && !linkerSupportsEmbedding) {
// Link a resource that contains the manifest without modifying the exe/dll after linking.
QString manifest_rc = target + "_manifest.rc";
QString manifest_res = target + "_manifest.res";
project->values("QMAKE_CLEAN") << manifest_rc << manifest_res;
manifest_rc = escapeFilePath(manifest_rc);
manifest_res = escapeFilePath(manifest_res);
t << "\n\techo " << resourceId
<< " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ "
<< cQuoted(manifest) << '>' << manifest_rc;
if (generateManifest) {
manifest = escapeFilePath(manifest);
QString manifest_bak = escapeFilePath(target + "_manifest.bak");
project->values("QMAKE_CLEAN") << manifest_bak;
t << "\n\tif not exist $(DESTDIR_TARGET) if exist " << manifest
<< " del " << manifest;
t << "\n\tif exist " << manifest << " copy /Y " << manifest << ' ' << manifest_bak;
const QString extraInlineFileContent = "\n!IF EXIST(" + manifest_res + ")\n" + manifest_res + "\n!ENDIF";
t << "\n\t";
writeLinkCommand(t, extraLFlags, extraInlineFileContent);
t << "\n\tif exist " << manifest_bak << " fc /b " << manifest << ' ' << manifest_bak << " >NUL || del " << manifest_bak;
t << "\n\tif not exist " << manifest_bak << " rc.exe /fo" << manifest_res << ' ' << manifest_rc;
t << "\n\tif not exist " << manifest_bak << ' ';
writeLinkCommand(t, extraLFlags, manifest_res);
t << "\n\tif exist " << manifest_bak << " del " << manifest_bak;
} else {
t << "\n\trc.exe /fo" << manifest_res << " " << manifest_rc;
t << "\n\t";
writeLinkCommand(t, extraLFlags, manifest_res);
}
} else {
// directly embed the manifest in the executable after linking
t << "\n\t";
writeLinkCommand(t, extraLFlags);
if (!linkerSupportsEmbedding) {
t << "\n\tmt.exe /nologo /manifest " << escapeFilePath(manifest)
<< " /outputresource:$(DESTDIR_TARGET);" << resourceId;
}
}
} else {
t << "\n\t";
writeLinkCommand(t);
}
}
if(!project->isEmpty("QMAKE_POST_LINK")) {
t << "\n\t" << var("QMAKE_POST_LINK");
}
t << Qt::endl;
}
void NmakeMakefileGenerator::writeLinkCommand(QTextStream &t, const QString &extraFlags, const QString &extraInlineFileContent)
{
t << "$(LINKER) $(LFLAGS)";
if (!extraFlags.isEmpty())
t << ' ' << extraFlags;
t << " " << var("QMAKE_LINK_O_FLAG") << "$(DESTDIR_TARGET) @<<\n";
writeResponseFileFiles(t, project->values("OBJECTS"));
t << "$(LIBS)\n";
if (!extraInlineFileContent.isEmpty())
t << extraInlineFileContent << '\n';
t << "<<";
}
void NmakeMakefileGenerator::writeResponseFileFiles(QTextStream &t, const ProStringList &files)
{
// Add line breaks in file lists in reponse files to work around LNK1170.
// The actual line length limit is 131070, but let's use a smaller limit
// in case other tools are similarly hampered.
const int maxLineLength = 1000;
int len = 0;
for (const ProString &file : files) {
const ProString escapedFilePath = escapeFilePath(file);
if (len) {
if (len + escapedFilePath.length() > maxLineLength) {
t << '\n';
len = 0;
} else {
t << ' ';
len++;
}
}
t << escapedFilePath;
len += escapedFilePath.length();
}
t << '\n';
}
int NmakeMakefileGenerator::msvcVersion() const
{
const int fallbackVersion = 800; // Visual Studio 2005
const QString ver = project->first(ProKey("MSVC_VER")).toQString();
bool ok;
float f = ver.toFloat(&ok);
return ok ? int(f * 100) : fallbackVersion;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,39 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MSVC_NMAKE_H
#define MSVC_NMAKE_H
#include "winmakefile.h"
QT_BEGIN_NAMESPACE
class NmakeMakefileGenerator : public Win32MakefileGenerator
{
void writeNmakeParts(QTextStream &);
bool writeMakefile(QTextStream &) override;
void writeImplicitRulesPart(QTextStream &t) override;
void writeBuildRulesPart(QTextStream &t) override;
void writeLinkCommand(QTextStream &t, const QString &extraFlags = QString(), const QString &extraInlineFileContent = QString());
void writeResponseFileFiles(QTextStream &t, const ProStringList &files);
int msvcVersion() const;
void init() override;
static QStringList sourceFilesForImplicitRulesFilter();
protected:
void writeSubMakeCall(QTextStream &t, const QString &callPrefix,
const QString &makeArguments) override;
ProStringList extraSubTargetDependencies() override;
QString defaultInstall(const QString &t) override;
QStringList &findDependencies(const QString &file) override;
QString var(const ProKey &value) const override;
void suppressBuiltinRules(QTextStream &t) const override;
QString precompH, precompObj, precompPch;
QString precompObjC, precompPchC;
bool usePCH = false;
bool usePCHC = false;
};
QT_END_NAMESPACE
#endif // MSVC_NMAKE_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MSVC_VCPROJ_H
#define MSVC_VCPROJ_H
#include "winmakefile.h"
#include "msvc_objectmodel.h"
QT_BEGIN_NAMESPACE
enum Target {
Application,
SharedLib,
StaticLib
};
class QUuid;
struct VcsolutionDepend;
class VcprojGenerator : public Win32MakefileGenerator
{
bool is64Bit;
bool writeVcprojParts(QTextStream &);
bool writeMakefile(QTextStream &) override;
bool writeProjectMakefile() override;
void init() override;
public:
VcprojGenerator();
~VcprojGenerator();
QString defaultMakefile() const;
QString precompH, precompHFilename, precompSource,
precompObj, precompPch;
bool autogenPrecompSource;
static bool hasBuiltinCompiler(const QString &file);
QHash<QString, QStringList> extraCompilerSources;
QHash<QString, QString> extraCompilerOutputs;
const QString customBuildToolFilterFileSuffix;
bool usePCH;
bool pchIsCFile = false;
VCProjectWriter *projectWriter;
using Win32MakefileGenerator::callExtraCompilerDependCommand;
protected:
virtual VCProjectWriter *createProjectWriter();
bool doDepends() const override { return false; } // Never necessary
using Win32MakefileGenerator::replaceExtraCompilerVariables;
QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor) override;
QString extraCompilerName(const ProString &extraCompiler, const QStringList &inputs,
const QStringList &outputs);
bool supportsMetaBuild() override { return true; }
bool supportsMergedBuilds() override { return true; }
bool mergeBuildProject(MakefileGenerator *other) override;
bool openOutput(QFile &file, const QString &build) const override;
virtual void initProject();
void initConfiguration();
void initCompilerTool();
void initLinkerTool();
void initLibrarianTool();
void initManifestTool();
void initResourceTool();
void initIDLTool();
void initCustomBuildTool();
void initPreBuildEventTools();
void initPostBuildEventTools();
void initDeploymentTool();
void initWinDeployQtTool();
void initPreLinkEventTools();
void initRootFiles();
void initSourceFiles();
void initHeaderFiles();
void initGeneratedFiles();
void initTranslationFiles();
void initFormFiles();
void initResourceFiles();
void initDeploymentFiles();
void initDistributionFiles();
void initLexYaccFiles();
void initExtraCompilerOutputs();
void writeSubDirs(QTextStream &t); // Called from VCXProj backend
QUuid getProjectUUID(const QString &filename=QString()); // Called from VCXProj backend
Target projectTarget;
// Used for single project
VCProjectSingleConfig vcProject;
// Holds all configurations for glue (merged) project
QList<VcprojGenerator*> mergedProjects;
private:
ProStringList collectDependencies(QMakeProject *proj, QHash<QString, QString> &projLookup,
QHash<QString, QString> &projGuids,
QHash<VcsolutionDepend *, QStringList> &extraSubdirs,
QHash<QString, VcsolutionDepend*> &solution_depends,
QList<VcsolutionDepend*> &solution_cleanup,
QTextStream &t,
QHash<QString, ProStringList> &subdirProjectLookup,
const ProStringList &allDependencies = ProStringList());
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);
void createCustomBuildToolFakeFile(const QString &cbtFilePath, const QString &realOutFilePath);
bool otherFiltersContain(const QString &fileName) const;
friend class VCFilter;
};
inline QString VcprojGenerator::defaultMakefile() const
{
return project->first("TARGET") + project->first("VCPROJ_EXTENSION");
}
QT_END_NAMESPACE
#endif // MSVC_VCPROJ_H

View File

@ -0,0 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "msvc_vcxproj.h"
#include "msbuild_objectmodel.h"
QT_BEGIN_NAMESPACE
VcxprojGenerator::VcxprojGenerator() : VcprojGenerator()
{
}
VCProjectWriter *VcxprojGenerator::createProjectWriter()
{
return new VCXProjectWriter;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MSVC_VCXPROJ_H
#define MSVC_VCXPROJ_H
#include "msvc_vcproj.h"
QT_BEGIN_NAMESPACE
class VcxprojGenerator : public VcprojGenerator
{
public:
VcxprojGenerator();
protected:
VCProjectWriter *createProjectWriter() override;
};
QT_END_NAMESPACE
#endif // MSVC_VCXPROJ_H

View File

@ -0,0 +1,861 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "winmakefile.h"
#include "option.h"
#include "project.h"
#include "meta.h"
#include <qtextstream.h>
#include <qstring.h>
#include <qhash.h>
#include <qregularexpression.h>
#include <qstringlist.h>
#include <qdir.h>
#include <stdlib.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
ProString Win32MakefileGenerator::fixLibFlag(const ProString &lib)
{
if (lib.startsWith("-l")) // Fallback for unresolved -l libs.
return escapeFilePath(lib.mid(2) + QLatin1String(".lib"));
if (lib.startsWith("-L")) // Lib search path. Needed only by -l above.
return QLatin1String("/LIBPATH:")
+ escapeFilePath(Option::fixPathToTargetOS(lib.mid(2).toQString(), false));
return escapeFilePath(Option::fixPathToTargetOS(lib.toQString(), false));
}
MakefileGenerator::LibFlagType
Win32MakefileGenerator::parseLibFlag(const ProString &flag, ProString *arg)
{
LibFlagType ret = MakefileGenerator::parseLibFlag(flag, arg);
if (ret != LibFlagFile)
return ret;
// MSVC compatibility. This should be deprecated.
if (flag.startsWith("/LIBPATH:")) {
*arg = flag.mid(9);
return LibFlagPath;
}
// These are pure qmake inventions. They *really* should be deprecated.
if (flag.startsWith("/L")) {
*arg = flag.mid(2);
return LibFlagPath;
}
if (flag.startsWith("/l")) {
*arg = flag.mid(2);
return LibFlagLib;
}
return LibFlagFile;
}
class LibrarySearchPath : public QMakeLocalFileName
{
public:
LibrarySearchPath() = default;
LibrarySearchPath(const QString &s)
: QMakeLocalFileName(s)
{
}
LibrarySearchPath(QString &&s, bool isDefault = false)
: QMakeLocalFileName(std::move(s)), _default(isDefault)
{
}
bool isDefault() const { return _default; }
private:
bool _default = false;
};
bool
Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
{
ProStringList impexts = project->values("QMAKE_LIB_EXTENSIONS");
if (impexts.isEmpty())
impexts = project->values("QMAKE_EXTENSION_STATICLIB");
QList<LibrarySearchPath> dirs;
int libidx = 0;
for (const ProString &dlib : project->values("QMAKE_DEFAULT_LIBDIRS"))
dirs.append(LibrarySearchPath(dlib.toQString(), true));
static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE",
"QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr };
for (int i = 0; lflags[i]; i++) {
ProStringList &l = project->values(lflags[i]);
for (ProStringList::Iterator it = l.begin(); it != l.end();) {
const ProString &opt = *it;
ProString arg;
LibFlagType type = parseLibFlag(opt, &arg);
if (type == LibFlagPath) {
const QString argqstr = arg.toQString();
auto dit = std::find_if(dirs.cbegin(), dirs.cend(),
[&argqstr](const LibrarySearchPath &p)
{
return p.real() == argqstr;
});
int idx = dit == dirs.cend()
? -1
: std::distance(dirs.cbegin(), dit);
if (idx >= 0 && idx < libidx) {
it = l.erase(it);
continue;
}
const LibrarySearchPath lp(argqstr);
dirs.insert(libidx++, lp);
(*it) = "-L" + lp.real();
} else if (type == LibFlagLib) {
QString lib = arg.toQString();
ProString verovr =
project->first(ProKey("QMAKE_" + lib.toUpper() + "_VERSION_OVERRIDE"));
for (auto dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
QString cand = (*dir_it).real() + Option::dir_sep + lib;
if (linkPrl && processPrlFile(cand, true)) {
(*it) = cand;
goto found;
}
QString libBase = (*dir_it).local() + '/' + lib + verovr;
for (ProStringList::ConstIterator extit = impexts.cbegin();
extit != impexts.cend(); ++extit) {
if (exists(libBase + '.' + *extit)) {
*it = (dir_it->isDefault() ? lib : cand)
+ verovr + '.' + *extit;
goto found;
}
}
}
// We assume if it never finds it that it's correct
found: ;
} else if (linkPrl && type == LibFlagFile) {
QString lib = opt.toQString();
if (fileInfo(lib).isAbsolute()) {
if (processPrlFile(lib, false))
(*it) = lib;
} else {
for (auto dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
QString cand = (*dir_it).real() + Option::dir_sep + lib;
if (processPrlFile(cand, false)) {
(*it) = cand;
break;
}
}
}
}
ProStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS");
for (int prl = 0; prl < prl_libs.size(); ++prl)
it = l.insert(++it, prl_libs.at(prl));
prl_libs.clear();
++it;
}
if (mergeLflags) {
ProStringList lopts;
for (int lit = 0; lit < l.size(); ++lit) {
ProString opt = l.at(lit);
if (opt.startsWith(QLatin1String("-L"))) {
if (!lopts.contains(opt))
lopts.append(opt);
} else {
// Make sure we keep the dependency order of libraries
lopts.removeAll(opt);
lopts.append(opt);
}
}
l = lopts;
}
}
return true;
}
bool Win32MakefileGenerator::processPrlFileBase(QString &origFile, QStringView origName,
QStringView fixedBase, int slashOff)
{
if (MakefileGenerator::processPrlFileBase(origFile, origName, fixedBase, slashOff))
return true;
for (int off = fixedBase.size(); off > slashOff; off--) {
if (!fixedBase.at(off - 1).isDigit()) {
if (off != fixedBase.size()) {
return MakefileGenerator::processPrlFileBase(
origFile, origName, fixedBase.left(off), slashOff);
}
break;
}
}
return false;
}
void Win32MakefileGenerator::processVars()
{
if (project->first("TEMPLATE").endsWith("aux"))
return;
project->values("PRL_TARGET") =
project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
if (project->isEmpty("QMAKE_PROJECT_NAME"))
project->values("QMAKE_PROJECT_NAME") = project->values("QMAKE_ORIG_TARGET");
else if (project->first("TEMPLATE").startsWith("vc"))
project->values("MAKEFILE") = project->values("QMAKE_PROJECT_NAME");
project->values("QMAKE_INCDIR") += project->values("QMAKE_INCDIR_POST");
project->values("QMAKE_LIBDIR") += project->values("QMAKE_LIBDIR_POST");
if (!project->values("QMAKE_INCDIR").isEmpty())
project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
if (!project->values("VERSION").isEmpty()) {
QStringList l = project->first("VERSION").toQString().split('.');
if (l.size() > 0)
project->values("VER_MAJ").append(l[0]);
if (l.size() > 1)
project->values("VER_MIN").append(l[1]);
}
// TARGET_VERSION_EXT will be used to add a version number onto the target name
if (!project->isActiveConfig("skip_target_version_ext")
&& project->values("TARGET_VERSION_EXT").isEmpty()
&& !project->values("VER_MAJ").isEmpty())
project->values("TARGET_VERSION_EXT").append(project->first("VER_MAJ"));
fixTargetExt();
processRcFileVar();
ProStringList libs;
ProStringList &libDir = project->values("QMAKE_LIBDIR");
for (ProStringList::Iterator libDir_it = libDir.begin(); libDir_it != libDir.end(); ++libDir_it) {
QString lib = (*libDir_it).toQString();
if (!lib.isEmpty()) {
if (lib.endsWith('\\'))
lib.chop(1);
libs << QLatin1String("-L") + lib;
}
}
ProStringList &qmklibs = project->values("LIBS");
qmklibs = libs + qmklibs;
if (project->values("TEMPLATE").contains("app")) {
project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP");
project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP");
project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP");
} else if (project->values("TEMPLATE").contains("lib") && project->isActiveConfig("dll")) {
if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) {
project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB");
project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB");
}
if (project->isActiveConfig("plugin")) {
project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN");
project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN");
project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN");
} else {
project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB");
}
}
}
void Win32MakefileGenerator::fixTargetExt()
{
if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
project->values("TARGET_EXT").append(".exe");
} else if (project->isActiveConfig("shared")) {
project->values("LIB_TARGET").prepend(project->first("QMAKE_PREFIX_STATICLIB")
+ project->first("TARGET") + project->first("TARGET_VERSION_EXT")
+ '.' + project->first("QMAKE_EXTENSION_STATICLIB"));
project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + "."
+ project->first("QMAKE_EXTENSION_SHLIB"));
project->values("TARGET").first() = project->first("QMAKE_PREFIX_SHLIB") + project->first("TARGET");
} else {
project->values("TARGET_EXT").append("." + project->first("QMAKE_EXTENSION_STATICLIB"));
project->values("TARGET").first() = project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET");
project->values("LIB_TARGET").prepend(project->first("TARGET") + project->first("TARGET_EXT")); // for the .prl only
}
}
void Win32MakefileGenerator::processRcFileVar()
{
if (Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
return;
const QString manifestFile = project->first("QMAKE_MANIFEST").toQString();
if (((!project->values("VERSION").isEmpty() || !project->values("RC_ICONS").isEmpty() || !manifestFile.isEmpty())
&& project->values("RC_FILE").isEmpty()
&& project->values("RES_FILE").isEmpty()
&& !project->isActiveConfig("no_generated_target_info")
&& (project->isActiveConfig("shared") || !project->values("QMAKE_APP_FLAG").isEmpty()))
|| !project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty()){
QByteArray rcString;
QTextStream ts(&rcString, QFile::WriteOnly);
QStringList vers = project->first("VERSION").toQString().split(".", Qt::SkipEmptyParts);
for (int i = vers.size(); i < 4; i++)
vers += "0";
QString versionString = vers.join('.');
QStringList rcIcons;
const auto icons = project->values("RC_ICONS");
rcIcons.reserve(icons.size());
for (const ProString &icon : icons)
rcIcons.append(fileFixify(icon.toQString(), FileFixifyAbsolute));
QString companyName;
if (!project->values("QMAKE_TARGET_COMPANY").isEmpty())
companyName = project->values("QMAKE_TARGET_COMPANY").join(' ');
QString description;
if (!project->values("QMAKE_TARGET_DESCRIPTION").isEmpty())
description = project->values("QMAKE_TARGET_DESCRIPTION").join(' ');
QString copyright;
if (!project->values("QMAKE_TARGET_COPYRIGHT").isEmpty())
copyright = project->values("QMAKE_TARGET_COPYRIGHT").join(' ');
QString productName;
if (!project->values("QMAKE_TARGET_PRODUCT").isEmpty())
productName = project->values("QMAKE_TARGET_PRODUCT").join(' ');
else
productName = project->first("TARGET").toQString();
QString originalName;
if (!project->values("QMAKE_TARGET_ORIGINAL_FILENAME").isEmpty())
originalName = project->values("QMAKE_TARGET_ORIGINAL_FILENAME").join(' ');
else
originalName = project->first("TARGET") + project->first("TARGET_EXT");
QString internalName;
if (!project->values("QMAKE_TARGET_INTERNALNAME").isEmpty())
internalName = project->values("QMAKE_TARGET_INTERNALNAME").join(' ');
QString comments;
if (!project->values("QMAKE_TARGET_COMMENTS").isEmpty())
comments = project->values("QMAKE_TARGET_COMMENTS").join(' ');
QString trademarks;
if (!project->values("QMAKE_TARGET_TRADEMARKS").isEmpty())
trademarks = project->values("QMAKE_TARGET_TRADEMARKS").join(' ');
int rcLang = project->intValue("RC_LANG", 1033); // default: English(USA)
int rcCodePage = project->intValue("RC_CODEPAGE", 1200); // default: Unicode
ts << "#include <windows.h>\n";
ts << Qt::endl;
if (!rcIcons.isEmpty()) {
for (int i = 0; i < rcIcons.size(); ++i)
ts << QString("IDI_ICON%1\tICON\t%2").arg(i + 1).arg(cQuoted(rcIcons[i])) << Qt::endl;
ts << Qt::endl;
}
if (!manifestFile.isEmpty()) {
QString manifestResourceId;
if (project->first("TEMPLATE") == "lib")
manifestResourceId = QStringLiteral("ISOLATIONAWARE_MANIFEST_RESOURCE_ID");
else
manifestResourceId = QStringLiteral("CREATEPROCESS_MANIFEST_RESOURCE_ID");
ts << manifestResourceId << " RT_MANIFEST \"" << manifestFile << "\"\n";
}
ts << "VS_VERSION_INFO VERSIONINFO\n";
ts << "\tFILEVERSION " << QString(versionString).replace(".", ",") << Qt::endl;
ts << "\tPRODUCTVERSION " << QString(versionString).replace(".", ",") << Qt::endl;
ts << "\tFILEFLAGSMASK 0x3fL\n";
ts << "#ifdef _DEBUG\n";
ts << "\tFILEFLAGS VS_FF_DEBUG\n";
ts << "#else\n";
ts << "\tFILEFLAGS 0x0L\n";
ts << "#endif\n";
ts << "\tFILEOS VOS_NT_WINDOWS32\n";
if (project->isActiveConfig("shared"))
ts << "\tFILETYPE VFT_DLL\n";
else
ts << "\tFILETYPE VFT_APP\n";
ts << "\tFILESUBTYPE VFT2_UNKNOWN\n";
ts << "\tBEGIN\n";
ts << "\t\tBLOCK \"StringFileInfo\"\n";
ts << "\t\tBEGIN\n";
ts << "\t\t\tBLOCK \""
<< QString("%1%2").arg(rcLang, 4, 16, QLatin1Char('0')).arg(rcCodePage, 4, 16, QLatin1Char('0'))
<< "\"\n";
ts << "\t\t\tBEGIN\n";
ts << "\t\t\t\tVALUE \"CompanyName\", \"" << companyName << "\\0\"\n";
ts << "\t\t\t\tVALUE \"FileDescription\", \"" << description << "\\0\"\n";
ts << "\t\t\t\tVALUE \"FileVersion\", \"" << versionString << "\\0\"\n";
ts << "\t\t\t\tVALUE \"LegalCopyright\", \"" << copyright << "\\0\"\n";
ts << "\t\t\t\tVALUE \"OriginalFilename\", \"" << originalName << "\\0\"\n";
ts << "\t\t\t\tVALUE \"ProductName\", \"" << productName << "\\0\"\n";
ts << "\t\t\t\tVALUE \"ProductVersion\", \"" << versionString << "\\0\"\n";
ts << "\t\t\t\tVALUE \"InternalName\", \"" << internalName << "\\0\"\n";
ts << "\t\t\t\tVALUE \"Comments\", \"" << comments << "\\0\"\n";
ts << "\t\t\t\tVALUE \"LegalTrademarks\", \"" << trademarks << "\\0\"\n";
ts << "\t\t\tEND\n";
ts << "\t\tEND\n";
ts << "\t\tBLOCK \"VarFileInfo\"\n";
ts << "\t\tBEGIN\n";
ts << "\t\t\tVALUE \"Translation\", "
<< QString("0x%1").arg(rcLang, 4, 16, QLatin1Char('0'))
<< ", " << QString("%1").arg(rcCodePage, 4) << Qt::endl;
ts << "\t\tEND\n";
ts << "\tEND\n";
ts << "/* End of Version info */\n";
ts << Qt::endl;
ts.flush();
QString rcFilename = project->first("OUT_PWD")
+ "/"
+ project->first("TARGET")
+ "_resource"
+ ".rc";
QFile rcFile(QDir::cleanPath(rcFilename));
bool writeRcFile = true;
if (rcFile.exists() && rcFile.open(QFile::ReadOnly)) {
writeRcFile = rcFile.readAll() != rcString;
rcFile.close();
}
if (writeRcFile) {
bool ok;
ok = rcFile.open(QFile::WriteOnly);
if (!ok) {
// The file can't be opened... try creating the containing
// directory first (needed for clean shadow builds)
QDir().mkpath(QFileInfo(rcFile).path());
ok = rcFile.open(QFile::WriteOnly);
}
if (!ok) {
::fprintf(stderr, "Cannot open for writing: %s", rcFile.fileName().toLatin1().constData());
::exit(1);
}
rcFile.write(rcString);
rcFile.close();
}
if (project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty())
project->values("RC_FILE").insert(0, rcFile.fileName());
}
if (!project->values("RC_FILE").isEmpty()) {
if (!project->values("RES_FILE").isEmpty()) {
fprintf(stderr, "Both rc and res file specified.\n");
fprintf(stderr, "Please specify one of them, not both.");
exit(1);
}
QString resFile = project->first("RC_FILE").toQString();
// if this is a shadow build then use the absolute path of the rc file
if (Option::output_dir != qmake_getpwd()) {
QFileInfo fi(resFile);
project->values("RC_FILE").first() = fi.absoluteFilePath();
}
resFile.replace(QLatin1String(".rc"), Option::res_ext);
project->values("RES_FILE").prepend(fileInfo(resFile).fileName());
QString resDestDir;
if (project->isActiveConfig("staticlib"))
resDestDir = project->first("DESTDIR").toQString();
else
resDestDir = project->first("OBJECTS_DIR").toQString();
if (!resDestDir.isEmpty()) {
resDestDir.append(Option::dir_sep);
project->values("RES_FILE").first().prepend(resDestDir);
}
project->values("RES_FILE").first() = Option::fixPathToTargetOS(
project->first("RES_FILE").toQString(), false);
project->values("POST_TARGETDEPS") += project->values("RES_FILE");
project->values("CLEAN_FILES") += project->values("RES_FILE");
}
}
void Win32MakefileGenerator::writeCleanParts(QTextStream &t)
{
t << "clean: compiler_clean " << depVar("CLEAN_DEPS");
{
const char *clean_targets[] = { "OBJECTS", "QMAKE_CLEAN", "CLEAN_FILES", nullptr };
for(int i = 0; clean_targets[i]; ++i) {
const ProStringList &list = project->values(clean_targets[i]);
const QString del_statement("-$(DEL_FILE)");
if(project->isActiveConfig("no_delete_multiple_files")) {
for (ProStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
t << "\n\t" << del_statement
<< ' ' << escapeFilePath(Option::fixPathToTargetOS((*it).toQString()));
} else {
QString files, file;
const int commandlineLimit = 2047; // NT limit, expanded
for (ProStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
file = ' ' + escapeFilePath(Option::fixPathToTargetOS((*it).toQString()));
if(del_statement.size() + files.size() +
qMax(fixEnvVariables(file).size(), file.size()) > commandlineLimit) {
t << "\n\t" << del_statement << files;
files.clear();
}
files += file;
}
if(!files.isEmpty())
t << "\n\t" << del_statement << files;
}
}
}
t << Qt::endl << Qt::endl;
t << "distclean: clean " << depVar("DISTCLEAN_DEPS");
{
const char *clean_targets[] = { "QMAKE_DISTCLEAN", nullptr };
for(int i = 0; clean_targets[i]; ++i) {
const ProStringList &list = project->values(clean_targets[i]);
const QString del_statement("-$(DEL_FILE)");
if(project->isActiveConfig("no_delete_multiple_files")) {
for (ProStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
t << "\n\t" << del_statement << " "
<< escapeFilePath(Option::fixPathToTargetOS((*it).toQString()));
} else {
QString files, file;
const int commandlineLimit = 2047; // NT limit, expanded
for (ProStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
file = " " + escapeFilePath(Option::fixPathToTargetOS((*it).toQString()));
if(del_statement.size() + files.size() +
qMax(fixEnvVariables(file).size(), file.size()) > commandlineLimit) {
t << "\n\t" << del_statement << files;
files.clear();
}
files += file;
}
if(!files.isEmpty())
t << "\n\t" << del_statement << files;
}
}
}
t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)\n";
{
QString ofile = fileFixify(Option::output.fileName());
if(!ofile.isEmpty())
t << "\t-$(DEL_FILE) " << escapeFilePath(ofile) << Qt::endl;
}
t << Qt::endl;
}
void Win32MakefileGenerator::writeIncPart(QTextStream &t)
{
t << "INCPATH = ";
const ProStringList &incs = project->values("INCLUDEPATH");
for(int i = 0; i < incs.size(); ++i) {
QString inc = incs.at(i).toQString();
inc.replace(QRegularExpression("\\\\$"), "");
if(!inc.isEmpty())
t << "-I" << escapeFilePath(inc) << ' ';
}
t << Qt::endl;
}
void Win32MakefileGenerator::writeStandardParts(QTextStream &t)
{
writeExportedVariables(t);
t << "####### Compiler, tools and options\n\n";
t << "CC = " << var("QMAKE_CC") << Qt::endl;
t << "CXX = " << var("QMAKE_CXX") << Qt::endl;
t << "DEFINES = "
<< varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
<< varGlue("DEFINES","-D"," -D","") << Qt::endl;
t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)\n";
t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)\n";
writeIncPart(t);
writeLibsPart(t);
writeDefaultVariables(t);
t << Qt::endl;
t << "####### Output directory\n\n";
if(!project->values("OBJECTS_DIR").isEmpty())
t << "OBJECTS_DIR = " << escapeFilePath(var("OBJECTS_DIR").remove(QRegularExpression("\\\\$"))) << Qt::endl;
else
t << "OBJECTS_DIR = . \n";
t << Qt::endl;
t << "####### Files\n\n";
t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES")))
<< " " << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << Qt::endl;
// do this here so we can set DEST_TARGET to be the complete path to the final target if it is needed.
QString orgDestDir = var("DESTDIR");
QString destDir = Option::fixPathToTargetOS(orgDestDir, false);
if (!destDir.isEmpty() && (orgDestDir.endsWith('/') || orgDestDir.endsWith(Option::dir_sep)))
destDir += Option::dir_sep;
QString target = QString(project->first("TARGET")+project->first("TARGET_EXT"));
project->values("DEST_TARGET").prepend(destDir + target);
writeObjectsPart(t);
writeExtraCompilerVariables(t);
writeExtraVariables(t);
t << "DIST = " << fileVarList("DISTFILES") << ' '
<< fileVarList("HEADERS") << ' ' << fileVarList("SOURCES") << Qt::endl;
t << "QMAKE_TARGET = " << fileVar("QMAKE_ORIG_TARGET") << Qt::endl; // unused
// The comment is important to maintain variable compatibility with Unix
// Makefiles, while not interpreting a trailing-slash as a linebreak
t << "DESTDIR = " << escapeFilePath(destDir) << " #avoid trailing-slash linebreak\n";
t << "TARGET = " << escapeFilePath(target) << Qt::endl;
t << "DESTDIR_TARGET = " << fileVar("DEST_TARGET") << Qt::endl;
t << Qt::endl;
writeImplicitRulesPart(t);
t << "####### Build rules\n\n";
writeBuildRulesPart(t);
if (project->first("TEMPLATE") != "aux") {
if (project->isActiveConfig("shared") && !project->values("DLLDESTDIR").isEmpty()) {
const ProStringList &dlldirs = project->values("DLLDESTDIR");
for (ProStringList::ConstIterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
t << "\t-$(COPY_FILE) $(DESTDIR_TARGET) "
<< escapeFilePath(Option::fixPathToTargetOS((*dlldir).toQString(), false)) << Qt::endl;
}
}
t << Qt::endl;
writeRcFilePart(t);
}
writeMakeQmake(t);
QStringList dist_files = fileFixify(Option::mkfile::project_files);
if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
dist_files += project->values("QMAKE_INTERNAL_INCLUDED_FILES").toQStringList();
if(!project->isEmpty("TRANSLATIONS"))
dist_files << var("TRANSLATIONS");
if(!project->isEmpty("FORMS")) {
const ProStringList &forms = project->values("FORMS");
for (ProStringList::ConstIterator formit = forms.begin(); formit != forms.end(); ++formit) {
QString ui_h = fileFixify((*formit) + Option::h_ext.first());
if(exists(ui_h))
dist_files << ui_h;
}
}
t << "dist:\n\t"
<< "$(ZIP) " << var("QMAKE_ORIG_TARGET") << ".zip $(SOURCES) $(DIST) "
<< escapeFilePaths(dist_files).join(' ') << ' ' << fileVar("TRANSLATIONS") << ' ';
if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
const ProStringList &inputs = project->values(ProKey(*it + ".input"));
for (ProStringList::ConstIterator input = inputs.begin(); input != inputs.end(); ++input) {
const ProStringList &val = project->values((*input).toKey());
t << escapeFilePaths(val).join(' ') << ' ';
}
}
}
t << Qt::endl << Qt::endl;
writeCleanParts(t);
writeExtraTargets(t);
writeExtraCompilerTargets(t);
t << Qt::endl << Qt::endl;
}
void Win32MakefileGenerator::writeLibsPart(QTextStream &t)
{
if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
t << "LIBAPP = " << var("QMAKE_LIB") << Qt::endl;
t << "LIBFLAGS = " << var("QMAKE_LIBFLAGS") << Qt::endl;
} else {
t << "LINKER = " << var("QMAKE_LINK") << Qt::endl;
t << "LFLAGS = " << var("QMAKE_LFLAGS") << Qt::endl;
t << "LIBS = " << fixLibFlags("LIBS").join(' ') << ' '
<< fixLibFlags("LIBS_PRIVATE").join(' ') << ' '
<< fixLibFlags("QMAKE_LIBS").join(' ') << ' '
<< fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << Qt::endl;
}
}
void Win32MakefileGenerator::writeObjectsPart(QTextStream &t)
{
// Used in both deps and commands.
t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << Qt::endl;
}
void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &)
{
}
void Win32MakefileGenerator::writeBuildRulesPart(QTextStream &)
{
}
void Win32MakefileGenerator::writeRcFilePart(QTextStream &t)
{
if(!project->values("RC_FILE").isEmpty()) {
const ProString res_file = project->first("RES_FILE");
const QString rc_file = fileFixify(project->first("RC_FILE").toQString());
const ProStringList rcIncPaths = project->values("RC_INCLUDEPATH");
QString incPathStr;
for (int i = 0; i < rcIncPaths.size(); ++i) {
const ProString &path = rcIncPaths.at(i);
if (path.isEmpty())
continue;
incPathStr += QStringLiteral(" /i ");
incPathStr += escapeFilePath(path);
}
addSourceFile(rc_file, QMakeSourceFileInfo::SEEK_DEPS);
const QStringList rcDeps = QStringList(rc_file) << dependencies(rc_file);
// The resource tool may use defines. This might be the same defines passed in as the
// compiler, since you may use these defines in the .rc file itself.
// As the escape syntax for the command line defines for RC is different from that for CL,
// we might have to set specific defines for RC.
ProString defines = varGlue("RC_DEFINES", " -D", " -D", "");
if (defines.isEmpty())
defines = ProString(" $(DEFINES)");
// Also, we need to add the _DEBUG define manually since the compiler defines this symbol
// by itself, and we use it in the automatically created rc file when VERSION is defined
// in the .pro file.
t << escapeDependencyPath(res_file) << ": "
<< escapeDependencyPaths(rcDeps).join(' ') << "\n\t"
<< var("QMAKE_RC") << (project->isActiveConfig("debug") ? " -D_DEBUG" : "")
<< defines << incPathStr << " -fo " << escapeFilePath(res_file)
<< ' ' << escapeFilePath(rc_file);
t << Qt::endl << Qt::endl;
}
}
QString Win32MakefileGenerator::defaultInstall(const QString &t)
{
if((t != "target" && t != "dlltarget") ||
(t == "dlltarget" && (project->first("TEMPLATE") != "lib" || !project->isActiveConfig("shared"))) ||
project->first("TEMPLATE") == "subdirs" || project->first("TEMPLATE") == "aux")
return QString();
const QString root = installRoot();
ProStringList &uninst = project->values(ProKey(t + ".uninstall"));
QString ret;
QString targetdir = fileFixify(project->first(ProKey(t + ".path")).toQString(), FileFixifyAbsolute);
if(targetdir.right(1) != Option::dir_sep)
targetdir += Option::dir_sep;
const ProStringList &targets = project->values(ProKey(t + ".targets"));
for (int i = 0; i < targets.size(); ++i) {
QString src = targets.at(i).toQString(),
dst = escapeFilePath(filePrefixRoot(root, targetdir + src.section('/', -1)));
if (!ret.isEmpty())
ret += "\n\t";
ret += "$(QINSTALL) " + escapeFilePath(Option::fixPathToTargetOS(src, false)) + ' ' + dst;
if (!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + dst);
}
if(t == "target" && project->first("TEMPLATE") == "lib") {
if(project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
!project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
QString dst_prl = Option::fixPathToTargetOS(project->first("QMAKE_INTERNAL_PRL_FILE").toQString());
int slsh = dst_prl.lastIndexOf(Option::dir_sep);
if(slsh != -1)
dst_prl = dst_prl.right(dst_prl.size() - slsh - 1);
dst_prl = filePrefixRoot(root, targetdir + dst_prl);
if (!ret.isEmpty())
ret += "\n\t";
ret += installMetaFile(ProKey("QMAKE_PRL_INSTALL_REPLACE"), project->first("QMAKE_INTERNAL_PRL_FILE").toQString(), dst_prl);
if(!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + escapeFilePath(dst_prl));
}
if(project->isActiveConfig("create_pc")) {
QString dst_pc = pkgConfigFileName(false);
if (!dst_pc.isEmpty()) {
dst_pc = filePrefixRoot(root, targetdir + dst_pc);
const QString dst_pc_dir = Option::fixPathToTargetOS(fileInfo(dst_pc).path(), false);
if (!dst_pc_dir.isEmpty()) {
if (!ret.isEmpty())
ret += "\n\t";
ret += mkdir_p_asstring(dst_pc_dir, true);
}
if(!ret.isEmpty())
ret += "\n\t";
ret += installMetaFile(ProKey("QMAKE_PKGCONFIG_INSTALL_REPLACE"), pkgConfigFileName(true), dst_pc);
if(!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + escapeFilePath(dst_pc));
}
}
if(project->isActiveConfig("shared") && !project->isActiveConfig("plugin")) {
ProString lib_target = project->first("LIB_TARGET");
QString src_targ = escapeFilePath(
(project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR"))
+ lib_target);
QString dst_targ = escapeFilePath(
filePrefixRoot(root, fileFixify(targetdir + lib_target, FileFixifyAbsolute)));
if(!ret.isEmpty())
ret += "\n\t";
ret += QString("-$(INSTALL_FILE) ") + src_targ + ' ' + dst_targ;
if(!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + dst_targ);
}
}
if (t == "dlltarget" || project->values(ProKey(t + ".CONFIG")).indexOf("no_dll") == -1) {
QString src_targ = "$(DESTDIR_TARGET)";
QString dst_targ = escapeFilePath(
filePrefixRoot(root, fileFixify(targetdir + "$(TARGET)", FileFixifyAbsolute)));
if(!ret.isEmpty())
ret += "\n\t";
ret += QString("-$(INSTALL_FILE) ") + src_targ + ' ' + dst_targ;
if(!uninst.isEmpty())
uninst.append("\n\t");
uninst.append("-$(DEL_FILE) " + dst_targ);
}
return ret;
}
void Win32MakefileGenerator::writeDefaultVariables(QTextStream &t)
{
MakefileGenerator::writeDefaultVariables(t);
t << "IDC = " << (project->isEmpty("QMAKE_IDC") ? QString("idc") : var("QMAKE_IDC"))
<< Qt::endl;
t << "IDL = " << (project->isEmpty("QMAKE_IDL") ? QString("midl") : var("QMAKE_IDL"))
<< Qt::endl;
t << "ZIP = " << var("QMAKE_ZIP") << Qt::endl;
t << "DEF_FILE = " << fileVar("DEF_FILE") << Qt::endl;
t << "RES_FILE = " << fileVar("RES_FILE") << Qt::endl; // Not on mingw, can't see why not though...
t << "SED = " << var("QMAKE_STREAM_EDITOR") << Qt::endl;
t << "MOVE = " << var("QMAKE_MOVE") << Qt::endl;
}
QString Win32MakefileGenerator::escapeFilePath(const QString &path) const
{
QString ret = path;
if(!ret.isEmpty()) {
if (ret.contains(' ') || ret.contains('\t'))
ret = "\"" + ret + "\"";
debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
}
return ret;
}
QString Win32MakefileGenerator::escapeDependencyPath(const QString &path) const
{
QString ret = path;
if (!ret.isEmpty()) {
static const QRegularExpression criticalChars(QStringLiteral("([\t #])"));
if (ret.contains(criticalChars))
ret = "\"" + ret + "\"";
debug_msg(2, "EscapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
}
return ret;
}
QString Win32MakefileGenerator::cQuoted(const QString &str)
{
QString ret = str;
ret.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
ret.replace(QLatin1Char('"'), QLatin1String("\\\""));
ret.prepend(QLatin1Char('"'));
ret.append(QLatin1Char('"'));
return ret;
}
ProKey Win32MakefileGenerator::fullTargetVariable() const
{
return "DEST_TARGET";
}
QT_END_NAMESPACE

View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef WINMAKEFILE_H
#define WINMAKEFILE_H
#include "makefile.h"
QT_BEGIN_NAMESPACE
class Win32MakefileGenerator : public MakefileGenerator
{
protected:
QString defaultInstall(const QString &) override;
void writeDefaultVariables(QTextStream &t) override;
virtual void writeCleanParts(QTextStream &t);
virtual void writeStandardParts(QTextStream &t);
virtual void writeIncPart(QTextStream &t);
virtual void writeLibsPart(QTextStream &t);
virtual void writeObjectsPart(QTextStream &t);
virtual void writeImplicitRulesPart(QTextStream &t);
virtual void writeBuildRulesPart(QTextStream &);
using MakefileGenerator::escapeFilePath;
QString escapeFilePath(const QString &path) const override;
using MakefileGenerator::escapeDependencyPath;
QString escapeDependencyPath(const QString &path) const override;
virtual void writeRcFilePart(QTextStream &t);
bool findLibraries(bool linkPrl, bool mergeLflags) override;
LibFlagType parseLibFlag(const ProString &flag, ProString *arg) override;
ProString fixLibFlag(const ProString &lib) override;
bool processPrlFileBase(QString &origFile, QStringView origName,
QStringView fixedBase, int slashOff) override;
void processVars();
void fixTargetExt();
void processRcFileVar();
static QString cQuoted(const QString &str);
public:
ProKey fullTargetVariable() const override;
};
QT_END_NAMESPACE
#endif // WINMAKEFILE_H