1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the qmake application of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#ifndef MAKEFILE_H
30#define MAKEFILE_H
31
32#include "option.h"
33#include "project.h"
34#include "makefiledeps.h"
35#include <qtextstream.h>
36#include <qlist.h>
37#include <qhash.h>
38#include <qfileinfo.h>
39
40QT_BEGIN_NAMESPACE
41
42#ifdef Q_OS_WIN32
43#define QT_POPEN _popen
44#define QT_POPEN_READ "rb"
45#define QT_PCLOSE _pclose
46#else
47#define QT_POPEN popen
48#define QT_POPEN_READ "r"
49#define QT_PCLOSE pclose
50#endif
51
52struct ReplaceExtraCompilerCacheKey;
53
54class MakefileGenerator : protected QMakeSourceFileInfo
55{
56    QString spec;
57    bool no_io = false;
58    bool resolveDependenciesInFrameworks = false;
59    QHash<QString, bool> init_compiler_already;
60    QString makedir, chkexists;
61    QString fullBuildArgs();
62
63    //internal caches
64    mutable QHash<QString, QMakeLocalFileName> depHeuristicsCache;
65    mutable QHash<QString, QStringList> dependsCache;
66    mutable QHash<ReplaceExtraCompilerCacheKey, QString> extraCompilerVariablesCache;
67
68public:
69    // We can't make it visible to VCFilter in VS2008 except by making it public or directly friending it.
70    enum ReplaceFor { NoShell, LocalShell, TargetShell };
71
72protected:
73    enum TARG_MODE { TARG_UNIX_MODE, TARG_MAC_MODE, TARG_WIN_MODE } target_mode;
74
75    ProStringList createObjectList(const ProStringList &sources);
76
77    //makefile style generator functions
78    void writeObj(QTextStream &, const char *src);
79    void writeInstalls(QTextStream &t, bool noBuild=false);
80    void writeHeader(QTextStream &t);
81    void writeSubDirs(QTextStream &t);
82    void writeMakeQmake(QTextStream &t, bool noDummyQmakeAll = false);
83    void writeExportedVariables(QTextStream &t);
84    void writeExtraVariables(QTextStream &t);
85    void writeExtraTargets(QTextStream &t);
86    QString resolveDependency(const QDir &outDir, const QString &file);
87    void callExtraCompilerDependCommand(const ProString &extraCompiler,
88                                        const QString &tmp_dep_cmd, const QString &inpf,
89                                        const QString &tmp_out, bool dep_lines, QStringList *deps,
90                                        bool existingDepsOnly,
91                                        bool checkCommandAvailability = false);
92    void writeExtraCompilerTargets(QTextStream &t);
93    void writeExtraCompilerVariables(QTextStream &t);
94    bool writeDummyMakefile(QTextStream &t);
95    virtual bool writeMakefile(QTextStream &t);
96    virtual void writeDefaultVariables(QTextStream &t);
97
98    QString pkgConfigPrefix() const;
99    QString pkgConfigFileName(bool fixify=true);
100    QString pkgConfigFixPath(QString) const;
101    void writePkgConfigFile();   // for pkg-config
102
103    //generating subtarget makefiles
104    struct SubTarget
105    {
106        QString name;
107        QString in_directory, out_directory;
108        QString profile, target, makefile;
109        ProStringList depends;
110    };
111    enum SubTargetFlags {
112        SubTargetInstalls=0x01,
113        SubTargetOrdered=0x02,
114        SubTargetSkipDefaultVariables=0x04,
115        SubTargetSkipDefaultTargets=0x08,
116
117        SubTargetsNoFlags=0x00
118    };
119    QList<MakefileGenerator::SubTarget*> findSubDirsSubTargets() const;
120    void writeSubTargetCall(QTextStream &t,
121            const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
122            const QString &out_directory_cdin, const QString &makefilein);
123    virtual void writeSubMakeCall(QTextStream &t, const QString &outDirectory_cdin,
124                                  const QString &makeFileIn);
125    virtual void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);
126    virtual ProStringList extraSubTargetDependencies() { return {}; }
127
128    //extra compiler interface
129    bool verifyExtraCompiler(const ProString &c, const QString &f);
130    virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor forShell);
131    inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out, ReplaceFor forShell)
132    { return replaceExtraCompilerVariables(val, QStringList(in), QStringList(out), forShell); }
133
134    //interface to the source file info
135    QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool) override;
136    QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &) override;
137    QFileInfo findFileInfo(const QMakeLocalFileName &) override;
138    QMakeProject *project = nullptr;
139
140    //escape
141    virtual QString escapeFilePath(const QString &path) const = 0;
142    ProString escapeFilePath(const ProString &path) const;
143    QStringList escapeFilePaths(const QStringList &paths) const;
144    ProStringList escapeFilePaths(const ProStringList &paths) const;
145    virtual QString escapeDependencyPath(const QString &path) const;
146    ProString escapeDependencyPath(const ProString &path) const;
147    QStringList escapeDependencyPaths(const QStringList &paths) const;
148    ProStringList escapeDependencyPaths(const ProStringList &paths) const;
149
150    QStringList finalizeDependencyPaths(const QStringList &paths) const;
151
152    //initialization
153    void verifyCompilers();
154    virtual void init();
155    void initOutPaths();
156    struct Compiler
157    {
158        QString variable_in;
159        enum CompilerFlag {
160            CompilerNoFlags                 = 0x00,
161            CompilerBuiltin                 = 0x01,
162            CompilerNoCheckDeps             = 0x02,
163            CompilerRemoveNoExist           = 0x04,
164            CompilerAddInputsAsMakefileDeps = 0x08
165        };
166        uint flags, type;
167    };
168    friend class QTypeInfo<Compiler>;
169
170    void initCompiler(const Compiler &comp);
171    enum VPATHFlag {
172        VPATH_NoFlag             = 0x00,
173        VPATH_WarnMissingFiles   = 0x01,
174        VPATH_RemoveMissingFiles = 0x02,
175        VPATH_NoFixify           = 0x04
176    };
177    ProStringList findFilesInVPATH(ProStringList l, uchar flags, const QString &var="");
178
179    inline int findExecutable(const QStringList &cmdline)
180    { int ret; canExecute(cmdline, &ret); return ret; }
181    bool canExecute(const QStringList &cmdline, int *argv0) const;
182    inline bool canExecute(const QString &cmdline) const
183    { return canExecute(cmdline.split(' '), nullptr); }
184
185    bool mkdir(const QString &dir) const;
186    QString mkdir_p_asstring(const QString &dir, bool escape=true) const;
187
188    QString specdir();
189
190    //subclasses can use these to query information about how the generator was "run"
191    QString buildArgs(bool withExtra);
192
193    virtual QStringList &findDependencies(const QString &file);
194    virtual bool doDepends() const { return Option::mkfile::do_deps; }
195
196    void filterIncludedFiles(const char *);
197    void processSources() {
198        filterIncludedFiles("SOURCES");
199        filterIncludedFiles("GENERATED_SOURCES");
200    }
201
202    //for installs
203    virtual QString defaultInstall(const QString &);
204    virtual QString installRoot() const;
205
206    //for prl
207    QString prlFileName(bool fixify=true);
208    void writePrlFile();
209    bool processPrlFile(QString &, bool baseOnly);
210    virtual void writePrlFile(QTextStream &);
211
212    //make sure libraries are found
213    virtual bool findLibraries(bool linkPrl, bool mergeLflags);
214
215    //for retrieving values and lists of values
216    virtual QString var(const ProKey &var) const;
217    QString varGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
218    QString varList(const ProKey &var) const;
219    QString fixFileVarGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
220    QString fileVarList(const ProKey &var) const;
221    QString fileVarGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const;
222    QString fileVar(const ProKey &var) const;
223    QString depVar(const ProKey &var) const;
224    QString val(const ProStringList &varList) const;
225    QString val(const QStringList &varList) const;
226    QString valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after) const;
227    QString valGlue(const ProStringList &varList, const QString &before, const QString &glue, const QString &after) const;
228    QString valList(const QStringList &varList) const;
229    QString valList(const ProStringList &varList) const;
230
231    QString filePrefixRoot(const QString &, const QString &);
232
233    enum LibFlagType { LibFlagLib, LibFlagPath, LibFlagFile, LibFlagOther };
234    virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg);
235    ProStringList fixLibFlags(const ProKey &var);
236    virtual ProString fixLibFlag(const ProString &lib);
237
238public:
239    //file fixification to unify all file names into a single pattern
240    enum FileFixifyType {
241        FileFixifyFromIndir = 0,
242        FileFixifyFromOutdir = 1,
243        FileFixifyToOutDir = 0,
244        FileFixifyToIndir = 2,
245        FileFixifyBackwards = FileFixifyFromOutdir | FileFixifyToIndir,
246        FileFixifyDefault = 0,
247        FileFixifyAbsolute = 4,
248        FileFixifyRelative = 8
249    };
250    Q_DECLARE_FLAGS(FileFixifyTypes, FileFixifyType)
251protected:
252    QString fileFixify(const QString &file, FileFixifyTypes fix = FileFixifyDefault, bool canon = true) const;
253    QStringList fileFixify(const QStringList &files, FileFixifyTypes fix = FileFixifyDefault, bool canon = true) const;
254    QString createSedArgs(const ProKey &replace_rule, const QString &file_type = QString()) const;
255    QString installMetaFile(const ProKey &replace_rule, const QString &src,
256                            const QString &dst) const;
257
258    virtual bool processPrlFileBase(QString &origFile, const QStringRef &origName,
259                                    const QStringRef &fixedBase, int slashOff);
260    bool processPrlFileCore(QString &origFile, const QStringRef &origName,
261                            const QString &fixedFile);
262    void createResponseFile(const QString &fileName, const ProStringList &objList);
263
264public:
265    QMakeProject *projectFile() const;
266    void setProjectFile(QMakeProject *p);
267
268    void setNoIO(bool o);
269    bool noIO() const;
270
271    inline bool exists(QString file) const { return fileInfo(file).exists(); }
272    QFileInfo fileInfo(QString file) const;
273
274    static MakefileGenerator *create(QMakeProject *);
275    virtual bool write();
276    virtual bool writeProjectMakefile();
277    virtual bool supportsMetaBuild() { return true; }
278    virtual bool supportsMergedBuilds() { return false; }
279    virtual bool mergeBuildProject(MakefileGenerator * /*other*/) { return false; }
280    virtual bool openOutput(QFile &, const QString &build) const;
281    bool isWindowsShell() const { return Option::dir_sep == QLatin1String("\\"); }
282    QString shellQuote(const QString &str) const;
283    virtual ProKey fullTargetVariable() const;
284};
285Q_DECLARE_TYPEINFO(MakefileGenerator::Compiler, Q_MOVABLE_TYPE);
286Q_DECLARE_OPERATORS_FOR_FLAGS(MakefileGenerator::FileFixifyTypes)
287
288inline void MakefileGenerator::setNoIO(bool o)
289{ no_io = o; }
290
291inline bool MakefileGenerator::noIO() const
292{ return no_io; }
293
294inline QString MakefileGenerator::defaultInstall(const QString &)
295{ return QString(""); }
296
297inline QString MakefileGenerator::installRoot() const
298{ return QStringLiteral("$(INSTALL_ROOT)"); }
299
300inline bool MakefileGenerator::findLibraries(bool, bool)
301{ return true; }
302
303struct ReplaceExtraCompilerCacheKey
304{
305    mutable uint hash;
306    QString var, in, out, pwd;
307    MakefileGenerator::ReplaceFor forShell;
308    ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o, MakefileGenerator::ReplaceFor s);
309    bool operator==(const ReplaceExtraCompilerCacheKey &f) const;
310    inline uint hashCode() const {
311        if (!hash)
312            hash = (uint)forShell ^ qHash(var) ^ qHash(in) ^ qHash(out) /*^ qHash(pwd)*/;
313        return hash;
314    }
315};
316inline uint qHash(const ReplaceExtraCompilerCacheKey &f) { return f.hashCode(); }
317
318QT_END_NAMESPACE
319
320#endif // MAKEFILE_H
321