1 /****************************************************************************
2 ** $Id: qt/pbuilder_pbx.cpp 3.3.8 edited Jan 11 14:37 $
3 **
4 ** Implementation of ProjectBuilderMakefileGenerator class.
5 **
6 ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
7 **
8 ** This file is part of qmake.
9 **
10 ** This file may be distributed under the terms of the Q Public License
11 ** as defined by Trolltech ASA of Norway and appearing in the file
12 ** LICENSE.QPL included in the packaging of this file.
13 **
14 ** This file may be distributed and/or modified under the terms of the
15 ** GNU General Public License version 2 as published by the Free Software
16 ** Foundation and appearing in the file LICENSE.GPL included in the
17 ** packaging of this file.
18 **
19 ** Licensees holding valid Qt Enterprise Edition licenses may use this
20 ** file in accordance with the Qt Commercial License Agreement provided
21 ** with the Software.
22 **
23 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 **
26 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27 ** information about Qt Commercial License Agreements.
28 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
29 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
30 **
31 ** Contact info@trolltech.com if any conditions of this licensing are
32 ** not clear to you.
33 **
34 **********************************************************************/
35
36 #include "pbuilder_pbx.h"
37 #include "option.h"
38 #include "meta.h"
39 #include <qdir.h>
40 #include <qdict.h>
41 #include <qregexp.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include "qtmd5.h"
45 #ifdef Q_OS_UNIX
46 # include <sys/types.h>
47 # include <sys/stat.h>
48 #endif
49
50 // Note: this is fairly hacky, but it does the job...
51
ProjectBuilderMakefileGenerator(QMakeProject * p)52 ProjectBuilderMakefileGenerator::ProjectBuilderMakefileGenerator(QMakeProject *p) : UnixMakefileGenerator(p)
53 {
54
55 }
56
57 bool
writeMakefile(QTextStream & t)58 ProjectBuilderMakefileGenerator::writeMakefile(QTextStream &t)
59 {
60 if(!project->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
61 /* for now just dump, I need to generated an empty xml or something.. */
62 fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
63 var("QMAKE_FAILED_REQUIREMENTS").latin1());
64 return TRUE;
65 }
66
67 project->variables()["MAKEFILE"].clear();
68 project->variables()["MAKEFILE"].append("Makefile");
69 if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib")
70 return writeMakeParts(t);
71 else if(project->first("TEMPLATE") == "subdirs")
72 return writeSubdirs(t, FALSE);
73 return FALSE;
74 }
75
76 bool
writeSubdirs(QTextStream & t,bool direct)77 ProjectBuilderMakefileGenerator::writeSubdirs(QTextStream &t, bool direct)
78 {
79 QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
80 QDir::currentDirPath());
81 QFile mkwrapf(mkwrap);
82 if(mkwrapf.open(IO_WriteOnly | IO_Translate)) {
83 debug_msg(1, "pbuilder: Creating file: %s", mkwrap.latin1());
84 QTextStream mkwrapt(&mkwrapf);
85 UnixMakefileGenerator::writeSubdirs(mkwrapt, direct);
86 }
87
88 //HEADER
89 const int pbVersion = pbuilderVersion();
90 t << "// !$*UTF8*$!" << "\n"
91 << "{" << "\n"
92 << "\t" << "archiveVersion = 1;" << "\n"
93 << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
94 << "\t" << "objectVersion = " << pbVersion << ";" << "\n"
95 << "\t" << "objects = {" << endl;
96
97 //SUBDIRS
98 QStringList subdirs = project->variables()["SUBDIRS"];
99 QString oldpwd = QDir::currentDirPath();
100 QMap<QString, QStringList> groups;
101 for(QStringList::Iterator it = subdirs.begin(); it != subdirs.end(); ++it) {
102 QFileInfo fi(Option::fixPathToLocalOS((*it), TRUE));
103 if(fi.exists()) {
104 if(fi.isDir()) {
105 QString profile = (*it);
106 if(!profile.endsWith(Option::dir_sep))
107 profile += Option::dir_sep;
108 profile += fi.baseName() + ".pro";
109 subdirs.append(profile);
110 } else {
111 QMakeProject tmp_proj;
112 QString dir = fi.dirPath(), fn = fi.fileName();
113 if(!dir.isEmpty()) {
114 if(!QDir::setCurrent(dir))
115 fprintf(stderr, "Cannot find directory: %s\n", dir.latin1());
116 }
117 if(tmp_proj.read(fn, oldpwd)) {
118 if(Option::debug_level) {
119 QMap<QString, QStringList> &vars = tmp_proj.variables();
120 for(QMap<QString, QStringList>::Iterator it = vars.begin();
121 it != vars.end(); ++it) {
122 if(it.key().left(1) != "." && !it.data().isEmpty())
123 debug_msg(1, "%s: %s === %s", fn.latin1(), it.key().latin1(),
124 it.data().join(" :: ").latin1());
125 }
126 }
127 if(tmp_proj.first("TEMPLATE") == "subdirs") {
128 subdirs += fileFixify(tmp_proj.variables()["SUBDIRS"]);
129 } else if(tmp_proj.first("TEMPLATE") == "app" || tmp_proj.first("TEMPLATE") == "lib") {
130 QString pbxproj = QDir::currentDirPath() + Option::dir_sep + tmp_proj.first("TARGET") + projectSuffix();
131 if(!QFile::exists(pbxproj)) {
132 warn_msg(WarnLogic, "Ignored (not found) '%s'", pbxproj.latin1());
133 goto nextfile; // # Dirty!
134 }
135 project->variables()["QMAKE_PBX_SUBDIRS"] += pbxproj;
136 //PROJECTREF
137 {
138 bool in_root = TRUE;
139 QString name = QDir::currentDirPath();
140 QString project_key = keyFor(pbxproj + "_PROJECTREF");
141 if(project->isActiveConfig("flat")) {
142 QString flat_file = fileFixify(name, oldpwd, Option::output_dir, TRUE);
143 if(flat_file.find(Option::dir_sep) != -1) {
144 QStringList dirs = QStringList::split(Option::dir_sep, flat_file);
145 name = dirs.back();
146 }
147 } else {
148 QString flat_file = fileFixify(name, oldpwd, Option::output_dir, TRUE);
149 if(QDir::isRelativePath(flat_file) && flat_file.find(Option::dir_sep) != -1) {
150 QString last_grp("QMAKE_PBX_HEIR_GROUP");
151 QStringList dirs = QStringList::split(Option::dir_sep, flat_file);
152 name = dirs.back();
153 for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
154 QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
155 if(dir_it == dirs.begin()) {
156 if(!groups.contains(new_grp))
157 project->variables()["QMAKE_PBX_GROUPS"].append(new_grp_key);
158 } else {
159 if(!groups[last_grp].contains(new_grp_key))
160 groups[last_grp] += new_grp_key;
161 }
162 last_grp = new_grp;
163 }
164 groups[last_grp] += project_key;
165 in_root = FALSE;
166 }
167 }
168 if(in_root)
169 project->variables()["QMAKE_PBX_GROUPS"] += project_key;
170 t << "\t\t" << project_key << " = {" << "\n"
171 << "\t\t\t" << "isa = PBXFileReference;" << "\n"
172 << "\t\t\t" << "name = " << tmp_proj.first("TARGET") << ";" << "\n"
173 << "\t\t\t" << "path = " << pbxproj << ";" << "\n"
174 << "\t\t\t" << "refType = 0;" << "\n"
175 << "\t\t\t" << "sourceTree = \"<absolute>\";" << "\n"
176 << "\t\t" << "};" << "\n";
177 //PRODUCTGROUP
178 t << "\t\t" << keyFor(pbxproj + "_PRODUCTGROUP") << " = {" << "\n"
179 << "\t\t\t" << "children = (" << "\n"
180 << "\t\t\t" << ");" << "\n"
181 << "\t\t\t" << "isa = PBXGroup;" << "\n"
182 << "\t\t\t" << "name = Products;" << "\n"
183 << "\t\t\t" << "refType = 4;" << "\n"
184 << "\t\t\t" << "sourceTree = \"<group>\";" << "\n"
185 << "\t\t" << "};" << "\n";
186 }
187 }
188 }
189 nextfile:
190 QDir::setCurrent(oldpwd);
191 }
192 }
193 }
194 for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
195 t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
196 << "\t\t\t" << "isa = PBXGroup;" << "\n"
197 << "\t\t\t" << "children = (" << "\n"
198 << valGlue(grp_it.data(), "\t\t\t\t", ",\n\t\t\t\t", "\n")
199 << "\t\t\t" << ");" << "\n"
200 << "\t\t\t" << "name = \"" << grp_it.key().section(Option::dir_sep, -1) << "\";" << "\n"
201 << "\t\t\t" << "refType = 4;" << "\n"
202 << "\t\t" << "};" << "\n";
203 }
204
205 //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
206 //BUILDSTYLE
207 QString active_buildstyle;
208 #if 0
209 for(int as_release = 0; as_release < 2; as_release++)
210 #else
211 bool as_release = !project->isActiveConfig("debug");
212 #endif
213 {
214 QMap<QString, QString> settings;
215 settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
216 if(as_release)
217 settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
218 QString name;
219 if(pbVersion >= 42)
220 name = (as_release ? "Release" : "Debug");
221 else
222 name = (as_release ? "Deployment" : "Development");
223
224 if(pbVersion >= 42) {
225 QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_" + name);
226 project->variables()["QMAKE_SUBDIR_PBX_BUILDCONFIGS"].append(key);
227 t << "\t\t" << key << " = {" << "\n"
228 << "\t\t\t" << "isa = XCBuildConfiguration;" << "\n"
229 << "\t\t\t" << "buildSettings = {" << "\n";
230 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
231 t << "\t\t\t\t" << set_it.key() << " = \"" << set_it.data() << "\";\n";
232 t << "\t\t\t" << "};" << "\n"
233 << "\t\t\t" << "name = " << name << ";" << "\n"
234 << "\t\t" << "};" << "\n";
235 }
236
237 QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDSTYLE_" + name);
238 if(project->isActiveConfig("debug") != (bool)as_release) {
239 project->variables()["QMAKE_SUBDIR_PBX_BUILDSTYLES"].append(key);
240 active_buildstyle = name;
241 } else if(pbVersion >= 42) {
242 project->variables()["QMAKE_SUBDIR_PBX_BUILDSTYLES"].append(key);
243 }
244 t << "\t\t" << key << " = {" << "\n"
245 << "\t\t\t" << "buildRules = (" << "\n"
246 << "\t\t\t" << ");" << "\n"
247 << "\t\t\t" << "buildSettings = {" << "\n";
248 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
249 t << "\t\t\t\t" << set_it.key() << " = \"" << set_it.data() << "\";\n";
250 t << "\t\t\t" << "};" << "\n"
251 << "\t\t\t" << "isa = PBXBuildStyle;" << "\n"
252 << "\t\t\t" << "name = " << name << ";" << "\n"
253 << "\t\t" << "};" << "\n";
254 }
255 if(pbVersion >= 42) {
256 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
257 << "\t\t\t" << "isa = XCConfigurationList;" << "\n"
258 << "\t\t\t" << "buildConfigurations = (" << "\n"
259 << varGlue("QMAKE_SUBDIR_PBX_BUILDCONFIGS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
260 << "\t\t\t" << ");" << "\n"
261 << "\t\t\t" << "defaultConfigurationIsVisible = 0;" << "\n"
262 << "\t\t\t" << "defaultConfigurationIsName = " << active_buildstyle << ";" << "\n"
263 << "\t\t" << "};" << "\n";
264 }
265
266 #ifdef GENERATE_AGGREGRATE_SUBDIR
267 //target
268 t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_AGGREGATE_TARGET") << " = {" << "\n"
269 << "\t\t\t" << "buidPhases = (" << "\n"
270 << "\t\t\t" << ");" << "\n"
271 << "\t\t\t" << "buildSettings = {" << "\n"
272 << "\t\t\t\t" << "PRODUCT_NAME = " << project->variables()["TARGET"].first() << ";" << "\n"
273 << "\t\t\t" << "};" << "\n"
274 << "\t\t\t" << "dependencies = (" << "\n";
275 {
276 const QStringList &qmake_subdirs = project->variables()["QMAKE_PBX_SUBDIRS"];
277 for(int i = 0; i < qmake_subdirs.count(); i++)
278 t << "\t\t\t\t" << keyFor(qmake_subdirs[i] + "_TARGETREF") << "," << "\n";
279 }
280 t << "\t\t\t" << ");" << "\n"
281 << "\t\t\t" << "isa = PBXAggregateTarget;" << "\n"
282 << "\t\t\t" << "name = " << project->variables()["TARGET"].first() << ";" << "\n"
283 << "\t\t\t" << "productName = " << project->variables()["TARGET"].first() << ";" << "\n"
284 << "\t\t" << "};" << "\n";
285 #endif
286
287 //ROOT_GROUP
288 t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n"
289 << "\t\t\t" << "children = (" << "\n"
290 << varGlue("QMAKE_PBX_GROUPS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
291 << "\t\t\t" << ");" << "\n"
292 << "\t\t\t" << "isa = PBXGroup;" << "\n"
293 << "\t\t\t" << "refType = 4;" << "\n"
294 << "\t\t\t" << "sourceTree = \"<group>\";" << "\n"
295 << "\t\t" << "};" << "\n";
296
297 //ROOT
298 t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n"
299 << "\t\t\t" << "buildSettings = {" << "\n"
300 << "\t\t\t" << "};" << "\n"
301 << "\t\t\t" << "buildStyles = (" << "\n"
302 << varGlue("QMAKE_PBX_BUILDSTYLES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
303 << "\t\t\t" << ");" << "\n"
304 << "\t\t\t" << "isa = PBXProject;" << "\n"
305 << "\t\t\t" << "mainGroup = " << keyFor("QMAKE_PBX_ROOT_GROUP") << ";" << "\n"
306 << "\t\t\t" << "projectDirPath = \"\";" << "\n";
307 if(pbVersion >= 42)
308 t << "\t\t\t" << "buildConfigurationList = " << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << ";" << "\n";
309 t << "\t\t\t" << "projectReferences = (" << "\n";
310 {
311 QStringList &libdirs = project->variables()["QMAKE_PBX_SUBDIRS"];
312 for(QStringList::Iterator it = libdirs.begin(); it != libdirs.end(); ++it)
313 t << "\t\t\t\t" << "{" << "\n"
314 << "\t\t\t\t\t" << "ProductGroup = " << keyFor((*it) + "_PRODUCTGROUP") << ";" << "\n"
315 << "\t\t\t\t\t" << "ProjectRef = " << keyFor((*it) + "_PROJECTREF") << ";" << "\n"
316 << "\t\t\t\t" << "}," << "\n";
317 }
318 t << "\t\t\t" << ");" << "\n"
319 << "\t\t\t" << "targets = (" << "\n"
320 << "\t\t\t" << ");" << "\n"
321 << "\t\t" << "};" << "\n";
322
323 //FOOTER
324 t << "\t" << "};" << "\n"
325 << "\t" << "rootObject = " << keyFor("QMAKE_PBX_ROOT") << ";" << "\n"
326 << "}" << endl;
327
328 return TRUE;
329 }
330
331 bool
writeMakeParts(QTextStream & t)332 ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
333 {
334 int i;
335 QStringList tmp;
336 bool did_preprocess = FALSE;
337
338 //HEADER
339 const int pbVersion = pbuilderVersion();
340 t << "// !$*UTF8*$!" << "\n"
341 << "{" << "\n"
342 << "\t" << "archiveVersion = 1;" << "\n"
343 << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
344 << "\t" << "objectVersion = " << pbVersion << ";" << "\n"
345 << "\t" << "objects = {" << endl;
346
347 //MAKE QMAKE equivelant
348 if(!project->isActiveConfig("no_autoqmake") && project->projectFile() != "(stdin)") {
349 QString mkfile = pbx_dir + Option::dir_sep + "qt_makeqmake.mak";
350 QFile mkf(mkfile);
351 if(mkf.open(IO_WriteOnly | IO_Translate)) {
352 debug_msg(1, "pbuilder: Creating file: %s", mkfile.latin1());
353 QTextStream mkt(&mkf);
354 writeHeader(mkt);
355 mkt << "QMAKE = " <<
356 (project->isEmpty("QMAKE_QMAKE") ? QString("$(QTDIR)/bin/qmake") :
357 var("QMAKE_QMAKE")) << endl;
358 writeMakeQmake(mkt);
359 mkf.close();
360 }
361 QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE");
362 mkfile = fileFixify(mkfile, QDir::currentDirPath());
363 project->variables()["QMAKE_PBX_PRESCRIPT_BUILDPHASES"].append(phase_key);
364 t << "\t\t" << phase_key << " = {" << "\n"
365 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
366 << "\t\t\t" << "files = (" << "\n"
367 << "\t\t\t" << ");" << "\n"
368 << "\t\t\t" << "generatedFileNames = (" << "\n"
369 << "\t\t\t" << ");" << "\n"
370 << "\t\t\t" << "isa = PBXShellScriptBuildPhase;" << "\n"
371 << "\t\t\t" << "name = \"Qt Qmake\";" << "\n"
372 << "\t\t\t" << "neededFileNames = (" << "\n"
373 << "\t\t\t" << ");" << "\n"
374 << "\t\t\t" << "shellPath = /bin/sh;" << "\n"
375 << "\t\t\t" << "shellScript = \"make -C " << QDir::currentDirPath() <<
376 " -f " << mkfile << "\";" << "\n"
377 << "\t\t" << "};" << "\n";
378 }
379
380 //DUMP SOURCES
381 QMap<QString, QStringList> groups;
382 QString srcs[] = { "HEADERS", "SOURCES", "SRCMOC", "UICIMPLS", "QMAKE_IMAGE_COLLECTION",
383 "FORMS", "QMAKE_INTERNAL_INCLUDED_FILES", QString::null };
384 for(i = 0; !srcs[i].isNull(); i++) {
385 tmp = project->variables()[srcs[i]];
386 if(srcs[i] == "QMAKE_INTERNAL_INCLUDED_FILES") {
387 QString pfile = project->projectFile();
388 if(pfile != "(stdin)")
389 tmp.prepend(pfile);
390 }
391 QStringList &src_list = project->variables()["QMAKE_PBX_" + srcs[i]];
392 QStringList &root_group_list = project->variables()["QMAKE_PBX_GROUPS"];
393
394 //hard coded groups..
395 QString src_group;
396 if(srcs[i] == "SOURCES")
397 src_group = "Sources";
398 else if(srcs[i] == "HEADERS")
399 src_group = "Headers";
400 else if(srcs[i] == "SRCMOC")
401 src_group = "Sources [moc]";
402 else if(srcs[i] == "UICIMPLS" || srcs[i] == "FORMS")
403 src_group = "Sources [uic]";
404 else if(srcs[i] == "QMAKE_IMAGE_COLLECTION")
405 src_group = "Sources [images]";
406 else if(srcs[i] == "QMAKE_INTERNAL_INCLUDED_FILES")
407 src_group = "Sources [qmake]";
408
409 for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
410 QStringList files = (*it);
411 bool buildable = TRUE;
412 if(srcs[i] == "FORMS") {
413 QString form_dot_h = (*it) + Option::h_ext.first();
414 if(QFile::exists(form_dot_h))
415 files += form_dot_h;
416 buildable = FALSE;
417 } else if(srcs[i] == "HEADERS" || srcs[i] == "QMAKE_INTERNAL_INCLUDED_FILES") {
418 buildable = FALSE;
419 }
420
421 files = fileFixify(files);
422 for(QStringList::Iterator file_it = files.begin(); file_it != files.end(); ++file_it) {
423 QString file = (*file_it);
424 if(file.length() >= 2 && (file[0] == '"' || file[0] == '\'') && file[(int) file.length()-1] == file[0])
425 file = file.mid(1, file.length()-2);
426 if(file.endsWith(Option::cpp_moc_ext) || file.endsWith(Option::prl_ext))
427 continue;
428 bool in_root = TRUE;
429 QString src_key = keyFor(file), name = file;
430 if(project->isActiveConfig("flat")) {
431 QString flat_file = fileFixify(file, QDir::currentDirPath(), Option::output_dir, TRUE);
432 if(flat_file.find(Option::dir_sep) != -1) {
433 QStringList dirs = QStringList::split(Option::dir_sep, flat_file);
434 name = dirs.back();
435 }
436 } else {
437 QString flat_file = fileFixify(file, QDir::currentDirPath(), Option::output_dir, TRUE);
438 if(QDir::isRelativePath(flat_file) && flat_file.find(Option::dir_sep) != -1) {
439 QString last_grp("QMAKE_PBX_" + src_group + "_HEIR_GROUP");
440 QStringList dirs = QStringList::split(Option::dir_sep, flat_file);
441 name = dirs.back();
442 dirs.pop_back(); //remove the file portion as it will be added via src_key
443 for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
444 QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
445 if(dir_it == dirs.begin()) {
446 if(!src_list.contains(new_grp_key))
447 src_list.append(new_grp_key);
448 } else {
449 if(!groups[last_grp].contains(new_grp_key))
450 groups[last_grp] += new_grp_key;
451 }
452 last_grp = new_grp;
453 }
454 groups[last_grp] += src_key;
455 in_root = FALSE;
456 }
457 }
458 if(in_root)
459 src_list.append(src_key);
460 //source reference
461 t << "\t\t" << src_key << " = {" << "\n"
462 << "\t\t\t" << "isa = PBXFileReference;" << "\n"
463 << "\t\t\t" << "name = \"" << name << "\";" << "\n"
464 << "\t\t\t" << "path = \"" << file << "\";" << "\n"
465 << "\t\t\t" << "refType = " << reftypeForFile(file) << ";" << "\n";
466 if(pbVersion >= 38) {
467 QString filetype;
468 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
469 if(file.endsWith((*cppit))) {
470 filetype = "sourcecode.cpp.cpp";
471 break;
472 }
473 }
474 if(!filetype.isNull())
475 t << "\t\t\t" << "lastKnownFileType = " << filetype << ";" << "\n";
476 }
477 t << "\t\t" << "};" << "\n";
478 if(buildable) { //build reference
479 QString obj_key = file + ".o";
480 obj_key = keyFor(obj_key);
481 t << "\t\t" << obj_key << " = {" << "\n"
482 << "\t\t\t" << "fileRef = " << src_key << ";" << "\n"
483 << "\t\t\t" << "isa = PBXBuildFile;" << "\n"
484 << "\t\t\t" << "settings = {" << "\n"
485 << "\t\t\t\t" << "ATTRIBUTES = (" << "\n"
486 << "\t\t\t\t" << ");" << "\n"
487 << "\t\t\t" << "};" << "\n"
488 << "\t\t" << "};" << "\n";
489 project->variables()["QMAKE_PBX_OBJ"].append(obj_key);
490 }
491 }
492 }
493 if(!src_list.isEmpty()) {
494 if(srcs[i] == "SOURCES") {
495 if(project->first("TEMPLATE") == "app" && !project->isEmpty("RC_FILE")) { //Icon
496 QString icns_file = keyFor("ICNS_FILE");
497 src_list.append(icns_file);
498 t << "\t\t" << icns_file << " = {" << "\n"
499 << "\t\t\t" << "isa = PBXFileReference;" << "\n"
500 << "\t\t\t" << "path = \"" << project->first("RC_FILE") << "\";" << "\n"
501 << "\t\t\t" << "refType = " << reftypeForFile(project->first("RC_FILE")) << ";" << "\n"
502 << "\t\t" << "};" << "\n";
503 t << "\t\t" << keyFor("ICNS_FILE_REFERENCE") << " = {" << "\n"
504 << "\t\t\t" << "fileRef = " << icns_file << ";" << "\n"
505 << "\t\t\t" << "isa = PBXBuildFile;" << "\n"
506 << "\t\t\t" << "settings = {" << "\n"
507 << "\t\t\t" << "};" << "\n"
508 << "\t\t" << "};" << "\n";
509 }
510 }
511
512 QString src_group_key = keyFor(src_group);
513 if(root_group_list.findIndex(src_group_key) == -1)
514 root_group_list += src_group_key;
515
516 QStringList &group = groups[src_group];
517 for(QStringList::Iterator src_it = src_list.begin(); src_it != src_list.end(); ++src_it) {
518 if(group.findIndex((*src_it)) == -1)
519 group += (*src_it);
520 }
521 }
522 }
523 for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
524 t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
525 << "\t\t\t" << "isa = PBXGroup;" << "\n"
526 << "\t\t\t" << "children = (" << "\n"
527 << valGlue(grp_it.data(), "\t\t\t\t", ",\n\t\t\t\t", "\n")
528 << "\t\t\t" << ");" << "\n"
529 << "\t\t\t" << "name = \"" << grp_it.key().section(Option::dir_sep, -1) << "\";" << "\n"
530 << "\t\t\t" << "refType = 4;" << "\n"
531 << "\t\t" << "};" << "\n";
532 }
533
534 //PREPROCESS BUILDPHASE (just a makefile)
535 if(!project->isEmpty("UICIMPLS") || !project->isEmpty("SRCMOC") || !project->isEmpty("IMAGES") ||
536 !project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES")) {
537 QString mkfile = pbx_dir + Option::dir_sep + "qt_preprocess.mak";
538 QFile mkf(mkfile);
539 if(mkf.open(IO_WriteOnly | IO_Translate)) {
540 did_preprocess = TRUE;
541 debug_msg(1, "pbuilder: Creating file: %s", mkfile.latin1());
542 QTextStream mkt(&mkf);
543 writeHeader(mkt);
544 mkt << "MOC = " << Option::fixPathToTargetOS(var("QMAKE_MOC")) << endl;
545 mkt << "UIC = " << Option::fixPathToTargetOS(var("QMAKE_UIC")) << endl;
546 mkt << "LEX = " << var("QMAKE_LEX") << endl;
547 mkt << "LEXFLAGS = " << var("QMAKE_LEXFLAGS") << endl;
548 mkt << "YACC = " << var("QMAKE_YACC") << endl;
549 mkt << "YACCFLAGS = " << var("QMAKE_YACCFLAGS") << endl;
550 mkt << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
551 mkt << "MOVE = " << var("QMAKE_MOVE") << endl << endl;
552 mkt << "FORMS = " << varList("UICIMPLS") << endl;
553 mkt << "IMAGES = " << varList("QMAKE_IMAGE_COLLECTION") << endl;
554 mkt << "MOCS = " << varList("SRCMOC") << endl;
555 mkt << "PARSERS =";
556 if(!project->isEmpty("YACCSOURCES")) {
557 QStringList &yaccs = project->variables()["YACCSOURCES"];
558 for(QStringList::Iterator yit = yaccs.begin(); yit != yaccs.end(); ++yit) {
559 QFileInfo fi((*yit));
560 mkt << " " << fi.dirPath() << Option::dir_sep << fi.baseName(TRUE)
561 << Option::yacc_mod << Option::cpp_ext.first();
562 }
563 }
564 if(!project->isEmpty("LEXSOURCES")) {
565 QStringList &lexs = project->variables()["LEXSOURCES"];
566 for(QStringList::Iterator lit = lexs.begin(); lit != lexs.end(); ++lit) {
567 QFileInfo fi((*lit));
568 mkt << " " << fi.dirPath() << Option::dir_sep << fi.baseName(TRUE)
569 << Option::lex_mod << Option::cpp_ext.first();
570 }
571 }
572 mkt << "\n";
573 mkt << "preprocess: $(FORMS) $(MOCS) $(PARSERS) $(IMAGES)" << endl;
574 mkt << "clean preprocess_clean: mocclean uiclean parser_clean" << endl << endl;
575 mkt << "mocclean:" << "\n";
576 if(!project->isEmpty("SRCMOC"))
577 mkt << "\t-rm -f $(MOCS)" << "\n";
578 mkt << "uiclean:" << "\n";
579 if(!project->isEmpty("UICIMPLS"))
580 mkt << "\t-rm -f $(FORMS)" << "\n";
581 if(!project->isEmpty("QMAKE_IMAGE_COLLECTION"))
582 mkt << "\t-rm -f $(IMAGES)" << "\n";
583 mkt << "parser_clean:" << "\n";
584 if(!project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES"))
585 mkt << "\t-rm -f $(PARSERS)" << "\n";
586 writeUicSrc(mkt, "FORMS");
587 writeMocSrc(mkt, "HEADERS");
588 writeMocSrc(mkt, "SOURCES");
589 writeMocSrc(mkt, "UICDECLS");
590 writeYaccSrc(mkt, "YACCSOURCES");
591 writeLexSrc(mkt, "LEXSOURCES");
592 writeImageSrc(mkt, "QMAKE_IMAGE_COLLECTION");
593 mkf.close();
594 }
595 mkfile = fileFixify(mkfile, QDir::currentDirPath());
596 QString phase_key = keyFor("QMAKE_PBX_PREPROCESS_TARGET");
597 // project->variables()["QMAKE_PBX_BUILDPHASES"].append(phase_key);
598 project->variables()["QMAKE_PBX_PRESCRIPT_BUILDPHASES"].append(phase_key);
599 t << "\t\t" << phase_key << " = {" << "\n"
600 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
601 << "\t\t\t" << "files = (" << "\n"
602 << "\t\t\t" << ");" << "\n"
603 << "\t\t\t" << "generatedFileNames = (" << "\n"
604 << varGlue("QMAKE_PBX_OBJ", "\t\t\t\t", ",\n\t\t\t\t", "\n")
605 << "\t\t\t" << ");" << "\n"
606 << "\t\t\t" << "isa = PBXShellScriptBuildPhase;" << "\n"
607 << "\t\t\t" << "name = \"Qt Preprocessors\";" << "\n"
608 << "\t\t\t" << "neededFileNames = (" << "\n"
609 << varGlue("QMAKE_PBX_OBJ", "\t\t\t\t", ",\n\t\t\t\t", "\n")
610 << "\t\t\t" << ");" << "\n"
611 << "\t\t\t" << "shellPath = /bin/sh;" << "\n"
612 << "\t\t\t" << "shellScript = \"make -C " << QDir::currentDirPath() <<
613 " -f " << mkfile << "\";" << "\n"
614 << "\t\t" << "};" << "\n";
615 }
616
617 //SOURCE BUILDPHASE
618 if(!project->isEmpty("QMAKE_PBX_OBJ")) {
619 QString grp = "Build Sources", key = keyFor(grp);
620 project->variables()["QMAKE_PBX_BUILDPHASES"].append(key);
621 t << "\t\t" << key << " = {" << "\n"
622 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
623 << "\t\t\t" << "files = (" << "\n"
624 << varGlue("QMAKE_PBX_OBJ", "\t\t\t\t", ",\n\t\t\t\t", "\n")
625 << "\t\t\t" << ");" << "\n"
626 << "\t\t\t" << "isa = PBXSourcesBuildPhase;" << "\n"
627 << "\t\t\t" << "name = \"" << grp << "\";" << "\n"
628 << "\t\t" << "};" << "\n";
629 }
630
631 if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
632 QStringList &libdirs = project->variables()["QMAKE_PBX_LIBPATHS"];
633 QString libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_LIBS", QString::null };
634 for(i = 0; !libs[i].isNull(); i++) {
635 tmp = project->variables()[libs[i]];
636 for(QStringList::Iterator it = tmp.begin(); it != tmp.end();) {
637 bool remove = FALSE;
638 QString library, name, opt = (*it).stripWhiteSpace();
639 if(opt.length() >= 2 && (opt[0] == '"' || opt[0] == '\'') && opt[(int) opt.length()-1] == opt[0])
640 opt = opt.mid(1, opt.length()-2);
641 if(opt.startsWith("-L")) {
642 QString r = opt.right(opt.length() - 2);
643 fixEnvVariables(r);
644 libdirs.append(r);
645 } else if(opt == "-prebind") {
646 project->variables()["QMAKE_DO_PREBINDING"].append("TRUE");
647 remove = TRUE;
648 } else if(opt.startsWith("-l")) {
649 name = opt.right(opt.length() - 2);
650 QString lib("lib" + name);
651 for(QStringList::Iterator lit = libdirs.begin(); lit != libdirs.end(); ++lit) {
652 if(project->isActiveConfig("link_prl")) {
653 /* This isn't real nice, but it is real usefull. This looks in a prl
654 for what the library will ultimately be called so we can stick it
655 in the ProjectFile. If the prl format ever changes (not likely) then
656 this will not really work. However, more concerning is that it will
657 encode the version number in the Project file which might be a bad
658 things in days to come? --Sam
659 */
660 QString lib_file = (*lit) + Option::dir_sep + lib;
661 if(QMakeMetaInfo::libExists(lib_file)) {
662 QMakeMetaInfo libinfo;
663 if(libinfo.readLib(lib_file)) {
664 if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) {
665 library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
666 debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
667 opt.latin1(), lib_file.latin1(), library.latin1());
668 remove = TRUE;
669 }
670 }
671 }
672 }
673 if(!remove) {
674 QString extns[] = { ".dylib", ".so", ".a", QString::null };
675 for(int n = 0; !remove && !extns[n].isNull(); n++) {
676 QString tmp = (*lit) + Option::dir_sep + lib + extns[n];
677 if(QFile::exists(tmp)) {
678 library = tmp;
679 debug_msg(1, "pbuilder: Found library (%s) via %s",
680 opt.latin1(), library.latin1());
681 remove = TRUE;
682 }
683 }
684 }
685 }
686 } else if(opt == "-framework") {
687 ++it;
688 if(it == tmp.end())
689 break;
690 QStringList &fdirs = project->variables()["QMAKE_FRAMEWORKDIR"];
691 if(fdirs.isEmpty())
692 fdirs.append("/System/Library/Frameworks/");
693 for(QStringList::Iterator fit = fdirs.begin(); fit != fdirs.end(); ++fit) {
694 if(QFile::exists((*fit) + QDir::separator() + (*it) + ".framework")) {
695 --it;
696 it = tmp.remove(it);
697 remove = TRUE;
698 library = (*fit) + Option::dir_sep + (*it) + ".framework";
699 break;
700 }
701 }
702 } else if(opt.left(1) != "-") {
703 if(QFile::exists(opt)) {
704 remove = TRUE;
705 library = opt;
706 }
707 }
708 if(!library.isEmpty()) {
709 if(name.isEmpty()) {
710 int slsh = library.findRev(Option::dir_sep);
711 if(slsh != -1)
712 name = library.right(library.length() - slsh - 1);
713 }
714 library = fileFixify(library);
715 QString key = keyFor(library);
716 bool is_frmwrk = (library.endsWith(".framework"));
717 t << "\t\t" << key << " = {" << "\n"
718 << "\t\t\t" << "isa = " << (is_frmwrk ? "PBXFrameworkReference" : "PBXFileReference") << ";" << "\n"
719 << "\t\t\t" << "name = \"" << name << "\";" << "\n"
720 << "\t\t\t" << "path = \"" << library << "\";" << "\n"
721 << "\t\t\t" << "refType = " << reftypeForFile(library) << ";" << "\n"
722 << "\t\t" << "};" << "\n";
723 project->variables()["QMAKE_PBX_LIBRARIES"].append(key);
724 QString obj_key = library + ".o";
725 obj_key = keyFor(obj_key);
726 t << "\t\t" << obj_key << " = {" << "\n"
727 << "\t\t\t" << "fileRef = " << key << ";" << "\n"
728 << "\t\t\t" << "isa = PBXBuildFile;" << "\n"
729 << "\t\t\t" << "settings = {" << "\n"
730 << "\t\t\t" << "};" << "\n"
731 << "\t\t" << "};" << "\n";
732 project->variables()["QMAKE_PBX_BUILD_LIBRARIES"].append(obj_key);
733 }
734 if(remove)
735 it = tmp.remove(it);
736 else
737 ++it;
738 }
739 project->variables()[libs[i]] = tmp;
740 }
741 }
742 //SUBLIBS BUILDPHASE (just another makefile)
743 if(!project->isEmpty("SUBLIBS")) {
744 QString mkfile = pbx_dir + Option::dir_sep + "qt_sublibs.mak";
745 QFile mkf(mkfile);
746 if(mkf.open(IO_WriteOnly | IO_Translate)) {
747 debug_msg(1, "pbuilder: Creating file: %s", mkfile.latin1());
748 QTextStream mkt(&mkf);
749 writeHeader(mkt);
750 mkt << "SUBLIBS= ";
751 tmp = project->variables()["SUBLIBS"];
752 QStringList::Iterator it;
753 for(it = tmp.begin(); it != tmp.end(); ++it)
754 t << "tmp/lib" << (*it) << ".a ";
755 t << endl << endl;
756 mkt << "sublibs: $(SUBLIBS)" << endl << endl;
757 tmp = project->variables()["SUBLIBS"];
758 for(it = tmp.begin(); it != tmp.end(); ++it)
759 t << "tmp/lib" << (*it) << ".a" << ":\n\t"
760 << var(QString("MAKELIB") + (*it)) << endl << endl;
761 mkf.close();
762 }
763 QString phase_key = keyFor("QMAKE_PBX_SUBLIBS_BUILDPHASE");
764 mkfile = fileFixify(mkfile, QDir::currentDirPath());
765 project->variables()["QMAKE_PBX_PRESCRIPT_BUILDPHASES"].append(phase_key);
766 t << "\t\t" << phase_key << " = {" << "\n"
767 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
768 << "\t\t\t" << "files = (" << "\n"
769 << "\t\t\t" << ");" << "\n"
770 << "\t\t\t" << "generatedFileNames = (" << "\n"
771 << "\t\t\t" << ");" << "\n"
772 << "\t\t\t" << "isa = PBXShellScriptBuildPhase;" << "\n"
773 << "\t\t\t" << "name = \"Qt Sublibs\";" << "\n"
774 << "\t\t\t" << "neededFileNames = (" << "\n"
775 << "\t\t\t" << ");" << "\n"
776 << "\t\t\t" << "shellPath = /bin/sh;" << "\n"
777 << "\t\t\t" << "shellScript = \"make -C " << QDir::currentDirPath() <<
778 " -f " << mkfile << "\";" << "\n"
779 << "\t\t" << "};" << "\n";
780 }
781 //LIBRARY BUILDPHASE
782 if(!project->isEmpty("QMAKE_PBX_LIBRARIES")) {
783 tmp = project->variables()["QMAKE_PBX_LIBRARIES"];
784 if(!tmp.isEmpty()) {
785 QString grp("External Frameworks and Libraries"), key = keyFor(grp);
786 project->variables()["QMAKE_PBX_GROUPS"].append(key);
787 t << "\t\t" << key << " = {" << "\n"
788 << "\t\t\t" << "children = (" << "\n"
789 << varGlue("QMAKE_PBX_LIBRARIES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
790 << "\t\t\t" << ");" << "\n"
791 << "\t\t\t" << "isa = PBXGroup;" << "\n"
792 << "\t\t\t" << "name = \"" << grp << "\"" << ";" << "\n"
793 << "\t\t\t" << "path = \"\";" << "\n"
794 << "\t\t\t" << "refType = 4;" << "\n"
795 << "\t\t" << "};" << "\n";
796 }
797 }
798 {
799 QString grp("Frameworks & Libraries"), key = keyFor(grp);
800 project->variables()["QMAKE_PBX_BUILDPHASES"].append(key);
801 t << "\t\t" << key << " = {" << "\n"
802 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
803 << "\t\t\t" << "files = (" << "\n"
804 << varGlue("QMAKE_PBX_BUILD_LIBRARIES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
805 << "\t\t\t" << ");" << "\n"
806 << "\t\t\t" << "isa = PBXFrameworksBuildPhase;" << "\n"
807 << "\t\t\t" << "name = \"" << grp << "\";" << "\n"
808 << "\t\t" << "};" << "\n";
809 }
810 if(!project->isActiveConfig("console") && project->first("TEMPLATE") == "app") { //BUNDLE RESOURCES
811 QString grp("Bundle Resources"), key = keyFor(grp);
812 project->variables()["QMAKE_PBX_BUILDPHASES"].append(key);
813 t << "\t\t" << key << " = {" << "\n"
814 << "\t\t\t" << "buildActionMask = 2147483647;" << "\n"
815 << "\t\t\t" << "files = (" << "\n"
816 << (!project->isEmpty("RC_FILE") ? keyFor("ICNS_FILE_REFERENCE") : QString(""))
817 << "\t\t\t" << ");" << "\n"
818 << "\t\t\t" << "isa = PBXResourcesBuildPhase;" << "\n"
819 << "\t\t\t" << "name = \"" << grp << "\";" << "\n"
820 << "\t\t" << "};" << "\n";
821 }
822 { //INSTALL BUILDPHASE (sh script)
823 QString phase_key = keyFor("QMAKE_PBX_TARGET_COPY_PHASE");
824 QString destDir = Option::output_dir;
825 if (!project->isEmpty("QMAKE_ORIG_DESTDIR"))
826 destDir = project->first("QMAKE_ORIG_DESTDIR");
827 fixEnvs(destDir);
828 destDir = QFileInfo(Option::fixPathToLocalOS(destDir)).absFilePath();
829 project->variables()["QMAKE_PBX_PRESCRIPT_BUILDPHASES"].append(phase_key);
830 t << "\t\t" << phase_key << " = {\n"
831 << "\t\t\tbuildActionMask = 2147483647;\n"
832 << "\t\t\tdstPath = " << destDir << ";\n"
833 << "\t\t\tdstSubfolderSpec = 0;\n"
834 << "\t\t\tfiles = (\n"
835 << "\t\t\t" << keyFor("QMAKE_PBX_TARGET_COPY_FILE") << ",\n"
836 << "\t\t\t);\n"
837 << "\t\t\tisa = PBXCopyFilesBuildPhase;\n"
838 << "\t\t\trunOnlyForDeploymentPostprocessing = 0;\n"
839 << "\t\t};\n"
840 << "\t\t" << keyFor("QMAKE_PBX_TARGET_COPY_FILE") << " = {\n"
841 << "\t\t\tfileRef = " << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << ";\n"
842 << "\t\t\tisa = PBXBuildFile;\n"
843 << "\t\t\tsettings = {\n"
844 << "\t\t\t};\n"
845 << "\t\t};\n";
846 }
847 if(/*ideType() == MAC_XCODE &&*/ !project->isEmpty("QMAKE_PBX_PRESCRIPT_BUILDPHASES") && 0) {
848 // build reference
849 t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPT_BUILDREFERENCE") << " = {" << "\n"
850 << "\t\t\t" << "includeInIndex = 0;" << "\n"
851 << "\t\t\t" << "isa = PBXFileReference;" << "\n"
852 << "\t\t\t" << "path = preprocessor.out;" << "\n"
853 << "\t\t\t" << "refType = 3;" << "\n"
854 << "\t\t\t" << "sourceTree = BUILT_PRODUCTS_DIR;" << "\n"
855 << "\t\t" << "};" << "\n";
856 project->variables()["QMAKE_PBX_PRODUCTS"].append(keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE"));
857 //build phase
858 QString prescript_key = keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE");
859 project->variables()["QMAKE_PBX_TARGETS"].append(prescript_key);
860 t << "\t\t" << prescript_key << " = {" << "\n"
861 << "\t\t\t" << "buildPhases = (" << "\n"
862 << varGlue("QMAKE_PBX_PRESCRIPT_BUILDPHASES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
863 << "\t\t\t" << ");" << "\n"
864 << "\t\t\t" << "buildRules = (" << "\n"
865 << "\t\t\t" << ");" << "\n"
866 << "\t\t\t" << "buildSettings = {" << "\n"
867 << "\t\t\t" << "};" << "\n"
868 << "\t\t\t" << "dependencies = (" << "\n"
869 << "\t\t\t" << ");" << "\n"
870 << "\t\t\t" << "isa = PBXNativeTarget;" << "\n"
871 << "\t\t\t" << "name = \"Qt Preprocessor Steps\";" << "\n"
872 << "\t\t\t" << "productName = \"Qt Preprocessor Steps\";" << "\n"
873 << "\t\t\t" << "productReference = " << keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE") << ";" << "\n"
874 << "\t\t\t" << "productType = \"com.apple.product-type.tool\";" << "\n"
875 << "\t\t" << "};" << "\n";
876 //dependency
877 t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY") << " = {" << "\n"
878 << "\t\t\t" << "isa = PBXTargetDependency;" << "\n"
879 << "\t\t\t" << "target = " << keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE") << ";" << "\n"
880 << "\t\t" << "};" << "\n";
881 project->variables()["QMAKE_PBX_TARGET_DEPENDS"].append(keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY"));
882 project->variables()["QMAKE_PBX_PRESCRIPT_BUILDPHASES"].clear(); //these are already consumed above
883 }
884
885 //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
886 //ROOT_GROUP
887 t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n"
888 << "\t\t\t" << "children = (" << "\n"
889 << varGlue("QMAKE_PBX_GROUPS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
890 << "\t\t\t" << ");" << "\n"
891 << "\t\t\t" << "isa = PBXGroup;" << "\n"
892 << "\t\t\t" << "name = " << project->first("QMAKE_ORIG_TARGET") << ";" << "\n"
893 << "\t\t\t" << "path = \"\";" << "\n"
894 << "\t\t\t" << "refType = 4;" << "\n"
895 << "\t\t" << "};" << "\n";
896 //REFERENCE
897 project->variables()["QMAKE_PBX_PRODUCTS"].append(keyFor(pbx_dir + "QMAKE_PBX_REFERENCE"));
898 t << "\t\t" << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << " = {" << "\n"
899 << "\t\t\t" << "fallbackIsa = PBXFileReference;" << "\n";
900 if(project->first("TEMPLATE") == "app") {
901 QString targ = project->first("QMAKE_ORIG_TARGET");
902 if(project->isActiveConfig("resource_fork") && !project->isActiveConfig("console")) {
903 targ += ".app";
904 t << "\t\t\t" << "isa = PBXApplicationReference;" << "\n";
905 } else {
906 t << "\t\t\t" << "isa = PBXExecutableFileReference;" << "\n";
907 }
908 QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") :
909 QDir::currentDirPath()) + Option::dir_sep + targ;
910 t << "\t\t\t" << "name = " << targ << ";" << "\n"
911 << "\t\t\t" << "path = \"" << targ << "\";" << "\n"
912 << "\t\t\t" << "refType = " << reftypeForFile(app) << ";" << "\n";
913 } else {
914 QString lib = project->first("QMAKE_ORIG_TARGET");
915 if(project->isActiveConfig("staticlib")) {
916 lib = project->first("TARGET");
917 } else if(!project->isActiveConfig("frameworklib")) {
918 if(project->isActiveConfig("plugin"))
919 lib = project->first("TARGET");
920 else
921 lib = project->first("TARGET_");
922 }
923 int slsh = lib.findRev(Option::dir_sep);
924 if(slsh != -1)
925 lib = lib.right(lib.length() - slsh - 1);
926 t << "\t\t\t" << "isa = PBXLibraryReference;" << "\n"
927 << "\t\t\t" << "expectedFileType = \"compiled.mach-o.dylib\";" << "\n"
928 << "\t\t\t" << "path = " << lib << ";\n"
929 << "\t\t\t" << "refType = " << 3/*reftypeForFile(lib)*/ << ";" << "\n"
930 << "\t\t\t" << "sourceTree = BUILT_PRODUCTS_DIR" << ";" << "\n";
931 }
932 t << "\t\t" << "};" << "\n";
933 { //Products group
934 QString grp("Products"), key = keyFor(grp);
935 project->variables()["QMAKE_PBX_GROUPS"].append(key);
936 t << "\t\t" << key << " = {" << "\n"
937 << "\t\t\t" << "children = (" << "\n"
938 << varGlue("QMAKE_PBX_PRODUCTS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
939 << "\t\t\t" << ");" << "\n"
940 << "\t\t\t" << "isa = PBXGroup;" << "\n"
941 << "\t\t\t" << "name = Products;" << "\n"
942 << "\t\t\t" << "refType = 4;" << "\n"
943 << "\t\t" << "};" << "\n";
944 }
945 //TARGET
946 QString target_key = keyFor("QMAKE_PBX_TARGET");
947 project->variables()["QMAKE_PBX_TARGETS"].append(target_key);
948 t << "\t\t" << target_key << " = {" << "\n"
949 << "\t\t\t" << "buildPhases = (" << "\n"
950 << varGlue("QMAKE_PBX_PRESCRIPT_BUILDPHASES", "\t\t\t\t", ",\n\t\t\t\t", ",\n")
951 << varGlue("QMAKE_PBX_BUILDPHASES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
952 << "\t\t\t" << ");" << "\n"
953 << "\t\t\t" << "buildSettings = {" << "\n"
954 << "\t\t\t\t" << "CC = \"" << fixEnvsList("QMAKE_CC") << "\";" << "\n"
955 << "\t\t\t\t" << "CPLUSPLUS = \"" << fixEnvsList("QMAKE_CXX") << "\";" << "\n"
956 << "\t\t\t\t" << "FRAMEWORK_SEARCH_PATHS = \"\";" << "\n"
957 << "\t\t\t\t" << "HEADER_SEARCH_PATHS = \"" << fixEnvsList("INCLUDEPATH") << " " << fixEnvs(specdir()) << "\";" << "\n"
958 << "\t\t\t\t" << "LIBRARY_SEARCH_PATHS = \"" << var("QMAKE_PBX_LIBPATHS") << "\";" << "\n"
959 << "\t\t\t\t" << "OPTIMIZATION_CFLAGS = \"\";" << "\n"
960 << "\t\t\t\t" << "GCC_GENERATE_DEBUGGING_SYMBOLS = " <<
961 (project->isActiveConfig("debug") ? "YES" : "NO") << ";" << "\n"
962 << "\t\t\t\t" << "OTHER_CFLAGS = \"" <<
963 fixEnvsList("QMAKE_CFLAGS") << fixQuotes(varGlue("PRL_EXPORT_DEFINES"," -D"," -D","")) <<
964 fixQuotes(varGlue("DEFINES"," -D"," -D","")) << "\";" << "\n"
965 << "\t\t\t\t" << "LEXFLAGS = \"" << var("QMAKE_LEXFLAGS") << "\";" << "\n"
966 << "\t\t\t\t" << "YACCFLAGS = \"" << var("QMAKE_YACCFLAGS") << "\";" << "\n"
967 << "\t\t\t\t" << "OTHER_CPLUSPLUSFLAGS = \"" <<
968 fixEnvsList("QMAKE_CXXFLAGS") << fixQuotes(varGlue("PRL_EXPORT_DEFINES"," -D"," -D","")) <<
969 fixQuotes(varGlue("DEFINES"," -D"," -D","")) << "\";" << "\n"
970 << "\t\t\t\t" << "OTHER_REZFLAGS = \"\";" << "\n"
971 << "\t\t\t\t" << "SECTORDER_FLAGS = \"\";" << "\n"
972 << "\t\t\t\t" << "WARNING_CFLAGS = \"\";" << "\n"
973 << "\t\t\t\t" << "PREBINDING = " << (project->isEmpty("QMAKE_DO_PREBINDING") ? "NO" : "YES") << ";" << "\n";
974 if(project->isActiveConfig("debug"))
975 t << "\t\t\t\t" << "GCC_OPTIMIZATION_LEVEL = 0" << ";" << "\n";
976 if(!project->isEmpty("PRECOMPILED_HEADER")) {
977 if(pbVersion >= 38) {
978 t << "\t\t\t\t" << "GCC_PRECOMPILE_PREFIX_HEADER = \"YES\";" << "\n"
979 << "\t\t\t\t" << "GCC_PREFIX_HEADER = \"" << project->first("PRECOMPILED_HEADER") << "\";" << "\n";
980 } else {
981 t << "\t\t\t\t" << "PRECOMPILE_PREFIX_HEADER = \"YES\";" << "\n"
982 << "\t\t\t\t" << "PREFIX_HEADER = \"" << project->first("PRECOMPILED_HEADER") << "\";" << "\n";
983 }
984 }
985 if(project->first("TEMPLATE") == "app") {
986 QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
987 if(plist.isEmpty())
988 plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
989 if(QFile::exists(plist)) {
990 QFile plist_in_file(plist);
991 if(plist_in_file.open(IO_ReadOnly)) {
992 QTextStream plist_in(&plist_in_file);
993 QString plist_in_text = plist_in.read();
994 plist_in_text = plist_in_text.replace("@ICON@", (project->isEmpty("RC_FILE") ? QString("") : project->first("RC_FILE").section(Option::dir_sep, -1)));
995 plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET"));
996 QFile plist_out_file("Info.plist");
997 if(plist_out_file.open(IO_WriteOnly | IO_Translate)) {
998 QTextStream plist_out(&plist_out_file);
999 plist_out << plist_in_text;
1000 t << "\t\t\t\t" << "INFOPLIST_FILE = \"Info.plist\";" << "\n";
1001 }
1002 }
1003 }
1004 }
1005 #if 1
1006 t << "\t\t\t\t" << "BUILD_ROOT = \"" << QDir::currentDirPath() << "\";" << "\n";
1007 #endif
1008 if(!project->isActiveConfig("staticlib"))
1009 t << "\t\t\t\t" << "OTHER_LDFLAGS = \"" << fixEnvsList("SUBLIBS") << " " <<
1010 fixEnvsList("QMAKE_LFLAGS") << " " << fixEnvsList("QMAKE_LIBDIR_FLAGS") <<
1011 " " << fixEnvsList("QMAKE_LIBS") << "\";" << "\n";
1012 if(!project->isEmpty("DESTDIR")) {
1013 QString dir = project->first("DESTDIR");
1014 if (QDir::isRelativePath(dir))
1015 dir.prepend(QDir::currentDirPath() + Option::dir_sep);
1016 t << "\t\t\t\t" << "INSTALL_DIR = \"" << dir << "\";" << "\n";
1017 }
1018 if ( project->first("TEMPLATE") == "lib") {
1019 t << "\t\t\t\t" << "INSTALL_PATH = \"" << "\";" << "\n";
1020 }
1021 if(!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") {
1022 t << "\t\t\t\t" << "DYLIB_CURRENT_VERSION = \"" << project->first("VER_MAJ") << "."
1023 << project->first("VER_MIN") << "." << project->first("VER_PAT") << "\";" << "\n";
1024 if(project->isEmpty("COMPAT_VERSION"))
1025 t << "\t\t\t\t" << "DYLIB_COMPATIBILITY_VERSION = \"" << project->first("VER_MAJ") << "."
1026 << project->first("VER_MIN") << "\";" << "\n";
1027 }
1028 if(!project->isEmpty("COMPAT_VERSION"))
1029 t << "\t\t\t\t" << "DYLIB_COMPATIBILITY_VERSION = \"" << project->first("COMPAT_VERSION") << "\";" << "\n";
1030 if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
1031 t << "\t\t\t\t" << "MACOSX_DEPLOYMENT_TARGET = \""
1032 << project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET") << "\";" << "\n";
1033 if(pbVersion >= 38) {
1034 if(!project->isEmpty("OBJECTS_DIR"))
1035 t << "\t\t\t\t" << "OBJROOT = \"" << project->first("OBJECTS_DIR") << "\";" << "\n";
1036 }
1037 #if 0
1038 if(!project->isEmpty("DESTDIR"))
1039 t << "\t\t\t\t" << "SYMROOT = \"" << project->first("DESTDIR") << "\";" << "\n";
1040 else
1041 t << "\t\t\t\t" << "SYMROOT = \"" << QDir::currentDirPath() << "\";" << "\n";
1042 #endif
1043 if(project->first("TEMPLATE") == "app") {
1044 if(pbVersion < 38 && !project->isActiveConfig("console"))
1045 t << "\t\t\t\t" << "WRAPPER_SUFFIX = app;" << "\n";
1046 t << "\t\t\t\t" << "PRODUCT_NAME = " << project->first("QMAKE_ORIG_TARGET") << ";" << "\n";
1047 } else {
1048 if(!project->isActiveConfig("plugin") && project->isActiveConfig("staticlib")) {
1049 t << "\t\t\t\t" << "LIBRARY_STYLE = STATIC;" << "\n";
1050 } else {
1051 t << "\t\t\t\t" << "LIBRARY_STYLE = DYNAMIC;" << "\n";
1052 }
1053 QString lib = project->first("QMAKE_ORIG_TARGET");
1054 if (!project->isActiveConfig("frameworklib") && !project->isActiveConfig("staticlib"))
1055 lib.prepend("lib");
1056 t << "\t\t\t\t" << "PRODUCT_NAME = " << lib << ";" << "\n";
1057 }
1058 tmp = project->variables()["QMAKE_PBX_VARS"];
1059 for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
1060 QString var = (*it), val = getenv(var);
1061 if(!val && var == "TB")
1062 val = "/usr/bin/";
1063 t << "\t\t\t\t" << var << " = \"" << val << "\";" << "\n";
1064 }
1065 t << "\t\t\t" << "};" << "\n"
1066 << "\t\t\t" << "conditionalBuildSettings = {" << "\n"
1067 << "\t\t\t" << "};" << "\n"
1068 << "\t\t\t" << "dependencies = (" << "\n"
1069 << varGlue("QMAKE_PBX_TARGET_DEPENDS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
1070 << "\t\t\t" << ");" << "\n"
1071 << "\t\t\t" << "productReference = " << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << ";" << "\n"
1072 << "\t\t\t" << "shouldUseHeadermap = 1;" << "\n";
1073 if(pbVersion >= 38)
1074 t << "\t\t\t" << "isa = PBXNativeTarget;" << "\n";
1075 if(project->first("TEMPLATE") == "app") {
1076 if(project->isActiveConfig("console")) {
1077 if(pbVersion >= 38)
1078 t << "\t\t\t" << "productType = \"com.apple.product-type.tool\";" << "\n";
1079 else
1080 t << "\t\t\t" << "isa = PBXToolTarget;" << "\n";
1081 } else {
1082 if(pbVersion >= 38)
1083 t << "\t\t\t" << "productType = \"com.apple.product-type.application\";" << "\n";
1084 else
1085 t << "\t\t\t" << "isa = PBXApplicationTarget;" << "\n";
1086 t << "\t\t\t" << "productSettingsXML = \"";
1087 bool read_plist = false;
1088 if(QFile::exists("Info.plist")) {
1089 QFile plist("Info.plist");
1090 if(plist.open(IO_ReadOnly)) {
1091 read_plist = true;
1092 QTextStream stream(&plist);
1093 while(!stream.eof())
1094 t << stream.readLine().replace('"', "\\\"") << endl;
1095 }
1096 }
1097 if(!read_plist) {
1098 t << "<?xml version="
1099 << "\\\"1.0\\\" encoding=" << "\\\"UTF-8\\\"" << "?>" << "\n"
1100 << "\t\t\t\t" << "<!DOCTYPE plist SYSTEM \\\"file://localhost/System/"
1101 << "Library/DTDs/PropertyList.dtd\\\">" << "\n"
1102 << "\t\t\t\t" << "<plist version=\\\"0.9\\\">" << "\n"
1103 << "\t\t\t\t" << "<dict>" << "\n"
1104 << "\t\t\t\t\t" << "<key>CFBundleDevelopmentRegion</key>" << "\n"
1105 << "\t\t\t\t\t" << "<string>English</string>" << "\n"
1106 << "\t\t\t\t\t" << "<key>CFBundleExecutable</key>" << "\n"
1107 << "\t\t\t\t\t" << "<string>" << project->first("QMAKE_ORIG_TARGET") << "</string>" << "\n"
1108 << "\t\t\t\t\t" << "<key>CFBundleIconFile</key>" << "\n"
1109 << "\t\t\t\t\t" << "<string>" << var("RC_FILE").section(Option::dir_sep, -1) << "</string>" << "\n"
1110 << "\t\t\t\t\t" << "<key>CFBundleInfoDictionaryVersion</key>" << "\n"
1111 << "\t\t\t\t\t" << "<string>6.0</string>" << "\n"
1112 << "\t\t\t\t\t" << "<key>CFBundlePackageType</key>" << "\n"
1113 << "\t\t\t\t\t" << "<string>APPL</string>" << "\n"
1114 << "\t\t\t\t\t" << "<key>CFBundleSignature</key>" << "\n"
1115 //Although the output below looks strange it is to avoid the trigraph ??<
1116 << "\t\t\t\t\t" << "<string>????" << "</string>" << "\n"
1117 << "\t\t\t\t\t" << "<key>CFBundleVersion</key>" << "\n"
1118 << "\t\t\t\t\t" << "<string>0.1</string>" << "\n"
1119 << "\t\t\t\t\t" << "<key>CSResourcesFileMapped</key>" << "\n"
1120 << "\t\t\t\t\t" << "<true/>" << "\n"
1121 << "\t\t\t\t" << "</dict>" << "\n"
1122 << "\t\t\t\t" << "</plist>";
1123 }
1124 }
1125 t << "\";" << "\n";
1126 t << "\t\t\t" << "name = \"" << project->first("QMAKE_ORIG_TARGET") << "\";" << "\n"
1127 << "\t\t\t" << "productName = " << project->first("QMAKE_ORIG_TARGET") << ";" << "\n";
1128 } else {
1129 QString lib = project->first("QMAKE_ORIG_TARGET");
1130 if(!project->isActiveConfig("frameworklib") && !project->isActiveConfig("staticlib"))
1131 lib.prepend("lib");
1132 t << "\t\t\t" << "name = \"" << lib << "\";" << "\n"
1133 << "\t\t\t" << "productName = " << lib << ";" << "\n";
1134 if(pbVersion >= 38) {
1135 if(project->isActiveConfig("staticlib"))
1136 t << "\t\t\t" << "productType = \"com.apple.product-type.library.static\";" << "\n";
1137 else
1138 t << "\t\t\t" << "productType = \"com.apple.product-type.library.dynamic\";" << "\n";
1139 } else {
1140 t << "\t\t\t" << "isa = PBXLibraryTarget;" << "\n";
1141 }
1142 }
1143 t << "\t\t\t" << "startupPath = \"<<ProjectDirectory>>\";" << "\n";
1144 if(!project->isEmpty("DESTDIR"))
1145 t << "\t\t\t" << "productInstallPath = \"" << project->first("DESTDIR") << "\";" << "\n";
1146 t << "\t\t" << "};" << "\n";
1147 //DEBUG/RELEASE
1148 QString active_buildstyle;
1149 #if 0
1150 for(int as_release = 0; as_release < 2; as_release++)
1151 #else
1152 bool as_release = !project->isActiveConfig("debug");
1153 #endif
1154 {
1155 QMap<QString, QString> settings;
1156 settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
1157 if(as_release)
1158 settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
1159 QString name;
1160 if(pbVersion >= 42)
1161 name = (as_release ? "Release" : "Debug");
1162 else
1163 name = (as_release ? "Deployment" : "Development");
1164
1165 if(pbVersion >= 42) {
1166 QString key = keyFor("QMAKE_PBX_BUILDCONFIG_" + name);
1167 project->variables()["QMAKE_PBX_BUILDCONFIGS"].append(key);
1168 t << "\t\t" << key << " = {" << "\n"
1169 << "\t\t\t" << "isa = XCBuildConfiguration;" << "\n"
1170 << "\t\t\t" << "buildSettings = {" << "\n";
1171 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
1172 t << "\t\t\t\t" << set_it.key() << " = \"" << set_it.data() << "\";\n";
1173 t << "\t\t\t" << "};" << "\n"
1174 << "\t\t\t" << "name = " << name << ";" << "\n"
1175 << "\t\t" << "};" << "\n";
1176 }
1177
1178 QString key = keyFor("QMAKE_PBX_BUILDSTYLE_" + name);
1179 if(project->isActiveConfig("debug") != (bool)as_release) {
1180 project->variables()["QMAKE_PBX_BUILDSTYLES"].append(key);
1181 active_buildstyle = name;
1182 } else if(pbVersion >= 42) {
1183 project->variables()["QMAKE_PBX_BUILDSTYLES"].append(key);
1184 }
1185 t << "\t\t" << key << " = {" << "\n"
1186 << "\t\t\t" << "buildRules = (" << "\n"
1187 << "\t\t\t" << ");" << "\n"
1188 << "\t\t\t" << "buildSettings = {" << "\n";
1189 for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
1190 t << "\t\t\t\t" << set_it.key() << " = \"" << set_it.data() << "\";\n";
1191 t << "\t\t\t" << "};" << "\n"
1192 << "\t\t\t" << "isa = PBXBuildStyle;" << "\n"
1193 << "\t\t\t" << "name = " << name << ";" << "\n"
1194 << "\t\t" << "};" << "\n";
1195 }
1196 if(pbVersion >= 42) {
1197 t << "\t\t" << keyFor("QMAKE_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
1198 << "\t\t\t" << "isa = XCConfigurationList;" << "\n"
1199 << "\t\t\t" << "buildConfigurations = (" << "\n"
1200 << varGlue("QMAKE_PBX_BUILDCONFIGS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
1201 << "\t\t\t" << ");" << "\n"
1202 << "\t\t\t" << "defaultConfigurationIsVisible = 0;" << "\n"
1203 << "\t\t\t" << "defaultConfigurationIsName = " << active_buildstyle << ";" << "\n"
1204 << "\t\t" << "};" << "\n";
1205 }
1206 //ROOT
1207 t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n"
1208 << "\t\t\t" << "buildStyles = (" << "\n"
1209 << varGlue("QMAKE_PBX_BUILDSTYLES", "\t\t\t\t", ",\n\t\t\t\t", "\n")
1210 << "\t\t\t" << ");" << "\n"
1211 << "\t\t\t" << "hasScannedForEncodings = 1;" << "\n"
1212 << "\t\t\t" << "isa = PBXProject;" << "\n"
1213 << "\t\t\t" << "mainGroup = " << keyFor("QMAKE_PBX_ROOT_GROUP") << ";" << "\n"
1214 << "\t\t\t" << "projectDirPath = \"\";" << "\n"
1215 << "\t\t\t" << "targets = (" << "\n"
1216 << varGlue("QMAKE_PBX_TARGETS", "\t\t\t\t", ",\n\t\t\t\t", "\n")
1217 << "\t\t\t" << ");" << "\n"
1218 << "\t\t" << "};" << "\n";
1219
1220 //FOOTER
1221 t << "\t" << "};" << "\n"
1222 << "\t" << "rootObject = " << keyFor("QMAKE_PBX_ROOT") << ";" << "\n"
1223 << "}" << endl;
1224
1225 if(project->isActiveConfig("generate_pbxbuild_makefile")) {
1226 QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
1227 QDir::currentDirPath());
1228 QFile mkwrapf(mkwrap);
1229 if(mkwrapf.open(IO_WriteOnly | IO_Translate)) {
1230 debug_msg(1, "pbuilder: Creating file: %s", mkwrap.latin1());
1231 QTextStream mkwrapt(&mkwrapf);
1232 writeHeader(mkwrapt);
1233 const char *cleans = "uiclean mocclean preprocess_clean ";
1234 mkwrapt << "#This is a makefile wrapper for PROJECT BUILDER\n"
1235 << "all:" << "\n\t"
1236 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << "\n"
1237 << "install: all" << "\n\t"
1238 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " install\n"
1239 << "distclean clean: preprocess_clean" << "\n\t"
1240 << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " clean" << "\n"
1241 << (!did_preprocess ? cleans : "") << ":" << "\n";
1242 if(did_preprocess)
1243 mkwrapt << cleans << ":" << "\n\t"
1244 << "make -f "
1245 << pbx_dir << Option::dir_sep << "qt_preprocess.mak $@" << endl;
1246 }
1247 }
1248 return TRUE;
1249 }
1250
1251 QString
fixQuotes(const QString & val)1252 ProjectBuilderMakefileGenerator::fixQuotes(const QString &val)
1253 {
1254 QString ret(val);
1255 ret = ret.replace(QRegExp("('|\\\\|\")"), "\\\\1");
1256 return ret;
1257 }
1258
1259 QString
fixEnvs(const QString & file)1260 ProjectBuilderMakefileGenerator::fixEnvs(const QString &file)
1261 {
1262 QRegExp reg_var("\\$\\((.*)\\)");
1263 for(int rep = 0; (rep = reg_var.search(file, rep)) != -1; ) {
1264 if(project->variables()["QMAKE_PBX_VARS"].findIndex(reg_var.cap(1)) == -1)
1265 project->variables()["QMAKE_PBX_VARS"].append(reg_var.cap(1));
1266 rep += reg_var.matchedLength();
1267 }
1268 return file;
1269 }
1270
1271 QString
fixEnvsList(const QString & where)1272 ProjectBuilderMakefileGenerator::fixEnvsList(const QString &where)
1273 {
1274 QString ret;
1275 const QStringList &l = project->variables()[where];
1276 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
1277 fixEnvs((*it));
1278 if(!ret.isEmpty())
1279 ret += " ";
1280 ret += fixQuotes((*it));
1281 }
1282 return ret;
1283 }
1284
1285 QString
keyFor(const QString & block)1286 ProjectBuilderMakefileGenerator::keyFor(const QString &block)
1287 {
1288 #if 1 //This make this code much easier to debug..
1289 if(project->isActiveConfig("no_pb_munge_key"))
1290 return block;
1291 #endif
1292 QString ret;
1293 if(!keys.contains(block)) {
1294 ret = qtMD5(block.utf8()).left(24).upper();
1295 keys.insert(block, ret);
1296 } else {
1297 ret = keys[block];
1298 }
1299 return ret;
1300 }
1301
1302 bool
openOutput(QFile & file) const1303 ProjectBuilderMakefileGenerator::openOutput(QFile &file) const
1304 {
1305 if(QDir::isRelativePath(file.name()))
1306 file.setName(Option::output_dir + file.name()); //pwd when qmake was run
1307 QFileInfo fi(file);
1308 if(fi.extension() != "pbxproj" || file.name().isEmpty()) {
1309 QString output = file.name();
1310 if(fi.isDir())
1311 output += QDir::separator();
1312 if(!output.endsWith(projectSuffix())) {
1313 if(file.name().isEmpty() || fi.isDir())
1314 output += project->first("TARGET");
1315 output += projectSuffix() + QDir::separator();
1316 } else if(output[(int)output.length() - 1] != QDir::separator()) {
1317 output += QDir::separator();
1318 }
1319 output += QString("project.pbxproj");
1320 file.setName(output);
1321 }
1322 bool ret = UnixMakefileGenerator::openOutput(file);
1323 ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
1324 Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
1325 return ret;
1326 }
1327
1328 /* This function is such a hack it is almost pointless, but it
1329 eliminates the warning message from ProjectBuilder that the project
1330 file is for an older version. I guess this could be used someday if
1331 the format of the output is dependant upon the version of
1332 ProjectBuilder as well.
1333 */
1334 int
pbuilderVersion() const1335 ProjectBuilderMakefileGenerator::pbuilderVersion() const
1336 {
1337 QString ret;
1338 if(project->isEmpty("QMAKE_PBUILDER_VERSION")) {
1339 QString version, version_plist = project->first("QMAKE_PBUILDER_VERSION_PLIST");
1340 if(version_plist.isEmpty()) {
1341 if(QFile::exists("/Developer/Applications/Xcode.app/Contents/version.plist"))
1342 version_plist = "/Developer/Applications/Xcode.app/Contents/version.plist";
1343 else
1344 version_plist = "/Developer/Applications/Project Builder.app/Contents/version.plist";
1345 } else {
1346 version_plist = version_plist.replace(QRegExp("\""), "");
1347 }
1348 QFile version_file(version_plist);
1349 if (version_file.open(IO_ReadOnly)) {
1350 debug_msg(1, "pbuilder: version.plist: Reading file: %s", version_plist.latin1());
1351 QTextStream plist(&version_file);
1352
1353 bool in_dict = false;
1354 QString current_key;
1355 QRegExp keyreg("^<key>(.*)</key>$"), stringreg("^<string>(.*)</string>$");
1356 while(!plist.atEnd()) {
1357 QString line = plist.readLine().stripWhiteSpace();
1358 if(line == "<dict>")
1359 in_dict = true;
1360 else if(line == "</dict>")
1361 in_dict = false;
1362 else if(in_dict) {
1363 if(keyreg.exactMatch(line))
1364 current_key = keyreg.cap(1);
1365 else if(current_key == "CFBundleShortVersionString" && stringreg.exactMatch(line))
1366 version = stringreg.cap(1);
1367 }
1368 }
1369 version_file.close();
1370 } else { debug_msg(1, "pbuilder: version.plist: Failure to open %s", version_plist.latin1()); }
1371 if(version.isEmpty() && version_plist.contains("Xcode")) {
1372 ret = "39";
1373 } else {
1374 if(version.startsWith("2."))
1375 ret = "42";
1376 else if(version == "1.5")
1377 ret = "39";
1378 else if(version == "1.1")
1379 ret = "34";
1380 }
1381 } else {
1382 ret = project->first("QMAKE_PBUILDER_VERSION");
1383 }
1384 if(!ret.isEmpty()) {
1385 bool ok;
1386 int int_ret = ret.toInt(&ok);
1387 if(ok) {
1388 debug_msg(1, "pbuilder: version.plist: Got version: %d", int_ret);
1389 return int_ret;
1390 }
1391 }
1392 debug_msg(1, "pbuilder: version.plist: Fallback to default version");
1393 return 34; //my fallback
1394 }
1395
1396 int
reftypeForFile(const QString & where)1397 ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where)
1398 {
1399 int ret = 0; //absolute is the default..
1400 if(QDir::isRelativePath(where))
1401 ret = 4; //relative
1402 return ret;
1403 }
1404
1405 QString
projectSuffix() const1406 ProjectBuilderMakefileGenerator::projectSuffix() const
1407 {
1408 const int pbVersion = pbuilderVersion();
1409 if(pbVersion >= 42)
1410 return ".xcodeproj";
1411 else if(pbVersion >= 38)
1412 return ".xcode";
1413 return ".pbproj";
1414 }
1415
1416 QString
pbxbuild()1417 ProjectBuilderMakefileGenerator::pbxbuild()
1418 {
1419 if(QFile::exists("/usr/bin/pbbuild"))
1420 return "pbbuild";
1421 if(QFile::exists("/usr/bin/xcodebuild"))
1422 return "xcodebuild";
1423 return (pbuilderVersion() >= 38 ? "xcodebuild" : "pbxbuild");
1424 }
1425
1426