QtBase  v6.3.1
mingw_make.cpp
Go to the documentation of this file.
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 #include "mingw_make.h"
30 #include "option.h"
31 
32 #include <proitems.h>
33 
34 #include <qregularexpression.h>
35 #include <qdir.h>
36 #include <stdlib.h>
37 #include <time.h>
38 
40 
42 {
43  QString ret = path;
44  ret.replace('\\', "/"); // ### this shouldn't be here
46 }
47 
49 {
50  if (lib.startsWith("-l")) // Fallback for unresolved -l libs.
51  return QLatin1String("-l") + escapeFilePath(lib.mid(2));
52  if (lib.startsWith("-L")) // Lib search path. Needed only by -l above.
53  return QLatin1String("-L")
55  if (lib.startsWith("lib")) // Fallback for unresolved MSVC-style libs.
56  return QLatin1String("-l") + escapeFilePath(lib.mid(3).toQString());
58 }
59 
61 MingwMakefileGenerator::parseLibFlag(const ProString &flag, ProString *arg)
62 {
63  // Skip MSVC handling from Win32MakefileGenerator
65 }
66 
68  QStringView fixedBase, int slashOff)
69 {
70  if (origName.startsWith(u"lib")) {
71  QString newFixedBase = fixedBase.left(slashOff) + fixedBase.mid(slashOff + 3);
72  if (Win32MakefileGenerator::processPrlFileBase(origFile, origName,
73  QStringView(newFixedBase), slashOff)) {
74  return true;
75  }
76  }
77  return Win32MakefileGenerator::processPrlFileBase(origFile, origName, fixedBase, slashOff);
78 }
79 
81 {
82  writeHeader(t);
83  if (writeDummyMakefile(t))
84  return true;
85 
86  if(project->first("TEMPLATE") == "app" ||
87  project->first("TEMPLATE") == "lib" ||
88  project->first("TEMPLATE") == "aux") {
89  if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
91  writeMingwParts(t);
93  }
94  else if(project->first("TEMPLATE") == "subdirs") {
95  writeSubDirs(t);
96  return true;
97  }
98  return false;
99  }
100 
102 {
103  /*
104  We include a magic prefix on the path to bypass mingw-make's "helpful"
105  intervention in the environment, recognising variables that look like
106  paths and adding the msys system root as prefix, which we don't want.
107  Once this hack has smuggled INSTALL_ROOT into make's variable space, we
108  can trivially strip the magic prefix back off to get the path we meant.
109  */
110  return QStringLiteral("$(INSTALL_ROOT:@msyshack@%=%)");
111 }
112 
113 void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
114 {
116 
117  if (!preCompHeaderOut.isEmpty()) {
118  QString header = project->first("PRECOMPILED_HEADER").toQString();
119  QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
120  t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
121  << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
122  << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
123  << "\n\t$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << escapeFilePath(cHeader)
124  << ' ' << escapeFilePath(header) << Qt::endl << Qt::endl;
125  QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
126  t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
127  << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
128  << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
129  << "\n\t$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << escapeFilePath(cppHeader)
130  << ' ' << escapeFilePath(header) << Qt::endl << Qt::endl;
131  }
132 }
133 
135 {
136  /* this should probably not be here, but I'm using it to wrap the .t files */
137  if(project->first("TEMPLATE") == "app")
138  project->values("QMAKE_APP_FLAG").append("1");
139  else if(project->first("TEMPLATE") == "lib")
140  project->values("QMAKE_LIB_FLAG").append("1");
141  else if(project->first("TEMPLATE") == "subdirs") {
143  if(project->values("MAKEFILE").isEmpty())
144  project->values("MAKEFILE").append("Makefile");
145  return;
146  }
147 
148  processVars();
149 
150  project->values("LIBS") += project->values("RES_FILE");
151 
152  if (project->isActiveConfig("dll")) {
153  QString destDir = "";
154  if(!project->first("DESTDIR").isEmpty())
155  destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
156  project->values("MINGW_IMPORT_LIB").prepend(destDir + project->first("LIB_TARGET"));
157  project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + fileVar("MINGW_IMPORT_LIB"));
158  }
159 
160  if (!project->values("DEF_FILE").isEmpty()) {
161  QString defFileName = fileFixify(project->first("DEF_FILE").toQString());
162  project->values("QMAKE_LFLAGS").append(QString("-Wl,") + escapeFilePath(defFileName));
163  }
164 
165  if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib")
166  project->values("QMAKE_LFLAGS").append("-static");
167 
169 
170  // precomp
171  if (!project->first("PRECOMPILED_HEADER").isEmpty()
172  && project->isActiveConfig("precompile_header")) {
173  QString preCompHeader = var("PRECOMPILED_DIR")
174  + QFileInfo(project->first("PRECOMPILED_HEADER").toQString()).fileName();
175  preCompHeaderOut = preCompHeader + ".gch";
176  project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
177  project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
178 
179  preCompHeader = escapeFilePath(preCompHeader);
180  project->values("QMAKE_RUN_CC").clear();
181  project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
182  " $(CFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$obj $src");
183  project->values("QMAKE_RUN_CC_IMP").clear();
184  project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
185  " $(CFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$@ $<");
186  project->values("QMAKE_RUN_CXX").clear();
187  project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
188  " $(CXXFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$obj $src");
189  project->values("QMAKE_RUN_CXX_IMP").clear();
190  project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
191  " $(CXXFLAGS) $(INCPATH) " + var("QMAKE_CC_O_FLAG") + "$@ $<");
192  }
193 
194  if(project->isActiveConfig("dll")) {
195  project->values("QMAKE_DISTCLEAN").append(project->first("MINGW_IMPORT_LIB"));
196  }
197 }
198 
199 void MingwMakefileGenerator::writeIncPart(QTextStream &t)
200 {
201  t << "INCPATH = ";
202 
203  const ProStringList &incs = project->values("INCLUDEPATH");
204  QFile responseFile;
205  QTextStream responseStream;
206  QChar sep(' ');
207  int totalLength = std::accumulate(incs.constBegin(), incs.constEnd(), 0,
208  [](int total, const ProString &inc) {
209  return total + inc.size() + 2;
210  });
211  if (totalLength > project->intValue("QMAKE_RESPONSEFILE_THRESHOLD", 8000)) {
212  const QString fileName = createResponseFile("incpath", incs, "-I");
213  if (!fileName.isEmpty()) {
214  t << '@' + fileName;
215  t << Qt::endl;
216  return;
217  }
218  }
219  for (const ProString &incit: qAsConst(incs)) {
220  QString inc = incit.toQString();
221  inc.replace(QRegularExpression("\\\\$"), "");
222  inc.replace('\\', '/');
223  t << "-I" << escapeFilePath(inc) << sep;
224  }
225  t << Qt::endl;
226 }
227 
228 void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
229 {
230  if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
231  t << "LIB = " << var("QMAKE_LIB") << Qt::endl;
232  } else {
233  t << "LINKER = " << var("QMAKE_LINK") << Qt::endl;
234  t << "LFLAGS = " << var("QMAKE_LFLAGS") << Qt::endl;
235  t << "LIBS = "
236  << fixLibFlags("LIBS").join(' ') << ' '
237  << fixLibFlags("LIBS_PRIVATE").join(' ') << ' '
238  << fixLibFlags("QMAKE_LIBS").join(' ') << ' '
239  << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << Qt::endl;
240  }
241 }
242 
243 void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
244 {
245  linkerResponseFile = maybeCreateLinkerResponseFile();
246  if (!linkerResponseFile.isValid()) {
247  objectsLinkLine = "$(OBJECTS)";
248  } else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
249  // QMAKE_LIB is used for win32, including mingw, whereas QMAKE_AR is used on Unix.
250  QString ar_cmd = var("QMAKE_LIB");
251  if (ar_cmd.isEmpty())
252  ar_cmd = "ar -rc";
253  objectsLinkLine = ar_cmd + ' ' + var("DEST_TARGET") + " @"
254  + escapeFilePath(linkerResponseFile.filePath);
255  } else {
256  objectsLinkLine = "@" + escapeFilePath(linkerResponseFile.filePath);
257  }
259 }
260 
261 void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
262 {
263  t << "first: all\n";
265  << ' ' << depVar("ALL_DEPS") << ' ' << depVar("DEST_TARGET") << "\n\n";
266  t << depVar("DEST_TARGET") << ": "
267  << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
268  if (project->first("TEMPLATE") == "aux") {
269  t << "\n\n";
270  return;
271  }
272 
273  if(!project->isEmpty("QMAKE_PRE_LINK"))
274  t << "\n\t" <<var("QMAKE_PRE_LINK");
275  if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
276  t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" << var("QMAKE_SHELL_NULL_DEVICE");
277  const ProString &objmax = project->first("QMAKE_LINK_OBJECT_MAX");
278  if (objmax.isEmpty() || project->values("OBJECTS").count() < objmax.toInt()) {
279  t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
280  } else {
281  t << "\n\t" << objectsLinkLine << " " ;
282  }
283  } else {
284  t << "\n\t$(LINKER) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(DESTDIR_TARGET) "
285  << objectsLinkLine;
286  if (!linkerResponseFile.isValid() || linkerResponseFile.onlyObjects)
287  t << " $(LIBS)";
288  }
289  if(!project->isEmpty("QMAKE_POST_LINK"))
290  t << "\n\t" <<var("QMAKE_POST_LINK");
291  t << Qt::endl;
292 }
293 
294 void MingwMakefileGenerator::writeRcFilePart(QTextStream &t)
295 {
296  const QString rc_file = fileFixify(project->first("RC_FILE").toQString());
297 
298  ProStringList rcIncPaths = project->values("RC_INCLUDEPATH");
299  rcIncPaths.prepend(fileInfo(rc_file).path());
300  QString incPathStr;
301  for (int i = 0; i < rcIncPaths.count(); ++i) {
302  const ProString &path = rcIncPaths.at(i);
303  if (path.isEmpty())
304  continue;
305  incPathStr += QStringLiteral(" --include-dir=");
306  if (path != "." && QDir::isRelativePath(path.toQString()))
307  incPathStr += "./";
308  incPathStr += escapeFilePath(path);
309  }
310 
311  if (!rc_file.isEmpty()) {
312 
313  ProString defines = varGlue("RC_DEFINES", " -D", " -D", "");
314  if (defines.isEmpty())
315  defines = ProString(" $(DEFINES)");
316 
318  const QStringList rcDeps = QStringList(rc_file) << dependencies(rc_file);
319 
320  t << escapeDependencyPath(var("RES_FILE")) << ": "
321  << escapeDependencyPaths(rcDeps).join(' ') << "\n\t"
322  << var("QMAKE_RC") << " -i " << escapeFilePath(rc_file) << " -o " << fileVar("RES_FILE")
323  << incPathStr << defines << "\n\n";
324  }
325 }
326 
327 QStringList &MingwMakefileGenerator::findDependencies(const QString &file)
328 {
330  if (preCompHeaderOut.isEmpty())
331  return aList;
333  if (file.endsWith(*it)) {
334  QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
335  if (!aList.contains(cHeader))
336  aList += cHeader;
337  break;
338  }
339  }
341  if (file.endsWith(*it)) {
342  QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
343  if (!aList.contains(cppHeader))
344  aList += cppHeader;
345  break;
346  }
347  }
348  return aList;
349 }
350 
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
virtual QStringList & findDependencies(const QString &file)
Definition: makefile.cpp:3189
QStringList escapeDependencyPaths(const QStringList &paths) const
Definition: makefile.cpp:2936
void writeSubDirs(QTextStream &t)
Definition: makefile.cpp:2458
virtual QString var(const ProKey &var) const
Definition: makefile.cpp:1417
bool writeDummyMakefile(QTextStream &t)
Definition: makefile.cpp:2232
QString mkdir_p_asstring(const QString &dir, bool escape=true) const
Definition: makefile.cpp:82
QString depVar(const ProKey &var) const
Definition: makefile.cpp:1435
QFileInfo fileInfo(QString file) const
Definition: makefile.cpp:2827
QString varGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const
Definition: makefile.cpp:1453
void writeHeader(QTextStream &t)
Definition: makefile.cpp:2319
virtual bool writeMakefile(QTextStream &t)
Definition: makefile.cpp:2250
ProStringList fixLibFlags(const ProKey &var)
Definition: makefile.cpp:2863
QString createResponseFile(const QString &baseName, const ProStringList &objList, const QString &prefix=QString()) const
Definition: makefile.cpp:3498
virtual void init()
Definition: makefile.cpp:372
QStringList finalizeDependencyPaths(const QStringList &paths) const
Definition: makefile.cpp:2958
void writePkgConfigFile()
Definition: makefile.cpp:3292
virtual QString escapeDependencyPath(const QString &path) const
Definition: makefile.cpp:2907
QString fileFixify(const QString &file, FileFixifyTypes fix=FileFixifyDefault, bool canon=true) const
Definition: makefile.cpp:2982
LinkerResponseFileInfo maybeCreateLinkerResponseFile() const
Definition: makefile.cpp:3538
virtual LibFlagType parseLibFlag(const ProString &flag, ProString *arg)
Definition: makefile.cpp:2847
QMakeProject * project
Definition: makefile.h:139
QString fileVar(const ProKey &var) const
Definition: makefile.cpp:1423
ProString fixLibFlag(const ProString &lib) override
Definition: mingw_make.cpp:48
bool processPrlFileBase(QString &origFile, QStringView origName, QStringView fixedBase, int slashOff) override
Definition: mingw_make.cpp:67
void init() override
Definition: mingw_make.cpp:134
QString installRoot() const override
Definition: mingw_make.cpp:101
bool writeMakefile(QTextStream &) override
Definition: mingw_make.cpp:80
virtual QString escapeDependencyPath(const QString &path) const
Definition: makefile.cpp:2907
bool startsWith(const ProString &sub, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: proitems.h:133
bool isEmpty() const
Definition: proitems.h:121
ProString mid(int off, int len=-1) const
Definition: proitems.cpp:298
QString toQString() const
Definition: proitems.cpp:153
int toInt(bool *ok=nullptr, int base=10) const
Definition: proitems.h:155
QString join(const ProString &sep) const
Definition: proitems.cpp:359
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
static bool isRelativePath(const QString &path)
Definition: qdir.cpp:2364
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString fileName() const
Definition: qfileinfo.cpp:772
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
bool isEmpty() const noexcept
Definition: qlist.h:418
iterator Iterator
Definition: qlist.h:279
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
const_iterator constBegin() const noexcept
Definition: qlist.h:630
qsizetype count() const noexcept
Definition: qlist.h:415
void prepend(rvalue_ref t)
Definition: qlist.h:484
void append(parameter_type t)
Definition: qlist.h:469
const_iterator constEnd() const noexcept
Definition: qlist.h:631
void clear()
Definition: qlist.h:445
bool isEmpty(const ProKey &v) const
Definition: project.cpp:147
bool isActiveConfig(const QString &config, bool regex=false)
Definition: project.h:67
ProString first(const ProKey &variableName) const
ProStringList & values(const ProKey &v)
Definition: project.h:63
int intValue(const ProKey &v, int defaultValue=0) const
Definition: project.h:96
QStringList dependencies(const QString &file)
void addSourceFile(const QString &, uchar seek, SourceFileType type=TYPE_C)
The QRegularExpression class provides pattern matching using regular expressions.
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition: qstring.cpp:3450
bool isEmpty() const
Definition: qstring.h:1216
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstringview.h:312
constexpr QStringView left(qsizetype n) const noexcept
Definition: qstringview.h:267
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Definition: qstringview.h:261
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:62
virtual void writeStandardParts(QTextStream &t)
virtual void writeObjectsPart(QTextStream &t)
bool processPrlFileBase(QString &origFile, QStringView origName, QStringView fixedBase, int slashOff) override
virtual QString escapeFilePath(const QString &path) const=0
QTextStream & endl(QTextStream &stream)
#define QString()
Definition: parse-defines.h:51
QList< QString > QStringList
Definition: qcontainerfwd.h:64
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
double accumulate
Definition: outofline.cpp:34
QFile file
[0]
QHttpRequestHeader header("GET", QUrl::toPercentEncoding("/index.html"))
[1]
QStringList::Iterator it
static QStringList cpp_ext
Definition: option.h:85
static QStringList c_ext
Definition: option.h:86
static QString dir_sep
Definition: option.h:96
static QString fixPathToTargetOS(const QString &in, bool fix_env=true, bool canonical=true)
Definition: option.h:133
static QFile output
Definition: option.h:167