summaryrefslogtreecommitdiff
path: root/qmake/generators/projectgenerator.cpp
Unidiff
Diffstat (limited to 'qmake/generators/projectgenerator.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/generators/projectgenerator.cpp462
1 files changed, 462 insertions, 0 deletions
diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp
new file mode 100644
index 0000000..5ff6250
--- a/dev/null
+++ b/qmake/generators/projectgenerator.cpp
@@ -0,0 +1,462 @@
1/****************************************************************************
2** $Id$
3**
4** Definition of ________ class.
5**
6** Created : 970521
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the network module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition licenses may use this
22** file in accordance with the Qt Commercial License Agreement provided
23** with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "projectgenerator.h"
39#include "option.h"
40#include <qdir.h>
41#include <qfile.h>
42#include <qfileinfo.h>
43#include <qregexp.h>
44
45
46ProjectGenerator::ProjectGenerator(QMakeProject *p) : MakefileGenerator(p), init_flag(FALSE)
47{
48}
49
50void
51ProjectGenerator::init()
52{
53 if(init_flag)
54 return;
55 int file_count = 0;
56 init_flag = TRUE;
57
58 QMap<QString, QStringList> &v = project->variables();
59 QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template;
60 if(!Option::user_template_prefix.isEmpty())
61 templ.prepend(Option::user_template_prefix);
62 v["TEMPLATE_ASSIGN"] += templ;
63
64 //figure out target
65 if(Option::output.name() == "-" || Option::output.name().isEmpty())
66 v["TARGET"] = QStringList("unknown");
67
68 //the scary stuff
69 if(project->first("TEMPLATE_ASSIGN") != "subdirs") {
70 QString builtin_regex;
71 { //calculate the builtin regular expression..
72 QStringList builtin_exts(".c");
73 builtin_exts << Option::ui_ext << Option::yacc_ext << Option::lex_ext;
74 builtin_exts += Option::h_ext + Option::cpp_ext;
75 for(QStringList::Iterator ext_it = builtin_exts.begin();
76 ext_it != builtin_exts.end(); ++ext_it) {
77 if(!builtin_regex.isEmpty())
78 builtin_regex += "; ";
79 builtin_regex += QString("*") + (*ext_it);
80 }
81 }
82 QStringList dirs = Option::projfile::project_dirs;
83 if(Option::projfile::do_pwd)
84 dirs.prepend(QDir::currentDirPath());
85
86 for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) {
87 QString dir, regex;
88 bool add_depend = FALSE;
89 if(QFile::exists((*pd))) {
90 QFileInfo fi((*pd));
91 if(fi.isDir()) {
92 dir = (*pd);
93 add_depend = TRUE;
94 if(dir.right(1) != Option::dir_sep)
95 dir += Option::dir_sep;
96 if(Option::projfile::do_recursive) {
97 QDir d(dir);
98 d.setFilter(QDir::Dirs);
99 for(int i = 0; i < (int)d.count(); i++) {
100 if(d[i] != "." && d[i] != "..")
101 dirs.append(dir + d[i] + QDir::separator() + builtin_regex);
102 }
103 }
104 regex = builtin_regex;
105 } else {
106 QString file = (*pd);
107 int s = file.findRev(Option::dir_sep);
108 if(s != -1)
109 dir = file.left(s+1);
110 if(addFile(file)) {
111 add_depend = TRUE;
112 file_count++;
113 }
114 }
115 } else { //regexp
116 regex = (*pd);
117 }
118 if(!regex.isEmpty()) {
119 int s = regex.findRev(Option::dir_sep);
120 if(s != -1) {
121 dir = regex.left(s+1);
122 regex = regex.right(regex.length() - (s+1));
123 }
124 if(Option::projfile::do_recursive) {
125 QDir d(dir);
126 d.setFilter(QDir::Dirs);
127 for(int i = 0; i < (int)d.count(); i++) {
128 if(d[i] != "." && d[i] != "..")
129 dirs.append(dir + d[i] + QDir::separator() + regex);
130 }
131 }
132 QDir d(dir, regex);
133 for(int i = 0; i < (int)d.count(); i++) {
134 QString file = dir + d[i];
135 if (addFile(file)) {
136 add_depend = TRUE;
137 file_count++;
138 }
139 }
140 }
141 if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir)) {
142 QFileInfo fi(dir);
143 if(fi.absFilePath() != QDir::currentDirPath()) {
144 v["DEPENDPATH"] += fileFixify(dir);
145 }
146 }
147 }
148 }
149 if(!file_count) { //shall we try a subdir?
150 QStringList dirs = Option::projfile::project_dirs;
151 if(Option::projfile::do_pwd)
152 dirs.prepend(".");
153 for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) {
154 if(QFile::exists((*pd))) {
155 QString newdir = (*pd);
156 QFileInfo fi(newdir);
157 if(fi.isDir()) {
158 newdir = fileFixify(newdir);
159 QStringList &subdirs = v["SUBDIRS"];
160 if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") &&
161 !subdirs.contains(newdir)) {
162 subdirs.append(newdir);
163 } else {
164 QDir d(newdir, "*.pro");
165 d.setFilter(QDir::Files);
166 for(int i = 0; i < (int)d.count(); i++) {
167 QString nd = newdir + QDir::separator() + d[i];
168 fileFixify(nd);
169 if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd)) {
170 if(newdir + d[i] != Option::output_dir + Option::output.name())
171 subdirs.append(nd);
172 }
173 }
174 }
175 if(Option::projfile::do_recursive) {
176 QDir d(newdir);
177 d.setFilter(QDir::Dirs);
178 for(int i = 0; i < (int)d.count(); i++) {
179 QString nd = fileFixify(newdir + QDir::separator() + d[i]);
180 if(d[i] != "." && d[i] != ".." && !dirs.contains(nd))
181 dirs.append(nd);
182 }
183 }
184 }
185 } else { //regexp
186 QString regx = (*pd), dir;
187 int s = regx.findRev(Option::dir_sep);
188 if(s != -1) {
189 dir = regx.left(s+1);
190 regx = regx.right(regx.length() - (s+1));
191 }
192 QDir d(dir, regx);
193 d.setFilter(QDir::Dirs);
194 QStringList &subdirs = v["SUBDIRS"];
195 for(int i = 0; i < (int)d.count(); i++) {
196 QString newdir(dir + d[i]);
197 QFileInfo fi(newdir);
198 if(fi.fileName() != "." && fi.fileName() != "..") {
199 newdir = fileFixify(newdir);
200 if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") &&
201 !subdirs.contains(newdir)) {
202 subdirs.append(newdir);
203 } else {
204 QDir d(newdir, "*.pro");
205 d.setFilter(QDir::Files);
206 for(int i = 0; i < (int)d.count(); i++) {
207 QString nd = newdir + QDir::separator() + d[i];
208 fileFixify(nd);
209 if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd)) {
210 if(newdir + d[i] != Option::output_dir + Option::output.name())
211 subdirs.append(nd);
212 }
213 }
214 }
215 if(Option::projfile::do_recursive && !dirs.contains(newdir))
216 dirs.append(newdir);
217 }
218 }
219 }
220 }
221 v["TEMPLATE_ASSIGN"] = "subdirs";
222 return;
223 }
224
225 QPtrList<MakefileDependDir> deplist;
226 deplist.setAutoDelete(TRUE);
227 {
228 QStringList &d = v["DEPENDPATH"];
229 for(QStringList::Iterator it = d.begin(); it != d.end(); ++it) {
230 QString r = (*it), l = Option::fixPathToLocalOS((*it));
231 deplist.append(new MakefileDependDir(r, l));
232 }
233 }
234 QStringList &h = v["HEADERS"];
235 bool no_qt_files = TRUE;
236 QString srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "INTERFACES", QString::null };
237 for(int i = 0; !srcs[i].isNull(); i++) {
238 QStringList &l = v[srcs[i]];
239 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
240 if(generateDependencies(deplist, (*val_it), TRUE)) {
241 QStringList &tmp = findDependencies((*val_it));
242 if(!tmp.isEmpty()) {
243 for(QStringList::Iterator dep_it = tmp.begin(); dep_it != tmp.end(); ++dep_it) {
244 QString file_no_path = (*dep_it).right(
245 (*dep_it).length() - ((*dep_it).findRev(Option::dir_sep)+1));
246 if(no_qt_files && file_no_path.find(QRegExp("^q[a-z_0-9].h$")) != -1)
247 no_qt_files = FALSE;
248 QString h_ext;
249 for(QStringList::Iterator hit = Option::h_ext.begin(); hit != Option::h_ext.end(); ++hit) {
250 if((*dep_it).endsWith((*hit))) {
251 h_ext = (*hit);
252 break;
253 }
254 }
255 if(!h_ext.isEmpty()) {
256 if((*dep_it).left(1).lower() == "q") {
257 QString qhdr = (*dep_it).lower();
258 if(file_no_path == "qthread.h")
259 addConfig("thread");
260 }
261 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
262 cppit != Option::cpp_ext.end(); ++cppit) {
263 QString src((*dep_it).left((*dep_it).length() - h_ext.length()) + (*cppit));
264 if(QFile::exists(src)) {
265 bool exists = FALSE;
266 QStringList &srcl = v["SOURCES"];
267 for(QStringList::Iterator src_it = srcl.begin(); src_it != srcl.end(); ++src_it) {
268 if((*src_it).lower() == src.lower()) {
269 exists = TRUE;
270 break;
271 }
272 }
273 if(!exists)
274 srcl.append(src);
275 }
276 }
277 } else if((*dep_it).endsWith(Option::lex_ext) &&
278 file_no_path.startsWith(Option::lex_mod)) {
279 addConfig("lex_included");
280 }
281 if(!h.contains((*dep_it))) {
282 if(generateMocList((*dep_it)) && !findMocDestination((*dep_it)).isEmpty())
283 h += (*dep_it);
284 }
285 }
286 }
287 }
288 }
289 }
290 if(h.isEmpty())
291 addConfig("moc", FALSE);
292
293 //if we find a file that matches an forms it needn't be included in the project
294 QStringList &u = v["INTERFACES"];
295 QString no_ui[] = { "SOURCES", "HEADERS", QString::null };
296 {
297 for(int i = 0; !no_ui[i].isNull(); i++) {
298 QStringList &l = v[no_ui[i]];
299 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ) {
300 bool found = FALSE;
301 for(QStringList::Iterator ui_it = u.begin(); ui_it != u.end(); ++ui_it) {
302 QString s1 = (*val_it).right((*val_it).length() - ((*val_it).findRev(Option::dir_sep) + 1));
303 if(s1.findRev('.') != -1)
304 s1 = s1.left(s1.findRev('.')) + Option::ui_ext;
305 QString u1 = (*ui_it).right((*ui_it).length() - ((*ui_it).findRev(Option::dir_sep) + 1));
306 if(s1 == u1) {
307 found = TRUE;
308 break;
309 }
310 }
311 if(!found && (*val_it).endsWith(Option::moc_ext))
312 found = TRUE;
313 if(found)
314 val_it = l.remove(val_it);
315 else
316 ++val_it;
317 }
318 }
319 }
320}
321
322
323bool
324ProjectGenerator::writeMakefile(QTextStream &t)
325{
326 t << "######################################################################" << endl;
327 t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl;
328 t << "######################################################################" << endl << endl;
329 QStringList::Iterator it;
330 for(it = Option::before_user_vars.begin(); it != Option::before_user_vars.end(); ++it)
331 t << (*it) << endl;
332 t << getWritableVar("TEMPLATE_ASSIGN", FALSE);
333 if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
334 t << endl << "# Directories" << "\n"
335 << getWritableVar("SUBDIRS");
336 } else {
337 t << getWritableVar("TARGET")
338 << getWritableVar("CONFIG", FALSE)
339 << getWritableVar("CONFIG_REMOVE", FALSE)
340 << getWritableVar("DEPENDPATH") << endl;
341
342 t << "# Input" << "\n";
343 t << getWritableVar("HEADERS")
344 << getWritableVar("INTERFACES")
345 << getWritableVar("LEXSOURCES")
346 << getWritableVar("YACCSOURCES")
347 << getWritableVar("SOURCES");
348 }
349 for(it = Option::after_user_vars.begin(); it != Option::after_user_vars.end(); ++it)
350 t << (*it) << endl;
351 return TRUE;
352}
353
354bool
355ProjectGenerator::addConfig(const QString &cfg, bool add)
356{
357 QString where = "CONFIG";
358 if(!add)
359 where = "CONFIG_REMOVE";
360 if(!project->variables()[where].contains(cfg)) {
361 project->variables()[where] += cfg;
362 return TRUE;
363 }
364 return FALSE;
365}
366
367
368bool
369ProjectGenerator::addFile(QString file)
370{
371 file = fileFixify(file, QDir::currentDirPath());
372 QString dir;
373 int s = file.findRev(Option::dir_sep);
374 if(s != -1)
375 dir = file.left(s+1);
376 if(file.mid(dir.length(), Option::moc_mod.length()) == Option::moc_mod)
377 return FALSE;
378
379 QString where;
380 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
381 if(file.endsWith((*cppit))) {
382 if(QFile::exists(file.left(file.length() - (*cppit).length()) + Option::ui_ext))
383 return FALSE;
384 else
385 where = "SOURCES";
386 break;
387 }
388 }
389 if(where.isEmpty()) {
390 for(QStringList::Iterator hit = Option::h_ext.begin(); hit != Option::h_ext.end(); ++hit) {
391 if(file.endsWith((*hit))) {
392 where = "HEADERS";
393 break;
394 }
395 }
396 }
397 if(where.isEmpty()) {
398 if(file.endsWith(Option::ui_ext))
399 where = "INTERFACES";
400 else if(file.endsWith(".c"))
401 where = "SOURCES";
402 else if(file.endsWith(Option::lex_ext))
403 where = "LEXSOURCES";
404 else if(file.endsWith(Option::yacc_ext))
405 where = "YACCSOURCES";
406 }
407
408 QString newfile = fileFixify(file);
409 if(!where.isEmpty() && !project->variables()[where].contains(file)) {
410 project->variables()[where] += newfile;
411 return TRUE;
412 }
413 return FALSE;
414}
415
416
417QString
418ProjectGenerator::getWritableVar(const QString &v, bool /*fixPath*/)
419{
420 QStringList &vals = project->variables()[v];
421 if(vals.isEmpty())
422 return "";
423
424 QString ret;
425 if(v.endsWith("_REMOVE"))
426 ret = v.left(v.length() - 7) + " -= ";
427 else if(v.endsWith("_ASSIGN"))
428 ret = v.left(v.length() - 7) + " = ";
429 else
430 ret = v + " += ";
431 QString join = vals.join(" ");
432 if(ret.length() + join.length() > 80) {
433 QString spaces;
434 for(unsigned int i = 0; i < ret.length(); i++)
435 spaces += " ";
436 join = vals.join(" \\\n" + spaces);
437 }
438 // ### Commented out for now so that project generation works.
439 // Sam: can you look at why this was needed?
440 /* if(fixPath)
441 join = join.replace("\\", "/");*/
442 return ret + join + "\n";
443}
444
445bool
446ProjectGenerator::openOutput(QFile &file) const
447{
448 QString outdir;
449 if(!file.name().isEmpty()) {
450 QFileInfo fi(file);
451 if(fi.isDir())
452 outdir = fi.dirPath() + QDir::separator();
453 }
454 if(!outdir.isEmpty() || file.name().isEmpty()) {
455 QString dir = QDir::currentDirPath();
456 int s = dir.findRev('/');
457 if(s != -1)
458 dir = dir.right(dir.length() - (s + 1));
459 file.setName(outdir + dir + ".pro");
460 }
461 return MakefileGenerator::openOutput(file);
462}