Diffstat (limited to 'qmake/generators/projectgenerator.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | qmake/generators/projectgenerator.cpp | 462 |
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 @@ +/**************************************************************************** +** $Id$ +** +** Definition of ________ class. +** +** Created : 970521 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the network module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition licenses may use this +** file in accordance with the Qt Commercial License Agreement provided +** with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "projectgenerator.h" +#include "option.h" +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> + + +ProjectGenerator::ProjectGenerator(QMakeProject *p) : MakefileGenerator(p), init_flag(FALSE) +{ +} + +void +ProjectGenerator::init() +{ + if(init_flag) + return; + int file_count = 0; + init_flag = TRUE; + + QMap<QString, QStringList> &v = project->variables(); + QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template; + if(!Option::user_template_prefix.isEmpty()) + templ.prepend(Option::user_template_prefix); + v["TEMPLATE_ASSIGN"] += templ; + + //figure out target + if(Option::output.name() == "-" || Option::output.name().isEmpty()) + v["TARGET"] = QStringList("unknown"); + + //the scary stuff + if(project->first("TEMPLATE_ASSIGN") != "subdirs") { + QString builtin_regex; + { //calculate the builtin regular expression.. + QStringList builtin_exts(".c"); + builtin_exts << Option::ui_ext << Option::yacc_ext << Option::lex_ext; + builtin_exts += Option::h_ext + Option::cpp_ext; + for(QStringList::Iterator ext_it = builtin_exts.begin(); + ext_it != builtin_exts.end(); ++ext_it) { + if(!builtin_regex.isEmpty()) + builtin_regex += "; "; + builtin_regex += QString("*") + (*ext_it); + } + } + QStringList dirs = Option::projfile::project_dirs; + if(Option::projfile::do_pwd) + dirs.prepend(QDir::currentDirPath()); + + for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) { + QString dir, regex; + bool add_depend = FALSE; + if(QFile::exists((*pd))) { + QFileInfo fi((*pd)); + if(fi.isDir()) { + dir = (*pd); + add_depend = TRUE; + if(dir.right(1) != Option::dir_sep) + dir += Option::dir_sep; + if(Option::projfile::do_recursive) { + QDir d(dir); + d.setFilter(QDir::Dirs); + for(int i = 0; i < (int)d.count(); i++) { + if(d[i] != "." && d[i] != "..") + dirs.append(dir + d[i] + QDir::separator() + builtin_regex); + } + } + regex = builtin_regex; + } else { + QString file = (*pd); + int s = file.findRev(Option::dir_sep); + if(s != -1) + dir = file.left(s+1); + if(addFile(file)) { + add_depend = TRUE; + file_count++; + } + } + } else { //regexp + regex = (*pd); + } + if(!regex.isEmpty()) { + int s = regex.findRev(Option::dir_sep); + if(s != -1) { + dir = regex.left(s+1); + regex = regex.right(regex.length() - (s+1)); + } + if(Option::projfile::do_recursive) { + QDir d(dir); + d.setFilter(QDir::Dirs); + for(int i = 0; i < (int)d.count(); i++) { + if(d[i] != "." && d[i] != "..") + dirs.append(dir + d[i] + QDir::separator() + regex); + } + } + QDir d(dir, regex); + for(int i = 0; i < (int)d.count(); i++) { + QString file = dir + d[i]; + if (addFile(file)) { + add_depend = TRUE; + file_count++; + } + } + } + if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir)) { + QFileInfo fi(dir); + if(fi.absFilePath() != QDir::currentDirPath()) { + v["DEPENDPATH"] += fileFixify(dir); + } + } + } + } + if(!file_count) { //shall we try a subdir? + QStringList dirs = Option::projfile::project_dirs; + if(Option::projfile::do_pwd) + dirs.prepend("."); + for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) { + if(QFile::exists((*pd))) { + QString newdir = (*pd); + QFileInfo fi(newdir); + if(fi.isDir()) { + newdir = fileFixify(newdir); + QStringList &subdirs = v["SUBDIRS"]; + if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") && + !subdirs.contains(newdir)) { + subdirs.append(newdir); + } else { + QDir d(newdir, "*.pro"); + d.setFilter(QDir::Files); + for(int i = 0; i < (int)d.count(); i++) { + QString nd = newdir + QDir::separator() + d[i]; + fileFixify(nd); + if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd)) { + if(newdir + d[i] != Option::output_dir + Option::output.name()) + subdirs.append(nd); + } + } + } + if(Option::projfile::do_recursive) { + QDir d(newdir); + d.setFilter(QDir::Dirs); + for(int i = 0; i < (int)d.count(); i++) { + QString nd = fileFixify(newdir + QDir::separator() + d[i]); + if(d[i] != "." && d[i] != ".." && !dirs.contains(nd)) + dirs.append(nd); + } + } + } + } else { //regexp + QString regx = (*pd), dir; + int s = regx.findRev(Option::dir_sep); + if(s != -1) { + dir = regx.left(s+1); + regx = regx.right(regx.length() - (s+1)); + } + QDir d(dir, regx); + d.setFilter(QDir::Dirs); + QStringList &subdirs = v["SUBDIRS"]; + for(int i = 0; i < (int)d.count(); i++) { + QString newdir(dir + d[i]); + QFileInfo fi(newdir); + if(fi.fileName() != "." && fi.fileName() != "..") { + newdir = fileFixify(newdir); + if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") && + !subdirs.contains(newdir)) { + subdirs.append(newdir); + } else { + QDir d(newdir, "*.pro"); + d.setFilter(QDir::Files); + for(int i = 0; i < (int)d.count(); i++) { + QString nd = newdir + QDir::separator() + d[i]; + fileFixify(nd); + if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd)) { + if(newdir + d[i] != Option::output_dir + Option::output.name()) + subdirs.append(nd); + } + } + } + if(Option::projfile::do_recursive && !dirs.contains(newdir)) + dirs.append(newdir); + } + } + } + } + v["TEMPLATE_ASSIGN"] = "subdirs"; + return; + } + + QPtrList<MakefileDependDir> deplist; + deplist.setAutoDelete(TRUE); + { + QStringList &d = v["DEPENDPATH"]; + for(QStringList::Iterator it = d.begin(); it != d.end(); ++it) { + QString r = (*it), l = Option::fixPathToLocalOS((*it)); + deplist.append(new MakefileDependDir(r, l)); + } + } + QStringList &h = v["HEADERS"]; + bool no_qt_files = TRUE; + QString srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "INTERFACES", QString::null }; + for(int i = 0; !srcs[i].isNull(); i++) { + QStringList &l = v[srcs[i]]; + for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { + if(generateDependencies(deplist, (*val_it), TRUE)) { + QStringList &tmp = findDependencies((*val_it)); + if(!tmp.isEmpty()) { + for(QStringList::Iterator dep_it = tmp.begin(); dep_it != tmp.end(); ++dep_it) { + QString file_no_path = (*dep_it).right( + (*dep_it).length() - ((*dep_it).findRev(Option::dir_sep)+1)); + if(no_qt_files && file_no_path.find(QRegExp("^q[a-z_0-9].h$")) != -1) + no_qt_files = FALSE; + QString h_ext; + for(QStringList::Iterator hit = Option::h_ext.begin(); hit != Option::h_ext.end(); ++hit) { + if((*dep_it).endsWith((*hit))) { + h_ext = (*hit); + break; + } + } + if(!h_ext.isEmpty()) { + if((*dep_it).left(1).lower() == "q") { + QString qhdr = (*dep_it).lower(); + if(file_no_path == "qthread.h") + addConfig("thread"); + } + for(QStringList::Iterator cppit = Option::cpp_ext.begin(); + cppit != Option::cpp_ext.end(); ++cppit) { + QString src((*dep_it).left((*dep_it).length() - h_ext.length()) + (*cppit)); + if(QFile::exists(src)) { + bool exists = FALSE; + QStringList &srcl = v["SOURCES"]; + for(QStringList::Iterator src_it = srcl.begin(); src_it != srcl.end(); ++src_it) { + if((*src_it).lower() == src.lower()) { + exists = TRUE; + break; + } + } + if(!exists) + srcl.append(src); + } + } + } else if((*dep_it).endsWith(Option::lex_ext) && + file_no_path.startsWith(Option::lex_mod)) { + addConfig("lex_included"); + } + if(!h.contains((*dep_it))) { + if(generateMocList((*dep_it)) && !findMocDestination((*dep_it)).isEmpty()) + h += (*dep_it); + } + } + } + } + } + } + if(h.isEmpty()) + addConfig("moc", FALSE); + + //if we find a file that matches an forms it needn't be included in the project + QStringList &u = v["INTERFACES"]; + QString no_ui[] = { "SOURCES", "HEADERS", QString::null }; + { + for(int i = 0; !no_ui[i].isNull(); i++) { + QStringList &l = v[no_ui[i]]; + for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ) { + bool found = FALSE; + for(QStringList::Iterator ui_it = u.begin(); ui_it != u.end(); ++ui_it) { + QString s1 = (*val_it).right((*val_it).length() - ((*val_it).findRev(Option::dir_sep) + 1)); + if(s1.findRev('.') != -1) + s1 = s1.left(s1.findRev('.')) + Option::ui_ext; + QString u1 = (*ui_it).right((*ui_it).length() - ((*ui_it).findRev(Option::dir_sep) + 1)); + if(s1 == u1) { + found = TRUE; + break; + } + } + if(!found && (*val_it).endsWith(Option::moc_ext)) + found = TRUE; + if(found) + val_it = l.remove(val_it); + else + ++val_it; + } + } + } +} + + +bool +ProjectGenerator::writeMakefile(QTextStream &t) +{ + t << "######################################################################" << endl; + t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl; + t << "######################################################################" << endl << endl; + QStringList::Iterator it; + for(it = Option::before_user_vars.begin(); it != Option::before_user_vars.end(); ++it) + t << (*it) << endl; + t << getWritableVar("TEMPLATE_ASSIGN", FALSE); + if(project->first("TEMPLATE_ASSIGN") == "subdirs") { + t << endl << "# Directories" << "\n" + << getWritableVar("SUBDIRS"); + } else { + t << getWritableVar("TARGET") + << getWritableVar("CONFIG", FALSE) + << getWritableVar("CONFIG_REMOVE", FALSE) + << getWritableVar("DEPENDPATH") << endl; + + t << "# Input" << "\n"; + t << getWritableVar("HEADERS") + << getWritableVar("INTERFACES") + << getWritableVar("LEXSOURCES") + << getWritableVar("YACCSOURCES") + << getWritableVar("SOURCES"); + } + for(it = Option::after_user_vars.begin(); it != Option::after_user_vars.end(); ++it) + t << (*it) << endl; + return TRUE; +} + +bool +ProjectGenerator::addConfig(const QString &cfg, bool add) +{ + QString where = "CONFIG"; + if(!add) + where = "CONFIG_REMOVE"; + if(!project->variables()[where].contains(cfg)) { + project->variables()[where] += cfg; + return TRUE; + } + return FALSE; +} + + +bool +ProjectGenerator::addFile(QString file) +{ + file = fileFixify(file, QDir::currentDirPath()); + QString dir; + int s = file.findRev(Option::dir_sep); + if(s != -1) + dir = file.left(s+1); + if(file.mid(dir.length(), Option::moc_mod.length()) == Option::moc_mod) + return FALSE; + + QString where; + for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) { + if(file.endsWith((*cppit))) { + if(QFile::exists(file.left(file.length() - (*cppit).length()) + Option::ui_ext)) + return FALSE; + else + where = "SOURCES"; + break; + } + } + if(where.isEmpty()) { + for(QStringList::Iterator hit = Option::h_ext.begin(); hit != Option::h_ext.end(); ++hit) { + if(file.endsWith((*hit))) { + where = "HEADERS"; + break; + } + } + } + if(where.isEmpty()) { + if(file.endsWith(Option::ui_ext)) + where = "INTERFACES"; + else if(file.endsWith(".c")) + where = "SOURCES"; + else if(file.endsWith(Option::lex_ext)) + where = "LEXSOURCES"; + else if(file.endsWith(Option::yacc_ext)) + where = "YACCSOURCES"; + } + + QString newfile = fileFixify(file); + if(!where.isEmpty() && !project->variables()[where].contains(file)) { + project->variables()[where] += newfile; + return TRUE; + } + return FALSE; +} + + +QString +ProjectGenerator::getWritableVar(const QString &v, bool /*fixPath*/) +{ + QStringList &vals = project->variables()[v]; + if(vals.isEmpty()) + return ""; + + QString ret; + if(v.endsWith("_REMOVE")) + ret = v.left(v.length() - 7) + " -= "; + else if(v.endsWith("_ASSIGN")) + ret = v.left(v.length() - 7) + " = "; + else + ret = v + " += "; + QString join = vals.join(" "); + if(ret.length() + join.length() > 80) { + QString spaces; + for(unsigned int i = 0; i < ret.length(); i++) + spaces += " "; + join = vals.join(" \\\n" + spaces); + } + // ### Commented out for now so that project generation works. + // Sam: can you look at why this was needed? + /* if(fixPath) + join = join.replace("\\", "/");*/ + return ret + join + "\n"; +} + +bool +ProjectGenerator::openOutput(QFile &file) const +{ + QString outdir; + if(!file.name().isEmpty()) { + QFileInfo fi(file); + if(fi.isDir()) + outdir = fi.dirPath() + QDir::separator(); + } + if(!outdir.isEmpty() || file.name().isEmpty()) { + QString dir = QDir::currentDirPath(); + int s = dir.findRev('/'); + if(s != -1) + dir = dir.right(dir.length() - (s + 1)); + file.setName(outdir + dir + ".pro"); + } + return MakefileGenerator::openOutput(file); +} |