mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-06 09:15:23 +08:00
qt 6.5.1 original
This commit is contained in:
326
qmake/generators/win32/mingw_make.cpp
Normal file
326
qmake/generators/win32/mingw_make.cpp
Normal 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
|
42
qmake/generators/win32/mingw_make.h
Normal file
42
qmake/generators/win32/mingw_make.h
Normal 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
|
1995
qmake/generators/win32/msbuild_objectmodel.cpp
Normal file
1995
qmake/generators/win32/msbuild_objectmodel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
168
qmake/generators/win32/msbuild_objectmodel.h
Normal file
168
qmake/generators/win32/msbuild_objectmodel.h
Normal 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
|
515
qmake/generators/win32/msvc_nmake.cpp
Normal file
515
qmake/generators/win32/msvc_nmake.cpp
Normal 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
|
39
qmake/generators/win32/msvc_nmake.h
Normal file
39
qmake/generators/win32/msvc_nmake.h
Normal 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
|
3062
qmake/generators/win32/msvc_objectmodel.cpp
Normal file
3062
qmake/generators/win32/msvc_objectmodel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1149
qmake/generators/win32/msvc_objectmodel.h
Normal file
1149
qmake/generators/win32/msvc_objectmodel.h
Normal file
File diff suppressed because it is too large
Load Diff
1651
qmake/generators/win32/msvc_vcproj.cpp
Normal file
1651
qmake/generators/win32/msvc_vcproj.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
qmake/generators/win32/msvc_vcproj.h
Normal file
125
qmake/generators/win32/msvc_vcproj.h
Normal 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
|
18
qmake/generators/win32/msvc_vcxproj.cpp
Normal file
18
qmake/generators/win32/msvc_vcxproj.cpp
Normal 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
|
22
qmake/generators/win32/msvc_vcxproj.h
Normal file
22
qmake/generators/win32/msvc_vcxproj.h
Normal 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
|
861
qmake/generators/win32/winmakefile.cpp
Normal file
861
qmake/generators/win32/winmakefile.cpp
Normal 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
|
48
qmake/generators/win32/winmakefile.h
Normal file
48
qmake/generators/win32/winmakefile.h
Normal 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
|
Reference in New Issue
Block a user