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