source: trunk/qmake/generators/mac/pbuilder_pbx.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 97.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the qmake application of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "pbuilder_pbx.h"
43#include "option.h"
44#include "meta.h"
45#include <qdir.h>
46#include <qregexp.h>
47#include <qcryptographichash.h>
48#include <qdebug.h>
49#include <stdlib.h>
50#include <time.h>
51#ifdef Q_OS_UNIX
52# include <sys/types.h>
53# include <sys/stat.h>
54#endif
55#ifdef Q_OS_DARWIN
56#include <ApplicationServices/ApplicationServices.h>
57#include <private/qcore_mac_p.h>
58#endif
59
60QT_BEGIN_NAMESPACE
61
62//#define GENERATE_AGGREGRATE_SUBDIR
63
64// Note: this is fairly hacky, but it does the job...
65
66static QString qtMD5(const QByteArray &src)
67{
68 QByteArray digest = QCryptographicHash::hash(src, QCryptographicHash::Md5);
69 return QString::fromLatin1(digest.toHex());
70}
71
72ProjectBuilderMakefileGenerator::ProjectBuilderMakefileGenerator() : UnixMakefileGenerator()
73{
74
75}
76
77bool
78ProjectBuilderMakefileGenerator::writeMakefile(QTextStream &t)
79{
80 writingUnixMakefileGenerator = false;
81 if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
82 /* for now just dump, I need to generated an empty xml or something.. */
83 fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
84 var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
85 return true;
86 }
87
88 project->values("MAKEFILE").clear();
89 project->values("MAKEFILE").append("Makefile");
90 if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib")
91 return writeMakeParts(t);
92 else if(project->first("TEMPLATE") == "subdirs")
93 return writeSubDirs(t);
94 return false;
95}
96
97struct ProjectBuilderSubDirs {
98 QMakeProject *project;
99 QString subdir;
100 bool autoDelete;
101 ProjectBuilderSubDirs(QMakeProject *p, QString s, bool a=true) : project(p), subdir(s), autoDelete(a) { }
102 ~ProjectBuilderSubDirs() {
103 if(autoDelete)
104 delete project;
105 }
106};
107
108bool
109ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
110{
111 if(project->isActiveConfig("generate_pbxbuild_makefile")) {
112 QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
113 qmake_getpwd());
114 QFile mkwrapf(mkwrap);
115 if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
116 debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
117 QTextStream mkwrapt(&mkwrapf);
118 writingUnixMakefileGenerator = true;
119 UnixMakefileGenerator::writeSubDirs(mkwrapt);
120 writingUnixMakefileGenerator = false;
121 }
122 }
123
124 //HEADER
125 const int pbVersion = pbuilderVersion();
126 t << "// !$*UTF8*$!" << "\n"
127 << "{" << "\n"
128 << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
129 << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
130 << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
131 << "\t" << "objects = {" << endl;
132
133 //SUBDIRS
134 QList<ProjectBuilderSubDirs*> pb_subdirs;
135 pb_subdirs.append(new ProjectBuilderSubDirs(project, QString(), false));
136 QString oldpwd = qmake_getpwd();
137 QMap<QString, QStringList> groups;
138 for(int pb_subdir = 0; pb_subdir < pb_subdirs.size(); ++pb_subdir) {
139 ProjectBuilderSubDirs *pb = pb_subdirs[pb_subdir];
140 const QStringList subdirs = pb->project->values("SUBDIRS");
141 for(int subdir = 0; subdir < subdirs.count(); subdir++) {
142 QString tmp = subdirs[subdir];
143 if(!pb->project->isEmpty(tmp + ".file"))
144 tmp = pb->project->first(tmp + ".file");
145 else if(!pb->project->isEmpty(tmp + ".subdir"))
146 tmp = pb->project->first(tmp + ".subdir");
147 if(fileInfo(tmp).isRelative() && !pb->subdir.isEmpty()) {
148 QString subdir = pb->subdir;
149 if(!subdir.endsWith(Option::dir_sep))
150 subdir += Option::dir_sep;
151 tmp = subdir + tmp;
152 }
153 QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
154 if(fi.exists()) {
155 if(fi.isDir()) {
156 QString profile = tmp;
157 if(!profile.endsWith(Option::dir_sep))
158 profile += Option::dir_sep;
159 profile += fi.baseName() + Option::pro_ext;
160 fi = QFileInfo(profile);
161 }
162 QMakeProject tmp_proj;
163 QString dir = fi.path(), fn = fi.fileName();
164 if(!dir.isEmpty()) {
165 if(!qmake_setpwd(dir))
166 fprintf(stderr, "Cannot find directory: %s\n", dir.toLatin1().constData());
167 }
168 if(tmp_proj.read(fn)) {
169 if(Option::debug_level) {
170 QMap<QString, QStringList> &vars = tmp_proj.variables();
171 for(QMap<QString, QStringList>::Iterator it = vars.begin();
172 it != vars.end(); ++it) {
173 if(it.key().left(1) != "." && !it.value().isEmpty())
174 debug_msg(1, "%s: %s === %s", fn.toLatin1().constData(), it.key().toLatin1().constData(),
175 it.value().join(" :: ").toLatin1().constData());
176 }
177 }
178 if(tmp_proj.first("TEMPLATE") == "subdirs") {
179 QMakeProject *pp = new QMakeProject(&tmp_proj);
180 pp->read(0);
181 pb_subdirs += new ProjectBuilderSubDirs(pp, dir);
182 } else if(tmp_proj.first("TEMPLATE") == "app" || tmp_proj.first("TEMPLATE") == "lib") {
183 QString pbxproj = qmake_getpwd() + Option::dir_sep + tmp_proj.first("TARGET") + projectSuffix();
184 if(!exists(pbxproj)) {
185 warn_msg(WarnLogic, "Ignored (not found) '%s'", pbxproj.toLatin1().constData());
186 goto nextfile; // # Dirty!
187 }
188 const QString project_key = keyFor(pbxproj + "_PROJECTREF");
189 project->values("QMAKE_PBX_SUBDIRS") += pbxproj;
190 //PROJECTREF
191 {
192 bool in_root = true;
193 QString name = qmake_getpwd();
194 if(project->isActiveConfig("flat")) {
195 QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
196 if(flat_file.indexOf(Option::dir_sep) != -1) {
197 QStringList dirs = flat_file.split(Option::dir_sep);
198 name = dirs.back();
199 }
200 } else {
201 QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
202 if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
203 QString last_grp("QMAKE_SUBDIR_PBX_HEIR_GROUP");
204 QStringList dirs = flat_file.split(Option::dir_sep);
205 name = dirs.back();
206 for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
207 QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
208 if(dir_it == dirs.begin()) {
209 if(!groups.contains(new_grp))
210 project->values("QMAKE_SUBDIR_PBX_GROUPS").append(new_grp_key);
211 } else {
212 if(!groups[last_grp].contains(new_grp_key))
213 groups[last_grp] += new_grp_key;
214 }
215 last_grp = new_grp;
216 }
217 groups[last_grp] += project_key;
218 in_root = false;
219 }
220 }
221 if(in_root)
222 project->values("QMAKE_SUBDIR_PBX_GROUPS") += project_key;
223 t << "\t\t" << project_key << " = {" << "\n"
224 << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
225 << "\t\t\t" << writeSettings("lastKnownFileType", "wrapper.pb-project") << ";" << "\n"
226 << "\t\t\t" << writeSettings("name", escapeFilePath(tmp_proj.first("TARGET") + projectSuffix())) << ";" << "\n"
227 << "\t\t\t" << writeSettings("path", pbxproj) << ";" << "\n"
228 << "\t\t\t" << writeSettings("refType", "0", SettingsNoQuote) << ";" << "\n"
229 << "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";" << "\n"
230 << "\t\t" << "};" << "\n";
231 //WRAPPER
232 t << "\t\t" << keyFor(pbxproj + "_WRAPPER") << " = {" << "\n"
233 << "\t\t\t" << writeSettings("isa", "PBXReferenceProxy", SettingsNoQuote) << ";" << "\n";
234 if(tmp_proj.first("TEMPLATE") == "app") {
235 t << "\t\t\t" << writeSettings("fileType", "wrapper.application") << ";" << "\n"
236 << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".app") << ";" << "\n";
237 } else {
238 t << "\t\t\t" << writeSettings("fileType", "compiled.mach-o.dylib") << ";" << "\n"
239 << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".dylib") << ";" << "\n";
240 }
241 t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
242 << "\t\t\t" << writeSettings("remoteRef", keyFor(pbxproj + "_WRAPPERREF")) << ";" << "\n"
243 << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
244 << "\t\t" << "};" << "\n";
245 t << "\t\t" << keyFor(pbxproj + "_WRAPPERREF") << " = {" << "\n"
246 << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
247 << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
248 << "\t\t\t" << writeSettings("proxyType", "2") << ";" << "\n"
249// << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
250 << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE!!!")) << ";" << "\n"
251 << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
252 << "\t\t" << "};" << "\n";
253 //PRODUCTGROUP
254 t << "\t\t" << keyFor(pbxproj + "_PRODUCTGROUP") << " = {" << "\n"
255 << "\t\t\t" << writeSettings("children", project->values(pbxproj + "_WRAPPER"), SettingsAsList, 4) << ";" << "\n"
256 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
257 << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
258 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
259 << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
260 << "\t\t" << "};" << "\n";
261 }
262#ifdef GENERATE_AGGREGRATE_SUBDIR
263 //TARGET (for aggregate)
264 {
265 //container
266 const QString container_proxy = keyFor(pbxproj + "_CONTAINERPROXY");
267 t << "\t\t" << container_proxy << " = {" << "\n"
268 << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
269 << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
270 << "\t\t\t" << writeSettings("proxyType", "1") << ";" << "\n"
271 << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_TARGET")) << ";" << "\n"
272 << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
273 << "\t\t" << "};" << "\n";
274 //targetref
275 t << "\t\t" << keyFor(pbxproj + "_TARGETREF") << " = {" << "\n"
276 << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
277 << "\t\t\t" << writeSettings("name", fixForOutput(tmp_proj.first("TARGET") +" (from " + tmp_proj.first("TARGET") + projectSuffix() + ")")) << ";" << "\n"
278 << "\t\t\t" << writeSettings("targetProxy", container_proxy) << ";" << "\n"
279 << "\t\t" << "};" << "\n";
280 }
281#endif
282 }
283 }
284 nextfile:
285 qmake_setpwd(oldpwd);
286 }
287 }
288 }
289 qDeleteAll(pb_subdirs);
290 pb_subdirs.clear();
291
292 for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
293 t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
294 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
295 << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
296 << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
297 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
298 << "\t\t" << "};" << "\n";
299 }
300
301 //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
302 //BUILDSTYLE
303 QString active_buildstyle;
304 for(int as_release = 0; as_release < 2; as_release++)
305 {
306 QMap<QString, QString> settings;
307 settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
308 if(as_release)
309 settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
310 if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
311 settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
312 {
313 const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
314 for(int i = 0; i < l.size(); ++i) {
315 QString name = l.at(i);
316 const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
317 if(!project->isEmpty(name + QLatin1String(".name")))
318 name = project->values(name + QLatin1String(".name")).first();
319 settings.insert(name, value);
320 }
321 }
322
323 QString name;
324 if(pbVersion >= 42)
325 name = (as_release ? "Release" : "Debug");
326 else
327 name = (as_release ? "Deployment" : "Development");
328 if(pbVersion >= 42) {
329 QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_" + name);
330 project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS").append(key);
331 t << "\t\t" << key << " = {" << "\n"
332 << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
333 << "\t\t\t" << "buildSettings = {" << "\n";
334 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
335 t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
336 t << "\t\t\t" << "};" << "\n"
337 << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
338 << "\t\t" << "};" << "\n";
339 }
340
341 QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDSTYLE_" + name);
342 if(project->isActiveConfig("debug") != (bool)as_release) {
343 project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
344 active_buildstyle = name;
345 } else if(pbVersion >= 42) {
346 project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
347 }
348 t << "\t\t" << key << " = {" << "\n"
349 << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
350 << "\t\t\t" << "buildSettings = {" << "\n";
351 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
352 t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
353 t << "\t\t\t" << "};" << "\n"
354 << "\t\t\t" << writeSettings("isa", "PBXBuildStyle", SettingsNoQuote) << ";" << "\n"
355 << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
356 << "\t\t" << "};" << "\n";
357 }
358 if(pbVersion >= 42) {
359 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
360 << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
361 << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
362 << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
363 << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
364 << "\t\t" << "};" << "\n";
365 }
366
367#ifdef GENERATE_AGGREGRATE_SUBDIR
368 //target
369 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_AGGREGATE_TARGET") << " = {" << "\n"
370 << "\t\t\t" << writeSettings("buildPhases", QStringList(), SettingsAsList, 4) << ";" << "\n"
371 << "\t\t\t" << "buildSettings = {" << "\n"
372 << "\t\t\t\t" << writeSettings("PRODUCT_NAME", project->values("TARGET").first()) << ";" << "\n"
373 << "\t\t\t" << "};" << "\n";
374 {
375 QStringList dependencies;
376 const QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
377 for(int i = 0; i < qmake_subdirs.count(); i++)
378 dependencies += keyFor(qmake_subdirs[i] + "_TARGETREF");
379 t << "\t\t\t" << writeSettings("dependencies", dependencies, SettingsAsList, 4) << ";" << "\n"
380 }
381 t << "\t\t\t" << writeSettings("isa", "PBXAggregateTarget", SettingsNoQuote) << ";" << "\n"
382 << "\t\t\t" << writeSettings("name", project->values("TARGET").first()) << ";" << "\n"
383 << "\t\t\t" << writeSettings("productName", project->values("TARGET").first()) << ";" << "\n"
384 << "\t\t" << "};" << "\n";
385#endif
386
387 //ROOT_GROUP
388 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP") << " = {" << "\n"
389 << "\t\t\t" << writeSettings("children", project->values("QMAKE_SUBDIR_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
390 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
391 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
392 << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
393 << "\t\t" << "};" << "\n";
394
395
396 //ROOT
397 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT") << " = {" << "\n"
398 << "\t\t\t" << "buildSettings = {" << "\n"
399 << "\t\t\t" << "};" << "\n"
400 << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
401 << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
402 << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP")) << ";" << "\n"
403 << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n";
404 if(pbVersion >= 42)
405 t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
406 t << "\t\t\t" << "projectReferences = (" << "\n";
407 {
408 QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
409 for(int i = 0; i < qmake_subdirs.count(); i++) {
410 QString subdir = qmake_subdirs[i];
411 t << "\t\t\t\t" << "{" << "\n"
412 << "\t\t\t\t\t" << writeSettings("ProductGroup", keyFor(subdir + "_PRODUCTGROUP")) << ";" << "\n"
413 << "\t\t\t\t\t" << writeSettings("ProjectRef", keyFor(subdir + "_PROJECTREF")) << ";" << "\n"
414 << "\t\t\t\t" << "}," << "\n";
415 }
416 }
417 t << "\t\t\t" << ");" << "\n"
418 << "\t\t\t" << writeSettings("targets",
419#ifdef GENERATE_AGGREGRATE_SUBDIR
420 project->values("QMAKE_SUBDIR_AGGREGATE_TARGET"),
421#else
422 QStringList(),
423#endif
424 SettingsAsList, 4) << ";" << "\n"
425 << "\t\t" << "};" << "\n";
426
427 //FOOTER
428 t << "\t" << "};" << "\n"
429 << "\t" << writeSettings("rootObject", keyFor("QMAKE_SUBDIR_PBX_ROOT")) << ";" << "\n"
430 << "}" << endl;
431
432 return true;
433}
434
435class ProjectBuilderSources
436{
437 bool buildable, object_output;
438 QString key, group, compiler;
439public:
440 ProjectBuilderSources(const QString &key, bool buildable=false, const QString &group=QString(), const QString &compiler=QString(), bool producesObject=false);
441 QStringList files(QMakeProject *project) const;
442 inline bool isBuildable() const { return buildable; }
443 inline QString keyName() const { return key; }
444 inline QString groupName() const { return group; }
445 inline QString compilerName() const { return compiler; }
446 inline bool isObjectOutput(const QString &file) const {
447 bool ret = object_output;
448 for(int i = 0; !ret && i < Option::c_ext.size(); ++i) {
449 if(file.endsWith(Option::c_ext.at(i))) {
450 ret = true;
451 break;
452 }
453 }
454 for(int i = 0; !ret && i < Option::cpp_ext.size(); ++i) {
455 if(file.endsWith(Option::cpp_ext.at(i))) {
456 ret = true;
457 break;
458 }
459 }
460 return ret;
461 }
462};
463
464ProjectBuilderSources::ProjectBuilderSources(const QString &k, bool b,
465 const QString &g, const QString &c, bool o) : buildable(b), object_output(o), key(k), group(g), compiler(c)
466{
467 if(group.isNull()) {
468 if(k == "SOURCES")
469 group = "Sources";
470 else if(k == "HEADERS")
471 group = "Headers";
472 else if(k == "QMAKE_INTERNAL_INCLUDED_FILES")
473 group = "Sources [qmake]";
474 else if(k == "GENERATED_SOURCES" || k == "GENERATED_FILES")
475 group = "Temporary Sources";
476 else
477 fprintf(stderr, "No group available for %s!\n", k.toLatin1().constData());
478 }
479}
480
481QStringList
482ProjectBuilderSources::files(QMakeProject *project) const
483{
484 QStringList ret = project->values(key);
485 if(key == "QMAKE_INTERNAL_INCLUDED_FILES") {
486 QString pfile = project->projectFile();
487 if(pfile != "(stdin)")
488 ret.prepend(pfile);
489 for(int i = 0; i < ret.size(); ++i) {
490 QStringList newret;
491 if(!ret.at(i).endsWith(Option::prf_ext))
492 newret.append(ret.at(i));
493 ret = newret;
494 }
495 }
496 if(key == "SOURCES" && project->first("TEMPLATE") == "app" && !project->isEmpty("ICON"))
497 ret.append(project->first("ICON"));
498 return ret;
499}
500
501
502bool
503ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
504{
505 QStringList tmp;
506 bool did_preprocess = false;
507
508 //HEADER
509 const int pbVersion = pbuilderVersion();
510 t << "// !$*UTF8*$!" << "\n"
511 << "{" << "\n"
512 << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
513 << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
514 << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
515 << "\t" << "objects = {" << endl;
516
517 //MAKE QMAKE equivelant
518 if(!project->isActiveConfig("no_autoqmake") && project->projectFile() != "(stdin)") {
519 QString mkfile = pbx_dir + Option::dir_sep + "qt_makeqmake.mak";
520 QFile mkf(mkfile);
521 if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
522 writingUnixMakefileGenerator = true;
523 debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
524 QTextStream mkt(&mkf);
525 writeHeader(mkt);
526 mkt << "QMAKE = " << var("QMAKE_QMAKE") << endl;
527 writeMakeQmake(mkt);
528 mkt.flush();
529 mkf.close();
530 writingUnixMakefileGenerator = false;
531 }
532 QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE");
533 mkfile = fileFixify(mkfile, qmake_getpwd());
534 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
535 t << "\t\t" << phase_key << " = {" << "\n"
536 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
537 << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
538 << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
539 << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
540 << "\t\t\t" << writeSettings("name", "Qt Qmake") << ";" << "\n"
541 << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
542 << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
543 << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
544 << "\t\t" << "};" << "\n";
545 }
546
547 //DUMP SOURCES
548 QMap<QString, QStringList> groups;
549 QList<ProjectBuilderSources> sources;
550 sources.append(ProjectBuilderSources("SOURCES", true));
551 sources.append(ProjectBuilderSources("GENERATED_SOURCES", true));
552 sources.append(ProjectBuilderSources("GENERATED_FILES"));
553 sources.append(ProjectBuilderSources("HEADERS"));
554 sources.append(ProjectBuilderSources("QMAKE_INTERNAL_INCLUDED_FILES"));
555 if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
556 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
557 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
558 QString tmp_out = project->first((*it) + ".output");
559 if(project->isEmpty((*it) + ".output"))
560 continue;
561 QString name = (*it);
562 if(!project->isEmpty((*it) + ".name"))
563 name = project->first((*it) + ".name");
564 const QStringList &inputs = project->values((*it) + ".input");
565 for(int input = 0; input < inputs.size(); ++input) {
566 if(project->isEmpty(inputs.at(input)))
567 continue;
568 bool duplicate = false;
569 for(int i = 0; i < sources.size(); ++i) {
570 if(sources.at(i).keyName() == inputs.at(input)) {
571 duplicate = true;
572 break;
573 }
574 }
575 if(!duplicate) {
576 bool isObj = project->values((*it) + ".CONFIG").indexOf("no_link") == -1;
577 const QStringList &outputs = project->values((*it) + ".variable_out");
578 for(int output = 0; output < outputs.size(); ++output) {
579 if(outputs.at(output) != "OBJECT") {
580 isObj = false;
581 break;
582 }
583 }
584 sources.append(ProjectBuilderSources(inputs.at(input), true,
585 QString("Sources [") + name + "]", (*it), isObj));
586 }
587 }
588 }
589 }
590 for(int source = 0; source < sources.size(); ++source) {
591 QStringList &src_list = project->values("QMAKE_PBX_" + sources.at(source).keyName());
592 QStringList &root_group_list = project->values("QMAKE_PBX_GROUPS");
593
594 QStringList files = fileFixify(sources.at(source).files(project));
595 for(int f = 0; f < files.count(); ++f) {
596 QString file = files[f];
597 if(file.length() >= 2 && (file[0] == '"' || file[0] == '\'') && file[(int) file.length()-1] == file[0])
598 file = file.mid(1, file.length()-2);
599 if(!sources.at(source).compilerName().isNull() &&
600 !verifyExtraCompiler(sources.at(source).compilerName(), file))
601 continue;
602 if(file.endsWith(Option::prl_ext))
603 continue;
604
605 bool in_root = true;
606 QString src_key = keyFor(file), name = file;
607 if(project->isActiveConfig("flat")) {
608 QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
609 if(flat_file.indexOf(Option::dir_sep) != -1) {
610 QStringList dirs = flat_file.split(Option::dir_sep);
611 name = dirs.back();
612 }
613 } else {
614 QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
615 if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
616 QString last_grp("QMAKE_PBX_" + sources.at(source).groupName() + "_HEIR_GROUP");
617 QStringList dirs = flat_file.split(Option::dir_sep);
618 name = dirs.back();
619 dirs.pop_back(); //remove the file portion as it will be added via src_key
620 for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
621 QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
622 if(dir_it == dirs.begin()) {
623 if(!src_list.contains(new_grp_key))
624 src_list.append(new_grp_key);
625 } else {
626 if(!groups[last_grp].contains(new_grp_key))
627 groups[last_grp] += new_grp_key;
628 }
629 last_grp = new_grp;
630 }
631 groups[last_grp] += src_key;
632 in_root = false;
633 }
634 }
635 if(in_root)
636 src_list.append(src_key);
637 //source reference
638 t << "\t\t" << src_key << " = {" << "\n"
639 << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
640 << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
641 << "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";" << "\n"
642 << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(file)), SettingsNoQuote) << ";" << "\n";
643 if(pbVersion >= 38) {
644 QString filetype;
645 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
646 if(file.endsWith((*cppit))) {
647 filetype = "sourcecode.cpp.cpp";
648 break;
649 }
650 }
651 if(!filetype.isNull())
652 t << "\t\t\t" << writeSettings("lastKnownFileType", filetype) << ";" << "\n";
653 }
654 t << "\t\t" << "};" << "\n";
655 if(sources.at(source).isBuildable()) { //build reference
656 QString build_key = keyFor(file + ".BUILDABLE");
657 t << "\t\t" << build_key << " = {" << "\n"
658 << "\t\t\t" << writeSettings("fileRef", src_key) << ";" << "\n"
659 << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
660 << "\t\t\t" << "settings = {" << "\n"
661 << "\t\t\t\t" << writeSettings("ATTRIBUTES", QStringList(), SettingsAsList, 5) << ";" << "\n"
662 << "\t\t\t" << "};" << "\n"
663 << "\t\t" << "};" << "\n";
664 if(sources.at(source).isObjectOutput(file))
665 project->values("QMAKE_PBX_OBJ").append(build_key);
666 }
667 }
668 if(!src_list.isEmpty()) {
669 QString group_key = keyFor(sources.at(source).groupName());
670 if(root_group_list.indexOf(group_key) == -1)
671 root_group_list += group_key;
672
673 QStringList &group = groups[sources.at(source).groupName()];
674 for(int src = 0; src < src_list.size(); ++src) {
675 if(group.indexOf(src_list.at(src)) == -1)
676 group += src_list.at(src);
677 }
678 }
679 }
680 for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
681 t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
682 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
683 << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
684 << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
685 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
686 << "\t\t" << "};" << "\n";
687 }
688
689 //PREPROCESS BUILDPHASE (just a makefile)
690 {
691 QString mkfile = pbx_dir + Option::dir_sep + "qt_preprocess.mak";
692 QFile mkf(mkfile);
693 if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
694 writingUnixMakefileGenerator = true;
695 did_preprocess = true;
696 debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
697 QTextStream mkt(&mkf);
698 writeHeader(mkt);
699 mkt << "MOC = " << Option::fixPathToTargetOS(var("QMAKE_MOC")) << endl;
700 mkt << "UIC = " << Option::fixPathToTargetOS(var("QMAKE_UIC")) << endl;
701 mkt << "LEX = " << var("QMAKE_LEX") << endl;
702 mkt << "LEXFLAGS = " << var("QMAKE_LEXFLAGS") << endl;
703 mkt << "YACC = " << var("QMAKE_YACC") << endl;
704 mkt << "YACCFLAGS = " << var("QMAKE_YACCFLAGS") << endl;
705 mkt << "DEFINES = "
706 << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
707 << varGlue("DEFINES","-D"," -D","") << endl;
708 mkt << "INCPATH = " << "-I" << specdir();
709 if(!project->isActiveConfig("no_include_pwd")) {
710 QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
711 if(pwd.isEmpty())
712 pwd = ".";
713 mkt << " -I" << pwd;
714 }
715 {
716 const QStringList &incs = project->values("INCLUDEPATH");
717 for(QStringList::ConstIterator incit = incs.begin(); incit != incs.end(); ++incit)
718 mkt << " " << "-I" << escapeFilePath((*incit));
719 }
720 if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
721 mkt << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
722 mkt << endl;
723 mkt << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
724 mkt << "MOVE = " << var("QMAKE_MOVE") << endl << endl;
725 mkt << "IMAGES = " << varList("QMAKE_IMAGE_COLLECTION") << endl;
726 mkt << "PARSERS =";
727 if(!project->isEmpty("YACCSOURCES")) {
728 QStringList &yaccs = project->values("YACCSOURCES");
729 for(QStringList::Iterator yit = yaccs.begin(); yit != yaccs.end(); ++yit) {
730 QFileInfo fi(fileInfo((*yit)));
731 mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
732 << Option::yacc_mod << Option::cpp_ext.first();
733 }
734 }
735 if(!project->isEmpty("LEXSOURCES")) {
736 QStringList &lexs = project->values("LEXSOURCES");
737 for(QStringList::Iterator lit = lexs.begin(); lit != lexs.end(); ++lit) {
738 QFileInfo fi(fileInfo((*lit)));
739 mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
740 << Option::lex_mod << Option::cpp_ext.first();
741 }
742 }
743 mkt << "\n";
744 mkt << "preprocess: $(PARSERS) compilers" << endl;
745 mkt << "clean preprocess_clean: parser_clean compiler_clean" << endl << endl;
746 mkt << "parser_clean:" << "\n";
747 if(!project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES"))
748 mkt << "\t-rm -f $(PARSERS)" << "\n";
749 writeExtraTargets(mkt);
750 if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
751 mkt << "compilers:";
752 const QStringList &compilers = project->values("QMAKE_EXTRA_COMPILERS");
753 for(int compiler = 0; compiler < compilers.size(); ++compiler) {
754 QString tmp_out = project->first(compilers.at(compiler) + ".output");
755 if(project->isEmpty(compilers.at(compiler) + ".output"))
756 continue;
757 const QStringList &inputs = project->values(compilers.at(compiler) + ".input");
758 for(int input = 0; input < inputs.size(); ++input) {
759 if(project->isEmpty(inputs.at(input)))
760 continue;
761 const QStringList &files = project->values(inputs.at(input));
762 for(int file = 0, added = 0; file < files.size(); ++file) {
763 if(!verifyExtraCompiler(compilers.at(compiler), files.at(file)))
764 continue;
765 if(added && !(added % 3))
766 mkt << "\\\n\t";
767 ++added;
768 const QString file_name = fileFixify(files.at(file), Option::output_dir, Option::output_dir);
769 mkt << " " << replaceExtraCompilerVariables(tmp_out, file_name, QString());
770 }
771 }
772 }
773 mkt << endl;
774 writeExtraCompilerTargets(mkt);
775 writingUnixMakefileGenerator = false;
776 }
777 mkt.flush();
778 mkf.close();
779 }
780 mkfile = fileFixify(mkfile, qmake_getpwd());
781 QString phase_key = keyFor("QMAKE_PBX_PREPROCESS_TARGET");
782// project->values("QMAKE_PBX_BUILDPHASES").append(phase_key);
783 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
784 t << "\t\t" << phase_key << " = {" << "\n"
785 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
786 << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
787 << "\t\t\t" << writeSettings("generatedFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
788 << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
789 << "\t\t\t" << writeSettings("name", "Qt Preprocessors") << ";" << "\n"
790 << "\t\t\t" << writeSettings("neededFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
791 << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
792 << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
793 << "\t\t" << "};" << "\n";
794 }
795
796 //SOURCE BUILDPHASE
797 if(!project->isEmpty("QMAKE_PBX_OBJ")) {
798 QString grp = "Build Sources", key = keyFor(grp);
799 project->values("QMAKE_PBX_BUILDPHASES").append(key);
800 t << "\t\t" << key << " = {" << "\n"
801 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
802 << "\t\t\t" << writeSettings("files", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
803 << "\t\t\t" << writeSettings("isa", "PBXSourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
804 << "\t\t\t" << writeSettings("name", grp) << ";" << "\n"
805 << "\t\t" << "};" << "\n";
806 }
807
808 if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
809 QStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"),
810 &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH");
811 QString libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS",
812 "QMAKE_LIBS", QString() };
813 for(int i = 0; !libs[i].isNull(); i++) {
814 tmp = project->values(libs[i]);
815 for(int x = 0; x < tmp.count();) {
816 bool remove = false;
817 QString library, name, opt = tmp[x].trimmed();
818 if(opt.length() >= 2 && (opt[0] == '"' || opt[0] == '\'') &&
819 opt[(int) opt.length()-1] == opt[0])
820 opt = opt.mid(1, opt.length()-2);
821 if(opt.startsWith("-L")) {
822 QString r = opt.right(opt.length() - 2);
823 fixForOutput(r);
824 libdirs.append(r);
825 } else if(opt == "-prebind") {
826 project->values("QMAKE_DO_PREBINDING").append("TRUE");
827 remove = true;
828 } else if(opt.startsWith("-l")) {
829 name = opt.right(opt.length() - 2);
830 QString lib("lib" + name);
831 for(QStringList::Iterator lit = libdirs.begin(); lit != libdirs.end(); ++lit) {
832 if(project->isActiveConfig("link_prl")) {
833 /* This isn't real nice, but it is real useful. This looks in a prl
834 for what the library will ultimately be called so we can stick it
835 in the ProjectFile. If the prl format ever changes (not likely) then
836 this will not really work. However, more concerning is that it will
837 encode the version number in the Project file which might be a bad
838 things in days to come? --Sam
839 */
840 QString lib_file = (*lit) + Option::dir_sep + lib;
841 if(QMakeMetaInfo::libExists(lib_file)) {
842 QMakeMetaInfo libinfo;
843 if(libinfo.readLib(lib_file)) {
844 if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) {
845 library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
846 debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
847 opt.toLatin1().constData(), lib_file.toLatin1().constData(), library.toLatin1().constData());
848 remove = true;
849 }
850 }
851 }
852 }
853 if(!remove) {
854 QString extns[] = { ".dylib", ".so", ".a", QString() };
855 for(int n = 0; !remove && !extns[n].isNull(); n++) {
856 QString tmp = (*lit) + Option::dir_sep + lib + extns[n];
857 if(exists(tmp)) {
858 library = tmp;
859 debug_msg(1, "pbuilder: Found library (%s) via %s",
860 opt.toLatin1().constData(), library.toLatin1().constData());
861 remove = true;
862 }
863 }
864 }
865 }
866 } else if(opt.startsWith("-F")) {
867 QString r;
868 if(opt.size() > 2) {
869 r = opt.right(opt.length() - 2);
870 } else {
871 if(x == tmp.count()-1)
872 break;
873 r = tmp[++x];
874 }
875 if(!r.isEmpty()) {
876 fixForOutput(r);
877 frameworkdirs.append(r);
878 }
879 } else if(opt == "-framework") {
880 if(x == tmp.count()-1)
881 break;
882 const QString framework = tmp[x+1];
883 QStringList fdirs = frameworkdirs;
884 fdirs << "/System/Library/Frameworks/" << "/Library/Frameworks/";
885 for(int fdir = 0; fdir < fdirs.count(); fdir++) {
886 if(exists(fdirs[fdir] + QDir::separator() + framework + ".framework")) {
887 tmp.removeAt(x);
888 remove = true;
889 library = fdirs[fdir] + Option::dir_sep + framework + ".framework";
890 break;
891 }
892 }
893 } else if(opt.left(1) != "-") {
894 if(exists(opt)) {
895 remove = true;
896 library = opt;
897 }
898 }
899 if(!library.isEmpty()) {
900 const int slsh = library.lastIndexOf(Option::dir_sep);
901 if(name.isEmpty()) {
902 if(slsh != -1)
903 name = library.right(library.length() - slsh - 1);
904 }
905 if(slsh != -1) {
906 const QString path = QFileInfo(library.left(slsh)).absoluteFilePath();
907 if(!path.isEmpty() && !libdirs.contains(path))
908 libdirs += path;
909 }
910 library = fileFixify(library);
911 QString key = keyFor(library);
912 bool is_frmwrk = (library.endsWith(".framework"));
913 t << "\t\t" << key << " = {" << "\n"
914 << "\t\t\t" << writeSettings("isa", (is_frmwrk ? "PBXFrameworkReference" : "PBXFileReference"), SettingsNoQuote) << ";" << "\n"
915 << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
916 << "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";" << "\n"
917 << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(library)), SettingsNoQuote) << ";" << "\n"
918 << "\t\t" << "};" << "\n";
919 project->values("QMAKE_PBX_LIBRARIES").append(key);
920 QString build_key = keyFor(library + ".BUILDABLE");
921 t << "\t\t" << build_key << " = {" << "\n"
922 << "\t\t\t" << writeSettings("fileRef", key) << ";" << "\n"
923 << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
924 << "\t\t\t" << "settings = {" << "\n"
925 << "\t\t\t" << "};" << "\n"
926 << "\t\t" << "};" << "\n";
927 project->values("QMAKE_PBX_BUILD_LIBRARIES").append(build_key);
928 }
929 if(remove)
930 tmp.removeAt(x);
931 else
932 x++;
933 }
934 project->values(libs[i]) = tmp;
935 }
936 }
937 //SUBLIBS BUILDPHASE (just another makefile)
938 if(!project->isEmpty("SUBLIBS")) {
939 QString mkfile = pbx_dir + Option::dir_sep + "qt_sublibs.mak";
940 QFile mkf(mkfile);
941 if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
942 writingUnixMakefileGenerator = true;
943 debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
944 QTextStream mkt(&mkf);
945 writeHeader(mkt);
946 mkt << "SUBLIBS= ";
947 tmp = project->values("SUBLIBS");
948 for(int i = 0; i < tmp.count(); i++)
949 t << "tmp/lib" << tmp[i] << ".a ";
950 t << endl << endl;
951 mkt << "sublibs: $(SUBLIBS)" << endl << endl;
952 tmp = project->values("SUBLIBS");
953 for(int i = 0; i < tmp.count(); i++)
954 t << "tmp/lib" << tmp[i] << ".a" << ":\n\t"
955 << var(QString("MAKELIB") + tmp[i]) << endl << endl;
956 mkt.flush();
957 mkf.close();
958 writingUnixMakefileGenerator = false;
959 }
960 QString phase_key = keyFor("QMAKE_PBX_SUBLIBS_BUILDPHASE");
961 mkfile = fileFixify(mkfile, qmake_getpwd());
962 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
963 t << "\t\t" << phase_key << " = {" << "\n"
964 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
965 << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
966 << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
967 << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
968 << "\t\t\t" << writeSettings("name", "Qt Sublibs") << ";" << "\n"
969 << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
970 << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << "\n"
971 << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
972 << "\t\t" << "};" << "\n";
973 }
974 //LIBRARY BUILDPHASE
975 if(!project->isEmpty("QMAKE_PBX_LIBRARIES")) {
976 tmp = project->values("QMAKE_PBX_LIBRARIES");
977 if(!tmp.isEmpty()) {
978 QString grp("External Frameworks and Libraries"), key = keyFor(grp);
979 project->values("QMAKE_PBX_GROUPS").append(key);
980 t << "\t\t" << key << " = {" << "\n"
981 << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
982 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
983 << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
984 << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
985 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
986 << "\t\t" << "};" << "\n";
987 }
988 }
989 {
990 QString grp("Frameworks & Libraries"), key = keyFor(grp);
991 project->values("QMAKE_PBX_BUILDPHASES").append(key);
992 t << "\t\t" << key << " = {" << "\n"
993 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
994 << "\t\t\t" << writeSettings("files", project->values("QMAKE_PBX_BUILD_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
995 << "\t\t\t" << writeSettings("isa", "PBXFrameworksBuildPhase", SettingsNoQuote) << ";" << "\n"
996 << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
997 << "\t\t" << "};" << "\n";
998 }
999 if(project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app") { //BUNDLE RESOURCES
1000 QString grp("Bundle Resources"), key = keyFor(grp);
1001 project->values("QMAKE_PBX_BUILDPHASES").append(key);
1002 t << "\t\t" << key << " = {" << "\n"
1003 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
1004 << "\t\t\t" << "files = (" << "\n";
1005 if(!project->isEmpty("ICON")) {
1006 QString icon = project->first("ICON");
1007 if(icon.length() >= 2 && (icon[0] == '"' || icon[0] == '\'') && icon[(int)icon.length()-1] == icon[0])
1008 icon = icon.mid(1, icon.length()-2);
1009 t << "\t\t\t\t" << keyFor(icon + ".BUILDABLE") << ",\n";
1010 }
1011 t << "\t\t\t" << ");" << "\n"
1012 << "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
1013 << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
1014 << "\t\t" << "};" << "\n";
1015 }
1016 { //INSTALL BUILDPHASE (copy)
1017 QString phase_key = keyFor("QMAKE_PBX_TARGET_COPY_PHASE");
1018 QString destDir = Option::output_dir;
1019 if (!project->isEmpty("QMAKE_ORIG_DESTDIR"))
1020 destDir = project->first("QMAKE_ORIG_DESTDIR");
1021 destDir = fixForOutput(destDir);
1022 destDir = fileInfo(Option::fixPathToLocalOS(destDir)).absoluteFilePath();
1023 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
1024 t << "\t\t" << phase_key << " = {\n"
1025 << "\t\t\t" << writeSettings("name", "Project Copy") << ";" << "\n"
1026 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
1027 << "\t\t\t" << writeSettings("dstPath", escapeFilePath(destDir)) << ";" << "\n"
1028 << "\t\t\t" << writeSettings("dstSubfolderSpec", "0", SettingsNoQuote) << ";" << "\n"
1029 << "\t\t\t" << writeSettings("files", keyFor("QMAKE_PBX_TARGET_COPY_FILE"), SettingsAsList, 4) << ";" << "\n"
1030 << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
1031 << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
1032 << "\t\t" << "};\n"
1033 << "\t\t" << keyFor("QMAKE_PBX_TARGET_COPY_FILE") << " = {\n"
1034 << "\t\t\t" << writeSettings("fileRef", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
1035 << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
1036 << "\t\t\t" << "settings = {\n"
1037 << "\t\t\t" << "};\n"
1038 << "\t\t" << "};\n";
1039 }
1040 //BUNDLE_DATA BUILDPHASE (copy)
1041 if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
1042 QStringList bundle_file_refs;
1043 //all bundle data
1044 const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
1045 for(int i = 0; i < bundle_data.count(); i++) {
1046 QStringList pbx_files;
1047 //all files
1048 const QStringList &files = project->values(bundle_data[i] + ".files");
1049 for(int file = 0; file < files.count(); file++) {
1050 QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE_REF." + bundle_data[i] + "-" + files[file]);
1051 bundle_file_refs += file_ref_key;
1052 t << "\t\t" << file_ref_key << " = {" << "\n"
1053 << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
1054 << "\t\t\t" << writeSettings("path", escapeFilePath(files[file])) << ";" << "\n"
1055 << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(files[file])), SettingsNoQuote) << ";" << "\n"
1056 << "\t\t" << "};" << "\n";
1057 QString copy_file_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE." + bundle_data[i] + "-" + files[file]);
1058 pbx_files += copy_file_key;
1059 t << "\t\t" << copy_file_key << " = {\n"
1060 << "\t\t\t" << writeSettings("fileRef", file_ref_key) << ";" << "\n"
1061 << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
1062 << "\t\t\t" << "settings = {\n"
1063 << "\t\t\t" << "}" << ";" << "\n"
1064 << "\t\t" << "}" << ";" << "\n";
1065 }
1066 //the phase
1067 QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]);
1068 QString path;
1069 if(!project->isEmpty(bundle_data[i] + ".version")) {
1070 //###
1071 }
1072 path += project->first(bundle_data[i] + ".path");
1073 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
1074 t << "\t\t" << phase_key << " = {\n"
1075 << "\t\t\t" << writeSettings("name", "Bundle Copy [" + bundle_data[i] + "]") << ";" << "\n"
1076 << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
1077 << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";" << "\n"
1078 << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";" << "\n"
1079 << "\t\t\t" << writeSettings("files", pbx_files, SettingsAsList, 4) << ";" << "\n"
1080 << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
1081 << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
1082 << "\t\t" << "}" << ";" << "\n";
1083 }
1084 QString bundle_copy_key = keyFor("QMAKE_PBX_BUNDLE_COPY");
1085 project->values("QMAKE_PBX_GROUPS").append(bundle_copy_key);
1086 t << "\t\t" << bundle_copy_key << " = {" << "\n"
1087 << "\t\t\t" << writeSettings("children", bundle_file_refs, SettingsAsList, 4) << ";" << "\n"
1088 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
1089 << "\t\t\t" << writeSettings("name", "Source [bundle data]") << ";" << "\n"
1090 << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
1091 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
1092 << "\t\t" << "};" << "\n";
1093 }
1094
1095 if(/*pbVersion >= 38 &&*/ !project->isEmpty("QMAKE_PBX_PRESCRIPT_BUILDPHASES") && 0) {
1096 // build reference
1097 t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPT_BUILDREFERENCE") << " = {" << "\n"
1098 << "\t\t\t" << writeSettings("includeInIndex", "0") << ";" << "\n"
1099 << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
1100 << "\t\t\t" << writeSettings("path", "preprocessor.out") << ";" << "\n"
1101 << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
1102 << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
1103 << "\t\t" << "};" << "\n";
1104 project->values("QMAKE_PBX_PRODUCTS").append(keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE"));
1105 //build phase
1106 t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE") << " = {" << "\n"
1107 << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES"), SettingsAsList, 4) << ";" << "\n"
1108 << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
1109 << "\t\t\t" << writeSettings("buildSettings", QStringList(), SettingsAsList, 4) << ";" << "\n"
1110 << "\t\t\t" << writeSettings("dependencies", QStringList(), SettingsAsList, 4) << ";" << "\n"
1111 << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n"
1112 << "\t\t\t" << writeSettings("name", "Qt Preprocessor Steps") << ";" << "\n"
1113 << "\t\t\t" << writeSettings("productName", "Qt Preprocessor Steps") << ";" << "\n"
1114 << "\t\t\t" << writeSettings("productReference", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE")) << ";" << "\n";
1115 if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
1116 t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
1117 else
1118 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
1119 t << "\t\t" << "};" << "\n";
1120 //dependency
1121 t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY") << " = {" << "\n"
1122 << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
1123 << "\t\t\t" << writeSettings("target", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE")) << ";" << "\n"
1124 << "\t\t" << "};" << "\n";
1125 project->values("QMAKE_PBX_TARGET_DEPENDS").append(keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY"));
1126 project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").clear(); //these are already consumed above
1127 }
1128
1129 //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
1130 //ROOT_GROUP
1131 t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n"
1132 << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
1133 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
1134 << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
1135 << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
1136 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
1137 << "\t\t" << "};" << "\n";
1138 //REFERENCE
1139 project->values("QMAKE_PBX_PRODUCTS").append(keyFor(pbx_dir + "QMAKE_PBX_REFERENCE"));
1140 t << "\t\t" << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << " = {" << "\n"
1141 << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n";
1142 if(project->first("TEMPLATE") == "app") {
1143 QString targ = project->first("QMAKE_ORIG_TARGET");
1144 if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
1145 if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
1146 targ = project->first("QMAKE_BUNDLE_NAME");
1147 targ += project->first("QMAKE_BUNDLE_EXTENSION");
1148 if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
1149 t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) + ";" << "\n";
1150 } else if(project->isActiveConfig("app_bundle")) {
1151 if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
1152 targ = project->first("QMAKE_APPLICATION_BUNDLE_NAME");
1153 targ += ".app";
1154 t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.application") << ";" << "\n";
1155 } else {
1156 t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.executable") << ";" << "\n";
1157 }
1158 QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") :
1159 qmake_getpwd()) + Option::dir_sep + targ;
1160 t << "\t\t\t" << writeSettings("path", escapeFilePath(targ)) << ";" << "\n";
1161 } else {
1162 QString lib = project->first("QMAKE_ORIG_TARGET");
1163 if(project->isActiveConfig("staticlib")) {
1164 lib = project->first("TARGET");
1165 } else if(!project->isActiveConfig("lib_bundle")) {
1166 if(project->isActiveConfig("plugin"))
1167 lib = project->first("TARGET");
1168 else
1169 lib = project->first("TARGET_");
1170 }
1171 int slsh = lib.lastIndexOf(Option::dir_sep);
1172 if(slsh != -1)
1173 lib = lib.right(lib.length() - slsh - 1);
1174 if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
1175 if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
1176 lib = project->first("QMAKE_BUNDLE_NAME");
1177 lib += project->first("QMAKE_BUNDLE_EXTENSION");
1178 if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
1179 t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) << ";" << "\n";
1180 } else if(!project->isActiveConfig("staticlib") && project->isActiveConfig("lib_bundle")) {
1181 if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
1182 lib = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME");
1183 lib += ".framework";
1184 t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.framework") << ";" << "\n";
1185 } else {
1186 t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.dylib") << ";" << "\n";
1187 }
1188 t << "\t\t\t" << writeSettings("path", escapeFilePath(lib)) << ";" << "\n";
1189 }
1190 t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
1191 << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
1192 << "\t\t" << "};" << "\n";
1193 { //Products group
1194 QString grp("Products"), key = keyFor(grp);
1195 project->values("QMAKE_PBX_GROUPS").append(key);
1196 t << "\t\t" << key << " = {" << "\n"
1197 << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_PRODUCTS"), SettingsAsList, 4) << ";" << "\n"
1198 << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
1199 << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
1200 << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
1201 << "\t\t" << "};" << "\n";
1202 }
1203 //TARGET
1204 QString target_key = keyFor(pbx_dir + "QMAKE_PBX_TARGET");
1205 project->values("QMAKE_PBX_TARGETS").append(target_key);
1206 t << "\t\t" << target_key << " = {" << "\n"
1207 << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES") + project->values("QMAKE_PBX_BUILDPHASES"),
1208 SettingsAsList, 4) << ";" << "\n"
1209 << "\t\t\t" << "buildSettings = {" << "\n";
1210 QString cCompiler = project->first("QMAKE_CC");
1211 if (!cCompiler.isEmpty()) {
1212 t << "\t\t\t\t" << writeSettings("CC", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
1213 }
1214 cCompiler = project->first("QMAKE_CXX");
1215 if (!cCompiler.isEmpty()) {
1216 t << "\t\t\t\t" << writeSettings("CPLUSPLUS", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
1217 }
1218
1219 t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH") + QStringList(fixForOutput(specdir())), SettingsAsList, 5) << ";" << "\n"
1220 << "\t\t\t\t" << writeSettings("LIBRARY_SEARCH_PATHS", fixListForOutput("QMAKE_PBX_LIBPATHS"), SettingsAsList, 5) << ";" << "\n"
1221 << "\t\t\t\t" << writeSettings("OPTIMIZATION_CFLAGS", QStringList(), SettingsAsList, 5) << ";" << "\n";
1222 {
1223 QStringList cflags = fixListForOutput("QMAKE_CFLAGS");
1224 const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
1225 for(int i = 0; i < prl_defines.size(); ++i)
1226 cflags += "-D" + prl_defines.at(i);
1227 const QStringList &defines = project->values("DEFINES");
1228 for(int i = 0; i < defines.size(); ++i)
1229 cflags += "-D" + defines.at(i);
1230 t << "\t\t\t\t" << writeSettings("OTHER_CFLAGS", cflags, SettingsAsList, 5) << ";" << "\n";
1231 }
1232 {
1233 QStringList cxxflags = fixListForOutput("QMAKE_CXXFLAGS");
1234 const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
1235 for(int i = 0; i < prl_defines.size(); ++i)
1236 cxxflags += "-D" + prl_defines.at(i);
1237 const QStringList &defines = project->values("DEFINES");
1238 for(int i = 0; i < defines.size(); ++i)
1239 cxxflags += "-D" + defines.at(i);
1240 t << "\t\t\t\t" << writeSettings("OTHER_CPLUSPLUSFLAGS", cxxflags, SettingsAsList, 5) << ";" << "\n";
1241 }
1242 t << "\t\t\t\t" << writeSettings("LEXFLAGS", fixListForOutput("QMAKE_LEXFLAGS")) << ";" << "\n"
1243 << "\t\t\t\t" << writeSettings("YACCFLAGS", fixListForOutput("QMAKE_YACCFLAGS")) << ";" << "\n"
1244 << "\t\t\t\t" << writeSettings("OTHER_REZFLAGS", QStringList()) << ";" << "\n"
1245 << "\t\t\t\t" << writeSettings("SECTORDER_FLAGS", QStringList()) << ";" << "\n"
1246 << "\t\t\t\t" << writeSettings("WARNING_CFLAGS", QStringList()) << ";" << "\n"
1247 << "\t\t\t\t" << writeSettings("PREBINDING", QStringList((project->isEmpty("QMAKE_DO_PREBINDING") ? "NO" : "YES")), SettingsNoQuote) << ";" << "\n";
1248 if(!project->isEmpty("PRECOMPILED_HEADER")) {
1249 if(pbVersion >= 38) {
1250 t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
1251 << "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
1252 } else {
1253 t << "\t\t\t\t" << writeSettings("PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
1254 << "\t\t\t\t" << writeSettings("PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
1255 }
1256 }
1257 if((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) ||
1258 (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
1259 project->isActiveConfig("lib_bundle"))) {
1260 QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
1261 if(plist.isEmpty())
1262 plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
1263 if(exists(plist)) {
1264 QFile plist_in_file(plist);
1265 if(plist_in_file.open(QIODevice::ReadOnly)) {
1266 QTextStream plist_in(&plist_in_file);
1267 QString plist_in_text = plist_in.readAll();
1268 plist_in_text = plist_in_text.replace("@ICON@",
1269 (project->isEmpty("ICON") ? QString("") : project->first("ICON").section(Option::dir_sep, -1)));
1270 if(project->first("TEMPLATE") == "app") {
1271 plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET"));
1272 } else {
1273 plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET"));
1274 plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." +
1275 project->first("VER_MIN"));
1276 }
1277 plist_in_text = plist_in_text.replace("@TYPEINFO@",
1278 (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") :
1279 project->first("QMAKE_PKGINFO_TYPEINFO").left(4)));
1280 QFile plist_out_file("Info.plist");
1281 if(plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
1282 QTextStream plist_out(&plist_out_file);
1283 plist_out << plist_in_text;
1284 t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n";
1285 }
1286 }
1287 }
1288 }
1289#if 1
1290 t << "\t\t\t\t" << writeSettings("BUILD_ROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n";
1291#endif
1292 if(!project->isActiveConfig("staticlib")) {
1293 t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS",
1294 fixListForOutput("SUBLIBS")
1295 + fixListForOutput("QMAKE_LFLAGS")
1296 + fixListForOutput("QMAKE_LIBDIR_FLAGS")
1297 + fixListForOutput("QMAKE_FRAMEWORKPATH_FLAGS")
1298 + fixListForOutput("QMAKE_LIBS"),
1299 SettingsAsList, 6) << ";" << "\n";
1300 }
1301 if(!project->isEmpty("DESTDIR")) {
1302 QString dir = project->first("DESTDIR");
1303 if (QDir::isRelativePath(dir))
1304 dir.prepend(qmake_getpwd() + Option::dir_sep);
1305 t << "\t\t\t\t" << writeSettings("INSTALL_DIR", dir) << ";" << "\n";
1306 }
1307 if (project->first("TEMPLATE") == "lib") {
1308 t << "\t\t\t\t" << writeSettings("INSTALL_PATH", QStringList()) << ";" << "\n";
1309 }
1310 if(!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") {
1311 t << "\t\t\t\t" << writeSettings("DYLIB_CURRENT_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")+"."+project->first("VER_PAT")) << ";" << "\n";
1312 if(project->isEmpty("COMPAT_VERSION"))
1313 t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")) << ";" << "\n";
1314 if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
1315 project->isActiveConfig("lib_bundle"))
1316 t << "\t\t\t\t" << writeSettings("FRAMEWORK_VERSION", project->first("QMAKE_FRAMEWORK_VERSION")) << ";" << "\n";
1317 }
1318 if(!project->isEmpty("COMPAT_FRAMEWORKPATH"))
1319 t << "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"), SettingsAsList, 5) << ";" << "\n";
1320 if(!project->isEmpty("COMPAT_VERSION"))
1321 t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("COMPAT_VERSION")) << ";" << "\n";
1322 if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
1323 t << "\t\t\t\t" << writeSettings("MACOSX_DEPLOYMENT_TARGET", project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET")) << ";" << "\n";
1324 if(pbVersion >= 38) {
1325 if(!project->isEmpty("OBJECTS_DIR"))
1326 t << "\t\t\t\t" << writeSettings("OBJROOT", fixForOutput(project->first("OBJECTS_DIR"))) << ";" << "\n";
1327 }
1328#if 0
1329 if(!project->isEmpty("DESTDIR"))
1330 t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(project->first("DESTDIR"))) << ";" << "\n";
1331 else
1332 t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(qmake_getpwd())) << ";" << "\n";
1333#endif
1334 {
1335 QStringList archs;
1336 if(project->isActiveConfig("x86"))
1337 archs += "i386";
1338 if(project->isActiveConfig("ppc")) {
1339 if(!archs.isEmpty())
1340 archs += " ";
1341 archs += "ppc";
1342 }
1343 if(project->isActiveConfig("ppc64")) {
1344 if(!archs.isEmpty())
1345 archs += " ";
1346 archs += "ppc64";
1347 }
1348 if(project->isActiveConfig("x86_64")) {
1349 if(!archs.isEmpty())
1350 archs += " ";
1351 archs += "x86_64";
1352 }
1353 if(!archs.isEmpty())
1354 t << "\t\t\t\t" << writeSettings("ARCHS", archs) << ";" << "\n";
1355
1356 }
1357 if(project->first("TEMPLATE") == "app") {
1358 if(pbVersion < 38 && project->isActiveConfig("app_bundle"))
1359 t << "\t\t\t\t" << writeSettings("WRAPPER_SUFFIX", "app") << ";" << "\n";
1360 t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", fixForOutput(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
1361 } else {
1362 if(!project->isActiveConfig("plugin") && project->isActiveConfig("staticlib")) {
1363 t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "STATIC") << ";" << "\n";
1364 } else {
1365 t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "DYNAMIC") << ";" << "\n";
1366 }
1367 QString lib = project->first("QMAKE_ORIG_TARGET");
1368 if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
1369 lib.prepend("lib");
1370 t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", escapeFilePath(lib)) << ";" << "\n";
1371 }
1372 tmp = project->values("QMAKE_PBX_VARS");
1373 for(int i = 0; i < tmp.count(); i++) {
1374 QString var = tmp[i], val = qgetenv(var.toLatin1());
1375 if(val.isEmpty() && var == "TB")
1376 val = "/usr/bin/";
1377 t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";" << "\n";
1378 }
1379 t << "\t\t\t" << "};" << "\n"
1380 << "\t\t\t" << "conditionalBuildSettings = {" << "\n"
1381 << "\t\t\t" << "};" << "\n"
1382 << "\t\t\t" << writeSettings("dependencies", project->values("QMAKE_PBX_TARGET_DEPENDS"), SettingsAsList, 4) << ";" << "\n"
1383 << "\t\t\t" << writeSettings("productReference", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
1384 << "\t\t\t" << writeSettings("shouldUseHeadermap", "1", SettingsNoQuote) << ";" << "\n";
1385 if(pbVersion >= 38)
1386 t << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n";
1387 if(project->first("TEMPLATE") == "app") {
1388 if(!project->isActiveConfig("app_bundle")) {
1389 if(pbVersion >= 38) {
1390 if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
1391 t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
1392 else
1393 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
1394 } else {
1395 t << "\t\t\t" << writeSettings("isa", "PBXToolTarget", SettingsNoQuote) << ";" << "\n";
1396 }
1397 } else {
1398 if(pbVersion >= 38) {
1399 if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
1400 t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
1401 else
1402 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.application") << ";" << "\n";
1403 } else {
1404 t << "\t\t\t" << writeSettings("isa", "PBXApplicationTarget", SettingsNoQuote) << ";" << "\n";
1405 }
1406 t << "\t\t\t" << "productSettingsXML = \"";
1407 bool read_plist = false;
1408 if(exists("Info.plist")) {
1409 QFile plist("Info.plist");
1410 if (plist.open(QIODevice::ReadOnly)) {
1411 read_plist = true;
1412 QTextStream stream(&plist);
1413 while(!stream.atEnd())
1414 t << stream.readLine().replace('"', "\\\"") << endl;
1415 }
1416 }
1417 if(!read_plist) {
1418 t << "<?xml version="
1419 << "\\\"1.0\\\" encoding=" << "\\\"UTF-8\\\"" << "?>" << "\n"
1420 << "\t\t\t\t" << "<!DOCTYPE plist SYSTEM \\\"file://localhost/System/"
1421 << "Library/DTDs/PropertyList.dtd\\\">" << "\n"
1422 << "\t\t\t\t" << "<plist version=\\\"0.9\\\">" << "\n"
1423 << "\t\t\t\t" << "<dict>" << "\n"
1424 << "\t\t\t\t\t" << "<key>CFBundleDevelopmentRegion</key>" << "\n"
1425 << "\t\t\t\t\t" << "<string>English</string>" << "\n"
1426 << "\t\t\t\t\t" << "<key>CFBundleExecutable</key>" << "\n"
1427 << "\t\t\t\t\t" << "<string>" << project->first("QMAKE_ORIG_TARGET") << "</string>" << "\n"
1428 << "\t\t\t\t\t" << "<key>CFBundleIconFile</key>" << "\n"
1429 << "\t\t\t\t\t" << "<string>" << var("ICON").section(Option::dir_sep, -1) << "</string>" << "\n"
1430 << "\t\t\t\t\t" << "<key>CFBundleInfoDictionaryVersion</key>" << "\n"
1431 << "\t\t\t\t\t" << "<string>6.0</string>" << "\n"
1432 << "\t\t\t\t\t" << "<key>CFBundlePackageType</key>" << "\n"
1433 << "\t\t\t\t\t" << "<string>APPL</string>" << "\n"
1434 << "\t\t\t\t\t" << "<key>CFBundleSignature</key>" << "\n"
1435 << "\t\t\t\t\t" << "<string>"
1436 << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") :
1437 project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << "</string>" << "\n"
1438 << "\t\t\t\t\t" << "<key>CFBundleVersion</key>" << "\n"
1439 << "\t\t\t\t\t" << "<string>0.1</string>" << "\n"
1440 << "\t\t\t\t\t" << "<key>CSResourcesFileMapped</key>" << "\n"
1441 << "\t\t\t\t\t" << "<true/>" << "\n"
1442 << "\t\t\t\t" << "</dict>" << "\n"
1443 << "\t\t\t\t" << "</plist>";
1444 }
1445 t << "\";" << "\n";
1446 }
1447 t << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
1448 << "\t\t\t" << writeSettings("productName", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
1449 } else {
1450 QString lib = project->first("QMAKE_ORIG_TARGET");
1451 if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
1452 lib.prepend("lib");
1453 t << "\t\t\t" << writeSettings("name", escapeFilePath(lib)) << ";" << "\n"
1454 << "\t\t\t" << writeSettings("productName", escapeFilePath(lib)) << ";" << "\n";
1455 if(pbVersion >= 38) {
1456 if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
1457 t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
1458 else if(project->isActiveConfig("staticlib"))
1459 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.static") << ";" << "\n";
1460 else if(project->isActiveConfig("lib_bundle"))
1461 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.framework") << ";" << "\n";
1462 else
1463 t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.dynamic") << ";" << "\n";
1464 } else {
1465 t << "\t\t\t" << writeSettings("isa", "PBXLibraryTarget", SettingsNoQuote) << ";" << "\n";
1466 }
1467 }
1468 t << "\t\t\t" << writeSettings("startupPath", "<<ProjectDirectory>>") << ";" << "\n";
1469 if(!project->isEmpty("DESTDIR"))
1470 t << "\t\t\t" << writeSettings("productInstallPath", escapeFilePath(project->first("DESTDIR"))) << ";" << "\n";
1471 t << "\t\t" << "};" << "\n";
1472 //DEBUG/RELEASE
1473 QString active_buildstyle;
1474 for(int as_release = 0; as_release < 2; as_release++)
1475 {
1476 QMap<QString, QString> settings;
1477 settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
1478 settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", as_release ? "NO" : "YES");
1479 if(!as_release)
1480 settings.insert("GCC_OPTIMIZATION_LEVEL", "0");
1481 if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
1482 settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
1483 {
1484 const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
1485 for(int i = 0; i < l.size(); ++i) {
1486 QString name = l.at(i);
1487 const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
1488 if(!project->isEmpty(name + QLatin1String(".name")))
1489 name = project->values(name + QLatin1String(".name")).first();
1490 settings.insert(name, value);
1491 }
1492 }
1493
1494 QString name;
1495 if(pbVersion >= 42)
1496 name = (as_release ? "Release" : "Debug");
1497 else
1498 name = (as_release ? "Deployment" : "Development");
1499 if(pbVersion >= 42) {
1500 QString key = keyFor("QMAKE_PBX_BUILDCONFIG_" + name);
1501 project->values("QMAKE_PBX_BUILDCONFIGS").append(key);
1502 t << "\t\t" << key << " = {" << "\n"
1503 << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
1504 << "\t\t\t" << "buildSettings = {" << "\n";
1505 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
1506 t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
1507 t << "\t\t\t" << "};" << "\n"
1508 << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
1509 << "\t\t" << "};" << "\n";
1510 }
1511
1512 QString key = keyFor("QMAKE_PBX_BUILDSTYLE_" + name);
1513 if(project->isActiveConfig("debug") != (bool)as_release) {
1514 project->values("QMAKE_PBX_BUILDSTYLES").append(key);
1515 active_buildstyle = name;
1516 } else if(pbVersion >= 42) {
1517 project->values("QMAKE_PBX_BUILDSTYLES").append(key);
1518 }
1519 t << "\t\t" << key << " = {" << "\n"
1520 << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
1521 << "\t\t\t" << "buildSettings = {" << "\n";
1522 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
1523 t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
1524 t << "\t\t\t" << "};" << "\n"
1525 << "\t\t\t" << writeSettings("isa", "PBXBuildStyle") << ";" << "\n"
1526 << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
1527 << "\t\t" << "};" << "\n";
1528 }
1529 if(pbVersion >= 42) {
1530 t << "\t\t" << keyFor("QMAKE_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
1531 << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
1532 << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
1533 << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
1534 << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
1535 << "\t\t" << "};" << "\n";
1536 }
1537 //ROOT
1538 t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n"
1539 << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
1540 << "\t\t\t" << writeSettings("hasScannedForEncodings", "1", SettingsNoQuote) << ";" << "\n"
1541 << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
1542 << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_PBX_ROOT_GROUP")) << ";" << "\n";
1543 if(pbVersion >= 42)
1544 t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
1545 t << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n"
1546 << "\t\t\t" << writeSettings("targets", project->values("QMAKE_PBX_TARGETS"), SettingsAsList, 4) << ";" << "\n"
1547 << "\t\t" << "};" << "\n";
1548
1549 //FOOTER
1550 t << "\t" << "};" << "\n"
1551 << "\t" << writeSettings("rootObject", keyFor("QMAKE_PBX_ROOT")) << ";" << "\n"
1552 << "}" << endl;
1553
1554 if(project->isActiveConfig("generate_pbxbuild_makefile")) {
1555 QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
1556 qmake_getpwd());
1557 QFile mkwrapf(mkwrap);
1558 if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
1559 writingUnixMakefileGenerator = true;
1560 debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
1561 QTextStream mkwrapt(&mkwrapf);
1562 writeHeader(mkwrapt);
1563 const char cleans[] = "preprocess_clean ";
1564 mkwrapt << "#This is a makefile wrapper for PROJECT BUILDER\n"
1565 << "all:" << "\n\t"
1566 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << "\n"
1567 << "install: all" << "\n\t"
1568 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " install\n"
1569 << "distclean clean: preprocess_clean" << "\n\t"
1570 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " clean" << "\n"
1571 << (!did_preprocess ? cleans : "") << ":" << "\n";
1572 if(did_preprocess)
1573 mkwrapt << cleans << ":" << "\n\t"
1574 << "make -f "
1575 << pbx_dir << Option::dir_sep << "qt_preprocess.mak $@" << endl;
1576 writingUnixMakefileGenerator = false;
1577 }
1578 }
1579 return true;
1580}
1581
1582QString
1583ProjectBuilderMakefileGenerator::findProgram(const QString &prog)
1584{
1585 QString ret = prog;
1586 if(QDir::isRelativePath(ret)) {
1587 QStringList paths = QString(qgetenv("PATH")).split(':');
1588 for(int i = 0; i < paths.size(); ++i) {
1589 QString path = paths.at(i) + "/" + prog;
1590 if(exists(path)) {
1591 ret = path;
1592 break;
1593 }
1594 }
1595 }
1596 return ret;
1597}
1598
1599QString
1600ProjectBuilderMakefileGenerator::fixForOutput(const QString &values)
1601{
1602 //get the environment variables references
1603 QRegExp reg_var("\\$\\((.*)\\)");
1604 for(int rep = 0; (rep = reg_var.indexIn(values, rep)) != -1;) {
1605 if(project->values("QMAKE_PBX_VARS").indexOf(reg_var.cap(1)) == -1)
1606 project->values("QMAKE_PBX_VARS").append(reg_var.cap(1));
1607 rep += reg_var.matchedLength();
1608 }
1609 QString ret = values;
1610 ret = ret.replace(QRegExp("\\\\ "), " "); //unescape spaces
1611 ret = ret.replace(QRegExp("('|\\\\|\")"), "\\\\1"); //fix quotes
1612 ret = ret.replace("\t", " "); //fix tabs
1613 ret = ret.replace(QRegExp(" "), "\\ "); //escape spaces
1614 return ret;
1615}
1616
1617QStringList
1618ProjectBuilderMakefileGenerator::fixListForOutput(const QString &where)
1619{
1620 QStringList ret;
1621 const QStringList &l = project->values(where);
1622 for(int i = 0; i < l.count(); i++)
1623 ret += fixForOutput(l[i]);
1624 return ret;
1625}
1626
1627QString
1628ProjectBuilderMakefileGenerator::keyFor(const QString &block)
1629{
1630#if 1 //This make this code much easier to debug..
1631 if(project->isActiveConfig("no_pb_munge_key"))
1632 return block;
1633#endif
1634 QString ret;
1635 if(!keys.contains(block)) {
1636 ret = qtMD5(block.toUtf8()).left(24).toUpper();
1637 keys.insert(block, ret);
1638 } else {
1639 ret = keys[block];
1640 }
1641 return ret;
1642}
1643
1644bool
1645ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) const
1646{
1647 if(QDir::isRelativePath(file.fileName()))
1648 file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
1649 QFileInfo fi(fileInfo(file.fileName()));
1650 if(fi.suffix() != "pbxproj" || file.fileName().isEmpty()) {
1651 QString output = file.fileName();
1652 if(fi.isDir())
1653 output += QDir::separator();
1654 if(!output.endsWith(projectSuffix())) {
1655 if(file.fileName().isEmpty() || fi.isDir()) {
1656 if(project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
1657 output += fileInfo(project->projectFile()).baseName();
1658 else
1659 output += project->first("QMAKE_ORIG_TARGET");
1660 }
1661 output += projectSuffix() + QDir::separator();
1662 } else if(output[(int)output.length() - 1] != QDir::separator()) {
1663 output += QDir::separator();
1664 }
1665 output += QString("project.pbxproj");
1666 output = unescapeFilePath(output);
1667 file.setFileName(output);
1668 }
1669 bool ret = UnixMakefileGenerator::openOutput(file, build);
1670 ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
1671 Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
1672 return ret;
1673}
1674
1675/* This function is such a hack it is almost pointless, but it
1676 eliminates the warning message from ProjectBuilder that the project
1677 file is for an older version. I guess this could be used someday if
1678 the format of the output is dependant upon the version of
1679 ProjectBuilder as well.
1680*/
1681int
1682ProjectBuilderMakefileGenerator::pbuilderVersion() const
1683{
1684 QString ret;
1685 if(!project->isEmpty("QMAKE_PBUILDER_VERSION")) {
1686 ret = project->first("QMAKE_PBUILDER_VERSION");
1687 } else {
1688 QString version, version_plist = project->first("QMAKE_PBUILDER_VERSION_PLIST");
1689 if(version_plist.isEmpty()) {
1690#ifdef Q_OS_DARWIN
1691 ret = QLatin1String("34");
1692 QCFType<CFURLRef> cfurl;
1693 OSStatus err = LSFindApplicationForInfo(0, CFSTR("com.apple.Xcode"), 0, 0, &cfurl);
1694 if (err == noErr) {
1695 QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
1696 if (bundle) {
1697 CFStringRef str = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle,
1698 CFSTR("CFBundleShortVersionString")));
1699 if (str) {
1700 QStringList versions = QCFString::toQString(str).split(QLatin1Char('.'));
1701 int versionMajor = versions.at(0).toInt();
1702 int versionMinor = versions.at(1).toInt();
1703 if (versionMajor >= 2) {
1704 ret = QLatin1String("42");
1705 } else if (versionMajor == 1 && versionMinor >= 5) {
1706 ret = QLatin1String("39");
1707 }
1708 }
1709 }
1710 }
1711#else
1712 if(exists("/Developer/Applications/Xcode.app/Contents/version.plist"))
1713 version_plist = "/Developer/Applications/Xcode.app/Contents/version.plist";
1714 else
1715 version_plist = "/Developer/Applications/Project Builder.app/Contents/version.plist";
1716#endif
1717 } else {
1718 version_plist = version_plist.replace(QRegExp("\""), "");
1719 }
1720 if (ret.isEmpty()) {
1721 QFile version_file(version_plist);
1722 if (version_file.open(QIODevice::ReadOnly)) {
1723 debug_msg(1, "pbuilder: version.plist: Reading file: %s", version_plist.toLatin1().constData());
1724 QTextStream plist(&version_file);
1725
1726 bool in_dict = false;
1727 QString current_key;
1728 QRegExp keyreg("^<key>(.*)</key>$"), stringreg("^<string>(.*)</string>$");
1729 while(!plist.atEnd()) {
1730 QString line = plist.readLine().trimmed();
1731 if(line == "<dict>")
1732 in_dict = true;
1733 else if(line == "</dict>")
1734 in_dict = false;
1735 else if(in_dict) {
1736 if(keyreg.exactMatch(line))
1737 current_key = keyreg.cap(1);
1738 else if(current_key == "CFBundleShortVersionString" && stringreg.exactMatch(line))
1739 version = stringreg.cap(1);
1740 }
1741 }
1742 plist.flush();
1743 version_file.close();
1744 } else {
1745 debug_msg(1, "pbuilder: version.plist: Failure to open %s", version_plist.toLatin1().constData());
1746 }
1747 if(version.isEmpty() && version_plist.contains("Xcode")) {
1748 ret = "39";
1749 } else {
1750 int versionMajor = version.left(1).toInt();
1751 if(versionMajor >= 2)
1752 ret = "42";
1753 else if(version == "1.5")
1754 ret = "39";
1755 else if(version == "1.1")
1756 ret = "34";
1757 }
1758 }
1759 }
1760
1761 if(!ret.isEmpty()) {
1762 bool ok;
1763 int int_ret = ret.toInt(&ok);
1764 if(ok) {
1765 debug_msg(1, "pbuilder: version.plist: Got version: %d", int_ret);
1766 return int_ret;
1767 }
1768 }
1769 debug_msg(1, "pbuilder: version.plist: Fallback to default version");
1770 return 42; //my fallback
1771}
1772
1773int
1774ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where)
1775{
1776 int ret = 0; //absolute is the default..
1777 if(QDir::isRelativePath(unescapeFilePath(where)))
1778 ret = 4; //relative
1779 return ret;
1780}
1781
1782QString
1783ProjectBuilderMakefileGenerator::projectSuffix() const
1784{
1785 const int pbVersion = pbuilderVersion();
1786 if(pbVersion >= 42)
1787 return ".xcodeproj";
1788 else if(pbVersion >= 38)
1789 return ".xcode";
1790 return ".pbproj";
1791}
1792
1793QString
1794ProjectBuilderMakefileGenerator::pbxbuild()
1795{
1796 if(exists("/usr/bin/pbbuild"))
1797 return "pbbuild";
1798 if(exists("/usr/bin/xcodebuild"))
1799 return "xcodebuild";
1800 return (pbuilderVersion() >= 38 ? "xcodebuild" : "pbxbuild");
1801}
1802
1803QString
1804ProjectBuilderMakefileGenerator::escapeFilePath(const QString &path) const
1805{
1806#if 1
1807 //in the middle of generating a Makefile!
1808 if(writingUnixMakefileGenerator)
1809 return UnixMakefileGenerator::escapeFilePath(path);
1810
1811 //generating stuff for the xml file!
1812 QString ret = path;
1813 if(!ret.isEmpty()) {
1814 ret = unescapeFilePath(ret);
1815 debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
1816 }
1817 return ret;
1818#else
1819 return UnixMakefileGenerator::escapeFilePath(path);
1820#endif
1821}
1822
1823QString
1824ProjectBuilderMakefileGenerator::writeSettings(QString var, QStringList vals, int flags, int indent_level)
1825{
1826 QString ret;
1827 const QString quote = (flags & SettingsNoQuote) ? "" : "\"";
1828 const QString escape_quote = quote.isEmpty() ? "" : "\\" + quote;
1829 QString newline = "\n";
1830 for(int i = 0; i < indent_level; ++i)
1831 newline += "\t";
1832 if(flags & SettingsAsList) {
1833 ret += var + " = (" + newline;
1834 for(int i = 0, count = 0; i < vals.size(); ++i) {
1835 QString val = vals.at(i);
1836 if(!val.isEmpty()) {
1837 if(count++ > 0)
1838 ret += "," + newline;
1839 ret += quote + val.replace(quote, escape_quote) + quote;
1840 }
1841 }
1842 ret += ")";
1843 } else {
1844 ret += var + " = " + quote;
1845 for(int i = 0; i < vals.size(); ++i) {
1846 QString val = vals.at(i);
1847// if(val.isEmpty())
1848// val = quote + quote;
1849 if(i)
1850 ret += " ";
1851 ret += val;
1852 }
1853 ret += quote;
1854 }
1855 return ret;
1856}
1857
1858QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.