00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "projectgenerator.h"
00037 #include "option.h"
00038 #include <qdir.h>
00039 #include <qfile.h>
00040 #include <qfileinfo.h>
00041 #include <qregexp.h>
00042
00043 QString project_builtin_regx()
00044 {
00045 QString ret;
00046 QStringList builtin_exts(".c");
00047 builtin_exts << Option::ui_ext << Option::yacc_ext << Option::lex_ext << ".ts";
00048 builtin_exts += Option::h_ext + Option::cpp_ext;
00049 for(QStringList::Iterator ext_it = builtin_exts.begin();
00050 ext_it != builtin_exts.end(); ++ext_it) {
00051 if(!ret.isEmpty())
00052 ret += "; ";
00053 ret += QString("*") + (*ext_it);
00054 }
00055 return ret;
00056 }
00057
00058
00059
00060 ProjectGenerator::ProjectGenerator(QMakeProject *p) : MakefileGenerator(p), init_flag(FALSE)
00061 {
00062 }
00063
00064 void
00065 ProjectGenerator::init()
00066 {
00067 if(init_flag)
00068 return;
00069 int file_count = 0;
00070 init_flag = TRUE;
00071
00072 QMap<QString, QStringList> &v = project->variables();
00073 QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template;
00074 if(!Option::user_template_prefix.isEmpty())
00075 templ.prepend(Option::user_template_prefix);
00076 v["TEMPLATE_ASSIGN"] += templ;
00077
00078
00079 if(Option::output.name() == "-" || Option::output.name().isEmpty())
00080 v["TARGET"] = QStringList("unknown");
00081
00082
00083 if(project->first("TEMPLATE_ASSIGN") != "subdirs") {
00084 QString builtin_regex = project_builtin_regx();
00085 QStringList dirs = Option::projfile::project_dirs;
00086 if(Option::projfile::do_pwd) {
00087 if(!v["INCLUDEPATH"].contains("."))
00088 v["INCLUDEPATH"] += ".";
00089 dirs.prepend(QDir::currentDirPath());
00090 }
00091
00092 for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) {
00093 QString dir, regex;
00094 bool add_depend = FALSE;
00095 if(QFile::exists((*pd))) {
00096 QFileInfo fi((*pd));
00097 if(fi.isDir()) {
00098 dir = (*pd);
00099 add_depend = TRUE;
00100 if(dir.right(1) != Option::dir_sep)
00101 dir += Option::dir_sep;
00102 if(Option::projfile::do_recursive) {
00103 QDir d(dir);
00104 d.setFilter(QDir::Dirs);
00105 for(int i = 0; i < (int)d.count(); i++) {
00106 if(d[i] != "." && d[i] != "..")
00107 dirs.append(dir + d[i] + QDir::separator() + builtin_regex);
00108 }
00109 }
00110 regex = builtin_regex;
00111 } else {
00112 QString file = (*pd);
00113 int s = file.findRev(Option::dir_sep);
00114 if(s != -1)
00115 dir = file.left(s+1);
00116 if(addFile(file)) {
00117 add_depend = TRUE;
00118 file_count++;
00119 }
00120 }
00121 } else {
00122 regex = (*pd);
00123 }
00124 if(!regex.isEmpty()) {
00125 int s = regex.findRev(Option::dir_sep);
00126 if(s != -1) {
00127 dir = regex.left(s+1);
00128 regex = regex.right(regex.length() - (s+1));
00129 }
00130 if(Option::projfile::do_recursive) {
00131 QDir d(dir);
00132 d.setFilter(QDir::Dirs);
00133 for(int i = 0; i < (int)d.count(); i++) {
00134 if(d[i] != "." && d[i] != "..")
00135 dirs.append(dir + d[i] + QDir::separator() + regex);
00136 }
00137 }
00138 QDir d(dir, regex);
00139 for(int i = 0; i < (int)d.count(); i++) {
00140 QString file = dir + d[i];
00141 if (addFile(file)) {
00142 add_depend = TRUE;
00143 file_count++;
00144 }
00145 }
00146 }
00147 if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir)) {
00148 QFileInfo fi(dir);
00149 if(fi.absFilePath() != QDir::currentDirPath())
00150 v["DEPENDPATH"] += fileFixify(dir);
00151 }
00152 }
00153 }
00154 if(!file_count) {
00155 QStringList dirs = Option::projfile::project_dirs;
00156 if(Option::projfile::do_pwd)
00157 dirs.prepend(".");
00158 const QString out_file = fileFixify(Option::output.name());
00159 for(QStringList::Iterator pd = dirs.begin(); pd != dirs.end(); pd++) {
00160 if(QFile::exists((*pd))) {
00161 QString newdir = (*pd);
00162 QFileInfo fi(newdir);
00163 if(fi.isDir()) {
00164 newdir = fileFixify(newdir);
00165 QStringList &subdirs = v["SUBDIRS"];
00166 if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") &&
00167 !subdirs.contains(newdir)) {
00168 subdirs.append(newdir);
00169 } else {
00170 QDir d(newdir, "*.pro");
00171 d.setFilter(QDir::Files);
00172 for(int i = 0; i < (int)d.count(); i++) {
00173 QString nd = newdir;
00174 if(nd == ".")
00175 nd = "";
00176 else if(!nd.isEmpty() && !nd.endsWith(QString(QChar(QDir::separator()))))
00177 nd += QDir::separator();
00178 nd += d[i];
00179 fileFixify(nd);
00180 if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd) && !out_file.endsWith(nd))
00181 subdirs.append(nd);
00182 }
00183 }
00184 if(Option::projfile::do_recursive) {
00185 QDir d(newdir);
00186 d.setFilter(QDir::Dirs);
00187 for(int i = 0; i < (int)d.count(); i++) {
00188 QString nd = fileFixify(newdir + QDir::separator() + d[i]);
00189 if(d[i] != "." && d[i] != ".." && !dirs.contains(nd))
00190 dirs.append(nd);
00191 }
00192 }
00193 }
00194 } else {
00195 QString regx = (*pd), dir;
00196 int s = regx.findRev(Option::dir_sep);
00197 if(s != -1) {
00198 dir = regx.left(s+1);
00199 regx = regx.right(regx.length() - (s+1));
00200 }
00201 QDir d(dir, regx);
00202 d.setFilter(QDir::Dirs);
00203 QStringList &subdirs = v["SUBDIRS"];
00204 for(int i = 0; i < (int)d.count(); i++) {
00205 QString newdir(dir + d[i]);
00206 QFileInfo fi(newdir);
00207 if(fi.fileName() != "." && fi.fileName() != "..") {
00208 newdir = fileFixify(newdir);
00209 if(QFile::exists(fi.filePath() + QDir::separator() + fi.fileName() + ".pro") &&
00210 !subdirs.contains(newdir)) {
00211 subdirs.append(newdir);
00212 } else {
00213 QDir d(newdir, "*.pro");
00214 d.setFilter(QDir::Files);
00215 for(int i = 0; i < (int)d.count(); i++) {
00216 QString nd = newdir + QDir::separator() + d[i];
00217 fileFixify(nd);
00218 if(d[i] != "." && d[i] != ".." && !subdirs.contains(nd)) {
00219 if(newdir + d[i] != Option::output_dir + Option::output.name())
00220 subdirs.append(nd);
00221 }
00222 }
00223 }
00224 if(Option::projfile::do_recursive && !dirs.contains(newdir))
00225 dirs.append(newdir);
00226 }
00227 }
00228 }
00229 }
00230 v["TEMPLATE_ASSIGN"] = "subdirs";
00231 return;
00232 }
00233
00234 QPtrList<MakefileDependDir> deplist;
00235 deplist.setAutoDelete(TRUE);
00236 {
00237 QStringList &d = v["DEPENDPATH"];
00238 for(QStringList::Iterator it = d.begin(); it != d.end(); ++it) {
00239 QString r = (*it), l = Option::fixPathToLocalOS((*it));
00240 deplist.append(new MakefileDependDir(r, l));
00241 }
00242 }
00243 QStringList &h = v["HEADERS"];
00244 bool no_qt_files = TRUE;
00245 QString srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "INTERFACES", QString::null };
00246 for(int i = 0; !srcs[i].isNull(); i++) {
00247 QStringList &l = v[srcs[i]];
00248 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
00249 if(generateDependencies(deplist, (*val_it), TRUE)) {
00250 QStringList &tmp = findDependencies((*val_it));
00251 if(!tmp.isEmpty()) {
00252 for(QStringList::Iterator dep_it = tmp.begin(); dep_it != tmp.end(); ++dep_it) {
00253 QString file_dir = (*dep_it).section(Option::dir_sep, 0, -2),
00254 file_no_path = (*dep_it).section(Option::dir_sep, -1);
00255 if(!file_dir.isEmpty()) {
00256 for(MakefileDependDir *mdd = deplist.first(); mdd; mdd = deplist.next()) {
00257 if(mdd->local_dir == file_dir && !v["INCLUDEPATH"].contains(mdd->real_dir))
00258 v["INCLUDEPATH"] += mdd->real_dir;
00259 }
00260 }
00261 if(no_qt_files && file_no_path.find(QRegExp("^q[a-z_0-9].h$")) != -1)
00262 no_qt_files = FALSE;
00263 QString h_ext;
00264 for(QStringList::Iterator hit = Option::h_ext.begin();
00265 hit != Option::h_ext.end(); ++hit) {
00266 if((*dep_it).endsWith((*hit))) {
00267 h_ext = (*hit);
00268 break;
00269 }
00270 }
00271 if(!h_ext.isEmpty()) {
00272 if((*dep_it).left(1).lower() == "q") {
00273 QString qhdr = (*dep_it).lower();
00274 if(file_no_path == "qthread.h")
00275 addConfig("thread");
00276 }
00277 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
00278 cppit != Option::cpp_ext.end(); ++cppit) {
00279 QString src((*dep_it).left((*dep_it).length() - h_ext.length()) +
00280 (*cppit));
00281 if(QFile::exists(src)) {
00282 bool exists = FALSE;
00283 QStringList &srcl = v["SOURCES"];
00284 for(QStringList::Iterator src_it = srcl.begin();
00285 src_it != srcl.end(); ++src_it) {
00286 if((*src_it).lower() == src.lower()) {
00287 exists = TRUE;
00288 break;
00289 }
00290 }
00291 if(!exists)
00292 srcl.append(src);
00293 }
00294 }
00295 } else if((*dep_it).endsWith(Option::lex_ext) &&
00296 file_no_path.startsWith(Option::lex_mod)) {
00297 addConfig("lex_included");
00298 }
00299 if(!h.contains((*dep_it))) {
00300 if(generateMocList((*dep_it)) && !findMocDestination((*dep_it)).isEmpty())
00301 h += (*dep_it);
00302 }
00303 }
00304 }
00305 }
00306 }
00307 }
00308 if(h.isEmpty())
00309 addConfig("moc", FALSE);
00310
00311
00312 QStringList &u = v["INTERFACES"];
00313 QString no_ui[] = { "SOURCES", "HEADERS", QString::null };
00314 {
00315 for(int i = 0; !no_ui[i].isNull(); i++) {
00316 QStringList &l = v[no_ui[i]];
00317 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ) {
00318 bool found = FALSE;
00319 for(QStringList::Iterator ui_it = u.begin(); ui_it != u.end(); ++ui_it) {
00320 QString s1 = (*val_it).right((*val_it).length() - ((*val_it).findRev(Option::dir_sep) + 1));
00321 if(s1.findRev('.') != -1)
00322 s1 = s1.left(s1.findRev('.')) + Option::ui_ext;
00323 QString u1 = (*ui_it).right((*ui_it).length() - ((*ui_it).findRev(Option::dir_sep) + 1));
00324 if(s1 == u1) {
00325 found = TRUE;
00326 break;
00327 }
00328 }
00329 if(!found && (*val_it).endsWith(Option::cpp_moc_ext))
00330 found = TRUE;
00331 if(found)
00332 val_it = l.remove(val_it);
00333 else
00334 ++val_it;
00335 }
00336 }
00337 }
00338 }
00339
00340
00341 bool
00342 ProjectGenerator::writeMakefile(QTextStream &t)
00343 {
00344 t << "######################################################################" << endl;
00345 t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl;
00346 t << "######################################################################" << endl << endl;
00347 QStringList::Iterator it;
00348 for(it = Option::before_user_vars.begin(); it != Option::before_user_vars.end(); ++it)
00349 t << (*it) << endl;
00350 t << getWritableVar("TEMPLATE_ASSIGN", FALSE);
00351 if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
00352 t << endl << "# Directories" << "\n"
00353 << getWritableVar("SUBDIRS");
00354 } else {
00355 t << getWritableVar("TARGET")
00356 << getWritableVar("CONFIG", FALSE)
00357 << getWritableVar("CONFIG_REMOVE", FALSE)
00358 << getWritableVar("DEPENDPATH")
00359 << getWritableVar("INCLUDEPATH") << endl;
00360
00361 t << "# Input" << "\n";
00362 t << getWritableVar("HEADERS")
00363 << getWritableVar("INTERFACES")
00364 << getWritableVar("LEXSOURCES")
00365 << getWritableVar("YACCSOURCES")
00366 << getWritableVar("SOURCES")
00367 << getWritableVar("TRANSLATIONS");
00368 }
00369 for(it = Option::after_user_vars.begin(); it != Option::after_user_vars.end(); ++it)
00370 t << (*it) << endl;
00371 return TRUE;
00372 }
00373
00374 bool
00375 ProjectGenerator::addConfig(const QString &cfg, bool add)
00376 {
00377 QString where = "CONFIG";
00378 if(!add)
00379 where = "CONFIG_REMOVE";
00380 if(!project->variables()[where].contains(cfg)) {
00381 project->variables()[where] += cfg;
00382 return TRUE;
00383 }
00384 return FALSE;
00385 }
00386
00387
00388 bool
00389 ProjectGenerator::addFile(QString file)
00390 {
00391 file = fileFixify(file, QDir::currentDirPath());
00392 QString dir;
00393 int s = file.findRev(Option::dir_sep);
00394 if(s != -1)
00395 dir = file.left(s+1);
00396 if(file.mid(dir.length(), Option::h_moc_mod.length()) == Option::h_moc_mod)
00397 return FALSE;
00398
00399 QString where;
00400 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
00401 if(file.endsWith((*cppit))) {
00402 if(QFile::exists(file.left(file.length() - (*cppit).length()) + Option::ui_ext))
00403 return FALSE;
00404 else
00405 where = "SOURCES";
00406 break;
00407 }
00408 }
00409 if(where.isEmpty()) {
00410 for(QStringList::Iterator hit = Option::h_ext.begin(); hit != Option::h_ext.end(); ++hit) {
00411 if(file.endsWith((*hit))) {
00412 where = "HEADERS";
00413 break;
00414 }
00415 }
00416 }
00417 if(where.isEmpty()) {
00418 if(file.endsWith(Option::ui_ext))
00419 where = "INTERFACES";
00420 else if(file.endsWith(".c"))
00421 where = "SOURCES";
00422 else if(file.endsWith(Option::lex_ext))
00423 where = "LEXSOURCES";
00424 else if(file.endsWith(Option::yacc_ext))
00425 where = "YACCSOURCES";
00426 else if(file.endsWith(".ts"))
00427 where = "TRANSLATIONS";
00428 }
00429
00430 QString newfile = fileFixify(file);
00431 if(!where.isEmpty() && !project->variables()[where].contains(file)) {
00432 project->variables()[where] += newfile;
00433 return TRUE;
00434 }
00435 return FALSE;
00436 }
00437
00438
00439 QString
00440 ProjectGenerator::getWritableVar(const QString &v, bool fixPath)
00441 {
00442 QStringList &vals = project->variables()[v];
00443 if(vals.isEmpty())
00444 return "";
00445
00446 QString ret;
00447 if(v.endsWith("_REMOVE"))
00448 ret = v.left(v.length() - 7) + " -= ";
00449 else if(v.endsWith("_ASSIGN"))
00450 ret = v.left(v.length() - 7) + " = ";
00451 else
00452 ret = v + " += ";
00453 QString join = vals.join(" ");
00454 if(ret.length() + join.length() > 80) {
00455 QString spaces;
00456 for(unsigned int i = 0; i < ret.length(); i++)
00457 spaces += " ";
00458 join = vals.join(" \\\n" + spaces);
00459 }
00460 #if 0
00461
00462
00463 if(fixPath)
00464 join = join.replace("\\", "/");
00465 #else
00466 Q_UNUSED(fixPath);
00467 #endif
00468 return ret + join + "\n";
00469 }
00470
00471 bool
00472 ProjectGenerator::openOutput(QFile &file) const
00473 {
00474 QString outdir;
00475 if(!file.name().isEmpty()) {
00476 QFileInfo fi(file);
00477 if(fi.isDir())
00478 outdir = fi.dirPath() + QDir::separator();
00479 }
00480 if(!outdir.isEmpty() || file.name().isEmpty()) {
00481 QString dir = QDir::currentDirPath();
00482 int s = dir.findRev('/');
00483 if(s != -1)
00484 dir = dir.right(dir.length() - (s + 1));
00485 file.setName(outdir + dir + ".pro");
00486 }
00487 return MakefileGenerator::openOutput(file);
00488 }