mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-03 07:45:30 +08:00
qt 6.5.1 original
This commit is contained in:
2058
qmake/generators/mac/pbuilder_pbx.cpp
Normal file
2058
qmake/generators/mac/pbuilder_pbx.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
qmake/generators/mac/pbuilder_pbx.h
Normal file
48
qmake/generators/mac/pbuilder_pbx.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 PBUILDER_PBX_H
|
||||
#define PBUILDER_PBX_H
|
||||
|
||||
#include "unixmake.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
|
||||
{
|
||||
bool writingUnixMakefileGenerator;
|
||||
mutable QString pbx_dir;
|
||||
int pbuilderVersion() const;
|
||||
bool writeSubDirs(QTextStream &);
|
||||
bool writeMakeParts(QTextStream &);
|
||||
bool writeMakefile(QTextStream &) override;
|
||||
bool replaceLibrarySuffix(const QString &lib_file, const ProString &opt, QString &name,
|
||||
QString &library);
|
||||
|
||||
QString pbxbuild();
|
||||
QHash<QString, QString> keys;
|
||||
QString keyFor(const QString &file);
|
||||
QString findProgram(const ProString &prog);
|
||||
QString fixForOutput(const QString &file);
|
||||
ProStringList fixListForOutput(const char *where);
|
||||
ProStringList fixListForOutput(const ProStringList &list);
|
||||
int reftypeForFile(const QString &where);
|
||||
QString projectSuffix() const;
|
||||
enum { SettingsAsList=0x01, SettingsNoQuote=0x02 };
|
||||
inline QString writeSettings(const QString &var, const char *val, int flags=0, int indent_level=0)
|
||||
{ return writeSettings(var, ProString(val), flags, indent_level); }
|
||||
inline QString writeSettings(const QString &var, const ProString &val, int flags=0, int indent_level=0)
|
||||
{ return writeSettings(var, ProStringList(val), flags, indent_level); }
|
||||
QString writeSettings(const QString &var, const ProStringList &vals, int flags=0, int indent_level=0);
|
||||
|
||||
public:
|
||||
bool supportsMetaBuild() override { return false; }
|
||||
bool openOutput(QFile &, const QString &) const override;
|
||||
protected:
|
||||
bool doPrecompiledHeaders() const override { return false; }
|
||||
bool doDepends() const override { return writingUnixMakefileGenerator && UnixMakefileGenerator::doDepends(); }
|
||||
bool inhibitMakeDirOutPath(const ProKey &path) const override;
|
||||
};
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // PBUILDER_PBX_H
|
3570
qmake/generators/makefile.cpp
Normal file
3570
qmake/generators/makefile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
314
qmake/generators/makefile.h
Normal file
314
qmake/generators/makefile.h
Normal file
@ -0,0 +1,314 @@
|
||||
// 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 MAKEFILE_H
|
||||
#define MAKEFILE_H
|
||||
|
||||
#include "option.h"
|
||||
#include "project.h"
|
||||
#include "makefiledeps.h"
|
||||
#include <qtextstream.h>
|
||||
#include <qlist.h>
|
||||
#include <qhash.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <functional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#define QT_POPEN _popen
|
||||
#define QT_POPEN_READ "rb"
|
||||
#define QT_PCLOSE _pclose
|
||||
#else
|
||||
#define QT_POPEN popen
|
||||
#define QT_POPEN_READ "r"
|
||||
#define QT_PCLOSE pclose
|
||||
#endif
|
||||
|
||||
struct ReplaceExtraCompilerCacheKey;
|
||||
|
||||
class MakefileGenerator : protected QMakeSourceFileInfo
|
||||
{
|
||||
QString spec;
|
||||
bool no_io = false;
|
||||
bool resolveDependenciesInFrameworks = false;
|
||||
QHash<QString, bool> init_compiler_already;
|
||||
QString makedir, chkexists;
|
||||
QString fullBuildArgs();
|
||||
|
||||
//internal caches
|
||||
mutable QHash<QString, QMakeLocalFileName> depHeuristicsCache;
|
||||
mutable QHash<QString, QStringList> dependsCache;
|
||||
mutable QHash<ReplaceExtraCompilerCacheKey, QString> extraCompilerVariablesCache;
|
||||
|
||||
public:
|
||||
// We can't make it visible to VCFilter in VS2008 except by making it public or directly friending it.
|
||||
enum ReplaceFor { NoShell, LocalShell, TargetShell };
|
||||
|
||||
protected:
|
||||
enum TARG_MODE { TARG_UNIX_MODE, TARG_MAC_MODE, TARG_WIN_MODE } target_mode;
|
||||
|
||||
ProStringList createObjectList(const ProStringList &sources);
|
||||
|
||||
//makefile style generator functions
|
||||
void writeObj(QTextStream &, const char *src);
|
||||
void writeInstalls(QTextStream &t, bool noBuild=false);
|
||||
void writeHeader(QTextStream &t);
|
||||
void writeSubDirs(QTextStream &t);
|
||||
void writeMakeQmake(QTextStream &t, bool noDummyQmakeAll = false);
|
||||
void writeExportedVariables(QTextStream &t);
|
||||
void writeExtraVariables(QTextStream &t);
|
||||
void writeExtraTargets(QTextStream &t);
|
||||
QString resolveDependency(const QDir &outDir, const QString &file);
|
||||
void callExtraCompilerDependCommand(const ProString &extraCompiler,
|
||||
const QString &tmp_dep_cmd, const QString &inpf,
|
||||
const QString &tmp_out, bool dep_lines, QStringList *deps,
|
||||
bool existingDepsOnly,
|
||||
bool checkCommandAvailability = false);
|
||||
void writeExtraCompilerTargets(QTextStream &t);
|
||||
void writeExtraCompilerVariables(QTextStream &t);
|
||||
bool writeDummyMakefile(QTextStream &t);
|
||||
virtual bool writeMakefile(QTextStream &t);
|
||||
virtual void writeDefaultVariables(QTextStream &t);
|
||||
|
||||
QString pkgConfigPrefix() const;
|
||||
QString pkgConfigFileName(bool fixify=true);
|
||||
QString pkgConfigFixPath(QString) const;
|
||||
void writePkgConfigFile(); // for pkg-config
|
||||
|
||||
//generating subtarget makefiles
|
||||
struct SubTarget
|
||||
{
|
||||
QString name;
|
||||
QString in_directory, out_directory;
|
||||
QString profile, target, makefile;
|
||||
ProStringList depends;
|
||||
};
|
||||
enum SubTargetFlags {
|
||||
SubTargetInstalls=0x01,
|
||||
SubTargetOrdered=0x02,
|
||||
SubTargetSkipDefaultVariables=0x04,
|
||||
SubTargetSkipDefaultTargets=0x08,
|
||||
|
||||
SubTargetsNoFlags=0x00
|
||||
};
|
||||
QList<MakefileGenerator::SubTarget*> findSubDirsSubTargets() const;
|
||||
void writeSubTargetCall(QTextStream &t,
|
||||
const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
|
||||
const QString &out_directory_cdin, const QString &makefilein);
|
||||
virtual void suppressBuiltinRules(QTextStream &t) const;
|
||||
virtual void writeSubMakeCall(QTextStream &t, const QString &outDirectory_cdin,
|
||||
const QString &makeFileIn);
|
||||
virtual void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);
|
||||
virtual ProStringList extraSubTargetDependencies() { return {}; }
|
||||
|
||||
//extra compiler interface
|
||||
bool verifyExtraCompiler(const ProString &c, const QString &f);
|
||||
virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor forShell);
|
||||
inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out, ReplaceFor forShell)
|
||||
{ return replaceExtraCompilerVariables(val, QStringList(in), QStringList(out), forShell); }
|
||||
|
||||
//interface to the source file info
|
||||
QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool) override;
|
||||
QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &) override;
|
||||
QFileInfo findFileInfo(const QMakeLocalFileName &) override;
|
||||
QMakeProject *project = nullptr;
|
||||
|
||||
//escape
|
||||
virtual QString escapeFilePath(const QString &path) const = 0;
|
||||
ProString escapeFilePath(const ProString &path) const;
|
||||
template<typename A, typename B>
|
||||
QString escapeFilePath(const QStringBuilder<A, B> &path) const
|
||||
{ return escapeFilePath(QString(path)); }
|
||||
QStringList escapeFilePaths(const QStringList &paths) const;
|
||||
ProStringList escapeFilePaths(const ProStringList &paths) const;
|
||||
virtual QString escapeDependencyPath(const QString &path) const;
|
||||
ProString escapeDependencyPath(const ProString &path) const;
|
||||
template<typename A, typename B>
|
||||
QString escapeDependencyPath(const QStringBuilder<A, B> &path) const
|
||||
{ return escapeDependencyPath(QString(path)); }
|
||||
QStringList escapeDependencyPaths(const QStringList &paths) const;
|
||||
ProStringList escapeDependencyPaths(const ProStringList &paths) const;
|
||||
|
||||
QStringList finalizeDependencyPaths(const QStringList &paths) const;
|
||||
|
||||
//initialization
|
||||
void verifyCompilers();
|
||||
virtual void init();
|
||||
void initOutPaths();
|
||||
virtual bool inhibitMakeDirOutPath(const ProKey &path) const;
|
||||
struct Compiler
|
||||
{
|
||||
QString variable_in;
|
||||
enum CompilerFlag {
|
||||
CompilerNoFlags = 0x00,
|
||||
CompilerBuiltin = 0x01,
|
||||
CompilerNoCheckDeps = 0x02,
|
||||
CompilerRemoveNoExist = 0x04,
|
||||
CompilerWarnNoExist = 0x08,
|
||||
CompilerAddInputsAsMakefileDeps = 0x10
|
||||
};
|
||||
uint flags, type;
|
||||
};
|
||||
friend class QTypeInfo<Compiler>;
|
||||
|
||||
void initCompiler(const Compiler &comp);
|
||||
enum VPATHFlag {
|
||||
VPATH_NoFlag = 0x00,
|
||||
VPATH_WarnMissingFiles = 0x01,
|
||||
VPATH_RemoveMissingFiles = 0x02,
|
||||
VPATH_NoFixify = 0x04
|
||||
};
|
||||
ProStringList findFilesInVPATH(ProStringList l, uchar flags, const QString &var="");
|
||||
|
||||
inline int findExecutable(const QStringList &cmdline)
|
||||
{ int ret; canExecute(cmdline, &ret); return ret; }
|
||||
bool canExecute(const QStringList &cmdline, int *argv0) const;
|
||||
inline bool canExecute(const QString &cmdline) const
|
||||
{ return canExecute(cmdline.split(' '), nullptr); }
|
||||
|
||||
bool mkdir(const QString &dir) const;
|
||||
QString mkdir_p_asstring(const QString &dir, bool escape=true) const;
|
||||
|
||||
QString specdir();
|
||||
|
||||
//subclasses can use these to query information about how the generator was "run"
|
||||
QString buildArgs(bool withExtra);
|
||||
|
||||
virtual QStringList &findDependencies(const QString &file);
|
||||
virtual bool doDepends() const { return Option::mkfile::do_deps; }
|
||||
|
||||
void filterIncludedFiles(const char *);
|
||||
void processSources();
|
||||
|
||||
//for installs
|
||||
virtual QString defaultInstall(const QString &);
|
||||
virtual QString installRoot() const;
|
||||
|
||||
//for prl
|
||||
QString prlFileName(bool fixify=true);
|
||||
void writePrlFile();
|
||||
bool processPrlFile(QString &, bool baseOnly);
|
||||
virtual void writePrlFile(QTextStream &);
|
||||
|
||||
//make sure libraries are found
|
||||
virtual bool findLibraries(bool linkPrl, bool mergeLflags);
|
||||
|
||||
//for retrieving values and lists of values
|
||||
virtual QString var(const ProKey &var) const;
|
||||
QString varGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
|
||||
QString varList(const ProKey &var) const;
|
||||
QString fixFileVarGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
|
||||
QString fileVarList(const ProKey &var) const;
|
||||
QString fileVarGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
|
||||
QString fileVar(const ProKey &var) const;
|
||||
QString depVar(const ProKey &var) const;
|
||||
QString val(const ProStringList &varList) const;
|
||||
QString val(const QStringList &varList) const;
|
||||
QString valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after) const;
|
||||
QString valGlue(const ProStringList &varList, const QString &before, const QString &glue, const QString &after) const;
|
||||
QString valList(const QStringList &varList) const;
|
||||
QString valList(const ProStringList &varList) const;
|
||||
|
||||
QString filePrefixRoot(const QString &, const QString &);
|
||||
|
||||
enum LibFlagType { LibFlagLib, LibFlagPath, LibFlagFile, LibFlagOther };
|
||||
virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg);
|
||||
ProStringList fixLibFlags(const ProKey &var);
|
||||
virtual ProString fixLibFlag(const ProString &lib);
|
||||
|
||||
public:
|
||||
//file fixification to unify all file names into a single pattern
|
||||
enum FileFixifyType {
|
||||
FileFixifyFromIndir = 0,
|
||||
FileFixifyFromOutdir = 1,
|
||||
FileFixifyToOutDir = 0,
|
||||
FileFixifyToIndir = 2,
|
||||
FileFixifyBackwards = FileFixifyFromOutdir | FileFixifyToIndir,
|
||||
FileFixifyDefault = 0,
|
||||
FileFixifyAbsolute = 4,
|
||||
FileFixifyRelative = 8
|
||||
};
|
||||
Q_DECLARE_FLAGS(FileFixifyTypes, FileFixifyType)
|
||||
protected:
|
||||
QString fileFixify(const QString &file, FileFixifyTypes fix = FileFixifyDefault, bool canon = true) const;
|
||||
QStringList fileFixify(const QStringList &files, FileFixifyTypes fix = FileFixifyDefault, bool canon = true) const;
|
||||
QString createSedArgs(const ProKey &replace_rule, const QString &file_type = QString()) const;
|
||||
QString installMetaFile(const ProKey &replace_rule, const QString &src,
|
||||
const QString &dst) const;
|
||||
|
||||
virtual bool processPrlFileBase(QString &origFile, QStringView origName,
|
||||
QStringView fixedBase, int slashOff);
|
||||
bool processPrlFileCore(QString &origFile, QStringView origName,
|
||||
const QString &fixedFile);
|
||||
QString createResponseFile(const QString &baseName,
|
||||
const ProStringList &objList,
|
||||
const QString &prefix = QString()) const;
|
||||
|
||||
struct LinkerResponseFileInfo
|
||||
{
|
||||
QString filePath;
|
||||
bool onlyObjects;
|
||||
|
||||
bool isValid() const { return !filePath.isEmpty(); }
|
||||
};
|
||||
|
||||
LinkerResponseFileInfo maybeCreateLinkerResponseFile() const;
|
||||
|
||||
public:
|
||||
QMakeProject *projectFile() const;
|
||||
void setProjectFile(QMakeProject *p);
|
||||
|
||||
void setNoIO(bool o);
|
||||
bool noIO() const;
|
||||
|
||||
inline bool exists(QString file) const { return fileInfo(file).exists(); }
|
||||
QFileInfo fileInfo(QString file) const;
|
||||
|
||||
static MakefileGenerator *create(QMakeProject *);
|
||||
virtual bool write();
|
||||
virtual bool writeProjectMakefile();
|
||||
virtual bool supportsMetaBuild() { return true; }
|
||||
virtual bool supportsMergedBuilds() { return false; }
|
||||
virtual bool mergeBuildProject(MakefileGenerator * /*other*/) { return false; }
|
||||
virtual bool openOutput(QFile &, const QString &build) const;
|
||||
bool isWindowsShell() const { return Option::dir_sep == QLatin1String("\\"); }
|
||||
QString shellQuote(const QString &str) const;
|
||||
virtual ProKey fullTargetVariable() const;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(MakefileGenerator::Compiler, Q_RELOCATABLE_TYPE);
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(MakefileGenerator::FileFixifyTypes)
|
||||
|
||||
inline void MakefileGenerator::setNoIO(bool o)
|
||||
{ no_io = o; }
|
||||
|
||||
inline bool MakefileGenerator::noIO() const
|
||||
{ return no_io; }
|
||||
|
||||
inline QString MakefileGenerator::defaultInstall(const QString &)
|
||||
{ return QString(""); }
|
||||
|
||||
inline QString MakefileGenerator::installRoot() const
|
||||
{ return QStringLiteral("$(INSTALL_ROOT)"); }
|
||||
|
||||
inline bool MakefileGenerator::findLibraries(bool, bool)
|
||||
{ return true; }
|
||||
|
||||
struct ReplaceExtraCompilerCacheKey
|
||||
{
|
||||
mutable size_t hash;
|
||||
QString var, in, out, pwd;
|
||||
MakefileGenerator::ReplaceFor forShell;
|
||||
ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o, MakefileGenerator::ReplaceFor s);
|
||||
bool operator==(const ReplaceExtraCompilerCacheKey &f) const;
|
||||
inline size_t hashCode() const {
|
||||
if (!hash)
|
||||
hash = (size_t)forShell ^ qHash(var) ^ qHash(in) ^ qHash(out) /*^ qHash(pwd)*/;
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
inline size_t qHash(const ReplaceExtraCompilerCacheKey &f) { return f.hashCode(); }
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // MAKEFILE_H
|
1013
qmake/generators/makefiledeps.cpp
Normal file
1013
qmake/generators/makefiledeps.cpp
Normal file
File diff suppressed because it is too large
Load Diff
95
qmake/generators/makefiledeps.h
Normal file
95
qmake/generators/makefiledeps.h
Normal file
@ -0,0 +1,95 @@
|
||||
// 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 MAKEFILEDEPS_H
|
||||
#define MAKEFILEDEPS_H
|
||||
|
||||
#include <proitems.h>
|
||||
|
||||
#include <qfileinfo.h>
|
||||
#include <qlist.h>
|
||||
#include <qstringlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct SourceFile;
|
||||
struct SourceDependChildren;
|
||||
class SourceFiles;
|
||||
|
||||
class QMakeLocalFileName
|
||||
{
|
||||
QString real_name;
|
||||
mutable QString local_name;
|
||||
public:
|
||||
QMakeLocalFileName() = default;
|
||||
QMakeLocalFileName(const QString &);
|
||||
bool isNull() const { return real_name.isNull(); }
|
||||
inline const QString &real() const { return real_name; }
|
||||
const QString &local() const;
|
||||
|
||||
bool operator==(const QMakeLocalFileName &other) const {
|
||||
return (this->real_name == other.real_name);
|
||||
}
|
||||
bool operator!=(const QMakeLocalFileName &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
class QMakeSourceFileInfo
|
||||
{
|
||||
private:
|
||||
//quick project lookups
|
||||
SourceFiles *files, *includes;
|
||||
bool files_changed;
|
||||
QList<QMakeLocalFileName> depdirs;
|
||||
QStringList systemIncludes;
|
||||
|
||||
//sleezy buffer code
|
||||
char *spare_buffer;
|
||||
int spare_buffer_size;
|
||||
char *getBuffer(int s);
|
||||
|
||||
//actual guts
|
||||
bool findMocs(SourceFile *);
|
||||
bool findDeps(SourceFile *);
|
||||
void dependTreeWalker(SourceFile *, SourceDependChildren *);
|
||||
|
||||
protected:
|
||||
virtual QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool forOpen=false);
|
||||
virtual QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &);
|
||||
virtual QFileInfo findFileInfo(const QMakeLocalFileName &);
|
||||
|
||||
public:
|
||||
|
||||
QMakeSourceFileInfo();
|
||||
virtual ~QMakeSourceFileInfo();
|
||||
|
||||
QList<QMakeLocalFileName> dependencyPaths() const { return depdirs; }
|
||||
void setDependencyPaths(const QList<QMakeLocalFileName> &);
|
||||
|
||||
enum DependencyMode { Recursive, NonRecursive };
|
||||
inline void setDependencyMode(DependencyMode mode) { dep_mode = mode; }
|
||||
inline DependencyMode dependencyMode() const { return dep_mode; }
|
||||
|
||||
void setSystemIncludes(const ProStringList &list)
|
||||
{ systemIncludes = list.toQStringList(); }
|
||||
|
||||
enum SourceFileType { TYPE_UNKNOWN, TYPE_C, TYPE_UI, TYPE_QRC };
|
||||
enum SourceFileSeek { SEEK_DEPS=0x01, SEEK_MOCS=0x02 };
|
||||
void addSourceFiles(const ProStringList &, uchar seek, SourceFileType type=TYPE_C);
|
||||
void addSourceFile(const QString &, uchar seek, SourceFileType type=TYPE_C);
|
||||
bool containsSourceFile(const QString &, SourceFileType type=TYPE_C);
|
||||
bool isSystemInclude(const QString &);
|
||||
|
||||
int included(const QString &file);
|
||||
QStringList dependencies(const QString &file);
|
||||
|
||||
bool mocable(const QString &file);
|
||||
|
||||
private:
|
||||
DependencyMode dep_mode;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // MAKEFILEDEPS_H
|
501
qmake/generators/metamakefile.cpp
Normal file
501
qmake/generators/metamakefile.cpp
Normal file
@ -0,0 +1,501 @@
|
||||
// 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 "metamakefile.h"
|
||||
#include "qdir.h"
|
||||
#include "qdebug.h"
|
||||
#include "makefile.h"
|
||||
#include "project.h"
|
||||
#include "cachekeys.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#define BUILDSMETATYPE 1
|
||||
#define SUBDIRSMETATYPE 2
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
MetaMakefileGenerator::~MetaMakefileGenerator()
|
||||
{
|
||||
if(own_project)
|
||||
delete project;
|
||||
}
|
||||
|
||||
#ifndef QT_QMAKE_PARSER_ONLY
|
||||
|
||||
class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
|
||||
{
|
||||
private:
|
||||
bool init_flag;
|
||||
struct Build {
|
||||
QString name, build;
|
||||
MakefileGenerator *makefile;
|
||||
};
|
||||
QList<Build *> makefiles;
|
||||
void clearBuilds();
|
||||
MakefileGenerator *processBuild(const ProString &);
|
||||
void accumulateVariableFromBuilds(const ProKey &name, Build *build) const;
|
||||
void checkForConflictingTargets() const;
|
||||
|
||||
public:
|
||||
|
||||
BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
|
||||
~BuildsMetaMakefileGenerator() { clearBuilds(); }
|
||||
|
||||
bool init() override;
|
||||
int type() const override { return BUILDSMETATYPE; }
|
||||
bool write() override;
|
||||
};
|
||||
|
||||
void
|
||||
BuildsMetaMakefileGenerator::clearBuilds()
|
||||
{
|
||||
for(int i = 0; i < makefiles.size(); i++) {
|
||||
Build *build = makefiles[i];
|
||||
if(QMakeProject *p = build->makefile->projectFile()) {
|
||||
if(p != project)
|
||||
delete p;
|
||||
}
|
||||
delete build->makefile;
|
||||
delete build;
|
||||
}
|
||||
makefiles.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
BuildsMetaMakefileGenerator::init()
|
||||
{
|
||||
if(init_flag)
|
||||
return false;
|
||||
init_flag = true;
|
||||
|
||||
const ProStringList &builds = project->values("BUILDS");
|
||||
bool use_single_build = builds.isEmpty();
|
||||
if(builds.size() > 1 && Option::output.fileName() == "-") {
|
||||
use_single_build = true;
|
||||
warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS.");
|
||||
}
|
||||
if(!use_single_build) {
|
||||
for(int i = 0; i < builds.size(); i++) {
|
||||
ProString build = builds[i];
|
||||
MakefileGenerator *makefile = processBuild(build);
|
||||
if(!makefile)
|
||||
return false;
|
||||
if(!makefile->supportsMetaBuild()) {
|
||||
warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
|
||||
clearBuilds();
|
||||
use_single_build = true;
|
||||
break;
|
||||
} else {
|
||||
Build *b = new Build;
|
||||
b->name = name;
|
||||
if(builds.size() != 1)
|
||||
b->build = build.toQString();
|
||||
b->makefile = makefile;
|
||||
makefiles += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(use_single_build) {
|
||||
Build *build = new Build;
|
||||
build->name = name;
|
||||
build->makefile = createMakefileGenerator(project, false);
|
||||
if (build->makefile){
|
||||
makefiles += build;
|
||||
}else {
|
||||
delete build;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BuildsMetaMakefileGenerator::write()
|
||||
{
|
||||
Build *glue = nullptr;
|
||||
if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()
|
||||
&& Option::qmake_mode != Option::QMAKE_GENERATE_PRL) {
|
||||
glue = new Build;
|
||||
glue->name = name;
|
||||
glue->makefile = createMakefileGenerator(project, true);
|
||||
makefiles += glue;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
const QString &output_name = Option::output.fileName();
|
||||
for(int i = 0; ret && i < makefiles.size(); i++) {
|
||||
Option::output.setFileName(output_name);
|
||||
Build *build = makefiles[i];
|
||||
|
||||
bool using_stdout = false;
|
||||
if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
|
||||
Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
|
||||
&& (!build->makefile->supportsMergedBuilds()
|
||||
|| (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) {
|
||||
//open output
|
||||
if(!(Option::output.isOpen())) {
|
||||
if(Option::output.fileName() == "-") {
|
||||
Option::output.setFileName("");
|
||||
Option::output_dir = qmake_getpwd();
|
||||
Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
|
||||
using_stdout = true;
|
||||
} else {
|
||||
if(Option::output.fileName().isEmpty() &&
|
||||
Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE)
|
||||
Option::output.setFileName(project->first("QMAKE_MAKEFILE").toQString());
|
||||
QString build_name = build->name;
|
||||
if(!build->build.isEmpty()) {
|
||||
if(!build_name.isEmpty())
|
||||
build_name += ".";
|
||||
build_name += build->build;
|
||||
}
|
||||
if(!build->makefile->openOutput(Option::output, build_name)) {
|
||||
fprintf(stderr, "Failure to open file: %s\n",
|
||||
Option::output.fileName().isEmpty() ? "(stdout)" :
|
||||
Option::output.fileName().toLatin1().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
using_stdout = true; //kind of..
|
||||
}
|
||||
|
||||
if(!build->makefile) {
|
||||
ret = false;
|
||||
} else if(build == glue) {
|
||||
checkForConflictingTargets();
|
||||
accumulateVariableFromBuilds("QMAKE_INTERNAL_INCLUDED_FILES", build);
|
||||
ret = build->makefile->writeProjectMakefile();
|
||||
} else {
|
||||
ret = build->makefile->write();
|
||||
if (glue && glue->makefile->supportsMergedBuilds())
|
||||
ret = glue->makefile->mergeBuildProject(build->makefile);
|
||||
}
|
||||
if(!using_stdout) {
|
||||
Option::output.close();
|
||||
if(!ret)
|
||||
Option::output.remove();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MakefileGenerator
|
||||
*BuildsMetaMakefileGenerator::processBuild(const ProString &build)
|
||||
{
|
||||
if(project) {
|
||||
debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
|
||||
project->projectFile().toLatin1().constData(),build.toLatin1().constData());
|
||||
|
||||
//initialize the base
|
||||
ProValueMap basevars;
|
||||
ProStringList basecfgs = project->values(ProKey(build + ".CONFIG"));
|
||||
basecfgs += build;
|
||||
basecfgs += "build_pass";
|
||||
basevars["BUILD_PASS"] = ProStringList(build);
|
||||
ProStringList buildname = project->values(ProKey(build + ".name"));
|
||||
basevars["BUILD_NAME"] = (buildname.isEmpty() ? ProStringList(build) : buildname);
|
||||
|
||||
//create project
|
||||
QMakeProject *build_proj = new QMakeProject;
|
||||
build_proj->setExtraVars(basevars);
|
||||
build_proj->setExtraConfigs(basecfgs);
|
||||
|
||||
if (build_proj->read(project->projectFile()))
|
||||
return createMakefileGenerator(build_proj);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BuildsMetaMakefileGenerator::accumulateVariableFromBuilds(const ProKey &name, Build *dst) const
|
||||
{
|
||||
ProStringList &values = dst->makefile->projectFile()->values(name);
|
||||
for (auto build : makefiles) {
|
||||
if (build != dst)
|
||||
values += build->makefile->projectFile()->values(name);
|
||||
}
|
||||
values.removeDuplicates();
|
||||
}
|
||||
|
||||
void BuildsMetaMakefileGenerator::checkForConflictingTargets() const
|
||||
{
|
||||
if (makefiles.size() < 3) {
|
||||
// Checking for conflicts only makes sense if we have more than one BUILD,
|
||||
// and the last entry in makefiles is the "glue" Build.
|
||||
return;
|
||||
}
|
||||
if (!project->isActiveConfig("build_all")) {
|
||||
// Only complain if we're about to build all configurations.
|
||||
return;
|
||||
}
|
||||
using TargetInfo = std::pair<Build *, ProString>;
|
||||
QList<TargetInfo> targets;
|
||||
const int last = makefiles.size() - 1;
|
||||
targets.resize(last);
|
||||
for (int i = 0; i < last; ++i) {
|
||||
Build *b = makefiles.at(i);
|
||||
auto mkf = b->makefile;
|
||||
auto prj = mkf->projectFile();
|
||||
targets[i] = std::make_pair(b, prj->first(mkf->fullTargetVariable()));
|
||||
}
|
||||
std::stable_sort(targets.begin(), targets.end(),
|
||||
[](const TargetInfo &lhs, const TargetInfo &rhs)
|
||||
{
|
||||
return lhs.second < rhs.second;
|
||||
});
|
||||
for (auto prev = targets.begin(), it = std::next(prev); it != targets.end(); ++prev, ++it) {
|
||||
if (prev->second == it->second) {
|
||||
warn_msg(WarnLogic, "Targets of builds '%s' and '%s' conflict: %s.",
|
||||
qPrintable(prev->first->build),
|
||||
qPrintable(it->first->build),
|
||||
qPrintable(prev->second.toQString()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
|
||||
{
|
||||
protected:
|
||||
bool init_flag;
|
||||
struct Subdir {
|
||||
Subdir() : makefile(nullptr), indent(0) { }
|
||||
~Subdir() { delete makefile; }
|
||||
QString input_dir;
|
||||
QString output_dir, output_file;
|
||||
MetaMakefileGenerator *makefile;
|
||||
int indent;
|
||||
};
|
||||
QList<Subdir *> subs;
|
||||
MakefileGenerator *processBuild(const QString &);
|
||||
|
||||
public:
|
||||
SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
|
||||
~SubdirsMetaMakefileGenerator();
|
||||
|
||||
bool init() override;
|
||||
int type() const override { return SUBDIRSMETATYPE; }
|
||||
bool write() override;
|
||||
};
|
||||
|
||||
bool
|
||||
SubdirsMetaMakefileGenerator::init()
|
||||
{
|
||||
if(init_flag)
|
||||
return false;
|
||||
init_flag = true;
|
||||
bool hasError = false;
|
||||
|
||||
bool recurse = Option::recursive;
|
||||
if (recurse && project->isActiveConfig("dont_recurse"))
|
||||
recurse = false;
|
||||
if(recurse) {
|
||||
QString old_output_dir = Option::output_dir;
|
||||
QString old_output = Option::output.fileName();
|
||||
QString oldpwd = qmake_getpwd();
|
||||
QString thispwd = oldpwd;
|
||||
if(!thispwd.endsWith('/'))
|
||||
thispwd += '/';
|
||||
const ProStringList &subdirs = project->values("SUBDIRS");
|
||||
Q_CONSTINIT static int recurseDepth = -1;
|
||||
++recurseDepth;
|
||||
for(int i = 0; i < subdirs.size(); ++i) {
|
||||
Subdir *sub = new Subdir;
|
||||
sub->indent = recurseDepth;
|
||||
|
||||
QFileInfo subdir(subdirs.at(i).toQString());
|
||||
const ProKey fkey(subdirs.at(i) + ".file");
|
||||
if (!project->isEmpty(fkey)) {
|
||||
subdir = QFileInfo(project->first(fkey).toQString());
|
||||
} else {
|
||||
const ProKey skey(subdirs.at(i) + ".subdir");
|
||||
if (!project->isEmpty(skey))
|
||||
subdir = QFileInfo(project->first(skey).toQString());
|
||||
}
|
||||
QString sub_name;
|
||||
if(subdir.isDir())
|
||||
subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext);
|
||||
else
|
||||
sub_name = subdir.baseName();
|
||||
if(!subdir.isRelative()) { //we can try to make it relative
|
||||
QString subdir_path = subdir.filePath();
|
||||
if(subdir_path.startsWith(thispwd))
|
||||
subdir = QFileInfo(subdir_path.mid(thispwd.size()));
|
||||
}
|
||||
|
||||
//handle sub project
|
||||
QMakeProject *sub_proj = new QMakeProject;
|
||||
for (int ind = 0; ind < sub->indent; ++ind)
|
||||
printf(" ");
|
||||
sub->input_dir = subdir.absolutePath();
|
||||
if(subdir.isRelative() && old_output_dir != oldpwd) {
|
||||
sub->output_dir = old_output_dir + (subdir.path() != "." ? "/" + subdir.path() : QString());
|
||||
printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData());
|
||||
} else { //what about shadow builds?
|
||||
sub->output_dir = sub->input_dir;
|
||||
printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
|
||||
}
|
||||
qmake_setpwd(sub->input_dir);
|
||||
Option::output_dir = sub->output_dir;
|
||||
bool tmpError = !sub_proj->read(subdir.fileName());
|
||||
if (!sub_proj->isEmpty("QMAKE_FAILED_REQUIREMENTS")) {
|
||||
fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
|
||||
subdir.fileName().toLatin1().constData(),
|
||||
sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(' ').toLatin1().constData());
|
||||
delete sub;
|
||||
delete sub_proj;
|
||||
Option::output_dir = old_output_dir;
|
||||
qmake_setpwd(oldpwd);
|
||||
continue;
|
||||
} else {
|
||||
hasError |= tmpError;
|
||||
}
|
||||
sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name);
|
||||
const QString output_name = Option::output.fileName();
|
||||
Option::output.setFileName(sub->output_file);
|
||||
hasError |= !sub->makefile->write();
|
||||
delete sub;
|
||||
qmakeClearCaches();
|
||||
sub = nullptr;
|
||||
Option::output.setFileName(output_name);
|
||||
Option::output_dir = old_output_dir;
|
||||
qmake_setpwd(oldpwd);
|
||||
|
||||
}
|
||||
--recurseDepth;
|
||||
Option::output.setFileName(old_output);
|
||||
Option::output_dir = old_output_dir;
|
||||
qmake_setpwd(oldpwd);
|
||||
}
|
||||
|
||||
Subdir *self = new Subdir;
|
||||
self->input_dir = qmake_getpwd();
|
||||
self->output_dir = Option::output_dir;
|
||||
if(!recurse || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir()))
|
||||
self->output_file = Option::output.fileName();
|
||||
self->makefile = new BuildsMetaMakefileGenerator(project, name, false);
|
||||
self->makefile->init();
|
||||
subs.append(self);
|
||||
|
||||
return !hasError;
|
||||
}
|
||||
|
||||
bool
|
||||
SubdirsMetaMakefileGenerator::write()
|
||||
{
|
||||
bool ret = true;
|
||||
const QString &pwd = qmake_getpwd();
|
||||
const QString &output_dir = Option::output_dir;
|
||||
const QString &output_name = Option::output.fileName();
|
||||
for(int i = 0; ret && i < subs.size(); i++) {
|
||||
const Subdir *sub = subs.at(i);
|
||||
qmake_setpwd(sub->input_dir);
|
||||
Option::output_dir = QFileInfo(sub->output_dir).absoluteFilePath();
|
||||
Option::output.setFileName(sub->output_file);
|
||||
if(i != subs.size()-1) {
|
||||
for (int ind = 0; ind < sub->indent; ++ind)
|
||||
printf(" ");
|
||||
printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
|
||||
Option::output.fileName()).toLatin1().constData());
|
||||
}
|
||||
if (!(ret = sub->makefile->write()))
|
||||
break;
|
||||
//restore because I'm paranoid
|
||||
qmake_setpwd(pwd);
|
||||
Option::output.setFileName(output_name);
|
||||
Option::output_dir = output_dir;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
|
||||
{
|
||||
for(int i = 0; i < subs.size(); i++)
|
||||
delete subs[i];
|
||||
subs.clear();
|
||||
}
|
||||
|
||||
//Factory things
|
||||
QT_BEGIN_INCLUDE_NAMESPACE
|
||||
#include "unixmake.h"
|
||||
#include "mingw_make.h"
|
||||
#include "projectgenerator.h"
|
||||
#include "pbuilder_pbx.h"
|
||||
#include "msvc_nmake.h"
|
||||
#include "msvc_vcproj.h"
|
||||
#include "msvc_vcxproj.h"
|
||||
QT_END_INCLUDE_NAMESPACE
|
||||
|
||||
MakefileGenerator *
|
||||
MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
|
||||
{
|
||||
Option::postProcessProject(proj);
|
||||
|
||||
MakefileGenerator *mkfile = nullptr;
|
||||
if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
|
||||
mkfile = new ProjectGenerator;
|
||||
mkfile->setProjectFile(proj);
|
||||
return mkfile;
|
||||
}
|
||||
|
||||
ProString gen = proj->first("MAKEFILE_GENERATOR");
|
||||
if(gen.isEmpty()) {
|
||||
fprintf(stderr, "MAKEFILE_GENERATOR variable not set as a result of parsing : %s. Possibly qmake was not able to find files included using \"include(..)\" - enable qmake debugging to investigate more.\n",
|
||||
proj->projectFile().toLatin1().constData());
|
||||
} else if(gen == "UNIX") {
|
||||
mkfile = new UnixMakefileGenerator;
|
||||
} else if(gen == "MINGW") {
|
||||
mkfile = new MingwMakefileGenerator;
|
||||
} else if(gen == "PROJECTBUILDER" || gen == "XCODE") {
|
||||
#ifdef Q_CC_MSVC
|
||||
fprintf(stderr, "Generating Xcode projects is not supported with an MSVC build of Qt.\n");
|
||||
#else
|
||||
mkfile = new ProjectBuilderMakefileGenerator;
|
||||
#endif
|
||||
} else if(gen == "MSVC.NET") {
|
||||
if (proj->first("TEMPLATE").startsWith("vc"))
|
||||
mkfile = new VcprojGenerator;
|
||||
else
|
||||
mkfile = new NmakeMakefileGenerator;
|
||||
} else if(gen == "MSBUILD") {
|
||||
// Visual Studio >= v11.0
|
||||
if (proj->first("TEMPLATE").startsWith("vc"))
|
||||
mkfile = new VcxprojGenerator;
|
||||
else
|
||||
mkfile = new NmakeMakefileGenerator;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
|
||||
}
|
||||
if (mkfile) {
|
||||
mkfile->setNoIO(noIO);
|
||||
mkfile->setProjectFile(proj);
|
||||
}
|
||||
return mkfile;
|
||||
}
|
||||
|
||||
MetaMakefileGenerator *
|
||||
MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &name, bool op, bool *success)
|
||||
{
|
||||
Option::postProcessProject(proj);
|
||||
|
||||
MetaMakefileGenerator *ret = nullptr;
|
||||
if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
|
||||
Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) {
|
||||
if (proj->first("TEMPLATE").endsWith("subdirs"))
|
||||
ret = new SubdirsMetaMakefileGenerator(proj, name, op);
|
||||
}
|
||||
if (!ret)
|
||||
ret = new BuildsMetaMakefileGenerator(proj, name, op);
|
||||
bool res = ret->init();
|
||||
if (success)
|
||||
*success = res;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // QT_QMAKE_PARSER_ONLY
|
||||
|
||||
QT_END_NAMESPACE
|
39
qmake/generators/metamakefile.h
Normal file
39
qmake/generators/metamakefile.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 METAMAKEFILE_H
|
||||
#define METAMAKEFILE_H
|
||||
|
||||
#include <qlist.h>
|
||||
#include <qstring.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMakeProject;
|
||||
class MakefileGenerator;
|
||||
|
||||
class MetaMakefileGenerator
|
||||
{
|
||||
protected:
|
||||
MetaMakefileGenerator(QMakeProject *p, const QString &n, bool op=true) : project(p), own_project(op), name(n) { }
|
||||
QMakeProject *project;
|
||||
bool own_project;
|
||||
QString name;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~MetaMakefileGenerator();
|
||||
|
||||
static MetaMakefileGenerator *createMetaGenerator(QMakeProject *proj, const QString &name, bool op=true, bool *success = nullptr);
|
||||
static MakefileGenerator *createMakefileGenerator(QMakeProject *proj, bool noIO = false);
|
||||
|
||||
inline QMakeProject *projectFile() const { return project; }
|
||||
|
||||
virtual bool init() = 0;
|
||||
virtual int type() const { return -1; }
|
||||
virtual bool write() = 0;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // METAMAKEFILE_H
|
462
qmake/generators/projectgenerator.cpp
Normal file
462
qmake/generators/projectgenerator.cpp
Normal file
@ -0,0 +1,462 @@
|
||||
// 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 "projectgenerator.h"
|
||||
#include "option.h"
|
||||
#include <qdatetime.h>
|
||||
#include <qdir.h>
|
||||
#include <qfile.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <qregularexpression.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QString project_builtin_regx() //calculate the builtin regular expression..
|
||||
{
|
||||
QString ret;
|
||||
QStringList builtin_exts;
|
||||
builtin_exts << Option::c_ext << Option::ui_ext << Option::yacc_ext << Option::lex_ext << ".ts" << ".xlf" << ".qrc";
|
||||
builtin_exts += Option::h_ext + Option::cpp_ext;
|
||||
for(int i = 0; i < builtin_exts.size(); ++i) {
|
||||
if(!ret.isEmpty())
|
||||
ret += "; ";
|
||||
ret += QString("*") + builtin_exts[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ProjectGenerator::init()
|
||||
{
|
||||
int file_count = 0;
|
||||
verifyCompilers();
|
||||
|
||||
project->loadSpec();
|
||||
project->evaluateFeatureFile("default_pre.prf");
|
||||
project->evaluateFeatureFile("default_post.prf");
|
||||
project->evaluateConfigFeatures();
|
||||
project->values("CONFIG").clear();
|
||||
Option::postProcessProject(project);
|
||||
|
||||
ProValueMap &v = project->variables();
|
||||
QString templ = Option::globals->user_template.isEmpty() ? QString("app") : Option::globals->user_template;
|
||||
if (!Option::globals->user_template_prefix.isEmpty())
|
||||
templ.prepend(Option::globals->user_template_prefix);
|
||||
v["TEMPLATE_ASSIGN"] += templ;
|
||||
|
||||
//the scary stuff
|
||||
if(project->first("TEMPLATE_ASSIGN") != "subdirs") {
|
||||
QString builtin_regex = project_builtin_regx();
|
||||
QStringList dirs = Option::projfile::project_dirs;
|
||||
if(Option::projfile::do_pwd) {
|
||||
if(!v["INCLUDEPATH"].contains("."))
|
||||
v["INCLUDEPATH"] += ".";
|
||||
dirs.prepend(qmake_getpwd());
|
||||
}
|
||||
|
||||
for(int i = 0; i < dirs.size(); ++i) {
|
||||
QString dir, regex, pd = dirs.at(i);
|
||||
bool add_depend = false;
|
||||
if(exists(pd)) {
|
||||
QFileInfo fi(fileInfo(pd));
|
||||
if(fi.isDir()) {
|
||||
dir = pd;
|
||||
add_depend = true;
|
||||
if(dir.right(1) != Option::dir_sep)
|
||||
dir += Option::dir_sep;
|
||||
if (Option::recursive) {
|
||||
QStringList files = QDir(dir).entryList(QDir::Files);
|
||||
for (int i = 0; i < files.size(); i++)
|
||||
dirs.append(dir + files[i] + QDir::separator() + builtin_regex);
|
||||
}
|
||||
regex = builtin_regex;
|
||||
} else {
|
||||
QString file = pd;
|
||||
int s = file.lastIndexOf(Option::dir_sep);
|
||||
if(s != -1)
|
||||
dir = file.left(s+1);
|
||||
if(addFile(file)) {
|
||||
add_depend = true;
|
||||
file_count++;
|
||||
}
|
||||
}
|
||||
} else { //regexp
|
||||
regex = pd;
|
||||
}
|
||||
if(!regex.isEmpty()) {
|
||||
int s = regex.lastIndexOf(Option::dir_sep);
|
||||
if(s != -1) {
|
||||
dir = regex.left(s+1);
|
||||
regex = regex.right(regex.size() - (s+1));
|
||||
}
|
||||
const QDir d(dir);
|
||||
if (Option::recursive) {
|
||||
QStringList entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (int i = 0; i < entries.size(); i++)
|
||||
dirs.append(dir + entries[i] + QDir::separator() + regex);
|
||||
}
|
||||
QStringList files = d.entryList(QDir::nameFiltersFromString(regex));
|
||||
for(int i = 0; i < (int)files.size(); i++) {
|
||||
QString file = d.absoluteFilePath(files[i]);
|
||||
if (addFile(file)) {
|
||||
add_depend = true;
|
||||
file_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir, Qt::CaseInsensitive)) {
|
||||
QFileInfo fi(fileInfo(dir));
|
||||
if(fi.absoluteFilePath() != qmake_getpwd())
|
||||
v["DEPENDPATH"] += fileFixify(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!file_count) { //shall we try a subdir?
|
||||
QStringList knownDirs = Option::projfile::project_dirs;
|
||||
if(Option::projfile::do_pwd)
|
||||
knownDirs.prepend(".");
|
||||
const QString out_file = fileFixify(Option::output.fileName());
|
||||
for(int i = 0; i < knownDirs.size(); ++i) {
|
||||
QString pd = knownDirs.at(i);
|
||||
if(exists(pd)) {
|
||||
QString newdir = pd;
|
||||
QFileInfo fi(fileInfo(newdir));
|
||||
if(fi.isDir()) {
|
||||
newdir = fileFixify(newdir, FileFixifyFromOutdir);
|
||||
ProStringList &subdirs = v["SUBDIRS"];
|
||||
if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
|
||||
!subdirs.contains(newdir, Qt::CaseInsensitive)) {
|
||||
subdirs.append(newdir);
|
||||
} else {
|
||||
QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
|
||||
for(int i = 0; i < (int)profiles.size(); i++) {
|
||||
QString nd = newdir;
|
||||
if(nd == ".")
|
||||
nd = "";
|
||||
else if (!nd.isEmpty() && !nd.endsWith(QDir::separator()))
|
||||
nd += QDir::separator();
|
||||
nd += profiles[i];
|
||||
fileFixify(nd);
|
||||
if (!subdirs.contains(nd, Qt::CaseInsensitive) && !out_file.endsWith(nd))
|
||||
subdirs.append(nd);
|
||||
}
|
||||
}
|
||||
if (Option::recursive) {
|
||||
QStringList dirs = QDir(newdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for(int i = 0; i < (int)dirs.size(); i++) {
|
||||
QString nd = fileFixify(newdir + QDir::separator() + dirs[i]);
|
||||
if (!knownDirs.contains(nd, Qt::CaseInsensitive))
|
||||
knownDirs.append(nd);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //regexp
|
||||
QString regx = pd, dir;
|
||||
int s = regx.lastIndexOf(Option::dir_sep);
|
||||
if(s != -1) {
|
||||
dir = regx.left(s+1);
|
||||
regx = regx.right(regx.size() - (s+1));
|
||||
}
|
||||
QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regx),
|
||||
QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
ProStringList &subdirs = v["SUBDIRS"];
|
||||
for(int i = 0; i < (int)files.size(); i++) {
|
||||
QString newdir(dir + files[i]);
|
||||
QFileInfo fi(fileInfo(newdir));
|
||||
{
|
||||
newdir = fileFixify(newdir);
|
||||
if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
|
||||
!subdirs.contains(newdir)) {
|
||||
subdirs.append(newdir);
|
||||
} else {
|
||||
QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
|
||||
for(int i = 0; i < (int)profiles.size(); i++) {
|
||||
QString nd = newdir + QDir::separator() + files[i];
|
||||
fileFixify(nd);
|
||||
if(files[i] != "." && files[i] != ".." && !subdirs.contains(nd, Qt::CaseInsensitive)) {
|
||||
if(newdir + files[i] != Option::output_dir + Option::output.fileName())
|
||||
subdirs.append(nd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Option::recursive && !knownDirs.contains(newdir, Qt::CaseInsensitive))
|
||||
knownDirs.append(newdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v["TEMPLATE_ASSIGN"] = ProStringList("subdirs");
|
||||
return;
|
||||
}
|
||||
|
||||
//setup deplist
|
||||
QList<QMakeLocalFileName> deplist;
|
||||
{
|
||||
const ProStringList &d = v["DEPENDPATH"];
|
||||
for(int i = 0; i < d.size(); ++i)
|
||||
deplist.append(QMakeLocalFileName(d[i].toQString()));
|
||||
}
|
||||
setDependencyPaths(deplist);
|
||||
|
||||
ProStringList &h = v["HEADERS"];
|
||||
bool no_qt_files = true;
|
||||
static const char *srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "FORMS", nullptr };
|
||||
for (int i = 0; srcs[i]; i++) {
|
||||
const ProStringList &l = v[srcs[i]];
|
||||
QMakeSourceFileInfo::SourceFileType type = QMakeSourceFileInfo::TYPE_C;
|
||||
QMakeSourceFileInfo::addSourceFiles(l, QMakeSourceFileInfo::SEEK_DEPS, type);
|
||||
for(int i = 0; i < l.size(); ++i) {
|
||||
QStringList tmp = QMakeSourceFileInfo::dependencies(l.at(i).toQString());
|
||||
if(!tmp.isEmpty()) {
|
||||
for(int dep_it = 0; dep_it < tmp.size(); ++dep_it) {
|
||||
QString dep = tmp[dep_it];
|
||||
dep = fixPathToQmake(dep);
|
||||
QString file_dir = dep.section(Option::dir_sep, 0, -2),
|
||||
file_no_path = dep.section(Option::dir_sep, -1);
|
||||
if(!file_dir.isEmpty()) {
|
||||
for(int inc_it = 0; inc_it < deplist.size(); ++inc_it) {
|
||||
QMakeLocalFileName inc = deplist[inc_it];
|
||||
if(inc.local() == file_dir && !v["INCLUDEPATH"].contains(inc.real(), Qt::CaseInsensitive))
|
||||
v["INCLUDEPATH"] += inc.real();
|
||||
}
|
||||
}
|
||||
if (no_qt_files && file_no_path.contains(QRegularExpression("^q[a-z_0-9].h$")))
|
||||
no_qt_files = false;
|
||||
QString h_ext;
|
||||
for(int hit = 0; hit < Option::h_ext.size(); ++hit) {
|
||||
if(dep.endsWith(Option::h_ext.at(hit))) {
|
||||
h_ext = Option::h_ext.at(hit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!h_ext.isEmpty()) {
|
||||
for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
|
||||
QString src(dep.left(dep.size() - h_ext.size()) +
|
||||
Option::cpp_ext.at(cppit));
|
||||
if(exists(src)) {
|
||||
ProStringList &srcl = v["SOURCES"];
|
||||
if(!srcl.contains(src, Qt::CaseInsensitive))
|
||||
srcl.append(src);
|
||||
}
|
||||
}
|
||||
} else if(dep.endsWith(Option::lex_ext) &&
|
||||
file_no_path.startsWith(Option::lex_mod)) {
|
||||
addConfig("lex_included");
|
||||
}
|
||||
if(!h.contains(dep, Qt::CaseInsensitive))
|
||||
h += dep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//strip out files that are actually output from internal compilers (ie temporary files)
|
||||
const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
|
||||
for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
|
||||
QString tmp_out = project->first(ProKey(*it + ".output")).toQString();
|
||||
if(tmp_out.isEmpty())
|
||||
continue;
|
||||
|
||||
ProStringList var_out = project->values(ProKey(*it + ".variable_out"));
|
||||
bool defaults = var_out.isEmpty();
|
||||
for(int i = 0; i < var_out.size(); ++i) {
|
||||
ProString v = var_out.at(i);
|
||||
if(v.startsWith("GENERATED_")) {
|
||||
defaults = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(defaults) {
|
||||
var_out << "SOURCES";
|
||||
var_out << "HEADERS";
|
||||
var_out << "FORMS";
|
||||
}
|
||||
const ProStringList &tmp = project->values(ProKey(*it + ".input"));
|
||||
for (ProStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
|
||||
ProStringList &inputs = project->values((*it2).toKey());
|
||||
for (ProStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
|
||||
QString path = replaceExtraCompilerVariables(tmp_out, (*input).toQString(), QString(), NoShell);
|
||||
path = fixPathToQmake(path).section('/', -1);
|
||||
for(int i = 0; i < var_out.size(); ++i) {
|
||||
ProString v = var_out.at(i);
|
||||
ProStringList &list = project->values(v.toKey());
|
||||
for(int src = 0; src < list.size(); ) {
|
||||
if(list[src] == path || list[src].endsWith("/" + path))
|
||||
list.removeAt(src);
|
||||
else
|
||||
++src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ProjectGenerator::writeMakefile(QTextStream &t)
|
||||
{
|
||||
t << "######################################################################" << Qt::endl;
|
||||
t << "# Automatically generated by qmake (" QMAKE_VERSION_STR ") " << QDateTime::currentDateTime().toString() << Qt::endl;
|
||||
t << "######################################################################" << Qt::endl << Qt::endl;
|
||||
if (!Option::globals->extra_cmds[QMakeEvalBefore].isEmpty())
|
||||
t << Option::globals->extra_cmds[QMakeEvalBefore] << Qt::endl;
|
||||
t << getWritableVar("TEMPLATE_ASSIGN", false);
|
||||
if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
|
||||
t << Qt::endl << "# Directories" << "\n"
|
||||
<< getWritableVar("SUBDIRS");
|
||||
} else {
|
||||
//figure out target
|
||||
QString ofn = QFileInfo(static_cast<QFile *>(t.device())->fileName()).completeBaseName();
|
||||
if (ofn.isEmpty() || ofn == "-")
|
||||
ofn = "unknown";
|
||||
project->values("TARGET_ASSIGN") = ProStringList(ofn);
|
||||
|
||||
t << getWritableVar("TARGET_ASSIGN")
|
||||
<< getWritableVar("CONFIG", false)
|
||||
<< getWritableVar("CONFIG_REMOVE", false)
|
||||
<< getWritableVar("INCLUDEPATH") << Qt::endl;
|
||||
|
||||
t << "# You can make your code fail to compile if you use deprecated APIs.\n"
|
||||
"# In order to do so, uncomment the following line.\n"
|
||||
"# Please consult the documentation of the deprecated API in order to know\n"
|
||||
"# how to port your code away from it.\n"
|
||||
"# You can also select to disable deprecated APIs only up to a certain version of Qt.\n"
|
||||
"#DEFINES += QT_DISABLE_DEPRECATED_UP_TO=0x060000 # disables all APIs deprecated in Qt 6.0.0 and earlier\n\n";
|
||||
|
||||
t << "# Input" << "\n";
|
||||
t << getWritableVar("HEADERS")
|
||||
<< getWritableVar("FORMS")
|
||||
<< getWritableVar("LEXSOURCES")
|
||||
<< getWritableVar("YACCSOURCES")
|
||||
<< getWritableVar("SOURCES")
|
||||
<< getWritableVar("RESOURCES")
|
||||
<< getWritableVar("TRANSLATIONS");
|
||||
}
|
||||
if (!Option::globals->extra_cmds[QMakeEvalAfter].isEmpty())
|
||||
t << Option::globals->extra_cmds[QMakeEvalAfter] << Qt::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ProjectGenerator::addConfig(const QString &cfg, bool add)
|
||||
{
|
||||
ProKey where = "CONFIG";
|
||||
if(!add)
|
||||
where = "CONFIG_REMOVE";
|
||||
if (!project->values(where).contains(cfg)) {
|
||||
project->values(where) += cfg;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ProjectGenerator::addFile(QString file)
|
||||
{
|
||||
file = fileFixify(file, FileFixifyToIndir);
|
||||
QString dir;
|
||||
int s = file.lastIndexOf(Option::dir_sep);
|
||||
if(s != -1)
|
||||
dir = file.left(s+1);
|
||||
if(file.mid(dir.size(), Option::h_moc_mod.size()) == Option::h_moc_mod)
|
||||
return false;
|
||||
|
||||
ProKey where;
|
||||
for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
|
||||
if(file.endsWith(Option::cpp_ext[cppit])) {
|
||||
where = "SOURCES";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(where.isEmpty()) {
|
||||
for(int hit = 0; hit < Option::h_ext.size(); ++hit)
|
||||
if(file.endsWith(Option::h_ext.at(hit))) {
|
||||
where = "HEADERS";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(where.isEmpty()) {
|
||||
for(int cit = 0; cit < Option::c_ext.size(); ++cit) {
|
||||
if(file.endsWith(Option::c_ext[cit])) {
|
||||
where = "SOURCES";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(where.isEmpty()) {
|
||||
if(file.endsWith(Option::ui_ext))
|
||||
where = "FORMS";
|
||||
else if(file.endsWith(Option::lex_ext))
|
||||
where = "LEXSOURCES";
|
||||
else if(file.endsWith(Option::yacc_ext))
|
||||
where = "YACCSOURCES";
|
||||
else if(file.endsWith(".ts") || file.endsWith(".xlf"))
|
||||
where = "TRANSLATIONS";
|
||||
else if(file.endsWith(".qrc"))
|
||||
where = "RESOURCES";
|
||||
}
|
||||
|
||||
QString newfile = fixPathToQmake(fileFixify(file));
|
||||
|
||||
ProStringList &endList = project->values(where);
|
||||
if(!endList.contains(newfile, Qt::CaseInsensitive)) {
|
||||
endList += newfile;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString
|
||||
ProjectGenerator::getWritableVar(const char *vk, bool)
|
||||
{
|
||||
const ProKey v(vk);
|
||||
ProStringList &vals = project->values(v);
|
||||
if(vals.isEmpty())
|
||||
return "";
|
||||
|
||||
// If values contain spaces, ensure that they are quoted
|
||||
for (ProStringList::iterator it = vals.begin(); it != vals.end(); ++it) {
|
||||
if ((*it).contains(' ') && !(*it).startsWith(' '))
|
||||
*it = "\"" + *it + "\"";
|
||||
}
|
||||
|
||||
QString ret;
|
||||
if(v.endsWith("_REMOVE"))
|
||||
ret = v.left(v.length() - 7) + " -= ";
|
||||
else if(v.endsWith("_ASSIGN"))
|
||||
ret = v.left(v.length() - 7) + " = ";
|
||||
else
|
||||
ret = v + " += ";
|
||||
QString join = vals.join(' ');
|
||||
if(ret.size() + join.size() > 80) {
|
||||
QString spaces;
|
||||
for(int i = 0; i < ret.size(); i++)
|
||||
spaces += " ";
|
||||
join = vals.join(" \\\n" + spaces);
|
||||
}
|
||||
return ret + join + "\n";
|
||||
}
|
||||
|
||||
bool
|
||||
ProjectGenerator::openOutput(QFile &file, const QString &build) const
|
||||
{
|
||||
ProString fileName = file.fileName();
|
||||
if (!fileName.endsWith(Option::pro_ext)) {
|
||||
if (fileName.isEmpty())
|
||||
fileName = fileInfo(Option::output_dir).fileName();
|
||||
file.setFileName(fileName + Option::pro_ext);
|
||||
}
|
||||
return MakefileGenerator::openOutput(file, build);
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
ProjectGenerator::fixPathToQmake(const QString &file)
|
||||
{
|
||||
QString ret = file;
|
||||
if(Option::dir_sep != QLatin1String("/"))
|
||||
ret.replace(Option::dir_sep, QLatin1String("/"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
30
qmake/generators/projectgenerator.h
Normal file
30
qmake/generators/projectgenerator.h
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 PROJECTGENERATOR_H
|
||||
#define PROJECTGENERATOR_H
|
||||
|
||||
#include "makefile.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class ProjectGenerator : public MakefileGenerator
|
||||
{
|
||||
bool addFile(QString);
|
||||
bool addConfig(const QString &, bool add=true);
|
||||
QString getWritableVar(const char *, bool fixPath=true);
|
||||
QString fixPathToQmake(const QString &file);
|
||||
protected:
|
||||
void init() override;
|
||||
bool writeMakefile(QTextStream &) override;
|
||||
|
||||
QString escapeFilePath(const QString &) const override { Q_ASSERT(false); return QString(); }
|
||||
|
||||
public:
|
||||
bool supportsMetaBuild() override { return false; }
|
||||
bool openOutput(QFile &, const QString &) const override;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // PROJECTGENERATOR_H
|
750
qmake/generators/unix/unixmake.cpp
Normal file
750
qmake/generators/unix/unixmake.cpp
Normal file
@ -0,0 +1,750 @@
|
||||
// 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 "unixmake.h"
|
||||
#include "option.h"
|
||||
#include <qfile.h>
|
||||
#include <qhash.h>
|
||||
#include <qdir.h>
|
||||
#include <time.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
ProStringList UnixMakefileGenerator::libdirToFlags(const ProKey &key)
|
||||
{
|
||||
ProStringList results;
|
||||
for (const auto &libdir : std::as_const(project->values(key))) {
|
||||
if (!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs"))
|
||||
project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdir;
|
||||
results.append("-L" + escapeFilePath(libdir));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void
|
||||
UnixMakefileGenerator::init()
|
||||
{
|
||||
ProStringList &configs = project->values("CONFIG");
|
||||
if(project->isEmpty("ICON") && !project->isEmpty("RC_FILE"))
|
||||
project->values("ICON") = project->values("RC_FILE");
|
||||
if(project->isEmpty("QMAKE_EXTENSION_PLUGIN"))
|
||||
project->values("QMAKE_EXTENSION_PLUGIN").append(project->first("QMAKE_EXTENSION_SHLIB"));
|
||||
|
||||
project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
|
||||
|
||||
//version handling
|
||||
if (project->isEmpty("VERSION")) {
|
||||
project->values("VERSION").append(
|
||||
"1.0." + (project->isEmpty("VER_PAT") ? QString("0") : project->first("VER_PAT")));
|
||||
}
|
||||
QStringList l = project->first("VERSION").toQString().split('.');
|
||||
l << "0" << "0"; //make sure there are three
|
||||
project->values("VER_MAJ").append(l[0]);
|
||||
project->values("VER_MIN").append(l[1]);
|
||||
project->values("VER_PAT").append(l[2]);
|
||||
|
||||
QString sroot = project->sourceRoot();
|
||||
for (const ProString &iif : project->values("QMAKE_INTERNAL_INCLUDED_FILES")) {
|
||||
if (iif == project->cacheFile())
|
||||
continue;
|
||||
if (iif.startsWith(sroot) && iif.at(sroot.size()) == QLatin1Char('/'))
|
||||
project->values("DISTFILES") += fileFixify(iif.toQString(), FileFixifyRelative);
|
||||
}
|
||||
|
||||
/* 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->isEmpty("MAKEFILE"))
|
||||
project->values("MAKEFILE").append("Makefile");
|
||||
return; /* subdirs is done */
|
||||
}
|
||||
|
||||
project->values("QMAKE_ORIG_DESTDIR") = project->values("DESTDIR");
|
||||
if((!project->isEmpty("QMAKE_LIB_FLAG") && !project->isActiveConfig("staticlib")) ||
|
||||
(project->isActiveConfig("qt") && project->isActiveConfig("plugin"))) {
|
||||
if(configs.indexOf("dll") == -1) configs.append("dll");
|
||||
} else if(!project->isEmpty("QMAKE_APP_FLAG") || project->isActiveConfig("dll")) {
|
||||
configs.removeAll("staticlib");
|
||||
}
|
||||
if(!project->isEmpty("QMAKE_INCREMENTAL"))
|
||||
project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_INCREMENTAL");
|
||||
else if(!project->isEmpty("QMAKE_LFLAGS_PREBIND") &&
|
||||
!project->values("QMAKE_LIB_FLAG").isEmpty() &&
|
||||
project->isActiveConfig("dll"))
|
||||
project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PREBIND");
|
||||
project->values("QMAKE_INCDIR") += project->values("QMAKE_INCDIR_POST");
|
||||
project->values("QMAKE_RPATHDIR") += project->values("QMAKE_RPATHDIR_POST");
|
||||
project->values("QMAKE_RPATHLINKDIR") += project->values("QMAKE_RPATHLINKDIR_POST");
|
||||
if(!project->isEmpty("QMAKE_INCDIR"))
|
||||
project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
|
||||
// The order of the next two lines is relevant due to side effect on QMAKE_LFLAGS.
|
||||
ProStringList ldadd = project->values("QMAKE_LIBDIR_FLAGS") + libdirToFlags("QMAKE_LIBDIR");
|
||||
ProStringList ldaddpost = libdirToFlags("QMAKE_LIBDIR_POST");
|
||||
if (project->isActiveConfig("mac")) {
|
||||
if (!project->isEmpty("QMAKE_FRAMEWORKPATH")) {
|
||||
const ProStringList &fwdirs = project->values("QMAKE_FRAMEWORKPATH");
|
||||
for (int i = 0; i < fwdirs.size(); ++i)
|
||||
project->values("QMAKE_FRAMEWORKPATH_FLAGS") += "-F" + escapeFilePath(fwdirs[i]);
|
||||
}
|
||||
ldadd += project->values("QMAKE_FRAMEWORKPATH_FLAGS");
|
||||
}
|
||||
ProStringList &qmklibs = project->values("LIBS");
|
||||
qmklibs = ldadd + qmklibs;
|
||||
ProStringList &qmklibspost = project->values("QMAKE_LIBS");
|
||||
qmklibspost = ldaddpost + qmklibspost;
|
||||
if (!project->isEmpty("QMAKE_RPATHDIR") && !project->isEmpty("QMAKE_LFLAGS_RPATH")) {
|
||||
const ProStringList &rpathdirs = project->values("QMAKE_RPATHDIR");
|
||||
for (int i = 0; i < rpathdirs.size(); ++i) {
|
||||
QString rpathdir = rpathdirs[i].toQString();
|
||||
if (rpathdir.size() > 1 && rpathdir.at(0) == '$' && rpathdir.at(1) != '(') {
|
||||
rpathdir.replace(0, 1, "\\$$"); // Escape from make and the shell
|
||||
} else if (!rpathdir.startsWith('@') && fileInfo(rpathdir).isRelative()) {
|
||||
QString rpathbase = project->first("QMAKE_REL_RPATH_BASE").toQString();
|
||||
if (rpathbase.isEmpty()) {
|
||||
fprintf(stderr, "Error: This platform does not support relative paths in QMAKE_RPATHDIR (%s)\n",
|
||||
rpathdir.toLatin1().constData());
|
||||
continue;
|
||||
}
|
||||
if (rpathbase.startsWith('$'))
|
||||
rpathbase.replace(0, 1, "\\$$"); // Escape from make and the shell
|
||||
if (rpathdir == ".")
|
||||
rpathdir = rpathbase;
|
||||
else
|
||||
rpathdir.prepend(rpathbase + '/');
|
||||
project->values("QMAKE_LFLAGS").insertUnique(project->values("QMAKE_LFLAGS_REL_RPATH"));
|
||||
}
|
||||
project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + escapeFilePath(rpathdir);
|
||||
}
|
||||
}
|
||||
if (!project->isEmpty("QMAKE_RPATHLINKDIR")) {
|
||||
const ProStringList &rpathdirs = project->values("QMAKE_RPATHLINKDIR");
|
||||
for (int i = 0; i < rpathdirs.size(); ++i) {
|
||||
if (!project->isEmpty("QMAKE_LFLAGS_RPATHLINK"))
|
||||
project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATHLINK") + escapeFilePath(QFileInfo(rpathdirs[i].toQString()).absoluteFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
if(project->isActiveConfig("GNUmake") && !project->isEmpty("QMAKE_CFLAGS_DEPS"))
|
||||
include_deps = true; //do not generate deps
|
||||
|
||||
MakefileGenerator::init();
|
||||
|
||||
if (project->isActiveConfig("objective_c"))
|
||||
project->values("QMAKE_BUILTIN_COMPILERS") << "OBJC" << "OBJCXX";
|
||||
|
||||
for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) {
|
||||
QString compile_flag = var("QMAKE_COMPILE_FLAG");
|
||||
if(compile_flag.isEmpty())
|
||||
compile_flag = "-c";
|
||||
|
||||
if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
|
||||
QString pchFlags = var(ProKey("QMAKE_" + compiler + "FLAGS_USE_PRECOMPILE"));
|
||||
|
||||
QString pchBaseName;
|
||||
if(!project->isEmpty("PRECOMPILED_DIR")) {
|
||||
pchBaseName = Option::fixPathToTargetOS(project->first("PRECOMPILED_DIR").toQString());
|
||||
if(!pchBaseName.endsWith(Option::dir_sep))
|
||||
pchBaseName += Option::dir_sep;
|
||||
}
|
||||
pchBaseName += project->first("QMAKE_ORIG_TARGET").toQString();
|
||||
|
||||
// replace place holders
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_INPUT}"),
|
||||
escapeFilePath(project->first("PRECOMPILED_HEADER").toQString()));
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), escapeFilePath(pchBaseName));
|
||||
if (project->isActiveConfig("icc_pch_style")) {
|
||||
// icc style
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"),
|
||||
escapeFilePath(pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT")));
|
||||
const ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
for (const ProString &arch : pchArchs) {
|
||||
QString suffix = project->first("QMAKE_PCH_OUTPUT_EXT").toQString();
|
||||
suffix.replace(QLatin1String("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT_") + arch + QLatin1Char('}'),
|
||||
escapeFilePath(pchBaseName + suffix));
|
||||
}
|
||||
} else {
|
||||
// gcc style (including clang_pch_style)
|
||||
QString headerSuffix;
|
||||
if (project->isActiveConfig("clang_pch_style"))
|
||||
headerSuffix = project->first("QMAKE_PCH_OUTPUT_EXT").toQString();
|
||||
|
||||
pchBaseName += project->first("QMAKE_PCH_OUTPUT_EXT").toQString();
|
||||
pchBaseName += Option::dir_sep;
|
||||
|
||||
ProString language = project->first(ProKey("QMAKE_LANGUAGE_" + compiler));
|
||||
if (!language.isEmpty()) {
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT}"),
|
||||
escapeFilePath(pchBaseName + language + headerSuffix));
|
||||
const ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
for (const ProString &arch : pchArchs) {
|
||||
QString file = pchBaseName + language + headerSuffix;
|
||||
file.replace(QLatin1String("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
if (project->isActiveConfig("clang_pch_style")
|
||||
&& (file.endsWith(QLatin1String(".pch"))
|
||||
|| file.endsWith(QLatin1String(".gch")))) {
|
||||
file.chop(4); // must omit header suffix for -include to recognize the PCH
|
||||
}
|
||||
pchFlags.replace(QLatin1String("${QMAKE_PCH_OUTPUT_") + arch + QLatin1Char('}'),
|
||||
escapeFilePath(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pchFlags.isEmpty())
|
||||
compile_flag += " " + pchFlags;
|
||||
}
|
||||
|
||||
QString compilerExecutable;
|
||||
if (compiler == "C" || compiler == "OBJC") {
|
||||
compilerExecutable = "$(CC)";
|
||||
compile_flag += " $(CFLAGS)";
|
||||
} else {
|
||||
compilerExecutable = "$(CXX)";
|
||||
compile_flag += " $(CXXFLAGS)";
|
||||
}
|
||||
|
||||
compile_flag += " $(INCPATH)";
|
||||
|
||||
ProString compilerVariable = compiler;
|
||||
if (compilerVariable == "C")
|
||||
compilerVariable = ProString("CC");
|
||||
|
||||
const ProKey runComp("QMAKE_RUN_" + compilerVariable);
|
||||
if(project->isEmpty(runComp))
|
||||
project->values(runComp).append(compilerExecutable + " " + compile_flag + " " + var("QMAKE_CC_O_FLAG") + "$obj $src");
|
||||
const ProKey runCompImp("QMAKE_RUN_" + compilerVariable + "_IMP");
|
||||
if(project->isEmpty(runCompImp))
|
||||
project->values(runCompImp).append(compilerExecutable + " " + compile_flag + " " + var("QMAKE_CC_O_FLAG") + "\"$@\" \"$<\"");
|
||||
}
|
||||
|
||||
if (project->isActiveConfig("mac") && !project->isEmpty("TARGET") &&
|
||||
((project->isActiveConfig("build_pass") || project->isEmpty("BUILDS")))) {
|
||||
ProString bundle;
|
||||
if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
|
||||
bundle = project->first("TARGET");
|
||||
if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
|
||||
bundle = project->first("QMAKE_BUNDLE_NAME");
|
||||
if(!bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
|
||||
bundle += project->first("QMAKE_BUNDLE_EXTENSION");
|
||||
} else if(project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) {
|
||||
bundle = project->first("TARGET");
|
||||
if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
|
||||
bundle = project->first("QMAKE_APPLICATION_BUNDLE_NAME");
|
||||
if(!bundle.endsWith(".app"))
|
||||
bundle += ".app";
|
||||
if(project->isEmpty("QMAKE_BUNDLE_LOCATION"))
|
||||
project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
|
||||
project->values("QMAKE_PKGINFO").append(project->first("DESTDIR") + bundle + "/Contents/PkgInfo");
|
||||
} else if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
|
||||
((!project->isActiveConfig("plugin") && project->isActiveConfig("lib_bundle")) ||
|
||||
(project->isActiveConfig("plugin") && project->isActiveConfig("plugin_bundle")))) {
|
||||
bundle = project->first("TARGET");
|
||||
if(project->isActiveConfig("plugin")) {
|
||||
if(!project->isEmpty("QMAKE_PLUGIN_BUNDLE_NAME"))
|
||||
bundle = project->first("QMAKE_PLUGIN_BUNDLE_NAME");
|
||||
if (project->isEmpty("QMAKE_BUNDLE_EXTENSION"))
|
||||
project->values("QMAKE_BUNDLE_EXTENSION").append(".plugin");
|
||||
if (!bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
|
||||
bundle += project->first("QMAKE_BUNDLE_EXTENSION");
|
||||
if(project->isEmpty("QMAKE_BUNDLE_LOCATION"))
|
||||
project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
|
||||
} else {
|
||||
if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
|
||||
bundle = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME");
|
||||
if (project->isEmpty("QMAKE_BUNDLE_EXTENSION"))
|
||||
project->values("QMAKE_BUNDLE_EXTENSION").append(".framework");
|
||||
if (!bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
|
||||
bundle += project->first("QMAKE_BUNDLE_EXTENSION");
|
||||
}
|
||||
}
|
||||
if(!bundle.isEmpty()) {
|
||||
project->values("QMAKE_BUNDLE") = ProStringList(bundle);
|
||||
} else {
|
||||
project->values("QMAKE_BUNDLE").clear();
|
||||
project->values("QMAKE_BUNDLE_LOCATION").clear();
|
||||
}
|
||||
} else { //no bundling here
|
||||
project->values("QMAKE_BUNDLE").clear();
|
||||
project->values("QMAKE_BUNDLE_LOCATION").clear();
|
||||
}
|
||||
|
||||
init2();
|
||||
ProString target = project->first("TARGET");
|
||||
int slsh = target.lastIndexOf(Option::dir_sep);
|
||||
if (slsh != -1)
|
||||
target.chopFront(slsh + 1);
|
||||
project->values("LIB_TARGET").prepend(target);
|
||||
}
|
||||
|
||||
QStringList
|
||||
&UnixMakefileGenerator::findDependencies(const QString &f)
|
||||
{
|
||||
QStringList &ret = MakefileGenerator::findDependencies(f);
|
||||
if (doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
|
||||
ProString file = f;
|
||||
QString header_prefix;
|
||||
if(!project->isEmpty("PRECOMPILED_DIR"))
|
||||
header_prefix = project->first("PRECOMPILED_DIR").toQString();
|
||||
header_prefix += project->first("QMAKE_ORIG_TARGET").toQString();
|
||||
header_prefix += project->first("QMAKE_PCH_OUTPUT_EXT").toQString();
|
||||
if (project->isActiveConfig("icc_pch_style")) {
|
||||
// icc style
|
||||
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
if (pchArchs.isEmpty())
|
||||
pchArchs << ProString(); // normal single-arch PCH
|
||||
for (const ProString &arch : std::as_const(pchArchs)) {
|
||||
auto pfx = header_prefix;
|
||||
if (!arch.isEmpty())
|
||||
pfx.replace(QLatin1String("${QMAKE_PCH_ARCH}"), arch.toQString());
|
||||
for (QStringList::Iterator it = Option::cpp_ext.begin();
|
||||
it != Option::cpp_ext.end(); ++it) {
|
||||
if (file.endsWith(*it)) {
|
||||
ret += pfx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// gcc style (including clang_pch_style)
|
||||
QString header_suffix = project->isActiveConfig("clang_pch_style")
|
||||
? project->first("QMAKE_PCH_OUTPUT_EXT").toQString() : "";
|
||||
header_prefix += Option::dir_sep + project->first("QMAKE_PRECOMP_PREFIX");
|
||||
|
||||
for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) {
|
||||
if (project->isEmpty(ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE")))
|
||||
continue;
|
||||
|
||||
ProString language = project->first(ProKey("QMAKE_LANGUAGE_" + compiler));
|
||||
if (language.isEmpty())
|
||||
continue;
|
||||
|
||||
// Unfortunately we were not consistent about the C++ naming
|
||||
ProString extensionSuffix = compiler;
|
||||
if (extensionSuffix == "CXX")
|
||||
extensionSuffix = ProString("CPP");
|
||||
|
||||
for (const ProString &extension : project->values(ProKey("QMAKE_EXT_" + extensionSuffix))) {
|
||||
if (!file.endsWith(extension.toQString()))
|
||||
continue;
|
||||
|
||||
ProStringList pchArchs = project->values("QMAKE_PCH_ARCHS");
|
||||
if (pchArchs.isEmpty())
|
||||
pchArchs << ProString(); // normal single-arch PCH
|
||||
for (const ProString &arch : std::as_const(pchArchs)) {
|
||||
QString precompiledHeader = header_prefix + language + header_suffix;
|
||||
if (!arch.isEmpty()) {
|
||||
precompiledHeader.replace(QLatin1String("${QMAKE_PCH_ARCH}"),
|
||||
arch.toQString());
|
||||
}
|
||||
if (!ret.contains(precompiledHeader))
|
||||
ret += precompiledHeader;
|
||||
}
|
||||
|
||||
goto foundPrecompiledDependency;
|
||||
}
|
||||
}
|
||||
foundPrecompiledDependency:
|
||||
; // Hurray!!
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ProString
|
||||
UnixMakefileGenerator::fixLibFlag(const ProString &lib)
|
||||
{
|
||||
return escapeFilePath(lib);
|
||||
}
|
||||
|
||||
bool
|
||||
UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
|
||||
{
|
||||
QList<QMakeLocalFileName> libdirs, frameworkdirs;
|
||||
int libidx = 0, fwidx = 0;
|
||||
for (const ProString &dlib : project->values("QMAKE_DEFAULT_LIBDIRS"))
|
||||
libdirs.append(QMakeLocalFileName(dlib.toQString()));
|
||||
frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks"));
|
||||
frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks"));
|
||||
ProStringList extens;
|
||||
extens << project->first("QMAKE_EXTENSION_SHLIB") << "a";
|
||||
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(); ) {
|
||||
QString opt = (*it).toQString();
|
||||
if(opt.startsWith("-")) {
|
||||
if(opt.startsWith("-L")) {
|
||||
QString lib = opt.mid(2);
|
||||
QMakeLocalFileName f(lib);
|
||||
int idx = libdirs.indexOf(f);
|
||||
if (idx >= 0 && idx < libidx) {
|
||||
it = l.erase(it);
|
||||
continue;
|
||||
}
|
||||
libdirs.insert(libidx++, f);
|
||||
} else if(opt.startsWith("-l")) {
|
||||
QString lib = opt.mid(2);
|
||||
for (const QMakeLocalFileName &libdir : std::as_const(libdirs)) {
|
||||
QString libBase = libdir.local() + '/'
|
||||
+ project->first("QMAKE_PREFIX_SHLIB") + lib;
|
||||
if (linkPrl && processPrlFile(libBase, true))
|
||||
goto found;
|
||||
for (ProStringList::Iterator extit = extens.begin(); extit != extens.end(); ++extit) {
|
||||
if (exists(libBase + '.' + (*extit)))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
found: ;
|
||||
} else if (target_mode == TARG_MAC_MODE && opt.startsWith("-F")) {
|
||||
QMakeLocalFileName f(opt.mid(2));
|
||||
if (!frameworkdirs.contains(f))
|
||||
frameworkdirs.insert(fwidx++, f);
|
||||
} else if (target_mode == TARG_MAC_MODE && opt == "-framework") {
|
||||
if (linkPrl) {
|
||||
opt = (*++it).toQString();
|
||||
static const QChar suffixMarker = ',';
|
||||
const int suffixPosition = opt.indexOf(suffixMarker);
|
||||
const bool hasSuffix = suffixPosition >= 0;
|
||||
QString frameworkName = opt;
|
||||
if (hasSuffix) {
|
||||
frameworkName.truncate(suffixPosition);
|
||||
opt.remove(suffixMarker); // Apply suffix by removing marker
|
||||
}
|
||||
for (const QMakeLocalFileName &dir : std::as_const(frameworkdirs)) {
|
||||
auto processPrlIfFound = [&](QString directory) {
|
||||
QString suffixedPrl = directory + opt;
|
||||
if (processPrlFile(suffixedPrl, true))
|
||||
return true;
|
||||
if (hasSuffix) {
|
||||
QString unsuffixedPrl = directory + frameworkName;
|
||||
if (processPrlFile(unsuffixedPrl, true))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
QString frameworkDirectory = dir.local() + "/" + frameworkName + + ".framework/";
|
||||
if (processPrlIfFound(frameworkDirectory + "Resources/")
|
||||
|| processPrlIfFound(frameworkDirectory))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (opt.size() == 10)
|
||||
++it;
|
||||
// Skip
|
||||
}
|
||||
}
|
||||
} else if (linkPrl) {
|
||||
processPrlFile(opt, false);
|
||||
}
|
||||
|
||||
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) {
|
||||
QHash<ProKey, ProStringList> lflags;
|
||||
for(int lit = 0; lit < l.size(); ++lit) {
|
||||
ProKey arch("default");
|
||||
ProString opt = l.at(lit);
|
||||
if (opt.startsWith('-')) {
|
||||
if (target_mode == TARG_MAC_MODE && opt.startsWith("-Xarch")) {
|
||||
if (opt.length() > 7) {
|
||||
arch = opt.mid(7).toKey();
|
||||
opt = l.at(++lit);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.startsWith("-L")
|
||||
|| (target_mode == TARG_MAC_MODE && opt.startsWith("-F"))) {
|
||||
if (!lflags[arch].contains(opt))
|
||||
lflags[arch].append(opt);
|
||||
} else if (opt.startsWith("-l") || opt == "-pthread") {
|
||||
// Make sure we keep the dependency order of libraries
|
||||
lflags[arch].removeAll(opt);
|
||||
lflags[arch].append(opt);
|
||||
} else if (target_mode == TARG_MAC_MODE
|
||||
&& (opt == "-framework" || opt == "-force_load")) {
|
||||
// Handle space separated options
|
||||
ProString dashOpt = opt;
|
||||
opt = l.at(++lit);
|
||||
if (opt.startsWith("-Xarch"))
|
||||
opt = l.at(++lit); // The user has done the right thing and prefixed each part
|
||||
for(int x = 0; x < lflags[arch].size(); ++x) {
|
||||
if (lflags[arch].at(x) == dashOpt && lflags[arch].at(++x) == opt) {
|
||||
lflags[arch].remove(x - 1, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lflags[arch].append(dashOpt);
|
||||
lflags[arch].append(opt);
|
||||
} else {
|
||||
lflags[arch].append(opt);
|
||||
}
|
||||
} else if(!opt.isNull()) {
|
||||
for (const ProString &ext : extens) {
|
||||
if (opt.size() > ext.size() && opt.endsWith(ext)
|
||||
&& opt.at(opt.size() - ext.size() - 1) == '.') {
|
||||
// Make sure we keep the dependency order of libraries
|
||||
lflags[arch].removeAll(opt);
|
||||
lflags[arch].append(opt);
|
||||
goto found2;
|
||||
}
|
||||
}
|
||||
if(!lflags[arch].contains(opt))
|
||||
lflags[arch].append(opt);
|
||||
found2: ;
|
||||
}
|
||||
}
|
||||
|
||||
l = lflags.take("default");
|
||||
|
||||
// Process architecture specific options (Xarch)
|
||||
QHash<ProKey, ProStringList>::const_iterator archIterator = lflags.constBegin();
|
||||
while (archIterator != lflags.constEnd()) {
|
||||
const ProStringList &archOptions = archIterator.value();
|
||||
for (int i = 0; i < archOptions.size(); ++i) {
|
||||
l.append(QLatin1String("-Xarch_") + archIterator.key());
|
||||
l.append(archOptions.at(i));
|
||||
}
|
||||
++archIterator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN // MinGW x-compiling for QNX
|
||||
QString UnixMakefileGenerator::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@%=%)");
|
||||
}
|
||||
#endif
|
||||
|
||||
QString
|
||||
UnixMakefileGenerator::defaultInstall(const QString &t)
|
||||
{
|
||||
if(t != "target" || project->first("TEMPLATE") == "subdirs")
|
||||
return QString();
|
||||
|
||||
enum { NoBundle, SolidBundle, SlicedBundle } bundle = NoBundle;
|
||||
bool isAux = (project->first("TEMPLATE") == "aux");
|
||||
const QString root = installRoot();
|
||||
ProStringList &uninst = project->values(ProKey(t + ".uninstall"));
|
||||
QString ret, destdir = project->first("DESTDIR").toQString();
|
||||
if(!destdir.isEmpty() && destdir.right(1) != Option::dir_sep)
|
||||
destdir += Option::dir_sep;
|
||||
QString targetdir = fileFixify(project->first("target.path").toQString(), FileFixifyAbsolute);
|
||||
if(targetdir.right(1) != Option::dir_sep)
|
||||
targetdir += Option::dir_sep;
|
||||
|
||||
ProStringList links;
|
||||
QString target="$(TARGET)";
|
||||
const ProStringList &targets = project->values(ProKey(t + ".targets"));
|
||||
if(!project->isEmpty("QMAKE_BUNDLE")) {
|
||||
target = project->first("QMAKE_BUNDLE").toQString();
|
||||
bundle = project->isActiveConfig("sliced_bundle") ? SlicedBundle : SolidBundle;
|
||||
} else if(project->first("TEMPLATE") == "app") {
|
||||
target = "$(QMAKE_TARGET)";
|
||||
} else if(project->first("TEMPLATE") == "lib") {
|
||||
if (!project->isActiveConfig("staticlib")
|
||||
&& !project->isActiveConfig("plugin")
|
||||
&& !project->isActiveConfig("unversioned_libname")) {
|
||||
if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
|
||||
links << "$(TARGET0)" << "$(TARGET1)" << "$(TARGET2)";
|
||||
} else {
|
||||
links << "$(TARGET0)";
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
QString src_targ = target;
|
||||
if(!destdir.isEmpty())
|
||||
src_targ = Option::fixPathToTargetOS(destdir + target, false);
|
||||
QString plain_targ = filePrefixRoot(root, fileFixify(targetdir + target, FileFixifyAbsolute));
|
||||
QString dst_targ = plain_targ;
|
||||
plain_targ = escapeFilePath(plain_targ);
|
||||
if (bundle != NoBundle) {
|
||||
QString suffix;
|
||||
if (project->first("TEMPLATE") == "lib") {
|
||||
if (!project->isActiveConfig("shallow_bundle"))
|
||||
suffix += "/Versions/" + project->first("QMAKE_FRAMEWORK_VERSION");
|
||||
suffix += "/$(TARGET)";
|
||||
} else {
|
||||
suffix = "/" + project->first("QMAKE_BUNDLE_LOCATION") + "/$(QMAKE_TARGET)";
|
||||
}
|
||||
dst_targ += suffix;
|
||||
if (bundle == SolidBundle) {
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += "$(DEL_FILE) -r " + plain_targ + "\n\t";
|
||||
} else {
|
||||
src_targ += suffix;
|
||||
}
|
||||
}
|
||||
src_targ = escapeFilePath(src_targ);
|
||||
dst_targ = escapeFilePath(dst_targ);
|
||||
|
||||
QString copy_cmd;
|
||||
if (bundle == SolidBundle) {
|
||||
copy_cmd += "$(QINSTALL) " + src_targ + ' ' + plain_targ;
|
||||
} else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) {
|
||||
copy_cmd += "$(QINSTALL) " + src_targ + ' ' + dst_targ;
|
||||
} else if (!isAux) {
|
||||
if (bundle == SlicedBundle) {
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += mkdir_p_asstring("\"`dirname " + dst_targ + "`\"", false);
|
||||
}
|
||||
copy_cmd += "$(QINSTALL_PROGRAM) " + src_targ + ' ' + dst_targ;
|
||||
}
|
||||
if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib")
|
||||
&& project->values(ProKey(t + ".CONFIG")).indexOf("fix_rpath") != -1) {
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
if(!project->isEmpty("QMAKE_FIX_RPATH")) {
|
||||
ret += copy_cmd;
|
||||
ret += "\n\t-" + var("QMAKE_FIX_RPATH") + ' ' + dst_targ + ' ' + dst_targ;
|
||||
} else if(!project->isEmpty("QMAKE_LFLAGS_RPATH")) {
|
||||
ret += "-$(LINK) $(LFLAGS) " + var("QMAKE_LFLAGS_RPATH") + targetdir + " -o " +
|
||||
dst_targ + " $(OBJECTS) $(LIBS) $(OBJCOMP)";
|
||||
} else {
|
||||
ret += copy_cmd;
|
||||
}
|
||||
} else if (!copy_cmd.isEmpty()) {
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += copy_cmd;
|
||||
}
|
||||
|
||||
if (isAux) {
|
||||
} else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) {
|
||||
if(!project->isEmpty("QMAKE_RANLIB"))
|
||||
ret += QString("\n\t$(RANLIB) ") + dst_targ;
|
||||
} else if (!project->isActiveConfig("debug_info") && !project->isActiveConfig("nostrip")
|
||||
&& !project->isEmpty("QMAKE_STRIP")) {
|
||||
ret += "\n\t-$(STRIP)";
|
||||
if (project->first("TEMPLATE") == "lib") {
|
||||
if (!project->isEmpty("QMAKE_STRIPFLAGS_LIB"))
|
||||
ret += " " + var("QMAKE_STRIPFLAGS_LIB");
|
||||
} else if (project->first("TEMPLATE") == "app") {
|
||||
if (!project->isEmpty("QMAKE_STRIPFLAGS_APP"))
|
||||
ret += " " + var("QMAKE_STRIPFLAGS_APP");
|
||||
}
|
||||
ret += ' ' + dst_targ;
|
||||
}
|
||||
if(!uninst.isEmpty())
|
||||
uninst.append("\n\t");
|
||||
if (bundle == SolidBundle)
|
||||
uninst.append("-$(DEL_FILE) -r " + plain_targ);
|
||||
else if (!isAux)
|
||||
uninst.append("-$(DEL_FILE) " + dst_targ);
|
||||
if (bundle == SlicedBundle) {
|
||||
int dstlen = project->first("DESTDIR").length();
|
||||
for (const ProString &src : project->values("QMAKE_BUNDLED_FILES")) {
|
||||
ProString file = src.mid(dstlen);
|
||||
QString dst = escapeFilePath(
|
||||
filePrefixRoot(root, fileFixify(targetdir + file, FileFixifyAbsolute)));
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += mkdir_p_asstring("\"`dirname " + dst + "`\"", false) + "\n\t";
|
||||
ret += "-$(DEL_FILE) " + dst + "\n\t"; // Can't overwrite symlinks to directories
|
||||
ret += "$(QINSTALL) " + escapeFilePath(src) + " " + dst;
|
||||
if (!uninst.isEmpty())
|
||||
uninst.append("\n\t");
|
||||
uninst.append("-$(DEL_FILE) " + dst);
|
||||
}
|
||||
}
|
||||
if(!links.isEmpty()) {
|
||||
for(int i = 0; i < links.size(); ++i) {
|
||||
if (target_mode == TARG_UNIX_MODE || target_mode == TARG_MAC_MODE) {
|
||||
QString link = Option::fixPathToTargetOS(destdir + links[i], false);
|
||||
int lslash = link.lastIndexOf(Option::dir_sep);
|
||||
if(lslash != -1)
|
||||
link = link.right(link.size() - (lslash + 1));
|
||||
QString dst_link = escapeFilePath(
|
||||
filePrefixRoot(root, fileFixify(targetdir + link, FileFixifyAbsolute)));
|
||||
ret += "\n\t-$(SYMLINK) $(TARGET) " + dst_link;
|
||||
if(!uninst.isEmpty())
|
||||
uninst.append("\n\t");
|
||||
uninst.append("-$(DEL_FILE) " + dst_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isAux || project->first("TEMPLATE") == "lib") {
|
||||
QStringList types;
|
||||
types << "prl" << "libtool" << "pkgconfig";
|
||||
for(int i = 0; i < types.size(); ++i) {
|
||||
const QString type = types.at(i);
|
||||
QString meta;
|
||||
if(type == "prl" && project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
|
||||
!project->isEmpty("QMAKE_INTERNAL_PRL_FILE"))
|
||||
meta = prlFileName(false);
|
||||
if (type == "libtool" && project->isActiveConfig("create_libtool"))
|
||||
meta = libtoolFileName(false);
|
||||
if(type == "pkgconfig" && project->isActiveConfig("create_pc"))
|
||||
meta = pkgConfigFileName(false);
|
||||
if(!meta.isEmpty()) {
|
||||
QString src_meta = meta;
|
||||
if(!destdir.isEmpty())
|
||||
src_meta = Option::fixPathToTargetOS(destdir + meta, false);
|
||||
QString dst_meta = filePrefixRoot(root, fileFixify(targetdir + meta, FileFixifyAbsolute));
|
||||
if(!uninst.isEmpty())
|
||||
uninst.append("\n\t");
|
||||
uninst.append("-$(DEL_FILE) " + escapeFilePath(dst_meta));
|
||||
const QString dst_meta_dir = fileInfo(dst_meta).path();
|
||||
if(!dst_meta_dir.isEmpty()) {
|
||||
if(!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += mkdir_p_asstring(dst_meta_dir, true);
|
||||
}
|
||||
if (!ret.isEmpty())
|
||||
ret += "\n\t";
|
||||
ret += installMetaFile(ProKey("QMAKE_" + type.toUpper() + "_INSTALL_REPLACE"), src_meta, dst_meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString
|
||||
UnixMakefileGenerator::escapeFilePath(const QString &path) const
|
||||
{
|
||||
QString ret = path;
|
||||
if(!ret.isEmpty()) {
|
||||
ret.replace(QLatin1Char(' '), QLatin1String("\\ "))
|
||||
.replace(QLatin1Char('\t'), QLatin1String("\\\t"));
|
||||
debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
44
qmake/generators/unix/unixmake.h
Normal file
44
qmake/generators/unix/unixmake.h
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 UNIXMAKE_H
|
||||
#define UNIXMAKE_H
|
||||
|
||||
#include "makefile.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class UnixMakefileGenerator : public MakefileGenerator
|
||||
{
|
||||
bool include_deps = false;
|
||||
QString libtoolFileName(bool fixify=true);
|
||||
void writeLibtoolFile(); // for libtool
|
||||
void writePrlFile(QTextStream &) override;
|
||||
|
||||
protected:
|
||||
virtual bool doPrecompiledHeaders() const { return project->isActiveConfig("precompile_header"); }
|
||||
#ifdef Q_OS_WIN // MinGW x-compiling for QNX
|
||||
QString installRoot() const override;
|
||||
#endif
|
||||
QString defaultInstall(const QString &) override;
|
||||
ProString fixLibFlag(const ProString &lib) override;
|
||||
|
||||
bool findLibraries(bool linkPrl, bool mergeLflags) override;
|
||||
QString escapeFilePath(const QString &path) const override;
|
||||
using MakefileGenerator::escapeFilePath;
|
||||
QStringList &findDependencies(const QString &) override;
|
||||
void init() override;
|
||||
|
||||
void writeDefaultVariables(QTextStream &t) override;
|
||||
void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags) override;
|
||||
void writeMakeParts(QTextStream &);
|
||||
bool writeMakefile(QTextStream &) override;
|
||||
bool writeObjectsPart(QTextStream &, bool do_incremental);
|
||||
private:
|
||||
void init2();
|
||||
ProStringList libdirToFlags(const ProKey &key);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // UNIXMAKE_H
|
1579
qmake/generators/unix/unixmake2.cpp
Normal file
1579
qmake/generators/unix/unixmake2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
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
|
345
qmake/generators/xmloutput.cpp
Normal file
345
qmake/generators/xmloutput.cpp
Normal file
@ -0,0 +1,345 @@
|
||||
// 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 "xmloutput.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
XmlOutput::XmlOutput(QTextStream &file, ConverstionType type)
|
||||
: xmlFile(file), indent("\t"), currentLevel(0), currentState(Bare), format(NewLine),
|
||||
conversion(type)
|
||||
{
|
||||
tagStack.clear();
|
||||
}
|
||||
|
||||
XmlOutput::~XmlOutput()
|
||||
{
|
||||
closeAll();
|
||||
}
|
||||
|
||||
// Settings ------------------------------------------------------------------
|
||||
void XmlOutput::setIndentString(const QString &indentString)
|
||||
{
|
||||
indent = indentString;
|
||||
}
|
||||
|
||||
QString XmlOutput::indentString()
|
||||
{
|
||||
return indent;
|
||||
}
|
||||
|
||||
void XmlOutput::setIndentLevel(int level)
|
||||
{
|
||||
currentLevel = level;
|
||||
}
|
||||
|
||||
int XmlOutput::indentLevel()
|
||||
{
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
void XmlOutput::setState(XMLState state)
|
||||
{
|
||||
currentState = state;
|
||||
}
|
||||
|
||||
void XmlOutput::setFormat(XMLFormat newFormat)
|
||||
{
|
||||
format = newFormat;
|
||||
}
|
||||
|
||||
XmlOutput::XMLState XmlOutput::state()
|
||||
{
|
||||
return currentState;
|
||||
}
|
||||
|
||||
void XmlOutput::updateIndent()
|
||||
{
|
||||
currentIndent.clear();
|
||||
currentIndent.reserve(currentLevel);
|
||||
for (int i = 0; i < currentLevel; ++i)
|
||||
currentIndent.append(indent);
|
||||
}
|
||||
|
||||
void XmlOutput::increaseIndent()
|
||||
{
|
||||
++currentLevel;
|
||||
updateIndent();
|
||||
}
|
||||
|
||||
void XmlOutput::decreaseIndent()
|
||||
{
|
||||
if (currentLevel)
|
||||
--currentLevel;
|
||||
updateIndent();
|
||||
if (!currentLevel)
|
||||
currentState = Bare;
|
||||
}
|
||||
|
||||
QString XmlOutput::doConversion(const QString &text)
|
||||
{
|
||||
if (!text.size())
|
||||
return QString();
|
||||
else if (conversion == NoConversion)
|
||||
return text;
|
||||
|
||||
QString output;
|
||||
if (conversion == XMLConversion) {
|
||||
|
||||
// this is a way to escape characters that shouldn't be converted
|
||||
for (int i=0; i<text.size(); ++i) {
|
||||
const QChar c = text.at(i);
|
||||
if (c == QLatin1Char('&')) {
|
||||
if ( (i + 7) < text.size() &&
|
||||
text.at(i + 1) == QLatin1Char('#') &&
|
||||
text.at(i + 2) == QLatin1Char('x') &&
|
||||
text.at(i + 7) == QLatin1Char(';') ) {
|
||||
output += text.at(i);
|
||||
} else {
|
||||
output += QLatin1String("&");
|
||||
}
|
||||
} else if (c == QLatin1Char('<')) {
|
||||
output += QLatin1String("<");
|
||||
} else if (c == QLatin1Char('>')) {
|
||||
output += QLatin1String(">");
|
||||
} else {
|
||||
if (c.unicode() < 0x20) {
|
||||
output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
|
||||
} else {
|
||||
output += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output = text;
|
||||
}
|
||||
|
||||
if (conversion == XMLConversion) {
|
||||
output.replace('\"', QLatin1String("""));
|
||||
output.replace('\'', QLatin1String("'"));
|
||||
} else if (conversion == EscapeConversion) {
|
||||
output.replace('\"', QLatin1String("\\\""));
|
||||
output.replace('\'', QLatin1String("\\\'"));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Stream functions ----------------------------------------------------------
|
||||
XmlOutput& XmlOutput::operator<<(const QString& o)
|
||||
{
|
||||
return operator<<(data(o));
|
||||
}
|
||||
|
||||
XmlOutput& XmlOutput::operator<<(const xml_output& o)
|
||||
{
|
||||
switch(o.xo_type) {
|
||||
case tNothing:
|
||||
break;
|
||||
case tRaw:
|
||||
addRaw(o.xo_text);
|
||||
break;
|
||||
case tDeclaration:
|
||||
addDeclaration(o.xo_text, o.xo_value);
|
||||
break;
|
||||
case tTag:
|
||||
newTagOpen(o.xo_text);
|
||||
break;
|
||||
case tTagValue:
|
||||
addRaw(QString("\n%1<%2>").arg(currentIndent).arg(o.xo_text));
|
||||
addRaw(doConversion(o.xo_value));
|
||||
addRaw(QString("</%1>").arg(o.xo_text));
|
||||
break;
|
||||
case tValueTag:
|
||||
addRaw(doConversion(o.xo_text));
|
||||
setFormat(NoNewLine);
|
||||
closeTag();
|
||||
setFormat(NewLine);
|
||||
break;
|
||||
case tImport:
|
||||
addRaw(QString("\n%1<Import %2=\"%3\" />").arg(currentIndent).arg(o.xo_text).arg(o.xo_value));
|
||||
break;
|
||||
case tCloseTag:
|
||||
if (o.xo_value.size())
|
||||
closeAll();
|
||||
else if (o.xo_text.size())
|
||||
closeTo(o.xo_text);
|
||||
else
|
||||
closeTag();
|
||||
break;
|
||||
case tAttribute:
|
||||
addAttribute(o.xo_text, o.xo_value);
|
||||
break;
|
||||
case tAttributeTag:
|
||||
addAttributeTag(o.xo_text, o.xo_value);
|
||||
break;
|
||||
case tData:
|
||||
{
|
||||
// Special case to be able to close tag in normal
|
||||
// way ("</tag>", not "/>") without using addRaw()..
|
||||
if (!o.xo_text.size()) {
|
||||
closeOpen();
|
||||
break;
|
||||
}
|
||||
QString output = doConversion(o.xo_text);
|
||||
output.replace('\n', "\n" + currentIndent);
|
||||
addRaw(QString("\n%1%2").arg(currentIndent).arg(output));
|
||||
}
|
||||
break;
|
||||
case tComment:
|
||||
{
|
||||
QString output("<!--%1-->");
|
||||
addRaw(output.arg(o.xo_text));
|
||||
}
|
||||
break;
|
||||
case tCDATA:
|
||||
{
|
||||
QString output("<![CDATA[\n%1\n]]>");
|
||||
addRaw(output.arg(o.xo_text));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Output functions ----------------------------------------------------------
|
||||
void XmlOutput::newTag(const QString &tag)
|
||||
{
|
||||
Q_ASSERT_X(tag.size(), "XmlOutput", "Cannot open an empty tag");
|
||||
newTagOpen(tag);
|
||||
closeOpen();
|
||||
}
|
||||
|
||||
void XmlOutput::newTagOpen(const QString &tag)
|
||||
{
|
||||
Q_ASSERT_X(tag.size(), "XmlOutput", "Cannot open an empty tag");
|
||||
closeOpen();
|
||||
|
||||
if (format == NewLine)
|
||||
xmlFile << Qt::endl << currentIndent;
|
||||
xmlFile << '<' << doConversion(tag);
|
||||
currentState = Attribute;
|
||||
tagStack.append(tag);
|
||||
increaseIndent(); // ---> indent
|
||||
}
|
||||
|
||||
void XmlOutput::closeOpen()
|
||||
{
|
||||
switch(currentState) {
|
||||
case Bare:
|
||||
case Tag:
|
||||
return;
|
||||
case Attribute:
|
||||
break;
|
||||
}
|
||||
xmlFile << '>';
|
||||
currentState = Tag;
|
||||
}
|
||||
|
||||
void XmlOutput::closeTag()
|
||||
{
|
||||
switch(currentState) {
|
||||
case Bare:
|
||||
if (tagStack.size())
|
||||
//warn_msg(WarnLogic, "<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
|
||||
qDebug("<Root>: Cannot close tag in Bare state, %d tags on stack", int(tagStack.size()));
|
||||
else
|
||||
//warn_msg(WarnLogic, "<Root>: Cannot close tag, no tags on stack");
|
||||
qDebug("<Root>: Cannot close tag, no tags on stack");
|
||||
return;
|
||||
case Tag:
|
||||
decreaseIndent(); // <--- Pre-decrease indent
|
||||
if (format == NewLine)
|
||||
xmlFile << Qt::endl << currentIndent;
|
||||
xmlFile << "</" << doConversion(tagStack.last()) << '>';
|
||||
tagStack.pop_back();
|
||||
break;
|
||||
case Attribute:
|
||||
xmlFile << " />";
|
||||
tagStack.pop_back();
|
||||
currentState = Tag;
|
||||
decreaseIndent(); // <--- Post-decrease indent
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XmlOutput::closeTo(const QString &tag)
|
||||
{
|
||||
bool cont = true;
|
||||
if (!tagStack.contains(tag) && !tag.isNull()) {
|
||||
//warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1());
|
||||
qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
int left = tagStack.size();
|
||||
while (left-- && cont) {
|
||||
cont = tagStack.last().compare(tag) != 0;
|
||||
closeTag();
|
||||
}
|
||||
}
|
||||
|
||||
void XmlOutput::closeAll()
|
||||
{
|
||||
if (!tagStack.size())
|
||||
return;
|
||||
closeTo(QString());
|
||||
}
|
||||
|
||||
void XmlOutput::addDeclaration(const QString &version, const QString &encoding)
|
||||
{
|
||||
switch(currentState) {
|
||||
case Bare:
|
||||
break;
|
||||
case Tag:
|
||||
case Attribute:
|
||||
//warn_msg(WarnLogic, "<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
|
||||
qDebug("<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
QString outData = QString("<?xml version=\"%1\" encoding=\"%2\"?>")
|
||||
.arg(doConversion(version))
|
||||
.arg(doConversion(encoding));
|
||||
addRaw(outData);
|
||||
}
|
||||
|
||||
void XmlOutput::addRaw(const QString &rawText)
|
||||
{
|
||||
closeOpen();
|
||||
xmlFile << rawText;
|
||||
}
|
||||
|
||||
void XmlOutput::addAttribute(const QString &attribute, const QString &value)
|
||||
{
|
||||
switch(currentState) {
|
||||
case Bare:
|
||||
case Tag:
|
||||
//warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
|
||||
qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
|
||||
(tagStack.size() ? tagStack.last().toLatin1().constData() : "Root"),
|
||||
attribute.toLatin1().constData());
|
||||
return;
|
||||
case Attribute:
|
||||
break;
|
||||
}
|
||||
if (format == NewLine)
|
||||
xmlFile << Qt::endl;
|
||||
xmlFile << currentIndent << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
|
||||
}
|
||||
|
||||
void XmlOutput::addAttributeTag(const QString &attribute, const QString &value)
|
||||
{
|
||||
switch(currentState) {
|
||||
case Bare:
|
||||
case Tag:
|
||||
//warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
|
||||
qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
|
||||
(tagStack.size() ? tagStack.last().toLatin1().constData() : "Root"),
|
||||
attribute.toLatin1().constData());
|
||||
return;
|
||||
case Attribute:
|
||||
break;
|
||||
}
|
||||
xmlFile << " " << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
206
qmake/generators/xmloutput.h
Normal file
206
qmake/generators/xmloutput.h
Normal file
@ -0,0 +1,206 @@
|
||||
// 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 XMLOUTPUT_H
|
||||
#define XMLOUTPUT_H
|
||||
|
||||
#include <qtextstream.h>
|
||||
#include <qstack.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class XmlOutput
|
||||
{
|
||||
public:
|
||||
enum ConverstionType {
|
||||
NoConversion, // No change
|
||||
EscapeConversion, // Use '\"'
|
||||
XMLConversion // Use "
|
||||
};
|
||||
enum XMLFormat {
|
||||
NoNewLine, // No new lines, unless added manually
|
||||
NewLine // All properties & tags indented on new lines
|
||||
};
|
||||
enum XMLState {
|
||||
Bare, // Not in tag or attribute
|
||||
Tag, // <tagname attribute1="value"
|
||||
Attribute // attribute2="value">
|
||||
};
|
||||
enum XMLType {
|
||||
tNothing, // No XML output, and not state change
|
||||
tRaw, // Raw text (no formating)
|
||||
tDeclaration, // <?xml version="x.x" encoding="xxx"?>
|
||||
tTag, // <tagname attribute1="value"
|
||||
tTagValue, // <tagname>value</tagname>
|
||||
tValueTag, // value</tagname>
|
||||
tCloseTag, // Closes an open tag
|
||||
tAttribute, // attribute2="value">
|
||||
tAttributeTag, // attribute on the same line as a tag
|
||||
tData, // Tag data (formating done)
|
||||
tImport, // <import "type"="path" />
|
||||
tComment, // <!-- Comment -->
|
||||
tCDATA // <![CDATA[ ... ]]>
|
||||
};
|
||||
|
||||
XmlOutput(QTextStream &file, ConverstionType type = XMLConversion);
|
||||
~XmlOutput();
|
||||
|
||||
// Settings
|
||||
void setIndentString(const QString &indentString);
|
||||
QString indentString();
|
||||
void setIndentLevel(int level);
|
||||
int indentLevel();
|
||||
void setState(XMLState state);
|
||||
void setFormat(XMLFormat newFormat);
|
||||
XMLState state();
|
||||
|
||||
|
||||
struct xml_output {
|
||||
XMLType xo_type; // Type of struct instance
|
||||
QString xo_text; // Tag/Attribute name/xml version
|
||||
QString xo_value; // Value of attributes/xml encoding
|
||||
|
||||
xml_output(XMLType type, const QString &text, const QString &value)
|
||||
: xo_type(type), xo_text(text), xo_value(value) {}
|
||||
xml_output(const xml_output &xo)
|
||||
: xo_type(xo.xo_type), xo_text(xo.xo_text), xo_value(xo.xo_value) {}
|
||||
};
|
||||
|
||||
// Streams
|
||||
XmlOutput& operator<<(const QString& o);
|
||||
XmlOutput& operator<<(const xml_output& o);
|
||||
|
||||
private:
|
||||
void increaseIndent();
|
||||
void decreaseIndent();
|
||||
void updateIndent();
|
||||
|
||||
QString doConversion(const QString &text);
|
||||
|
||||
// Output functions
|
||||
void newTag(const QString &tag);
|
||||
void newTagOpen(const QString &tag);
|
||||
void closeOpen();
|
||||
void closeTag();
|
||||
void closeTo(const QString &tag);
|
||||
void closeAll();
|
||||
|
||||
void addDeclaration(const QString &version, const QString &encoding);
|
||||
void addRaw(const QString &rawText);
|
||||
void addAttribute(const QString &attribute, const QString &value);
|
||||
void addAttributeTag(const QString &attribute, const QString &value);
|
||||
void addData(const QString &data);
|
||||
|
||||
// Data
|
||||
QTextStream &xmlFile;
|
||||
QString indent;
|
||||
|
||||
QString currentIndent;
|
||||
int currentLevel;
|
||||
XMLState currentState;
|
||||
|
||||
XMLFormat format;
|
||||
ConverstionType conversion;
|
||||
QStack<QString> tagStack;
|
||||
};
|
||||
|
||||
inline XmlOutput::xml_output noxml()
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tNothing, QString(), QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output raw(const QString &rawText)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tRaw, rawText, QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output declaration(const QString &version = QString("1.0"),
|
||||
const QString &encoding = QString())
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tDeclaration, version, encoding);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output decl(const QString &version = QString("1.0"),
|
||||
const QString &encoding = QString())
|
||||
{
|
||||
return declaration(version, encoding);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output tag(const QString &name)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tTag, name, QString());
|
||||
}
|
||||
|
||||
|
||||
inline XmlOutput::xml_output valueTag(const QString &value)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tValueTag, value, QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output tagValue(const QString &tagName, const QString &value)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tTagValue, tagName, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output import(const QString &tagName, const QString &value)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tImport, tagName, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output closetag()
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output closetag(const QString &toTag)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tCloseTag, toTag, QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output closeall()
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString("all"));
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output attribute(const QString &name,
|
||||
const QString &value)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tAttribute, name, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output attributeTag(const QString &name,
|
||||
const QString &value)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tAttributeTag, name, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output attr(const QString &name,
|
||||
const QString &value)
|
||||
{
|
||||
return attribute(name, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output attrTag(const QString &name,
|
||||
const QString &value)
|
||||
{
|
||||
return attributeTag(name, value);
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output data(const QString &text = QString())
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tData, text, QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output comment(const QString &text)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tComment, text, QString());
|
||||
}
|
||||
|
||||
inline XmlOutput::xml_output cdata(const QString &text)
|
||||
{
|
||||
return XmlOutput::xml_output(XmlOutput::tCDATA, text, QString());
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // XMLOUTPUT_H
|
Reference in New Issue
Block a user