1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
4
5#include "unixmake.h"
6#include "option.h"
7#include "meta.h"
8#include <qregularexpression.h>
9#include <qbytearray.h>
10#include <qfile.h>
11#include <qdir.h>
12#include <qdebug.h>
13#include <qtversion.h>
14#include <time.h>
15
16#include <tuple>
17#include <utility>
18
19QT_BEGIN_NAMESPACE
20
21void
22UnixMakefileGenerator::writePrlFile(QTextStream &t)
23{
24 MakefileGenerator::writePrlFile(t);
25 const ProString tmplt = project->first(variableName: "TEMPLATE");
26 if (tmplt != "lib" && tmplt != "aux")
27 return;
28 // libtool support
29 if (project->isActiveConfig(config: "create_libtool")) {
30 writeLibtoolFile();
31 }
32 // pkg-config support
33 if (project->isActiveConfig(config: "create_pc"))
34 writePkgConfigFile();
35}
36
37bool
38UnixMakefileGenerator::writeMakefile(QTextStream &t)
39{
40
41 writeHeader(t);
42 if (writeDummyMakefile(t))
43 return true;
44
45 if (project->first(variableName: "TEMPLATE") == "app" ||
46 project->first(variableName: "TEMPLATE") == "lib" ||
47 project->first(variableName: "TEMPLATE") == "aux") {
48 writeMakeParts(t);
49 return MakefileGenerator::writeMakefile(t);
50 } else if (project->first(variableName: "TEMPLATE") == "subdirs") {
51 MakefileGenerator::writeSubDirs(t);
52 return true;
53 }
54 return false;
55}
56
57void
58UnixMakefileGenerator::writeDefaultVariables(QTextStream &t)
59{
60 MakefileGenerator::writeDefaultVariables(t);
61 t << "TAR = " << var(var: "QMAKE_TAR") << Qt::endl;
62 t << "COMPRESS = " << var(var: "QMAKE_GZIP") << Qt::endl;
63
64 if (project->isEmpty(v: "QMAKE_DISTNAME")) {
65 ProString distname = project->first(variableName: "QMAKE_ORIG_TARGET");
66 if (!project->isActiveConfig(config: "no_dist_version"))
67 distname += project->first(variableName: "VERSION");
68 project->values(v: "QMAKE_DISTNAME") = distname;
69 }
70 t << "DISTNAME = " << fileVar(var: "QMAKE_DISTNAME") << Qt::endl;
71
72 if (project->isEmpty(v: "QMAKE_DISTDIR"))
73 project->values(v: "QMAKE_DISTDIR") = project->first(variableName: "QMAKE_DISTNAME");
74 t << "DISTDIR = " << escapeFilePath(path: fileFixify(
75 file: (project->isEmpty(v: "OBJECTS_DIR") ? ProString(".tmp/") : project->first(variableName: "OBJECTS_DIR")) + project->first(variableName: "QMAKE_DISTDIR"),
76 fix: FileFixifyFromOutdir | FileFixifyAbsolute)) << Qt::endl;
77}
78
79void
80UnixMakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags)
81{
82 MakefileGenerator::writeSubTargets(t, subtargets: targets, flags);
83
84 t << "dist: distdir FORCE" << Qt::endl;
85 t << "\t(cd `dirname $(DISTDIR)` && $(TAR) $(DISTNAME).tar $(DISTNAME) && $(COMPRESS) $(DISTNAME).tar)"
86 " && $(MOVE) `dirname $(DISTDIR)`/$(DISTNAME).tar.gz . && $(DEL_FILE) -r $(DISTDIR)";
87 t << Qt::endl << Qt::endl;
88
89 t << "distdir:";
90 for (int target = 0; target < targets.size(); ++target) {
91 SubTarget *subtarget = targets.at(i: target);
92 t << " " << subtarget->target << "-distdir";
93 }
94 t << " FORCE\n\t"
95 << mkdir_p_asstring(dir: "$(DISTDIR)", escape: false) << "\n\t"
96 << "$(COPY_FILE) --parents " << fileVar(var: "DISTFILES") << " $(DISTDIR)" << Option::dir_sep << Qt::endl << Qt::endl;
97
98 const QString abs_source_path = project->first(variableName: "QMAKE_ABSOLUTE_SOURCE_PATH").toQString();
99 for (int target = 0; target < targets.size(); ++target) {
100 SubTarget *subtarget = targets.at(i: target);
101 QString in_directory = subtarget->in_directory;
102 if (!in_directory.isEmpty() && !in_directory.endsWith(s: Option::dir_sep))
103 in_directory += Option::dir_sep;
104 QString out_directory = subtarget->out_directory;
105 if (!out_directory.isEmpty() && !out_directory.endsWith(s: Option::dir_sep))
106 out_directory += Option::dir_sep;
107 if (!abs_source_path.isEmpty() && out_directory.startsWith(s: abs_source_path))
108 out_directory = Option::output_dir + out_directory.mid(position: abs_source_path.size());
109
110 QString dist_directory = out_directory;
111 if (dist_directory.endsWith(s: Option::dir_sep))
112 dist_directory.chop(n: Option::dir_sep.size());
113 if (!dist_directory.startsWith(s: Option::dir_sep))
114 dist_directory.prepend(s: Option::dir_sep);
115
116 QString out_directory_cdin = out_directory.isEmpty() ? QString("\n\t")
117 : "\n\tcd " + escapeFilePath(path: out_directory) + " && ";
118 QString makefilein = " -e -f " + escapeFilePath(path: subtarget->makefile)
119 + " distdir DISTDIR=$(DISTDIR)" + escapeFilePath(path: dist_directory);
120
121 QString out = subtarget->makefile;
122 QString in = escapeFilePath(path: fileFixify(file: in_directory + subtarget->profile, fix: FileFixifyAbsolute));
123 if (out.startsWith(s: in_directory))
124 out.remove(i: 0, len: in_directory.size());
125
126 t << subtarget->target << "-distdir: FORCE";
127 writeSubTargetCall(t, in_directory, in, out_directory, out: escapeFilePath(path: out),
128 out_directory_cdin, makefilein);
129 t << Qt::endl;
130 }
131}
132
133static QString rfc1034Identifier(const QString &str)
134{
135 QString s = str;
136 for (QChar &ch : s) {
137 const char c = ch.toLatin1();
138
139 const bool okChar = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
140 || (c >= 'a' && c <= 'z') || c == '-' || c == '.';
141 if (!okChar)
142 ch = QChar::fromLatin1(c: '-');
143 }
144 return s;
145}
146
147static QString escapeDir(const QString &dir)
148{
149 // When building on non-MSys MinGW, the path ends with a backslash, which
150 // GNU make will interpret that as a line continuation. Doubling the backslash
151 // avoids the problem, at the cost of the variable containing *both* backslashes.
152 if (dir.endsWith(c: '\\'))
153 return dir + '\\';
154 return dir;
155}
156
157void
158UnixMakefileGenerator::writeMakeParts(QTextStream &t)
159{
160 bool do_incremental = (project->isActiveConfig(config: "incremental") &&
161 !project->values(v: "QMAKE_INCREMENTAL").isEmpty() &&
162 (!project->values(v: "QMAKE_APP_FLAG").isEmpty() ||
163 (!project->isActiveConfig(config: "staticlib")))),
164 src_incremental=false;
165
166 ProStringList &bundledFiles = project->values(v: "QMAKE_BUNDLED_FILES");
167
168 writeExportedVariables(t);
169
170 t << "####### Compiler, tools and options\n\n";
171 t << "CC = " << var(var: "QMAKE_CC") << Qt::endl;
172 t << "CXX = " << var(var: "QMAKE_CXX") << Qt::endl;
173 t << "DEFINES = "
174 << varGlue(var: "PRL_EXPORT_DEFINES",before: "-D",glue: " -D",after: " ")
175 << varGlue(var: "DEFINES",before: "-D",glue: " -D",after: "") << Qt::endl;
176 t << "CFLAGS = " << var(var: "QMAKE_CFLAGS") << " $(DEFINES)\n";
177 t << "CXXFLAGS = " << var(var: "QMAKE_CXXFLAGS") << " $(DEFINES)\n";
178 t << "INCPATH =";
179 {
180 const ProStringList &incs = project->values(v: "INCLUDEPATH");
181 for(int i = 0; i < incs.size(); ++i) {
182 const ProString &inc = incs.at(i);
183 if (inc.isEmpty())
184 continue;
185
186 t << " -I" << escapeFilePath(path: inc);
187 }
188 }
189 if(!project->isEmpty(v: "QMAKE_FRAMEWORKPATH_FLAGS"))
190 t << " " << var(var: "QMAKE_FRAMEWORKPATH_FLAGS");
191 t << Qt::endl;
192
193 writeDefaultVariables(t);
194
195 if(!project->isActiveConfig(config: "staticlib")) {
196 t << "LINK = " << var(var: "QMAKE_LINK") << Qt::endl;
197 t << "LFLAGS = " << var(var: "QMAKE_LFLAGS") << Qt::endl;
198 t << "LIBS = $(SUBLIBS) " << fixLibFlags(var: "LIBS").join(sep: ' ') << ' '
199 << fixLibFlags(var: "LIBS_PRIVATE").join(sep: ' ') << ' '
200 << fixLibFlags(var: "QMAKE_LIBS").join(sep: ' ') << ' '
201 << fixLibFlags(var: "QMAKE_LIBS_PRIVATE").join(sep: ' ') << Qt::endl;
202 }
203
204 t << "AR = " << var(var: "QMAKE_AR") << Qt::endl;
205 t << "RANLIB = " << var(var: "QMAKE_RANLIB") << Qt::endl;
206 t << "SED = " << var(var: "QMAKE_STREAM_EDITOR") << Qt::endl;
207 t << "STRIP = " << var(var: "QMAKE_STRIP") << Qt::endl;
208
209 t << Qt::endl;
210
211 t << "####### Output directory\n\n";
212 // This is used in commands by some .prf files.
213 if (! project->values(v: "OBJECTS_DIR").isEmpty())
214 t << "OBJECTS_DIR = " << escapeDir(dir: fileVar(var: "OBJECTS_DIR")) << Qt::endl;
215 else
216 t << "OBJECTS_DIR = ./\n";
217 t << Qt::endl;
218
219 /* files */
220 t << "####### Files\n\n";
221 // This is used by the dist target.
222 t << "SOURCES = " << fileVarList(var: "SOURCES") << ' ' << fileVarList(var: "GENERATED_SOURCES") << Qt::endl;
223
224 src_incremental = writeObjectsPart(t, do_incremental);
225 if(do_incremental && !src_incremental)
226 do_incremental = false;
227 t << "DIST = " << valList(varList: fileFixify(files: project->values(v: "DISTFILES").toQStringList())) << " "
228 << fileVarList(var: "HEADERS") << ' ' << fileVarList(var: "SOURCES") << Qt::endl;
229 t << "QMAKE_TARGET = " << fileVar(var: "QMAKE_ORIG_TARGET") << Qt::endl;
230 t << "DESTDIR = " << escapeDir(dir: fileVar(var: "DESTDIR")) << Qt::endl;
231 t << "TARGET = " << fileVar(var: "TARGET") << Qt::endl;
232 if(project->isActiveConfig(config: "plugin")) {
233 t << "TARGETD = " << fileVar(var: "TARGET") << Qt::endl;
234 } else if(!project->isActiveConfig(config: "staticlib") && project->values(v: "QMAKE_APP_FLAG").isEmpty()) {
235 t << "TARGETA = " << fileVar(var: "TARGETA") << Qt::endl;
236 if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
237 t << "TARGETD = " << fileVar(var: "TARGET_x.y") << Qt::endl;
238 t << "TARGET0 = " << fileVar(var: "TARGET_") << Qt::endl;
239 } else if (!project->isActiveConfig(config: "unversioned_libname")) {
240 t << "TARGET0 = " << fileVar(var: "TARGET_") << Qt::endl;
241 if (project->isEmpty(v: "QMAKE_HPUX_SHLIB")) {
242 t << "TARGETD = " << fileVar(var: "TARGET_x.y.z") << Qt::endl;
243 t << "TARGET1 = " << fileVar(var: "TARGET_x") << Qt::endl;
244 t << "TARGET2 = " << fileVar(var: "TARGET_x.y") << Qt::endl;
245 } else {
246 t << "TARGETD = " << fileVar(var: "TARGET_x") << Qt::endl;
247 }
248 }
249 }
250 writeExtraCompilerVariables(t);
251 writeExtraVariables(t);
252 t << Qt::endl;
253
254 // blasted includes
255 const ProStringList &qeui = project->values(v: "QMAKE_EXTRA_INCLUDES");
256 ProStringList::ConstIterator it;
257 for(it = qeui.begin(); it != qeui.end(); ++it)
258 t << "include " << escapeDependencyPath(path: *it) << Qt::endl;
259
260 /* rules */
261 t << "first:" << (!project->isActiveConfig(config: "no_default_goal_deps") ? " all" : "") << "\n";
262
263 if(include_deps) {
264 if (project->isActiveConfig(config: "gcc_MD_depends")) {
265 ProStringList objects = project->values(v: "OBJECTS");
266 for (ProStringList::Iterator it = objects.begin(); it != objects.end(); ++it) {
267 QString d_file = (*it).toQString().replace(re: QRegularExpression(Option::obj_ext + "$"), after: ".d");
268 t << "-include " << escapeDependencyPath(path: d_file) << Qt::endl;
269 project->values(v: "QMAKE_DISTCLEAN") << d_file;
270 }
271 } else {
272 QString cmd=var(var: "QMAKE_CFLAGS_DEPS") + " ";
273 cmd += varGlue(var: "DEFINES",before: "-D",glue: " -D",after: "") + varGlue(var: "PRL_EXPORT_DEFINES",before: " -D",glue: " -D",after: "");
274 if(!project->isEmpty(v: "QMAKE_ABSOLUTE_SOURCE_PATH"))
275 cmd += " -I" + fileVar(var: "QMAKE_ABSOLUTE_SOURCE_PATH") + ' ';
276 cmd += " $(INCPATH) " + fileVarGlue(var: "DEPENDPATH", before: "-I", glue: " -I", after: "");
277 ProString odir;
278 if(!project->values(v: "OBJECTS_DIR").isEmpty())
279 odir = project->first(variableName: "OBJECTS_DIR");
280 QString odird = escapeDependencyPath(path: odir.toQString());
281
282 QString pwd = escapeFilePath(path: fileFixify(file: qmake_getpwd()));
283
284 t << "###### Dependencies\n\n";
285 t << odird << ".deps/%.d: " << pwd << "/%.cpp\n\t";
286 if(project->isActiveConfig(config: "echo_depend_creation"))
287 t << "@echo Creating depend for $<\n\t";
288 t << mkdir_p_asstring(dir: "$(@D)", escape: false) << "\n\t"
289 << "@$(CXX) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@\n\n";
290
291 t << odird << ".deps/%.d: " << pwd << "/%.c\n\t";
292 if(project->isActiveConfig(config: "echo_depend_creation"))
293 t << "@echo Creating depend for $<\n\t";
294 t << mkdir_p_asstring(dir: "$(@D)", escape: false) << "\n\t"
295 << "@$(CC) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@\n\n";
296
297 static const char * const src[] = { "SOURCES", "GENERATED_SOURCES", nullptr };
298 for (int x = 0; src[x]; x++) {
299 const ProStringList &l = project->values(v: src[x]);
300 for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
301 if(!(*it).isEmpty()) {
302 QString d_file;
303 for(QStringList::Iterator cit = Option::c_ext.begin();
304 cit != Option::c_ext.end(); ++cit) {
305 if((*it).endsWith(sub: (*cit))) {
306 d_file = (*it).left(len: (*it).length() - (*cit).size()).toQString();
307 break;
308 }
309 }
310 if(d_file.isEmpty()) {
311 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
312 cppit != Option::cpp_ext.end(); ++cppit) {
313 if((*it).endsWith(sub: (*cppit))) {
314 d_file = (*it).left(len: (*it).length() - (*cppit).size()).toQString();
315 break;
316 }
317 }
318 }
319
320 if(!d_file.isEmpty()) {
321 d_file = odir + ".deps/" + fileFixify(file: d_file, fix: FileFixifyBackwards) + ".d";
322 QString d_file_d = escapeDependencyPath(path: d_file);
323 QStringList deps = findDependencies((*it).toQString()).filter(re: QRegularExpression(
324 "((^|/)" + Option::h_moc_mod + "|" + Option::cpp_moc_ext + "$)"));
325 if(!deps.isEmpty())
326 t << d_file_d << ": " << finalizeDependencyPaths(paths: deps).join(sep: ' ') << Qt::endl;
327 t << "-include " << d_file_d << Qt::endl;
328 project->values(v: "QMAKE_DISTCLEAN") += d_file;
329 }
330 }
331 }
332 }
333 }
334 }
335
336 t << "####### Build rules\n\n";
337 if(!project->values(v: "SUBLIBS").isEmpty()) {
338 ProString libdir = "tmp/";
339 if(!project->isEmpty(v: "SUBLIBS_DIR"))
340 libdir = project->first(variableName: "SUBLIBS_DIR");
341 t << "SUBLIBS = ";
342 const ProStringList &l = project->values(v: "SUBLIBS");
343 for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
344 t << escapeFilePath(path: libdir + project->first(variableName: "QMAKE_PREFIX_STATICLIB") + (*it) + '.'
345 + project->first(variableName: "QMAKE_EXTENSION_STATICLIB")) << ' ';
346 t << Qt::endl << Qt::endl;
347 }
348 QString target_deps;
349 if ((project->isActiveConfig(config: "depend_prl") || project->isActiveConfig(config: "fast_depend_prl"))
350 && !project->isEmpty(v: "QMAKE_PRL_INTERNAL_FILES")) {
351 const ProStringList &l = project->values(v: "QMAKE_PRL_INTERNAL_FILES");
352 ProStringList::ConstIterator it;
353 for(it = l.begin(); it != l.end(); ++it) {
354 QMakeMetaInfo libinfo;
355 if (libinfo.readLib(meta_file: (*it).toQString()) && !libinfo.isEmpty(v: "QMAKE_PRL_BUILD_DIR")) {
356 ProString dir;
357 int slsh = (*it).lastIndexOf(s: Option::dir_sep);
358 if(slsh != -1)
359 dir = (*it).left(len: slsh + 1);
360 QString targ = dir + libinfo.first(v: "QMAKE_PRL_TARGET");
361 QString targ_d = escapeDependencyPath(path: targ);
362 target_deps += ' ' + targ_d;
363 t << targ_d;
364 if (project->isActiveConfig(config: "fast_depend_prl"))
365 t << ":\n\t@echo \"Creating '";
366 else
367 t << ": FORCE\n\t@echo \"Creating/updating '";
368 t << targ << "'\"\n\t"
369 << "(cd " << escapeFilePath(path: libinfo.first(v: "QMAKE_PRL_BUILD_DIR")) << ';'
370 << "$(MAKE))\n";
371 }
372 }
373 }
374 LinkerResponseFileInfo linkerResponseFile = maybeCreateLinkerResponseFile();
375 QString deps = escapeDependencyPath(path: fileFixify(file: Option::output.fileName()));
376 QString allDeps;
377 if (!project->values(v: "QMAKE_APP_FLAG").isEmpty() || project->first(variableName: "TEMPLATE") == "aux") {
378 QString destdir = project->first(variableName: "DESTDIR").toQString();
379 if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
380 QString bundle_loc = project->first(variableName: "QMAKE_BUNDLE_LOCATION").toQString();
381 if(!bundle_loc.isEmpty() && !bundle_loc.startsWith(s: "/"))
382 bundle_loc.prepend(s: "/");
383 if(!bundle_loc.endsWith(s: "/"))
384 bundle_loc += "/";
385 destdir += project->first(variableName: "QMAKE_BUNDLE") + bundle_loc;
386 }
387 if(do_incremental) {
388 //incremental target
389 QString incr_target = var(var: "TARGET") + "_incremental";
390 if(incr_target.indexOf(s: Option::dir_sep) != -1)
391 incr_target = incr_target.right(n: incr_target.size() -
392 (incr_target.lastIndexOf(s: Option::dir_sep) + 1));
393 QString incr_deps, incr_objs;
394 if(project->first(variableName: "QMAKE_INCREMENTAL_STYLE") == "ld") {
395 QString incr_target_dir = var(var: "OBJECTS_DIR") + incr_target + Option::obj_ext;
396 QString incr_target_dir_d = escapeDependencyPath(path: incr_target_dir);
397 QString incr_target_dir_f = escapeFilePath(path: incr_target_dir);
398 //actual target
399 t << incr_target_dir_d << ": $(OBJECTS)\n\t"
400 << "ld -r -o " << incr_target_dir_f << " $(OBJECTS)\n";
401 //communicated below
402 deps.prepend(s: incr_target_dir_d + ' ');
403 incr_deps = "$(INCREMENTAL_OBJECTS)";
404 if(!incr_objs.isEmpty())
405 incr_objs += " ";
406 incr_objs += incr_target_dir_f;
407 } else {
408 //actual target
409 QString incr_target_dir = var(var: "DESTDIR") + "lib" + incr_target + "." +
410 project->first(variableName: "QMAKE_EXTENSION_SHLIB");
411 QString incr_target_dir_d = escapeDependencyPath(path: incr_target_dir);
412 QString incr_target_dir_f = escapeFilePath(path: incr_target_dir);
413 QString incr_lflags = var(var: "QMAKE_LFLAGS_SHLIB") + " ";
414 if(project->isActiveConfig(config: "debug"))
415 incr_lflags += var(var: "QMAKE_LFLAGS_DEBUG");
416 else if (project->isActiveConfig(config: "debug_info"))
417 incr_lflags += var(var: "QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO");
418 else
419 incr_lflags += var(var: "QMAKE_LFLAGS_RELEASE");
420 t << incr_target_dir_d << ": $(INCREMENTAL_OBJECTS)\n\t";
421 if(!destdir.isEmpty())
422 t << "\n\t" << mkdir_p_asstring(dir: destdir) << "\n\t";
423 t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir_f <<
424 " $(INCREMENTAL_OBJECTS)\n";
425 //communicated below
426 if(!destdir.isEmpty()) {
427 if(!incr_objs.isEmpty())
428 incr_objs += " ";
429 incr_objs += "-L" + escapeFilePath(path: destdir);
430 } else {
431 if(!incr_objs.isEmpty())
432 incr_objs += " ";
433 incr_objs += "-L" + escapeFilePath(path: qmake_getpwd());
434 }
435 if(!incr_objs.isEmpty())
436 incr_objs += " ";
437 incr_objs += " -l" + escapeFilePath(path: incr_target);
438 deps.prepend(s: incr_target_dir_d + ' ');
439 incr_deps = "$(OBJECTS)";
440 }
441
442 //real target
443 t << var(var: "TARGET") << ": " << depVar(var: "PRE_TARGETDEPS") << ' ' << incr_deps << ' ' << target_deps
444 << ' ' << depVar(var: "POST_TARGETDEPS") << "\n\t";
445 if(!destdir.isEmpty())
446 t << "\n\t" << mkdir_p_asstring(dir: destdir) << "\n\t";
447 if(!project->isEmpty(v: "QMAKE_PRE_LINK"))
448 t << var(var: "QMAKE_PRE_LINK") << "\n\t";
449 t << "$(LINK) $(LFLAGS) " << var(var: "QMAKE_LINK_O_FLAG") << "$(TARGET) " << incr_deps << " " << incr_objs << " $(OBJCOMP) $(LIBS)";
450 if(!project->isEmpty(v: "QMAKE_POST_LINK"))
451 t << "\n\t" << var(var: "QMAKE_POST_LINK");
452 t << Qt::endl << Qt::endl;
453 } else {
454 t << depVar(var: "TARGET") << ": " << depVar(var: "PRE_TARGETDEPS") << " $(OBJECTS) "
455 << target_deps << ' ' << depVar(var: "POST_TARGETDEPS") << "\n\t";
456 if (project->first(variableName: "TEMPLATE") != "aux") {
457 if (!destdir.isEmpty())
458 t << mkdir_p_asstring(dir: destdir) << "\n\t";
459 if (!project->isEmpty(v: "QMAKE_PRE_LINK"))
460 t << var(var: "QMAKE_PRE_LINK") << "\n\t";
461 t << "$(LINK) $(LFLAGS) " << var(var: "QMAKE_LINK_O_FLAG") << "$(TARGET) ";
462 if (!linkerResponseFile.isValid())
463 t << " $(OBJECTS) $(OBJCOMP) $(LIBS)";
464 else if (linkerResponseFile.onlyObjects)
465 t << " @" << linkerResponseFile.filePath << " $(OBJCOMP) $(LIBS)";
466 else
467 t << " $(OBJCOMP) @" << linkerResponseFile.filePath;
468 if (!project->isEmpty(v: "QMAKE_POST_LINK"))
469 t << "\n\t" << var(var: "QMAKE_POST_LINK");
470 }
471 t << Qt::endl << Qt::endl;
472 }
473 allDeps = ' ' + depVar(var: "TARGET");
474 } else if(!project->isActiveConfig(config: "staticlib")) {
475 QString destdir_r = project->first(variableName: "DESTDIR").toQString(), incr_deps;
476 if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
477 QString bundle_loc = project->first(variableName: "QMAKE_BUNDLE_LOCATION").toQString();
478 if(!bundle_loc.isEmpty() && !bundle_loc.startsWith(s: "/"))
479 bundle_loc.prepend(s: "/");
480 if(!bundle_loc.endsWith(s: "/"))
481 bundle_loc += "/";
482 destdir_r += project->first(variableName: "QMAKE_BUNDLE") + bundle_loc;
483 }
484 QString destdir_d = escapeDependencyPath(path: destdir_r);
485 QString destdir = escapeFilePath(path: destdir_r);
486
487 if(do_incremental) {
488 ProString s_ext = project->first(variableName: "QMAKE_EXTENSION_SHLIB");
489 QString incr_target = var(var: "QMAKE_ORIG_TARGET").replace(
490 re: QRegularExpression("\\." + s_ext), after: "").replace(re: QRegularExpression("^lib"), after: "") + "_incremental";
491 if(incr_target.indexOf(s: Option::dir_sep) != -1)
492 incr_target = incr_target.right(n: incr_target.size() -
493 (incr_target.lastIndexOf(s: Option::dir_sep) + 1));
494
495 if(project->first(variableName: "QMAKE_INCREMENTAL_STYLE") == "ld") {
496 QString incr_target_dir = var(var: "OBJECTS_DIR") + incr_target + Option::obj_ext;
497 QString incr_target_dir_d = escapeDependencyPath(path: incr_target_dir);
498 QString incr_target_dir_f = escapeFilePath(path: incr_target_dir);
499 //actual target
500 const QString link_deps = "$(OBJECTS) ";
501 t << incr_target_dir_d << ": " << link_deps << "\n\t"
502 << "ld -r -o " << incr_target_dir_f << ' ' << link_deps << Qt::endl;
503 //communicated below
504 ProStringList &cmd = project->values(v: "QMAKE_LINK_SHLIB_CMD");
505 cmd[0] = cmd.at(i: 0).toQString().replace(before: QLatin1String("$(OBJECTS) "), after: QLatin1String("$(INCREMENTAL_OBJECTS)")); //ick
506 cmd.append(t: incr_target_dir_f);
507 deps.prepend(s: incr_target_dir_d + ' ');
508 incr_deps = "$(INCREMENTAL_OBJECTS)";
509 } else {
510 //actual target
511 QString incr_target_dir = destdir_r + "lib" + incr_target + '.' + s_ext;
512 QString incr_target_dir_d = escapeDependencyPath(path: incr_target_dir);
513 QString incr_target_dir_f = escapeFilePath(path: incr_target_dir);
514 QString incr_lflags = var(var: "QMAKE_LFLAGS_SHLIB") + " ";
515 if(!project->isEmpty(v: "QMAKE_LFLAGS_INCREMENTAL"))
516 incr_lflags += var(var: "QMAKE_LFLAGS_INCREMENTAL") + " ";
517 if(project->isActiveConfig(config: "debug"))
518 incr_lflags += var(var: "QMAKE_LFLAGS_DEBUG");
519 else if (project->isActiveConfig(config: "debug_info"))
520 incr_lflags += var(var: "QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO");
521 else
522 incr_lflags += var(var: "QMAKE_LFLAGS_RELEASE");
523 t << incr_target_dir_d << ": $(INCREMENTAL_OBJECTS)\n\t";
524 if(!destdir.isEmpty())
525 t << mkdir_p_asstring(dir: destdir, escape: false) << "\n\t";
526 t << "$(LINK) " << incr_lflags << ' ' << var(var: "QMAKE_LINK_O_FLAG") << incr_target_dir_f <<
527 " $(INCREMENTAL_OBJECTS)\n";
528 //communicated below
529 ProStringList &cmd = project->values(v: "QMAKE_LINK_SHLIB_CMD");
530 if(!destdir.isEmpty())
531 cmd.append(t: " -L" + destdir);
532 cmd.append(t: " -l" + escapeFilePath(path: incr_target));
533 deps.prepend(s: incr_target_dir_d + ' ');
534 incr_deps = "$(OBJECTS)";
535 }
536
537 //real target
538 t << destdir_d << depVar(var: "TARGET") << ": " << depVar(var: "PRE_TARGETDEPS") << ' '
539 << incr_deps << " $(SUBLIBS) " << target_deps << ' ' << depVar(var: "POST_TARGETDEPS");
540 } else {
541 ProStringList &cmd = project->values(v: "QMAKE_LINK_SHLIB_CMD");
542 if (linkerResponseFile.isValid()) {
543 cmd[0] = cmd.at(i: 0).toQString().replace(before: QLatin1String("$(OBJECTS)"),
544 after: "@" + linkerResponseFile.filePath);
545 }
546 t << destdir_d << depVar(var: "TARGET") << ": " << depVar(var: "PRE_TARGETDEPS")
547 << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps
548 << ' ' << depVar(var: "POST_TARGETDEPS");
549 }
550 allDeps = ' ' + destdir_d + depVar(var: "TARGET");
551 if(!destdir.isEmpty())
552 t << "\n\t" << mkdir_p_asstring(dir: destdir, escape: false);
553 if(!project->isEmpty(v: "QMAKE_PRE_LINK"))
554 t << "\n\t" << var(var: "QMAKE_PRE_LINK");
555
556 if (project->isActiveConfig(config: "plugin")) {
557 t << "\n\t"
558 << "-$(DEL_FILE) $(TARGET)\n\t"
559 << var(var: "QMAKE_LINK_SHLIB_CMD");
560 if(!destdir.isEmpty())
561 t << "\n\t"
562 << "-$(MOVE) $(TARGET) " << destdir << "$(TARGET)";
563 if(!project->isEmpty(v: "QMAKE_POST_LINK"))
564 t << "\n\t" << var(var: "QMAKE_POST_LINK");
565 t << Qt::endl << Qt::endl;
566 } else if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
567 bundledFiles << destdir_r + var(var: "TARGET");
568 t << "\n\t"
569 << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(DESTDIR)$(TARGET0)\n\t"
570 << var(var: "QMAKE_LINK_SHLIB_CMD") << "\n\t"
571 << mkdir_p_asstring(dir: "\"`dirname $(DESTDIR)$(TARGETD)`\"", escape: false) << "\n\t"
572 << "-$(MOVE) $(TARGET) $(DESTDIR)$(TARGETD)\n\t"
573 << mkdir_p_asstring(dir: "\"`dirname $(DESTDIR)$(TARGET0)`\"", escape: false) << "\n\t";
574 if (!project->isActiveConfig(config: "shallow_bundle"))
575 t << varGlue(var: "QMAKE_LN_SHLIB", before: "-", glue: " ",
576 after: " Versions/Current/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t";
577 if(!project->isEmpty(v: "QMAKE_POST_LINK"))
578 t << "\n\t" << var(var: "QMAKE_POST_LINK");
579 t << Qt::endl << Qt::endl;
580 } else if(project->isEmpty(v: "QMAKE_HPUX_SHLIB")) {
581 t << "\n\t";
582
583 if (!project->isActiveConfig(config: "unversioned_libname"))
584 t << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)";
585 else
586 t << "-$(DEL_FILE) $(TARGET)";
587
588 t << "\n\t" << var(var: "QMAKE_LINK_SHLIB_CMD");
589
590 if (!project->isActiveConfig(config: "unversioned_libname")) {
591 t << "\n\t"
592 << varGlue(var: "QMAKE_LN_SHLIB",before: "-",glue: " ",after: " $(TARGET) $(TARGET0)") << "\n\t"
593 << varGlue(var: "QMAKE_LN_SHLIB",before: "-",glue: " ",after: " $(TARGET) $(TARGET1)") << "\n\t"
594 << varGlue(var: "QMAKE_LN_SHLIB",before: "-",glue: " ",after: " $(TARGET) $(TARGET2)");
595 }
596 if (!destdir.isEmpty()) {
597 t << "\n\t"
598 << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
599 << "-$(MOVE) $(TARGET) " << destdir << "$(TARGET)";
600
601 if (!project->isActiveConfig(config: "unversioned_libname")) {
602 t << "\n\t"
603 << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
604 << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t"
605 << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t"
606 << "-$(MOVE) $(TARGET0) " << destdir << "$(TARGET0)\n\t"
607 << "-$(MOVE) $(TARGET1) " << destdir << "$(TARGET1)\n\t"
608 << "-$(MOVE) $(TARGET2) " << destdir << "$(TARGET2)";
609 }
610 }
611 if(!project->isEmpty(v: "QMAKE_POST_LINK"))
612 t << "\n\t" << var(var: "QMAKE_POST_LINK");
613 t << Qt::endl << Qt::endl;
614 } else {
615 t << "\n\t"
616 << "-$(DEL_FILE) $(TARGET) $(TARGET0)\n\t"
617 << var(var: "QMAKE_LINK_SHLIB_CMD") << "\n\t";
618 t << varGlue(var: "QMAKE_LN_SHLIB",before: "",glue: " ",after: " $(TARGET) $(TARGET0)");
619 if(!destdir.isEmpty())
620 t << "\n\t"
621 << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
622 << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
623 << "-$(MOVE) $(TARGET) " << destdir << "$(TARGET)\n\t"
624 << "-$(MOVE) $(TARGET0) " << destdir << "$(TARGET0)\n\t";
625 if(!project->isEmpty(v: "QMAKE_POST_LINK"))
626 t << "\n\t" << var(var: "QMAKE_POST_LINK");
627 t << Qt::endl << Qt::endl;
628 }
629 t << Qt::endl << Qt::endl;
630
631 if (! project->isActiveConfig(config: "plugin")) {
632 t << "staticlib: " << depVar(var: "TARGETA") << "\n\n";
633 t << depVar(var: "TARGETA") << ": " << depVar(var: "PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
634 if(do_incremental)
635 t << " $(INCREMENTAL_OBJECTS)";
636 t << ' ' << depVar(var: "POST_TARGETDEPS") << "\n\t";
637 if (!project->isEmpty(v: "QMAKE_PRE_LINK"))
638 t << var(var: "QMAKE_PRE_LINK") << "\n\t";
639 t << "-$(DEL_FILE) $(TARGETA) \n\t"
640 << var(var: "QMAKE_AR_CMD");
641 if(do_incremental)
642 t << " $(INCREMENTAL_OBJECTS)";
643 if (!project->isEmpty(v: "QMAKE_POST_LINK"))
644 t << "\n\t" << var(var: "QMAKE_POST_LINK");
645 if(!project->isEmpty(v: "QMAKE_RANLIB"))
646 t << "\n\t$(RANLIB) $(TARGETA)";
647 t << Qt::endl << Qt::endl;
648 }
649 } else {
650 QString destdir_r = project->first(variableName: "DESTDIR").toQString();
651 QString destdir_d = escapeDependencyPath(path: destdir_r);
652 QString destdir = escapeFilePath(path: destdir_r);
653 allDeps = ' ' + destdir_d + depVar(var: "TARGET");
654 t << "staticlib: " << destdir_d << "$(TARGET)\n\n"
655 << destdir_d << depVar(var: "TARGET") << ": " << depVar(var: "PRE_TARGETDEPS")
656 << " $(OBJECTS) $(OBJCOMP) " << depVar(var: "POST_TARGETDEPS") << "\n\t";
657 if (!destdir.isEmpty())
658 t << mkdir_p_asstring(dir: destdir, escape: false) << "\n\t";
659 if (!project->isEmpty(v: "QMAKE_PRE_LINK"))
660 t << var(var: "QMAKE_PRE_LINK") << "\n\t";
661 t << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
662 << var(var: "QMAKE_AR_CMD") << "\n";
663 if (!project->isEmpty(v: "QMAKE_POST_LINK"))
664 t << "\t" << var(var: "QMAKE_POST_LINK") << "\n";
665 if (!project->isEmpty(v: "QMAKE_RANLIB"))
666 t << "\t$(RANLIB) " << destdir << "$(TARGET)\n";
667 t << Qt::endl << Qt::endl;
668 }
669
670 writeMakeQmake(t);
671 if(project->isEmpty(v: "QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig(config: "no_autoqmake")) {
672 QStringList meta_files;
673 if (project->isActiveConfig(config: "create_libtool") && project->first(variableName: "TEMPLATE") == "lib") { //libtool
674 meta_files += libtoolFileName();
675 }
676 if(project->isActiveConfig(config: "create_pc") && project->first(variableName: "TEMPLATE") == "lib") { //pkg-config
677 meta_files += pkgConfigFileName();
678 }
679 if(!meta_files.isEmpty())
680 t << escapeDependencyPaths(paths: meta_files).join(sep: " ") << ": \n\t"
681 << "@$(QMAKE) -prl " << escapeFilePath(path: project->projectFile()) << ' ' << buildArgs(withExtra: true) << Qt::endl;
682 }
683
684 if (!project->isEmpty(v: "QMAKE_BUNDLE")) {
685 QHash<QString, QString> symlinks;
686 ProStringList &alldeps = project->values(v: "ALL_DEPS");
687 QString bundle_dir = project->first(variableName: "DESTDIR") + project->first(variableName: "QMAKE_BUNDLE") + "/";
688 if (!project->first(variableName: "QMAKE_PKGINFO").isEmpty()) {
689 ProString pkginfo = project->first(variableName: "QMAKE_PKGINFO");
690 ProString pkginfo_f = escapeFilePath(path: pkginfo);
691 ProString pkginfo_d = escapeDependencyPath(path: pkginfo);
692 bundledFiles << pkginfo;
693 alldeps << pkginfo;
694 QString destdir = bundle_dir + "Contents";
695 t << pkginfo_d << ": \n\t";
696 if (!destdir.isEmpty())
697 t << mkdir_p_asstring(dir: destdir) << "\n\t";
698 t << "@$(DEL_FILE) " << pkginfo_f << "\n\t"
699 << "@echo \"APPL"
700 << (project->isEmpty(v: "QMAKE_PKGINFO_TYPEINFO")
701 ? QString::fromLatin1(ba: "????") : project->first(variableName: "QMAKE_PKGINFO_TYPEINFO").left(len: 4))
702 << "\" > " << pkginfo_f << Qt::endl;
703 }
704 if (!project->first(variableName: "QMAKE_BUNDLE_RESOURCE_FILE").isEmpty()) {
705 ProString resources = project->first(variableName: "QMAKE_BUNDLE_RESOURCE_FILE");
706 ProString resources_f = escapeFilePath(path: resources);
707 ProString resources_d = escapeDependencyPath(path: resources);
708 bundledFiles << resources;
709 alldeps << resources;
710 QString destdir = bundle_dir + "Contents/Resources";
711 t << resources_d << ": \n\t";
712 t << mkdir_p_asstring(dir: destdir) << "\n\t";
713 t << "@touch " << resources_f << "\n\t\n";
714 }
715 //copy the plist
716 while (!project->isActiveConfig(config: "no_plist")) { // 'while' just to be able to 'break'
717 QString info_plist = project->first(variableName: "QMAKE_INFO_PLIST").toQString();
718 if (info_plist.isEmpty()) {
719 info_plist = escapeFilePath(path: specdir() + QDir::separator() + "Info.plist." + project->first(variableName: "TEMPLATE"));
720 } else if (!exists(file: Option::normalizePath(in: info_plist))) {
721 warn_msg(t: WarnLogic, fmt: "Could not resolve Info.plist: '%s'. Check if QMAKE_INFO_PLIST points to a valid file.",
722 info_plist.toLatin1().constData());
723 break;
724 } else {
725 info_plist = escapeFilePath(path: fileFixify(file: info_plist));
726 }
727 bool isFramework = project->first(variableName: "TEMPLATE") == "lib"
728 && !project->isActiveConfig(config: "plugin")
729 && project->isActiveConfig(config: "lib_bundle");
730 bool isShallowBundle = project->isActiveConfig(config: "shallow_bundle");
731 QString info_plist_out = bundle_dir +
732 (!isShallowBundle
733 ? (isFramework
734 ? ("Versions/" + project->first(variableName: "QMAKE_FRAMEWORK_VERSION") + "/Resources/")
735 : QString("Contents/"))
736 : QString())
737 + "Info.plist";
738 bundledFiles << info_plist_out;
739 alldeps << info_plist_out;
740 QString destdir = info_plist_out.section(in_sep: Option::dir_sep, start: 0, end: -2);
741 t << escapeDependencyPath(path: info_plist_out) << ": \n\t";
742 info_plist_out = escapeFilePath(path: info_plist_out);
743 if (!destdir.isEmpty())
744 t << mkdir_p_asstring(dir: destdir) << "\n\t";
745 ProStringList commonSedArgs;
746 if (!project->values(v: "VERSION").isEmpty()) {
747 const ProString shortVersion =
748 project->first(variableName: "VER_MAJ") + "." +
749 project->first(variableName: "VER_MIN");
750 commonSedArgs << "-e \"s,@SHORT_VERSION@," << shortVersion << ",g\" ";
751 commonSedArgs << "-e \"s,\\$${QMAKE_SHORT_VERSION}," << shortVersion << ",g\" ";
752 const ProString fullVersion =
753 project->first(variableName: "VER_MAJ") + "." +
754 project->first(variableName: "VER_MIN") + "." +
755 project->first(variableName: "VER_PAT");
756 commonSedArgs << "-e \"s,@FULL_VERSION@," << fullVersion << ",g\" ";
757 commonSedArgs << "-e \"s,\\$${QMAKE_FULL_VERSION}," << fullVersion << ",g\" ";
758 }
759 const ProString typeInfo = project->isEmpty(v: "QMAKE_PKGINFO_TYPEINFO")
760 ? QString::fromLatin1(ba: "????")
761 : project->first(variableName: "QMAKE_PKGINFO_TYPEINFO").left(len: 4);
762 commonSedArgs << "-e \"s,@TYPEINFO@," << typeInfo << ",g\" ";
763 commonSedArgs << "-e \"s,\\$${QMAKE_PKGINFO_TYPEINFO}," << typeInfo << ",g\" ";
764
765 QString bundlePrefix = project->first(variableName: "QMAKE_TARGET_BUNDLE_PREFIX").toQString();
766 if (bundlePrefix.isEmpty())
767 bundlePrefix = "com.yourcompany";
768 if (bundlePrefix.endsWith(s: "."))
769 bundlePrefix.chop(n: 1);
770 QString bundleIdentifier = bundlePrefix + "." + var(var: "QMAKE_BUNDLE");
771 if (bundleIdentifier.endsWith(s: ".app"))
772 bundleIdentifier.chop(n: 4);
773 if (bundleIdentifier.endsWith(s: ".framework"))
774 bundleIdentifier.chop(n: 10);
775 // replace invalid bundle id characters
776 bundleIdentifier = rfc1034Identifier(str: bundleIdentifier);
777 commonSedArgs << "-e \"s,@BUNDLEIDENTIFIER@," << bundleIdentifier << ",g\" ";
778 commonSedArgs << "-e \"s,\\$${PRODUCT_BUNDLE_IDENTIFIER}," << bundleIdentifier << ",g\" ";
779
780 commonSedArgs << "-e \"s,\\$${MACOSX_DEPLOYMENT_TARGET},"
781 << project->first(variableName: "QMAKE_MACOSX_DEPLOYMENT_TARGET").toQString() << ",g\" ";
782 commonSedArgs << "-e \"s,\\$${IPHONEOS_DEPLOYMENT_TARGET},"
783 << project->first(variableName: "QMAKE_IPHONEOS_DEPLOYMENT_TARGET").toQString() << ",g\" ";
784 commonSedArgs << "-e \"s,\\$${TVOS_DEPLOYMENT_TARGET},"
785 << project->first(variableName: "QMAKE_TVOS_DEPLOYMENT_TARGET").toQString() << ",g\" ";
786 commonSedArgs << "-e \"s,\\$${WATCHOS_DEPLOYMENT_TARGET},"
787 << project->first(variableName: "QMAKE_WATCHOS_DEPLOYMENT_TARGET").toQString() << ",g\" ";
788
789 QString launchScreen = var(var: "QMAKE_IOS_LAUNCH_SCREEN");
790 if (launchScreen.isEmpty())
791 launchScreen = QLatin1String("LaunchScreen");
792 else
793 launchScreen = QFileInfo(launchScreen).baseName();
794 commonSedArgs << "-e \"s,\\$${IOS_LAUNCH_SCREEN}," << launchScreen << ",g\" ";
795
796 if (!isFramework) {
797 ProString app_bundle_name = var(var: "QMAKE_APPLICATION_BUNDLE_NAME");
798 if (app_bundle_name.isEmpty())
799 app_bundle_name = var(var: "QMAKE_ORIG_TARGET");
800
801 ProString plugin_bundle_name = var(var: "QMAKE_PLUGIN_BUNDLE_NAME");
802 if (plugin_bundle_name.isEmpty())
803 plugin_bundle_name = var(var: "QMAKE_ORIG_TARGET");
804
805 QString icon = fileFixify(file: var(var: "ICON"));
806 t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
807 << "@plutil -convert xml1 -o - " << info_plist << " | "
808 << "sed ";
809 for (const ProString &arg : std::as_const(t&: commonSedArgs))
810 t << arg;
811 const QString iconName = icon.section(in_sep: Option::dir_sep, start: -1);
812 t << "-e \"s,@ICON@," << iconName << ",g\" "
813 << "-e \"s,\\$${ASSETCATALOG_COMPILER_APPICON_NAME}," << iconName << ",g\" "
814 << "-e \"s,@EXECUTABLE@," << app_bundle_name << ",g\" "
815 << "-e \"s,@LIBRARY@," << plugin_bundle_name << ",g\" "
816 << "-e \"s,\\$${EXECUTABLE_NAME}," << (!app_bundle_name.isEmpty() ? app_bundle_name : plugin_bundle_name) << ",g\" "
817 << "-e \"s,@TYPEINFO@,"<< typeInfo << ",g\" "
818 << "-e \"s,\\$${QMAKE_PKGINFO_TYPEINFO},"<< typeInfo << ",g\" "
819 << ">" << info_plist_out << Qt::endl;
820 //copy the icon
821 if (!project->isEmpty(v: "ICON")) {
822 QString dir = bundle_dir + "Contents/Resources/";
823 const QString icon_path = dir + icon.section(in_sep: Option::dir_sep, start: -1);
824 QString icon_path_f = escapeFilePath(path: icon_path);
825 bundledFiles << icon_path;
826 alldeps << icon_path;
827 t << escapeDependencyPath(path: icon_path) << ": " << escapeDependencyPath(path: icon) << "\n\t"
828 << mkdir_p_asstring(dir) << "\n\t"
829 << "@$(DEL_FILE) " << icon_path_f << "\n\t"
830 << "@$(COPY_FILE) " << escapeFilePath(path: icon) << ' ' << icon_path_f << Qt::endl;
831 }
832 } else {
833 ProString lib_bundle_name = var(var: "QMAKE_FRAMEWORK_BUNDLE_NAME");
834 if (lib_bundle_name.isEmpty())
835 lib_bundle_name = var(var: "QMAKE_ORIG_TARGET");
836
837 if (!isShallowBundle)
838 symlinks[bundle_dir + "Resources"] = "Versions/Current/Resources";
839 t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
840 << "@plutil -convert xml1 -o - " << info_plist << " | "
841 << "sed ";
842 for (const ProString &arg : std::as_const(t&: commonSedArgs))
843 t << arg;
844 t << "-e \"s,@LIBRARY@," << lib_bundle_name << ",g\" "
845 << "-e \"s,\\$${EXECUTABLE_NAME}," << lib_bundle_name << ",g\" "
846 << "-e \"s,@TYPEINFO@," << typeInfo << ",g\" "
847 << "-e \"s,\\$${QMAKE_PKGINFO_TYPEINFO}," << typeInfo << ",g\" "
848 << ">" << info_plist_out << Qt::endl;
849 }
850 break;
851 } // project->isActiveConfig("no_plist")
852 //copy other data
853 if(!project->isEmpty(v: "QMAKE_BUNDLE_DATA")) {
854 const ProStringList &bundle_data = project->values(v: "QMAKE_BUNDLE_DATA");
855 for(int i = 0; i < bundle_data.size(); i++) {
856 const ProStringList &files = project->values(v: ProKey(bundle_data[i] + ".files"));
857 QString path = bundle_dir;
858 const ProKey pkey(bundle_data[i] + ".path");
859 if (!project->isActiveConfig(config: "shallow_bundle")) {
860 const ProKey vkey(bundle_data[i] + ".version");
861 if (!project->isEmpty(v: vkey)) {
862 QString version = project->first(variableName: vkey) + "/" +
863 project->first(variableName: "QMAKE_FRAMEWORK_VERSION") + "/";
864 ProString name = project->first(variableName: pkey);
865 int pos = name.indexOf(c: '/');
866 if (pos > 0)
867 name = name.mid(off: 0, len: pos);
868 symlinks[Option::fixPathToTargetOS(in: path + name)] =
869 project->first(variableName: vkey) + "/Current/" + name;
870 path += version;
871 }
872 }
873 path += project->first(variableName: pkey).toQString();
874 path = Option::fixPathToTargetOS(in: path);
875 for(int file = 0; file < files.size(); file++) {
876 QString fn = files.at(i: file).toQString();
877 QString src = fileFixify(file: fn, fix: FileFixifyAbsolute);
878 if (!QFile::exists(fileName: src))
879 src = fileFixify(file: fn, fix: FileFixifyFromOutdir);
880 else
881 src = fileFixify(file: fn);
882 QString dst = path + Option::dir_sep + fileInfo(file: fn).fileName();
883 bundledFiles << dst;
884 alldeps << dst;
885 t << escapeDependencyPath(path: dst) << ": " << escapeDependencyPath(path: src) << "\n\t"
886 << mkdir_p_asstring(dir: path) << "\n\t";
887 src = escapeFilePath(path: src);
888 dst = escapeFilePath(path: dst);
889 QFileInfo fi(fileInfo(file: fn));
890 if(fi.isDir())
891 t << "@$(DEL_FILE) -r " << dst << "\n\t"
892 << "@$(COPY_DIR) " << src << " " << dst << Qt::endl;
893 else
894 t << "@$(DEL_FILE) " << dst << "\n\t"
895 << "@$(COPY_FILE) " << src << " " << dst << Qt::endl;
896 }
897 }
898 }
899 if (!symlinks.isEmpty()) {
900 QString bundle_dir_f = escapeFilePath(path: bundle_dir);
901 QHash<QString, QString>::ConstIterator symIt = symlinks.constBegin(),
902 symEnd = symlinks.constEnd();
903 for (; symIt != symEnd; ++symIt) {
904 bundledFiles << symIt.key();
905 alldeps << symIt.key();
906 t << escapeDependencyPath(path: symIt.key()) << ":\n\t"
907 << mkdir_p_asstring(dir: bundle_dir) << "\n\t"
908 << "@$(SYMLINK) " << escapeFilePath(path: symIt.value()) << ' ' << bundle_dir_f << Qt::endl;
909 }
910
911 if (!project->isActiveConfig(config: "shallow_bundle")) {
912 QString currentLink = bundle_dir + "Versions/Current";
913 QString currentLink_f = escapeDependencyPath(path: currentLink);
914 bundledFiles << currentLink;
915 alldeps << currentLink;
916 t << currentLink_f << ": $(MAKEFILE)\n\t"
917 << mkdir_p_asstring(dir: bundle_dir + "Versions") << "\n\t"
918 << "@-$(DEL_FILE) " << currentLink_f << "\n\t"
919 << "@$(SYMLINK) " << project->first(variableName: "QMAKE_FRAMEWORK_VERSION")
920 << ' ' << currentLink_f << Qt::endl;
921 }
922 }
923 }
924
925 t << Qt::endl << "all: " << deps
926 << valGlue(varList: escapeDependencyPaths(paths: project->values(v: "ALL_DEPS")), before: " \\\n\t\t", glue: " \\\n\t\t", after: "")
927 << allDeps << Qt::endl << Qt::endl;
928
929 t << "dist: distdir FORCE\n\t";
930 t << "(cd `dirname $(DISTDIR)` && $(TAR) $(DISTNAME).tar $(DISTNAME) && $(COMPRESS) $(DISTNAME).tar)"
931 " && $(MOVE) `dirname $(DISTDIR)`" << Option::dir_sep << "$(DISTNAME).tar.gz ."
932 " && $(DEL_FILE) -r $(DISTDIR)";
933 t << Qt::endl << Qt::endl;
934
935 t << "distdir: FORCE\n\t"
936 << mkdir_p_asstring(dir: "$(DISTDIR)", escape: false) << "\n\t"
937 << "$(COPY_FILE) --parents $(DIST) $(DISTDIR)" << Option::dir_sep << Qt::endl;
938 if(!project->isEmpty(v: "QMAKE_EXTRA_COMPILERS")) {
939 const ProStringList &quc = project->values(v: "QMAKE_EXTRA_COMPILERS");
940 for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
941 const ProStringList &var = project->values(v: ProKey(*it + ".input"));
942 for (ProStringList::ConstIterator var_it = var.begin(); var_it != var.end(); ++var_it) {
943 const ProStringList &val = project->values(v: (*var_it).toKey());
944 if(val.isEmpty())
945 continue;
946 t << "\t$(COPY_FILE) --parents " << escapeFilePaths(paths: val).join(sep: ' ')
947 << " $(DISTDIR)" << Option::dir_sep << Qt::endl;
948 }
949 }
950 }
951 if(!project->isEmpty(v: "TRANSLATIONS"))
952 t << "\t$(COPY_FILE) --parents " << fileVar(var: "TRANSLATIONS") << " $(DISTDIR)" << Option::dir_sep << Qt::endl;
953 t << Qt::endl << Qt::endl;
954
955 QString clean_targets = " compiler_clean " + depVar(var: "CLEAN_DEPS");
956 if(do_incremental) {
957 t << "incrclean:\n";
958 if(src_incremental)
959 t << "\t-$(DEL_FILE) $(INCREMENTAL_OBJECTS)\n";
960 t << Qt::endl;
961 }
962
963 t << "clean:" << clean_targets << "\n\t";
964 if(!project->isEmpty(v: "OBJECTS")) {
965 t << "-$(DEL_FILE) $(OBJECTS)\n\t";
966 }
967 if(doPrecompiledHeaders() && !project->isEmpty(v: "PRECOMPILED_HEADER")) {
968 ProStringList precomp_files;
969 ProString precomph_out_dir;
970
971 if(!project->isEmpty(v: "PRECOMPILED_DIR"))
972 precomph_out_dir = project->first(variableName: "PRECOMPILED_DIR");
973 precomph_out_dir += project->first(variableName: "QMAKE_ORIG_TARGET");
974 precomph_out_dir += project->first(variableName: "QMAKE_PCH_OUTPUT_EXT");
975
976 if (project->isActiveConfig(config: "icc_pch_style")) {
977 // icc style
978 ProString pchBaseName = project->first(variableName: "QMAKE_ORIG_TARGET");
979 ProStringList pchArchs = project->values(v: "QMAKE_PCH_ARCHS");
980 if (pchArchs.isEmpty())
981 pchArchs << ProString(); // normal single-arch PCH
982 for (const ProString &arch : std::as_const(t&: pchArchs)) {
983 ProString pchOutput;
984 if (!project->isEmpty(v: "PRECOMPILED_DIR"))
985 pchOutput = project->first(variableName: "PRECOMPILED_DIR");
986 pchOutput += pchBaseName + project->first(variableName: "QMAKE_PCH_OUTPUT_EXT");
987 if (!arch.isEmpty())
988 pchOutput = ProString(pchOutput.toQString().replace(
989 QStringLiteral("${QMAKE_PCH_ARCH}"), after: arch.toQString()));
990
991 ProString sourceFile = pchOutput + Option::cpp_ext.first();
992 ProString objectFile = createObjectList(sources: ProStringList(sourceFile)).first();
993 precomp_files << precomph_out_dir << sourceFile << objectFile;
994 }
995 } else {
996 // gcc style (including clang_pch_style)
997 precomph_out_dir += Option::dir_sep;
998
999 ProString header_prefix = project->first(variableName: "QMAKE_PRECOMP_PREFIX");
1000 ProString header_suffix = project->isActiveConfig(config: "clang_pch_style")
1001 ? project->first(variableName: "QMAKE_PCH_OUTPUT_EXT") : "";
1002
1003 for (const ProString &compiler : project->values(v: "QMAKE_BUILTIN_COMPILERS")) {
1004 if (project->isEmpty(v: ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE")))
1005 continue;
1006 ProString language = project->first(variableName: ProKey("QMAKE_LANGUAGE_" + compiler));
1007 if (language.isEmpty())
1008 continue;
1009
1010 ProStringList pchArchs = project->values(v: "QMAKE_PCH_ARCHS");
1011 if (pchArchs.isEmpty())
1012 pchArchs << ProString(); // normal single-arch PCH
1013 for (const ProString &arch : std::as_const(t&: pchArchs)) {
1014 QString file = precomph_out_dir + header_prefix + language + header_suffix;
1015 if (!arch.isEmpty())
1016 file.replace(QStringLiteral("${QMAKE_PCH_ARCH}"), after: arch.toQString());
1017 precomp_files += file;
1018 }
1019 }
1020 }
1021 t << "-$(DEL_FILE) " << escapeFilePaths(paths: precomp_files).join(sep: ' ') << "\n\t";
1022 }
1023 if(src_incremental)
1024 t << "-$(DEL_FILE) $(INCREMENTAL_OBJECTS)\n\t";
1025 t << fileVarGlue(var: "QMAKE_CLEAN",before: "-$(DEL_FILE) ",glue: " ",after: "\n\t")
1026 << "-$(DEL_FILE) *~ core *.core\n"
1027 << fileVarGlue(var: "CLEAN_FILES",before: "\t-$(DEL_FILE) ",glue: " ",after: "") << Qt::endl << Qt::endl;
1028
1029 ProString destdir = project->first(variableName: "DESTDIR");
1030 if (!destdir.isEmpty() && !destdir.endsWith(sub: Option::dir_sep))
1031 destdir += Option::dir_sep;
1032 t << "distclean: clean " << depVar(var: "DISTCLEAN_DEPS") << '\n';
1033 if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
1034 QString bundlePath = escapeFilePath(path: destdir + project->first(variableName: "QMAKE_BUNDLE"));
1035 t << "\t-$(DEL_FILE) -r " << bundlePath << Qt::endl;
1036 } else if (project->isActiveConfig(config: "staticlib") || project->isActiveConfig(config: "plugin")) {
1037 t << "\t-$(DEL_FILE) " << escapeFilePath(path: destdir) << "$(TARGET) \n";
1038 } else if (project->values(v: "QMAKE_APP_FLAG").isEmpty()) {
1039 destdir = escapeFilePath(path: destdir);
1040 t << "\t-$(DEL_FILE) " << destdir << "$(TARGET) \n";
1041 if (!project->isActiveConfig(config: "unversioned_libname")) {
1042 t << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) "
1043 << destdir << "$(TARGET2) $(TARGETA)\n";
1044 } else {
1045 t << "\t-$(DEL_FILE) $(TARGETA)\n";
1046 }
1047 } else {
1048 t << "\t-$(DEL_FILE) $(TARGET) \n";
1049 }
1050 t << fileVarGlue(var: "QMAKE_DISTCLEAN",before: "\t-$(DEL_FILE) ",glue: " ",after: "\n");
1051 {
1052 QString ofile = fileFixify(file: Option::output.fileName());
1053 if(!ofile.isEmpty())
1054 t << "\t-$(DEL_FILE) " << escapeFilePath(path: ofile) << Qt::endl;
1055 }
1056 t << Qt::endl << Qt::endl;
1057
1058 t << "####### Sub-libraries\n\n";
1059 if (!project->values(v: "SUBLIBS").isEmpty()) {
1060 ProString libdir = "tmp/";
1061 if (!project->isEmpty(v: "SUBLIBS_DIR"))
1062 libdir = project->first(variableName: "SUBLIBS_DIR");
1063 const ProStringList &l = project->values(v: "SUBLIBS");
1064 for (it = l.begin(); it != l.end(); ++it)
1065 t << escapeDependencyPath(path: libdir + project->first(variableName: "QMAKE_PREFIX_STATICLIB") + (*it) + '.'
1066 + project->first(variableName: "QMAKE_EXTENSION_STATICLIB")) << ":\n\t"
1067 << var(var: ProKey("MAKELIB" + *it)) << Qt::endl << Qt::endl;
1068 }
1069
1070 if(doPrecompiledHeaders() && !project->isEmpty(v: "PRECOMPILED_HEADER")) {
1071 QString pchInput = project->first(variableName: "PRECOMPILED_HEADER").toQString();
1072 t << "###### Precompiled headers\n";
1073 for (const ProString &compiler : project->values(v: "QMAKE_BUILTIN_COMPILERS")) {
1074 QString pchOutputDir;
1075 QString pchFlags = var(var: ProKey("QMAKE_" + compiler + "FLAGS_PRECOMPILE"));
1076 if(pchFlags.isEmpty())
1077 continue;
1078
1079 QString cflags;
1080 if (compiler == "C" || compiler == "OBJC")
1081 cflags += " $(CFLAGS)";
1082 else
1083 cflags += " $(CXXFLAGS)";
1084
1085 ProStringList pchArchs = project->values(v: "QMAKE_PCH_ARCHS");
1086 if (pchArchs.isEmpty())
1087 pchArchs << ProString(); // normal single-arch PCH
1088 ProString pchBaseName = project->first(variableName: "QMAKE_ORIG_TARGET");
1089 ProString pchOutput;
1090 if(!project->isEmpty(v: "PRECOMPILED_DIR"))
1091 pchOutput = project->first(variableName: "PRECOMPILED_DIR");
1092 pchOutput += pchBaseName;
1093 pchOutput += project->first(variableName: "QMAKE_PCH_OUTPUT_EXT");
1094
1095 if (!project->isActiveConfig(config: "icc_pch_style")) {
1096 // gcc style (including clang_pch_style)
1097 ProString header_prefix = project->first(variableName: "QMAKE_PRECOMP_PREFIX");
1098 ProString header_suffix = project->isActiveConfig(config: "clang_pch_style")
1099 ? project->first(variableName: "QMAKE_PCH_OUTPUT_EXT") : "";
1100 pchOutput += Option::dir_sep;
1101 pchOutputDir = pchOutput.toQString();
1102
1103 QString language = project->first(variableName: ProKey("QMAKE_LANGUAGE_" + compiler)).toQString();
1104 if (language.isEmpty())
1105 continue;
1106
1107 pchOutput += header_prefix + language + header_suffix;
1108 }
1109 pchFlags.replace(before: QLatin1String("${QMAKE_PCH_INPUT}"), after: escapeFilePath(path: pchInput))
1110 .replace(before: QLatin1String("${QMAKE_PCH_OUTPUT_BASE}"), after: escapeFilePath(path: pchBaseName.toQString()));
1111 for (const ProString &arch : std::as_const(t&: pchArchs)) {
1112 auto pchArchOutput = pchOutput.toQString();
1113 if (!arch.isEmpty())
1114 pchArchOutput.replace(QStringLiteral("${QMAKE_PCH_ARCH}"), after: arch.toQString());
1115
1116 const auto pchFilePath_d = escapeDependencyPath(path: pchArchOutput);
1117 if (!arch.isEmpty()) {
1118 t << pchFilePath_d << ": " << "EXPORT_ARCH_ARGS = -arch " << arch << "\n\n";
1119 t << pchFilePath_d << ": "
1120 << "EXPORT_QMAKE_XARCH_CFLAGS = $(EXPORT_QMAKE_XARCH_CFLAGS_" << arch << ")" << "\n\n";
1121 t << pchFilePath_d << ": "
1122 << "EXPORT_QMAKE_XARCH_LFLAGS = $(EXPORT_QMAKE_XARCH_LFLAGS_" << arch << ")" << "\n\n";
1123 }
1124 t << pchFilePath_d << ": " << escapeDependencyPath(path: pchInput) << ' '
1125 << finalizeDependencyPaths(paths: findDependencies(pchInput)).join(sep: " \\\n\t\t");
1126 if (project->isActiveConfig(config: "icc_pch_style")) {
1127 QString sourceFile = pchArchOutput + Option::cpp_ext.first();
1128 QString sourceFile_f = escapeFilePath(path: sourceFile);
1129 QString objectFile = createObjectList(sources: ProStringList(sourceFile)).first().toQString();
1130
1131 pchFlags.replace(before: QLatin1String("${QMAKE_PCH_TEMP_SOURCE}"), after: sourceFile_f)
1132 .replace(before: QLatin1String("${QMAKE_PCH_TEMP_OBJECT}"), after: escapeFilePath(path: objectFile));
1133
1134 t << "\n\techo \"// Automatically generated, do not modify\" > " << sourceFile_f
1135 << "\n\trm -f " << escapeFilePath(path: pchArchOutput);
1136 } else {
1137 QString outDir = pchOutputDir;
1138 if (!arch.isEmpty())
1139 outDir.replace(QStringLiteral("${QMAKE_PCH_ARCH}"), after: arch.toQString());
1140 t << "\n\t" << mkdir_p_asstring(dir: outDir);
1141 }
1142
1143 auto pchArchFlags = pchFlags;
1144 pchArchFlags.replace(before: QLatin1String("${QMAKE_PCH_OUTPUT}"), after: escapeFilePath(path: pchArchOutput));
1145
1146 QString compilerExecutable;
1147 if (compiler == "C" || compiler == "OBJC")
1148 compilerExecutable = "$(CC)";
1149 else
1150 compilerExecutable = "$(CXX)";
1151
1152 // compile command
1153 t << "\n\t" << compilerExecutable << cflags << " $(INCPATH) " << pchArchFlags << Qt::endl << Qt::endl;
1154 }
1155 }
1156 }
1157
1158 writeExtraTargets(t);
1159 writeExtraCompilerTargets(t);
1160}
1161
1162void UnixMakefileGenerator::init2()
1163{
1164 if(project->isEmpty(v: "QMAKE_FRAMEWORK_VERSION"))
1165 project->values(v: "QMAKE_FRAMEWORK_VERSION").append(t: project->first(variableName: "VER_MAJ"));
1166
1167 if (project->first(variableName: "TEMPLATE") == "aux") {
1168 project->values(v: "PRL_TARGET") = {
1169 project->first(variableName: "QMAKE_PREFIX_STATICLIB") +
1170 project->first(variableName: "TARGET")
1171 };
1172 } else if (!project->values(v: "QMAKE_APP_FLAG").isEmpty()) {
1173 if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
1174 ProString bundle_loc = project->first(variableName: "QMAKE_BUNDLE_LOCATION");
1175 if(!bundle_loc.isEmpty() && !bundle_loc.startsWith(sub: "/"))
1176 bundle_loc.prepend(other: "/");
1177 if(!bundle_loc.endsWith(sub: "/"))
1178 bundle_loc += "/";
1179 project->values(v: "TARGET").first().prepend(other: project->first(variableName: "QMAKE_BUNDLE") + bundle_loc);
1180 }
1181 if(!project->isEmpty(v: "TARGET"))
1182 project->values(v: "TARGET").first().prepend(other: project->first(variableName: "DESTDIR"));
1183 } else if (project->isActiveConfig(config: "staticlib")) {
1184 project->values(v: "PRL_TARGET") =
1185 project->values(v: "TARGET").first().prepend(other: project->first(variableName: "QMAKE_PREFIX_STATICLIB"));
1186 project->values(v: "TARGET").first() += "." + project->first(variableName: "QMAKE_EXTENSION_STATICLIB");
1187 if(project->values(v: "QMAKE_AR_CMD").isEmpty())
1188 project->values(v: "QMAKE_AR_CMD").append(t: "$(AR) $(DESTDIR)$(TARGET) $(OBJECTS)");
1189 } else {
1190 project->values(v: "TARGETA").append(t: project->first(variableName: "DESTDIR") + project->first(variableName: "QMAKE_PREFIX_STATICLIB")
1191 + project->first(variableName: "TARGET") + "." + project->first(variableName: "QMAKE_EXTENSION_STATICLIB"));
1192
1193 ProStringList &ar_cmd = project->values(v: "QMAKE_AR_CMD");
1194 if (!ar_cmd.isEmpty())
1195 ar_cmd[0] = ar_cmd.at(i: 0).toQString().replace(before: QLatin1String("(TARGET)"), after: QLatin1String("(TARGETA)"));
1196 else
1197 ar_cmd.append(t: "$(AR) $(TARGETA) $(OBJECTS)");
1198 if (!project->isEmpty(v: "QMAKE_BUNDLE")) {
1199 project->values(v: "PRL_TARGET").prepend(t: project->first(variableName: "QMAKE_BUNDLE") +
1200 "/Versions/" + project->first(variableName: "QMAKE_FRAMEWORK_VERSION") +
1201 "/Resources/" + project->first(variableName: "TARGET"));
1202 ProString bundle_loc = project->first(variableName: "QMAKE_BUNDLE_LOCATION");
1203 if(!bundle_loc.isEmpty() && !bundle_loc.startsWith(sub: "/"))
1204 bundle_loc.prepend(other: "/");
1205 if(!bundle_loc.endsWith(sub: "/"))
1206 bundle_loc += "/";
1207 const QString target = project->first(variableName: "QMAKE_BUNDLE") +
1208 bundle_loc + project->first(variableName: "TARGET");
1209 project->values(v: "TARGET_").append(t: target);
1210 if (!project->isActiveConfig(config: "shallow_bundle")) {
1211 project->values(v: "TARGET_x.y").append(t: project->first(variableName: "QMAKE_BUNDLE") +
1212 "/Versions/" +
1213 project->first(variableName: "QMAKE_FRAMEWORK_VERSION") +
1214 bundle_loc + project->first(variableName: "TARGET"));
1215 } else {
1216 project->values(v: "TARGET_x.y").append(t: target);
1217 }
1218 } else if(project->isActiveConfig(config: "plugin")) {
1219 QString prefix;
1220 if(!project->isActiveConfig(config: "no_plugin_name_prefix"))
1221 prefix = "lib";
1222 project->values(v: "PRL_TARGET").prepend(t: prefix + project->first(variableName: "TARGET"));
1223 project->values(v: "TARGET_x.y.z").append(t: prefix +
1224 project->first(variableName: "TARGET") + "." +
1225 project->first(variableName: "QMAKE_EXTENSION_PLUGIN"));
1226 if(project->isActiveConfig(config: "lib_version_first"))
1227 project->values(v: "TARGET_x").append(t: prefix + project->first(variableName: "TARGET") + "." +
1228 project->first(variableName: "VER_MAJ") + "." +
1229 project->first(variableName: "QMAKE_EXTENSION_PLUGIN"));
1230 else
1231 project->values(v: "TARGET_x").append(t: prefix + project->first(variableName: "TARGET") + "." +
1232 project->first(variableName: "QMAKE_EXTENSION_PLUGIN") +
1233 "." + project->first(variableName: "VER_MAJ"));
1234 project->values(v: "TARGET") = project->values(v: "TARGET_x.y.z");
1235 } else if (!project->isEmpty(v: "QMAKE_HPUX_SHLIB")) {
1236 project->values(v: "PRL_TARGET").prepend(t: "lib" + project->first(variableName: "TARGET"));
1237 project->values(v: "TARGET_").append(t: "lib" + project->first(variableName: "TARGET") + ".sl");
1238 if(project->isActiveConfig(config: "lib_version_first"))
1239 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "VER_MAJ") + "." +
1240 project->first(variableName: "TARGET"));
1241 else
1242 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1243 project->first(variableName: "VER_MAJ"));
1244 project->values(v: "TARGET") = project->values(v: "TARGET_x");
1245 } else if (!project->isEmpty(v: "QMAKE_AIX_SHLIB")) {
1246 project->values(v: "PRL_TARGET").prepend(t: "lib" + project->first(variableName: "TARGET"));
1247 project->values(v: "TARGET_").append(t: project->first(variableName: "QMAKE_PREFIX_STATICLIB") + project->first(variableName: "TARGET")
1248 + "." + project->first(variableName: "QMAKE_EXTENSION_STATICLIB"));
1249 if(project->isActiveConfig(config: "lib_version_first")) {
1250 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1251 project->first(variableName: "VER_MAJ") + "." +
1252 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1253 project->values(v: "TARGET_x.y").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1254 project->first(variableName: "VER_MAJ") +
1255 "." + project->first(variableName: "VER_MIN") + "." +
1256 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1257 project->values(v: "TARGET_x.y.z").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1258 project->first(variableName: "VER_MAJ") + "." +
1259 project->first(variableName: "VER_MIN") + "." +
1260 project->first(variableName: "VER_PAT") + "." +
1261 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1262 } else {
1263 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1264 project->first(variableName: "QMAKE_EXTENSION_SHLIB") +
1265 "." + project->first(variableName: "VER_MAJ"));
1266 project->values(v: "TARGET_x.y").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1267 project->first(variableName: "QMAKE_EXTENSION_SHLIB") +
1268 "." + project->first(variableName: "VER_MAJ") +
1269 "." + project->first(variableName: "VER_MIN"));
1270 project->values(v: "TARGET_x.y.z").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1271 project->first(variableName: "QMAKE_EXTENSION_SHLIB") + "." +
1272 project->first(variableName: "VER_MAJ") + "." +
1273 project->first(variableName: "VER_MIN") + "." +
1274 project->first(variableName: "VER_PAT"));
1275 }
1276 project->values(v: "TARGET") = project->values(v: "TARGET_x.y.z");
1277 } else {
1278 project->values(v: "PRL_TARGET").prepend(t: "lib" + project->first(variableName: "TARGET"));
1279 project->values(v: "TARGET_").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1280 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1281 if(project->isActiveConfig(config: "lib_version_first")) {
1282 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1283 project->first(variableName: "VER_MAJ") + "." +
1284 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1285 project->values(v: "TARGET_x.y").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1286 project->first(variableName: "VER_MAJ") +
1287 "." + project->first(variableName: "VER_MIN") + "." +
1288 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1289 project->values(v: "TARGET_x.y.z").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1290 project->first(variableName: "VER_MAJ") + "." +
1291 project->first(variableName: "VER_MIN") + "." +
1292 project->first(variableName: "VER_PAT") + "." +
1293 project->first(variableName: "QMAKE_EXTENSION_SHLIB"));
1294 } else {
1295 project->values(v: "TARGET_x").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1296 project->first(variableName: "QMAKE_EXTENSION_SHLIB") +
1297 "." + project->first(variableName: "VER_MAJ"));
1298 project->values(v: "TARGET_x.y").append(t: "lib" + project->first(variableName: "TARGET") + "." +
1299 project->first(variableName: "QMAKE_EXTENSION_SHLIB")
1300 + "." + project->first(variableName: "VER_MAJ") +
1301 "." + project->first(variableName: "VER_MIN"));
1302 project->values(v: "TARGET_x.y.z").append(t: "lib" + project->first(variableName: "TARGET") +
1303 "." +
1304 project->first(
1305 variableName: "QMAKE_EXTENSION_SHLIB") + "." +
1306 project->first(variableName: "VER_MAJ") + "." +
1307 project->first(variableName: "VER_MIN") + "." +
1308 project->first(variableName: "VER_PAT"));
1309 }
1310 if (project->isActiveConfig(config: "unversioned_libname"))
1311 project->values(v: "TARGET") = project->values(v: "TARGET_");
1312 else
1313 project->values(v: "TARGET") = project->values(v: "TARGET_x.y.z");
1314 }
1315 if (!project->values(v: "QMAKE_LFLAGS_SONAME").isEmpty()) {
1316 ProString soname;
1317 if(project->isActiveConfig(config: "plugin")) {
1318 if(!project->values(v: "TARGET").isEmpty())
1319 soname += project->first(variableName: "TARGET");
1320 } else if(!project->isEmpty(v: "QMAKE_BUNDLE")) {
1321 soname += project->first(variableName: "TARGET_x.y");
1322 } else if(project->isActiveConfig(config: "unversioned_soname")) {
1323 soname = "lib" + project->first(variableName: "QMAKE_ORIG_TARGET")
1324 + "." + project->first(variableName: "QMAKE_EXTENSION_SHLIB");
1325 } else if(!project->values(v: "TARGET_x").isEmpty()) {
1326 soname += project->first(variableName: "TARGET_x");
1327 }
1328 if(!soname.isEmpty()) {
1329 if(project->isActiveConfig(config: "absolute_library_soname") &&
1330 project->values(v: "INSTALLS").indexOf(t: "target") != -1 &&
1331 !project->isEmpty(v: "target.path")) {
1332 QString instpath = Option::fixPathToTargetOS(in: project->first(variableName: "target.path").toQString());
1333 if(!instpath.endsWith(s: Option::dir_sep))
1334 instpath += Option::dir_sep;
1335 soname.prepend(other: instpath);
1336 } else if (!project->isEmpty(v: "QMAKE_SONAME_PREFIX")) {
1337 QString sonameprefix = project->first(variableName: "QMAKE_SONAME_PREFIX").toQString();
1338 if (!sonameprefix.startsWith(c: '@'))
1339 sonameprefix = Option::fixPathToTargetOS(in: sonameprefix, fix_env: false);
1340 if (!sonameprefix.endsWith(s: Option::dir_sep))
1341 sonameprefix += Option::dir_sep;
1342 soname.prepend(other: sonameprefix);
1343 }
1344 project->values(v: "QMAKE_LFLAGS_SONAME").first() += escapeFilePath(path: soname);
1345 }
1346 }
1347 if (project->values(v: "QMAKE_LINK_SHLIB_CMD").isEmpty())
1348 project->values(v: "QMAKE_LINK_SHLIB_CMD").append(
1349 t: "$(LINK) $(LFLAGS) " + project->first(variableName: "QMAKE_LINK_O_FLAG") + "$(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)");
1350 }
1351 if (!project->values(v: "QMAKE_APP_FLAG").isEmpty() || project->first(variableName: "TEMPLATE") == "aux") {
1352 project->values(v: "QMAKE_CFLAGS") += project->values(v: "QMAKE_CFLAGS_APP");
1353 project->values(v: "QMAKE_CXXFLAGS") += project->values(v: "QMAKE_CXXFLAGS_APP");
1354 project->values(v: "QMAKE_LFLAGS") += project->values(v: "QMAKE_LFLAGS_APP");
1355 } else if (project->isActiveConfig(config: "dll")) {
1356 if(!project->isActiveConfig(config: "plugin") || !project->isActiveConfig(config: "plugin_no_share_shlib_cflags")) {
1357 project->values(v: "QMAKE_CFLAGS") += project->values(v: "QMAKE_CFLAGS_SHLIB");
1358 project->values(v: "QMAKE_CXXFLAGS") += project->values(v: "QMAKE_CXXFLAGS_SHLIB");
1359 }
1360 if (project->isActiveConfig(config: "plugin")) {
1361 project->values(v: "QMAKE_CFLAGS") += project->values(v: "QMAKE_CFLAGS_PLUGIN");
1362 project->values(v: "QMAKE_CXXFLAGS") += project->values(v: "QMAKE_CXXFLAGS_PLUGIN");
1363 project->values(v: "QMAKE_LFLAGS") += project->values(v: "QMAKE_LFLAGS_PLUGIN");
1364 if (project->isActiveConfig(config: "plugin_with_soname"))
1365 project->values(v: "QMAKE_LFLAGS") += project->values(v: "QMAKE_LFLAGS_SONAME");
1366 } else {
1367 project->values(v: "QMAKE_LFLAGS") += project->values(v: "QMAKE_LFLAGS_SHLIB");
1368 if(!project->isEmpty(v: "QMAKE_LFLAGS_COMPAT_VERSION")) {
1369 if(project->isEmpty(v: "COMPAT_VERSION"))
1370 project->values(v: "QMAKE_LFLAGS") += QString(project->first(variableName: "QMAKE_LFLAGS_COMPAT_VERSION") +
1371 project->first(variableName: "VER_MAJ") + "." +
1372 project->first(variableName: "VER_MIN"));
1373 else
1374 project->values(v: "QMAKE_LFLAGS") += QString(project->first(variableName: "QMAKE_LFLAGS_COMPAT_VERSION") +
1375 project->first(variableName: "COMPATIBILITY_VERSION"));
1376 }
1377 if(!project->isEmpty(v: "QMAKE_LFLAGS_VERSION")) {
1378 project->values(v: "QMAKE_LFLAGS") += QString(project->first(variableName: "QMAKE_LFLAGS_VERSION") +
1379 project->first(variableName: "VER_MAJ") + "." +
1380 project->first(variableName: "VER_MIN") + "." +
1381 project->first(variableName: "VER_PAT"));
1382 }
1383 project->values(v: "QMAKE_LFLAGS") += project->values(v: "QMAKE_LFLAGS_SONAME");
1384 }
1385 }
1386
1387 if (include_deps && project->isActiveConfig(config: "gcc_MD_depends")) {
1388 ProString MD_flag("-MD");
1389 project->values(v: "QMAKE_CFLAGS") += MD_flag;
1390 project->values(v: "QMAKE_CXXFLAGS") += MD_flag;
1391 }
1392}
1393
1394QString
1395UnixMakefileGenerator::libtoolFileName(bool fixify)
1396{
1397 QString ret = var(var: "TARGET");
1398 int slsh = ret.lastIndexOf(s: Option::dir_sep);
1399 if(slsh != -1)
1400 ret = ret.right(n: ret.size() - slsh - 1);
1401 int dot = ret.indexOf(c: '.');
1402 if(dot != -1)
1403 ret = ret.left(n: dot);
1404 ret += Option::libtool_ext;
1405 if(!project->isEmpty(v: "QMAKE_LIBTOOL_DESTDIR"))
1406 ret.prepend(s: project->first(variableName: "QMAKE_LIBTOOL_DESTDIR") + Option::dir_sep);
1407 if(fixify) {
1408 if(QDir::isRelativePath(path: ret) && !project->isEmpty(v: "DESTDIR"))
1409 ret.prepend(s: project->first(variableName: "DESTDIR").toQString());
1410 ret = fileFixify(file: ret, fix: FileFixifyBackwards);
1411 }
1412 return ret;
1413}
1414
1415static std::pair<ProStringList, ProStringList>
1416splitFrameworksAndLibs(const ProStringList &linkArgs)
1417{
1418 std::pair<ProStringList, ProStringList> result;
1419 bool frameworkArg = false;
1420 for (auto arg : linkArgs) {
1421 if (frameworkArg) {
1422 frameworkArg = false;
1423 result.second += arg;
1424 } else if (arg == "-framework") {
1425 frameworkArg = true;
1426 result.second += arg;
1427 } else {
1428 result.first += arg;
1429 }
1430 }
1431 return result;
1432}
1433
1434void
1435UnixMakefileGenerator::writeLibtoolFile()
1436{
1437 auto fixDependencyLibs
1438 = [this](const ProStringList &libs)
1439 {
1440 ProStringList result;
1441 for (auto lib : libs) {
1442 auto fi = fileInfo(file: lib.toQString());
1443 if (fi.isAbsolute()) {
1444 const QString libDirArg = "-L" + fi.path();
1445 if (!result.contains(str: libDirArg))
1446 result += libDirArg;
1447 QString namespec = fi.fileName();
1448 int dotPos = namespec.lastIndexOf(c: '.');
1449 if (dotPos != -1 && namespec.startsWith(s: "lib")) {
1450 namespec.truncate(pos: dotPos);
1451 namespec.remove(i: 0, len: 3);
1452 } else {
1453 debug_msg(level: 1, fmt: "Ignoring dependency library %s",
1454 lib.toLatin1().constData());
1455 continue;
1456 }
1457 result += "-l" + namespec;
1458 } else {
1459 result += lib;
1460 }
1461 }
1462 return result;
1463 };
1464
1465 QString fname = libtoolFileName(), lname = fname;
1466 debug_msg(level: 1, fmt: "Writing libtool file %s", fname.toLatin1().constData());
1467 mkdir(dir: fileInfo(file: fname).path());
1468 int slsh = lname.lastIndexOf(s: Option::dir_sep);
1469 if(slsh != -1)
1470 lname = lname.right(n: lname.size() - slsh - 1);
1471 QFile ft(fname);
1472 if(!ft.open(flags: QIODevice::WriteOnly))
1473 return;
1474 QString ffname(fileFixify(file: fname));
1475 project->values(v: "ALL_DEPS").append(t: ffname);
1476 project->values(v: "QMAKE_DISTCLEAN").append(t: ffname);
1477
1478 QTextStream t(&ft);
1479 t << "# " << lname << " - a libtool library file\n";
1480 t << "# Generated by qmake/libtool (" QMAKE_VERSION_STR ") (Qt "
1481 << QT_VERSION_STR << ")";
1482 t << "\n";
1483
1484 t << "# The name that we can dlopen(3).\n"
1485 << "dlname='" << fileVar(var: project->isActiveConfig(config: "plugin") ? "TARGET" : "TARGET_x")
1486 << "'\n\n";
1487
1488 t << "# Names of this library.\n";
1489 t << "library_names='";
1490 if(project->isActiveConfig(config: "plugin")) {
1491 t << fileVar(var: "TARGET");
1492 } else {
1493 if (project->isEmpty(v: "QMAKE_HPUX_SHLIB"))
1494 t << fileVar(var: "TARGET_x.y.z") << ' ';
1495 t << fileVar(var: "TARGET_x") << ' ' << fileVar(var: "TARGET_");
1496 }
1497 t << "'\n\n";
1498
1499 t << "# The name of the static archive.\n"
1500 << "old_library='" << escapeFilePath(path: lname.left(n: lname.size()-Option::libtool_ext.size()))
1501 << ".a'\n\n";
1502
1503 t << "# Libraries that this one depends upon.\n";
1504 static const ProKey libVars[] = { "LIBS", "QMAKE_LIBS" };
1505 ProStringList libs;
1506 for (auto var : libVars)
1507 libs += fixLibFlags(var);
1508 ProStringList frameworks;
1509 std::tie(args&: libs, args&: frameworks) = splitFrameworksAndLibs(linkArgs: libs);
1510 t << "dependency_libs='" << fixDependencyLibs(libs).join(sep: ' ') << "'\n\n";
1511 if (!frameworks.isEmpty()) {
1512 t << "# Frameworks that this library depends upon.\n";
1513 t << "inherited_linker_flags='" << frameworks.join(sep: ' ') << "'\n\n";
1514 }
1515
1516 t << "# Version information for " << lname << "\n";
1517 int maj = project->first(variableName: "VER_MAJ").toInt();
1518 int min = project->first(variableName: "VER_MIN").toInt();
1519 int pat = project->first(variableName: "VER_PAT").toInt();
1520 t << "current=" << (10*maj + min) << "\n" // best I can think of
1521 << "age=0\n"
1522 << "revision=" << pat << "\n\n";
1523
1524 t << "# Is this an already installed library.\n"
1525 "installed=yes\n\n"; // ###
1526
1527 t << "# Files to dlopen/dlpreopen.\n"
1528 "dlopen=''\n"
1529 "dlpreopen=''\n\n";
1530
1531 ProString install_dir = project->first(variableName: "QMAKE_LIBTOOL_LIBDIR");
1532 if(install_dir.isEmpty())
1533 install_dir = project->first(variableName: "target.path");
1534 if(install_dir.isEmpty())
1535 install_dir = project->first(variableName: "DESTDIR");
1536 t << "# Directory that this library needs to be installed in:\n"
1537 "libdir='" << Option::fixPathToTargetOS(in: install_dir.toQString(), fix_env: false) << "'\n";
1538}
1539
1540bool UnixMakefileGenerator::writeObjectsPart(QTextStream &t, bool do_incremental)
1541{
1542 bool src_incremental = false;
1543 QString objectsLinkLine;
1544 const ProStringList &objs = project->values(v: "OBJECTS");
1545 if (do_incremental) {
1546 const ProStringList &incrs = project->values(v: "QMAKE_INCREMENTAL");
1547 ProStringList incrs_out;
1548 t << "OBJECTS = ";
1549 for (ProStringList::ConstIterator objit = objs.begin(); objit != objs.end(); ++objit) {
1550 bool increment = false;
1551 for (ProStringList::ConstIterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
1552 auto regexp = QRegularExpression::fromWildcard(pattern: (*incrit).toQString(), cs: Qt::CaseSensitive,
1553 options: QRegularExpression::UnanchoredWildcardConversion);
1554 if ((*objit).toQString().contains(re: regexp)) {
1555 increment = true;
1556 incrs_out.append(t: (*objit));
1557 break;
1558 }
1559 }
1560 if (!increment)
1561 t << "\\\n\t\t" << (*objit);
1562 }
1563 if (incrs_out.size() == objs.size()) { //we just switched places, no real incrementals to be done!
1564 t << escapeFilePaths(paths: incrs_out).join(sep: QString(" \\\n\t\t")) << Qt::endl;
1565 } else if (!incrs_out.size()) {
1566 t << Qt::endl;
1567 } else {
1568 src_incremental = true;
1569 t << Qt::endl;
1570 t << "INCREMENTAL_OBJECTS = "
1571 << escapeFilePaths(paths: incrs_out).join(sep: QString(" \\\n\t\t")) << Qt::endl;
1572 }
1573 } else {
1574 t << "OBJECTS = " << valList(varList: escapeDependencyPaths(paths: objs)) << Qt::endl;
1575 }
1576 return src_incremental;
1577}
1578
1579QT_END_NAMESPACE
1580

source code of qtbase/qmake/generators/unix/unixmake2.cpp