Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

makefile.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** 
00003 **
00004 ** Implementation of MakefileGenerator class.
00005 **
00006 ** Copyright (C) 1992-2003 Trolltech AS.  All rights reserved.
00007 **
00008 ** This file is part of qmake.
00009 **
00010 ** This file may be distributed under the terms of the Q Public License
00011 ** as defined by Trolltech AS of Norway and appearing in the file
00012 ** LICENSE.QPL included in the packaging of this file.
00013 **
00014 ** This file may be distributed and/or modified under the terms of the
00015 ** GNU General Public License version 2 as published by the Free Software
00016 ** Foundation and appearing in the file LICENSE.GPL included in the
00017 ** packaging of this file.
00018 **
00019 ** Licensees holding valid Qt Enterprise Edition licenses may use this
00020 ** file in accordance with the Qt Commercial License Agreement provided
00021 ** with the Software.
00022 **
00023 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00024 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00025 **
00026 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00027 **   information about Qt Commercial License Agreements.
00028 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00029 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00030 **
00031 ** Contact info@trolltech.com if any conditions of this licensing are
00032 ** not clear to you.
00033 **
00034 **********************************************************************/
00035 
00036 #include "makefile.h"
00037 #include "option.h"
00038 #include "meta.h"
00039 #include <qdir.h>
00040 #include <qfile.h>
00041 #include <qtextstream.h>
00042 #include <qregexp.h>
00043 #include <qdict.h>
00044 #if defined(Q_OS_UNIX)
00045 #include <unistd.h>
00046 #else
00047 #include <io.h>
00048 #endif
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 #include <time.h>
00052 #include <fcntl.h>
00053 #include <sys/types.h>
00054 #include <sys/stat.h>
00055 
00056 // Well, Windows doesn't have this, so here's the macro
00057 #ifndef S_ISDIR
00058 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
00059 #endif
00060 #define QMAKE_EOL(x) (x == '\r' || x == '\n')
00061 
00062 QString mkdir_p_asstring(const QString &dir)
00063 {
00064     QString ret =  "@$(CHK_DIR_EXISTS) \"" + dir + "\" ";
00065     if(Option::target_mode == Option::TARG_WIN_MODE)
00066         ret += "$(MKDIR)";
00067     else
00068         ret += "|| $(MKDIR)";
00069     ret += " \"" + dir + "\"";
00070     return ret;
00071 }
00072 
00073 static bool createDir(const QString& fullPath)
00074 {
00075     if(QFile::exists(fullPath))
00076         return FALSE;
00077     QDir dirTmp;
00078     bool ret = TRUE;
00079     QString pathComponent, tmpPath;
00080     QStringList hierarchy = QStringList::split(QString(Option::dir_sep), fullPath, TRUE);
00081     for(QStringList::Iterator it = hierarchy.begin(); it != hierarchy.end(); ++it) {
00082         pathComponent = *it + QDir::separator();
00083         tmpPath += pathComponent;
00084         if(!dirTmp.mkdir(tmpPath)) {
00085             ret = FALSE;
00086 //          break;
00087         }
00088     }
00089     return ret;
00090 }
00091 
00092 
00093 MakefileGenerator::MakefileGenerator(QMakeProject *p) : init_opath_already(FALSE),
00094                                                         init_already(FALSE), moc_aware(FALSE),
00095                                                         no_io(FALSE), project(p)
00096 {
00097 }
00098 
00099 static char *gimme_buffer(off_t s)
00100 {
00101     static char *big_buffer = NULL;
00102     static int big_buffer_size = 0;
00103     if(!big_buffer || big_buffer_size < s)
00104         big_buffer = (char *)realloc(big_buffer, s);
00105     return big_buffer;
00106 }
00107 
00108 bool
00109 MakefileGenerator::generateMocList(const QString &fn_target)
00110 {
00111     if(!findMocDestination(fn_target).isEmpty())
00112         return TRUE;
00113 
00114     QString fn_local = Option::fixPathToLocalOS(fileFixify(fn_target, QDir::currentDirPath(), Option::output_dir));
00115 
00116     int file = open(fn_local.latin1(), O_RDONLY);
00117     if(file == -1)
00118         return FALSE;
00119 
00120     struct stat fst;
00121     if(fstat(file, &fst) || S_ISDIR(fst.st_mode))
00122         return FALSE; //shouldn't happen
00123     char *big_buffer = gimme_buffer(fst.st_size);
00124 
00125     int total_size_read;
00126     for(int have_read = total_size_read = 0;
00127         (have_read = read(file, big_buffer + total_size_read,
00128                           fst.st_size - total_size_read));
00129         total_size_read += have_read);
00130     close(file);
00131 
00132     bool ignore_qobject = FALSE;
00133     int line_count = 1;
00134  /* qmake ignore Q_OBJECT */
00135 #define COMP_LEN 8 //strlen("Q_OBJECT")
00136 #define OBJ_LEN 8 //strlen("Q_OBJECT")
00137 #define DIS_LEN 10 //strlen("Q_DISPATCH")
00138     int x;
00139     for(x = 0; x < (total_size_read-COMP_LEN); x++) {
00140         if(*(big_buffer + x) == '/') {
00141             x++;
00142             if(total_size_read >= x) {
00143                 if(*(big_buffer + x) == '/') { //c++ style comment
00144                     for( ;x < total_size_read && !QMAKE_EOL(*(big_buffer + x)); x++);
00145                     line_count++;
00146                 } else if(*(big_buffer + x) == '*') { //c style comment
00147                     for( ;x < total_size_read; x++) {
00148                         if(*(big_buffer + x) == 't' || *(big_buffer + x) == 'q') { //ignore
00149                             if(total_size_read >= (x + 20)) {
00150                                 if(!strncmp(big_buffer + x + 1, "make ignore Q_OBJECT", 20)) {
00151                                     debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
00152                                               fn_target.latin1(), line_count);
00153                                     x += 20;
00154                                     ignore_qobject = TRUE;
00155                                 }
00156                             }
00157                         } else if(*(big_buffer + x) == '*') {
00158                             if(total_size_read >= (x+1) && *(big_buffer + (x+1)) == '/') {
00159                                 x += 2;
00160                                 break;
00161                             }
00162                         } else if(QMAKE_EOL(*(big_buffer + x))) {
00163                             line_count++;
00164                         }
00165                     }
00166                 }
00167             }
00168         }
00169 #define SYMBOL_CHAR(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || \
00170                         (x <= '0' && x >= '9') || x == '_')
00171 
00172         bool interesting = *(big_buffer+x) == 'Q' && (!strncmp(big_buffer+x, "Q_OBJECT", OBJ_LEN) ||
00173                                                       !strncmp(big_buffer+x, "Q_DISPATCH", DIS_LEN));
00174         if(interesting) {
00175             int len = 0;
00176             if(!strncmp(big_buffer+x, "Q_OBJECT", OBJ_LEN)) {
00177                 if(ignore_qobject) {
00178                     debug_msg(2, "Mocgen: %s:%d Ignoring Q_OBJECT", fn_target.latin1(), line_count);
00179                     interesting = FALSE;
00180                 }
00181                 len=OBJ_LEN;
00182             } else if(!strncmp(big_buffer+x, "Q_DISPATCH", DIS_LEN)) {
00183                 len=DIS_LEN;
00184             }
00185             if(SYMBOL_CHAR(*(big_buffer+x+len)))
00186                 interesting = FALSE;
00187             if(interesting) {
00188                 *(big_buffer+x+len) = '\0';
00189                 debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", fn_target.latin1(),
00190                           line_count, big_buffer+x);
00191 
00192                 int ext_pos = fn_target.findRev('.');
00193                 int ext_len = fn_target.length() - ext_pos;
00194                 int dir_pos =  fn_target.findRev(Option::dir_sep, ext_pos);
00195                 QString mocFile;
00196                 if(!project->isEmpty("MOC_DIR"))
00197                     mocFile = project->first("MOC_DIR");
00198                 else if(dir_pos != -1)
00199                     mocFile = fn_target.left(dir_pos+1);
00200 
00201                 bool cpp_ext = FALSE;
00202                 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
00203                     cppit != Option::cpp_ext.end(); ++cppit) {
00204                     if((cpp_ext = (fn_target.right(ext_len) == (*cppit))))
00205                         break;
00206                 }
00207                 if(cpp_ext) {
00208                     mocFile += Option::cpp_moc_mod + fn_target.mid(dir_pos+1, ext_pos - dir_pos-1) + Option::cpp_moc_ext;
00209                     project->variables()["_SRCMOC"].append(mocFile);
00210                 } else if(project->variables()["HEADERS"].findIndex(fn_target) != -1) {
00211                     for(QStringList::Iterator hit = Option::h_ext.begin();
00212                         hit != Option::h_ext.end(); ++hit) {
00213                         if((fn_target.right(ext_len) == (*hit))) {
00214                             mocFile += Option::h_moc_mod + fn_target.mid(dir_pos+1, ext_pos - dir_pos-1) +
00215                                        Option::h_moc_ext;
00216                             logicWarn(mocFile, "SOURCES");
00217                             project->variables()["_HDRMOC"].append(mocFile);
00218                             break;
00219                         }
00220                     }
00221                 }
00222 
00223                 if(!mocFile.isEmpty()) {
00224                     mocFile = Option::fixPathToTargetOS(mocFile);
00225                     mocablesToMOC[cleanFilePath(fn_target)] = mocFile;
00226                     mocablesFromMOC[cleanFilePath(mocFile)] = fn_target;
00227                 }
00228                 break;
00229             }
00230         }
00231 
00232         while(x < total_size_read && SYMBOL_CHAR(*(big_buffer+x)))
00233             x++;
00234         if(QMAKE_EOL(*(big_buffer+x)))
00235             line_count++;
00236     }
00237 #undef OBJ_LEN
00238 #undef DIS_LEN
00239     return TRUE;
00240 }
00241 
00242 bool
00243 MakefileGenerator::generateDependencies(QPtrList<MakefileDependDir> &dirs, const QString &f, bool recurse)
00244 {
00245     if(processedDependencies(f))
00246         return TRUE;
00247     setProcessedDependencies(f, TRUE);
00248 
00249     QStringList &fndeps = findDependencies(f);
00250     QString fn = fileFixify(f, QDir::currentDirPath(), Option::output_dir);
00251     fn = Option::fixPathToLocalOS(fn, FALSE);
00252     QString fix_env_fn = Option::fixPathToLocalOS(fn);
00253     int file = open(fix_env_fn.latin1(), O_RDONLY);
00254     if(file == -1)
00255         return FALSE;
00256     struct stat fst;
00257     if(fstat(file, &fst) || S_ISDIR(fst.st_mode))
00258         return FALSE; //shouldn't happen
00259 
00260     QString fndir, fix_env_fndir;
00261     int dl = fn.findRev(Option::dir_sep);
00262     if(dl != -1)
00263         fndir = fn.left(dl+1);
00264     dl = fix_env_fn.findRev(Option::dir_sep);
00265     if(dl != -1)
00266         fix_env_fndir = fix_env_fn.left(dl + 1);
00267 
00268     int line_count = 1;
00269     char *big_buffer = gimme_buffer(fst.st_size);
00270 
00271     int total_size_read;
00272     for(int have_read = total_size_read = 0;
00273         (have_read = read(file, big_buffer + total_size_read,
00274                           fst.st_size - total_size_read));
00275         total_size_read += have_read);
00276     close(file);
00277 
00278     bool ui_file = fn.endsWith(Option::ui_ext);
00279     for(int x = 0; x < total_size_read; x++) {
00280         QStringList *outdeps=&fndeps;
00281         QString inc;
00282         if(!ui_file) {
00283             if(*(big_buffer + x) == '/') {
00284                 x++;
00285                 if(total_size_read >= x) {
00286                     if(*(big_buffer + x) == '/') { //c++ style comment
00287                         for( ; x < total_size_read && !QMAKE_EOL(*(big_buffer + x)); x++);
00288                     } else if(*(big_buffer + x) == '*') { //c style comment
00289                         for( ; x < total_size_read; x++) {
00290                             if(*(big_buffer + x) == '*') {
00291                                 if(total_size_read >= (x+1) && *(big_buffer + (x+1)) == '/') {
00292                                     x += 2;
00293                                     break;
00294                                 }
00295                             } else if(QMAKE_EOL(*(big_buffer + x))) {
00296                                 line_count++;
00297                             }
00298                         }
00299                     }
00300                 }
00301             }
00302             while(x < total_size_read && //Skip spaces
00303                   (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t'))
00304                 x++;
00305             if(*(big_buffer + x) == '#') {
00306                 x++;
00307                 while(x < total_size_read && //Skip spaces after hash
00308                       (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t'))
00309                     x++;
00310                 if(total_size_read >= x + 8 && !strncmp(big_buffer + x, "include", 7) &&
00311                    (*(big_buffer + x + 7) == ' ' || *(big_buffer + x + 7) == '\t' ||
00312                     *(big_buffer + x + 7) == '<' || *(big_buffer + x + 7) == '"')) {
00313                     for(x+=7; //skip spaces after keyword
00314                         x < total_size_read && (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t');
00315                         x++);
00316                     char term = *(big_buffer + x);
00317                     if(term == '"');
00318                     else if(term == '<')
00319                         term = '>';
00320                     else
00321                         continue; //wtf?
00322                     x++;
00323 
00324                     int inc_len;
00325                     for(inc_len = 0; *(big_buffer + x + inc_len) != term &&
00326                                      !QMAKE_EOL(*(big_buffer + x + inc_len)); inc_len++);
00327                     *(big_buffer + x + inc_len) = '\0';
00328                     inc = big_buffer + x;
00329                 } else if(total_size_read >= x + 14 && !strncmp(big_buffer + x,  "qmake_warning ", 14)) {
00330                     for(x+=14; //skip spaces after keyword
00331                         x < total_size_read && (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t');
00332                         x++);
00333                     char term = 0;
00334                     if(*(big_buffer + x) == '"')
00335                         term = '"';
00336                     if(*(big_buffer + x) == '\'')
00337                         term = '\'';
00338                     if(term)
00339                         x++;
00340 
00341                     int msg_len;
00342                     for(msg_len = 0; (term && *(big_buffer + x + msg_len) != term) &&
00343                                      !QMAKE_EOL(*(big_buffer + x + msg_len)); msg_len++);
00344                     const char saved_term = *(big_buffer + x + msg_len);
00345                     *(big_buffer + x + msg_len) = '\0';
00346                     QString msg = big_buffer + x;
00347                     debug_msg(0, "%s:%d qmake_warning -- %s", fix_env_fn.latin1(),
00348                               line_count, msg.latin1());
00349                     *(big_buffer + x + msg_len) = saved_term; //put it back
00350                 }
00351             }
00352         } else if(ui_file) {
00353             // skip whitespaces
00354             while(x < total_size_read &&
00355                   (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t'))
00356                 x++;
00357             if(*(big_buffer + x) == '<') {
00358                 x++;
00359                 if(total_size_read >= x + 12 && !strncmp(big_buffer + x, "includehint", 11) &&
00360                     (*(big_buffer + x + 11) == ' ' || *(big_buffer + x + 11) == '>')) {
00361                     for(x += 11; *(big_buffer + x) != '>'; x++);
00362                     int inc_len = 0;
00363                     for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
00364                     *(big_buffer + x + inc_len) = '\0';
00365                     inc = big_buffer + x;
00366                 } else if(total_size_read >= x + 13 && !strncmp(big_buffer + x, "customwidget", 12) &&
00367                           (*(big_buffer + x + 12) == ' ' || *(big_buffer + x + 12) == '>')) {
00368                     for(x += 13; *(big_buffer + x) != '>'; x++); //skip up to >
00369                     while(x < total_size_read) {
00370                         for(x++; *(big_buffer + x) != '<'; x++); //skip up to <
00371                         x++;
00372                         if(total_size_read >= x + 7 && !strncmp(big_buffer+x, "header", 6) &&
00373                            (*(big_buffer + x + 6) == ' ' || *(big_buffer + x + 6) == '>')) {
00374                             for(x += 7; *(big_buffer + x) != '>'; x++); //skip up to >
00375                             int inc_len = 0;
00376                             for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
00377                             *(big_buffer + x + inc_len) = '\0';
00378                             inc = big_buffer + x;
00379                             break;
00380                         } else if(total_size_read >= x + 14 && !strncmp(big_buffer+x, "/customwidget", 13) &&
00381                                   (*(big_buffer + x + 13) == ' ' || *(big_buffer + x + 13) == '>')) {
00382                             x += 14;
00383                             break;
00384                         }
00385                     }
00386                 } else if(total_size_read >= x + 8 && !strncmp(big_buffer + x, "include", 7) &&
00387                     (*(big_buffer + x + 7) == ' ' || *(big_buffer + x + 7) == '>')) {
00388                     for(x += 8; *(big_buffer + x) != '>'; x++) {
00389                         if(total_size_read >= x + 9 && *(big_buffer + x) == 'i' &&
00390                            !strncmp(big_buffer + x, "impldecl", 8)) {
00391                             for(x += 8; *(big_buffer + x) != '='; x++);
00392                             if(*(big_buffer + x) != '=')
00393                                 continue;
00394                             for(x++; *(big_buffer+x) == '\t' || *(big_buffer+x) == ' '; x++);
00395                             char quote = 0;
00396                             if(*(big_buffer+x) == '\'' || *(big_buffer+x) == '"') {
00397                                 quote = *(big_buffer + x);
00398                                 x++;
00399                             }
00400                             int val_len;
00401                             for(val_len = 0; TRUE; val_len++) {
00402                                 if(quote) {
00403                                     if(*(big_buffer+x+val_len) == quote)
00404                                         break;
00405                                 } else if(*(big_buffer + x + val_len) == '>' ||
00406                                           *(big_buffer + x + val_len) == ' ') {
00407                                     break;
00408                                 }
00409                             }
00410                             char saved = *(big_buffer + x + val_len);
00411                             *(big_buffer + x + val_len) = '\0';
00412                             QString where = big_buffer + x;
00413                             *(big_buffer + x + val_len) = saved;
00414                             if(where == "in implementation") {
00415                                 QString cpp = fn.left(fn.length() - Option::ui_ext.length()) +
00416                                                       Option::cpp_ext.first();
00417                                 outdeps = &findDependencies(cpp);
00418                             }
00419                         }
00420                     }
00421                     int inc_len = 0;
00422                     for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
00423                     *(big_buffer + x + inc_len) = '\0';
00424                     inc = big_buffer + x;
00425                 }
00426             }
00427         }
00428 
00429         if(!inc.isEmpty()) {
00430             bool from_source_dir = TRUE;
00431             debug_msg(5, "%s:%d Found dependency to %s", fix_env_fn.latin1(),
00432                       line_count, inc.latin1());
00433             if(!project->isEmpty("SKIP_DEPENDS")) {
00434                 bool found = FALSE;
00435                 QStringList &nodeplist = project->values("SKIP_DEPENDS");
00436                 for(QStringList::Iterator it = nodeplist.begin();
00437                     it != nodeplist.end(); ++it) {
00438                     QRegExp regx((*it));
00439                     if(regx.search(inc) != -1) {
00440                         found = TRUE;
00441                         break;
00442                     }
00443                 }
00444                 if(found)
00445                     continue;
00446             }
00447             QString fqn;
00448             if(project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH") &&
00449                !stat(fix_env_fndir + inc, &fst) && !S_ISDIR(fst.st_mode)) {
00450                 fqn = fndir + inc;
00451                 goto handle_fqn;
00452             } else if(project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH") &&
00453                !stat(inc, &fst) && !S_ISDIR(fst.st_mode)) {
00454                 fqn = inc;
00455                 goto handle_fqn;
00456             } else {
00457                 if((Option::target_mode == Option::TARG_MAC9_MODE && inc.find(':')) ||
00458                    (Option::target_mode == Option::TARG_WIN_MODE && inc[1] != ':') ||
00459                    ((Option::target_mode == Option::TARG_UNIX_MODE ||
00460                      Option::target_mode == Option::TARG_QNX6_MODE ||
00461                      Option::target_mode == Option::TARG_MACX_MODE) &&
00462                     inc[0] != '/')) {
00463                     for(MakefileDependDir *mdd = dirs.first(); mdd; mdd = dirs.next() ) {
00464                         if(!stat(mdd->local_dir + QDir::separator() + inc, &fst) &&
00465                            !S_ISDIR(fst.st_mode)) {
00466                             fqn = mdd->real_dir + QDir::separator() + inc;
00467                             goto handle_fqn;
00468                         }
00469                     }
00470                 }
00471             }
00472             if(fqn.isEmpty() && Option::mkfile::do_dep_heuristics) {
00473                 //these are some hacky heuristics it will try to do on an include
00474                 //however these can be turned off at runtime, I'm not sure how
00475                 //reliable these will be, most likely when problems arise turn it off
00476                 //and see if they go away..
00477                 if(depHeuristics.contains(inc)) {
00478                     fqn = depHeuristics[inc];
00479                     from_source_dir = FALSE;
00480                 } else if(Option::mkfile::do_dep_heuristics) { //some heuristics..
00481                     //is it a file from a .ui?
00482                     QString inc_file = inc.section(Option::dir_sep, -1);
00483                     int extn = inc_file.findRev('.');
00484                     if(extn != -1 &&
00485                        (inc_file.right(inc_file.length()-extn) == Option::cpp_ext.first() ||
00486                         inc_file.right(inc_file.length()-extn) == Option::h_ext.first())) {
00487                         QString uip = inc_file.left(extn) + Option::ui_ext;
00488                         QStringList uil = project->variables()["FORMS"];
00489                         for(QStringList::Iterator it = uil.begin(); it != uil.end(); ++it) {
00490                             if((*it).section(Option::dir_sep, -1) == uip) {
00491                                 if(!project->isEmpty("UI_DIR"))
00492                                     fqn = project->first("UI_DIR");
00493                                 else if(!project->isEmpty("UI_HEADERS_DIR"))
00494                                     fqn = project->first("UI_HEADERS_DIR");
00495                                 else
00496                                     fqn = (*it).section(Option::dir_sep, 0, -2);
00497                                 if(!fqn.isEmpty() && !fqn.endsWith(Option::dir_sep))
00498                                     fqn += Option::dir_sep;
00499                                 fqn += inc_file;
00500                                 from_source_dir = FALSE; //uics go in the output_dir (so don't fix them)
00501                                 fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
00502                                 goto cache_fqn;
00503                             }
00504                         }
00505                     }
00506                     if(project->isActiveConfig("lex_included")) { //is this the lex file?
00507                         QString rhs = Option::lex_mod + Option::cpp_ext.first();
00508                         if(inc.endsWith(rhs)) {
00509                             QString lhs = inc.left(inc.length() - rhs.length()) + Option::lex_ext;
00510                             QStringList ll = project->variables()["LEXSOURCES"];
00511                             for(QStringList::Iterator it = ll.begin(); it != ll.end(); ++it) {
00512                                 QString s = (*it), d;
00513                                 int slsh = s.findRev(Option::dir_sep);
00514                                 if(slsh != -1) {
00515                                     d = s.left(slsh + 1);
00516                                     s = s.right(s.length() - slsh - 1);
00517                                 }
00518                                 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
00519                                     d = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
00520                                 if(s == lhs) {
00521                                     fqn = d + inc;
00522                                     from_source_dir = FALSE;  //uics go in the output_dir (so don't fix them)
00523                                     fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
00524                                     goto cache_fqn;
00525                                 }
00526                             }
00527                         }
00528                     }
00529                     { //is it from a .y?
00530                         QString rhs = Option::yacc_mod + Option::h_ext.first();
00531                         if(inc.endsWith(rhs)) {
00532                             QString lhs = inc.left(inc.length() - rhs.length()) + Option::yacc_ext;
00533                             QStringList yl = project->variables()["YACCSOURCES"];
00534                             for(QStringList::Iterator it = yl.begin(); it != yl.end(); ++it) {
00535                                 QString s = (*it), d;
00536                                 int slsh = s.findRev(Option::dir_sep);
00537                                 if(slsh != -1) {
00538                                     d = s.left(slsh + 1);
00539                                     s = s.right(s.length() - slsh - 1);
00540                                 }
00541                                 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
00542                                     d = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
00543                                 if(s == lhs) {
00544                                     fqn = d + inc;
00545                                     from_source_dir = FALSE;  //uics go in the output_dir (so don't fix them)
00546                                     fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
00547                                     goto cache_fqn;
00548                                 }
00549                             }
00550                         }
00551                     }
00552                     if( mocAware() &&               //is it a moc file?
00553                        ( inc.endsWith(Option::cpp_ext.first()) || inc.endsWith(Option::cpp_moc_ext) )
00554                        || ( (Option::cpp_ext.first() != Option::h_moc_ext) && inc.endsWith(Option::h_moc_ext) )) {
00555                         QString mocs[] = { QString("_HDRMOC"), QString("_SRCMOC"), QString::null };
00556                         for(int moc = 0; !mocs[moc].isNull(); moc++) {
00557                             QStringList &l = project->variables()[mocs[moc]];
00558                             for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
00559                                 QString file = Option::fixPathToTargetOS((*it));
00560                                 if(file.section(Option::dir_sep, -(inc.contains('/')+1)) == inc) {
00561                                     fqn = (*it);
00562                                     if(mocs[moc] == "_HDRMOC") {
00563                                         //Since it is include, no need to link it in as well
00564                                         project->variables()["_SRCMOC"].append((*it));
00565                                         l.remove(it);
00566                                     } else if(!findMocSource(fqn).endsWith(fileFixify(fn))) {
00567                                         /* Not really a very good test, but this will at least avoid
00568                                            confusion if it really does happen (since tmake/qmake
00569                                            previously didn't even allow this the test is mostly accurate) */
00570                                         warn_msg(WarnLogic,
00571                                                  "Found potential multiple MOC include %s (%s) in '%s'",
00572                                                  inc.latin1(), fqn.latin1(), fix_env_fn.latin1());
00573                                     }
00574                                     from_source_dir = FALSE; //mocs go in the output_dir (so don't fix them)
00575                                     goto cache_fqn;
00576                                 }
00577                             }
00578                         }
00579                     }
00580                     fqn = findDependency(inc); //all else fails..
00581                 cache_fqn:
00582                     if(from_source_dir) {
00583                         fqn = fileFixify(fqn);
00584                         from_source_dir = FALSE;
00585                     }
00586                     depHeuristics.insert(inc, fqn);
00587                 }
00588             }
00589         handle_fqn:
00590             if(fqn.isEmpty()) //I give up
00591               continue;
00592             fqn = Option::fixPathToTargetOS(fqn, FALSE);
00593             if(from_source_dir)
00594                 fqn = fileFixify(fqn);
00595             debug_msg(4, "Resolved dependency of %s to %s", inc.latin1(), fqn.latin1());
00596             if(outdeps && outdeps->findIndex(fqn) == -1)
00597                 outdeps->append(fqn);
00598         }
00599         //read past new line now..
00600         for( ; x < total_size_read && !QMAKE_EOL(*(big_buffer + x)); x++);
00601         line_count++;
00602     }
00603 
00604     if(recurse) {
00605         for(QStringList::Iterator fnit = fndeps.begin(); fnit != fndeps.end(); ++fnit) {
00606             generateDependencies(dirs, (*fnit), recurse);
00607             QStringList &deplist = findDependencies((*fnit));
00608             for(QStringList::Iterator it = deplist.begin(); it != deplist.end(); ++it) 
00609                 if(fndeps.findIndex((*it)) == -1 && (*it) != fn)
00610                     fndeps.append((*it));
00611         }
00612     }
00613     debug_msg(2, "Dependencies: %s -> %s", fn.latin1(), fndeps.join(" :: ").latin1());
00614     return TRUE;
00615 }
00616 
00617 void
00618 MakefileGenerator::initOutPaths()
00619 {
00620     if(init_opath_already)
00621         return;
00622     init_opath_already = TRUE;
00623     QMap<QString, QStringList> &v = project->variables();
00624         if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
00625             if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() &&
00626                v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
00627                 QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first();
00628                 root = Option::fixPathToTargetOS( root );
00629                 if(!root.isEmpty()) {
00630                     QFileInfo fi(Option::mkfile::cachefile);
00631                     if(!fi.convertToAbs()) {
00632                         QString cache_r = fi.dirPath(), pwd = Option::output_dir;
00633                         if ( pwd.startsWith(cache_r) && !pwd.startsWith(root) ) {
00634                             pwd = Option::fixPathToTargetOS(root + pwd.mid(cache_r.length()));
00635                             if(QFile::exists(pwd))
00636                                 v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", pwd);
00637                         }
00638                     }
00639                 }
00640             }
00641         }
00642         if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) {
00643             QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first();
00644             asp = Option::fixPathToTargetOS( asp );
00645             if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother?
00646                 v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear();
00647         }
00648         QString currentDir = QDir::currentDirPath();
00649         QString dirs[] = { QString("OBJECTS_DIR"), QString("MOC_DIR"), QString("UI_HEADERS_DIR"),
00650                            QString("UI_SOURCES_DIR"), QString("UI_DIR"), QString("DESTDIR"),
00651                            QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString::null };
00652         for(int x = 0; dirs[x] != QString::null; x++) {
00653             if ( !v[dirs[x]].isEmpty() ) {
00654                 QString orig_path = v[dirs[x]].first();
00655 #ifdef Q_WS_WIN
00656                 // We don't want to add a separator for DLLDESTDIR on Windows
00657                 if (!(dirs[x] == "DLLDESTDIR"))
00658 #endif
00659                 {
00660                     QString &path = v[dirs[x]].first();
00661                     path = fileFixify(path, Option::output_dir, Option::output_dir);
00662                     if(path.right(Option::dir_sep.length()) != Option::dir_sep)
00663                         path += Option::dir_sep;
00664                 }
00665                 if(noIO())
00666                     continue;
00667 
00668                 QString path = project->first(dirs[x]); //not to be changed any further
00669                 path = Option::fixPathToTargetOS(fileFixify(path, QDir::currentDirPath(), Option::output_dir));
00670                 debug_msg(3, "Fixed output_dir %s (%s) into %s (%s)", dirs[x].latin1(), orig_path.latin1(),
00671                           v[dirs[x]].join("::").latin1(), path.latin1());
00672 
00673                 QDir d;
00674                 if(path.startsWith(Option::dir_sep)) {
00675                     d.cd(Option::dir_sep);
00676                     path = path.right(path.length() - 1);
00677                 }
00678 #ifdef Q_WS_WIN
00679                 bool driveExists = TRUE;
00680                 if ( !QDir::isRelativePath( path ) ) {
00681                     if ( QFile::exists( path.left( 3 ) ) ) {
00682                         d.cd( path.left( 3 ) );
00683                         path = path.right( path.length() - 3 );
00684                     } else {
00685                         warn_msg(WarnLogic, "%s: Cannot access drive '%s' (%s)", dirs[x].latin1(),
00686                             path.left( 3 ).latin1(), path.latin1() );
00687                         driveExists = FALSE;
00688                     }
00689                 }
00690                 if ( driveExists ) {
00691 #endif
00692                     QStringList subs = QStringList::split(Option::dir_sep, path);
00693                     for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) {
00694                         if(!d.cd(*subit)) {
00695                             d.mkdir((*subit));
00696                             if ( d.exists( (*subit) ) )
00697                                 d.cd((*subit));
00698                             else {
00699                                 warn_msg(WarnLogic, "%s: Cannot access directory '%s' (%s)", dirs[x].latin1(),
00700                                     (*subit).latin1(), path.latin1() );
00701                                 break;
00702                             }
00703                         }
00704                     }
00705 #ifdef Q_WS_WIN
00706                 }
00707 #endif
00708             }
00709         }
00710         if ( !v["DESTDIR"].isEmpty() ) {
00711             QDir d(v["DESTDIR"].first());
00712             if(Option::fixPathToLocalOS(d.absPath()) == Option::fixPathToLocalOS(Option::output_dir))
00713                 v.remove("DESTDIR");
00714         }
00715         QDir::current().cd( currentDir );
00716 }
00717 
00718 void
00719 MakefileGenerator::init()
00720 {
00721     initOutPaths();
00722     if(init_already)
00723         return;
00724     init_already = TRUE;
00725 
00726     QMap<QString, QStringList> &v = project->variables();
00727     QString paths[] = { QString("SOURCES"), QString("FORMS"), QString("YACCSOURCES"), QString("INCLUDEPATH"),
00728                         QString("HEADERS"), QString("HEADERS_ORIG"), QString("LEXSOURCES"),
00729                         QString("QMAKE_INTERNAL_INCLUDED_FILES"),
00730                         QString("PRECOMPILED_HEADER"), QString::null };
00731     for(int y = 0; paths[y] != QString::null; y++) {
00732         QStringList &l = v[paths[y]];
00733         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
00734             if ((*it).isEmpty())
00735                 continue;
00736             if(QFile::exists((*it)))
00737                 (*it) = fileFixify((*it));
00738         }
00739     }
00740 
00741     /* get deps and mocables */
00742     QDict<void> cache_found_files;
00743     QString cache_file(".qmake.internal.cache");
00744     if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE"))
00745         cache_file = Option::fixPathToLocalOS(project->first("QMAKE_INTERNAL_CACHE_FILE"));
00746     if(cache_file.find(QDir::separator()) == -1) //guess they know what they are doing..
00747         cache_file.prepend(Option::output_dir + QDir::separator());
00748     if((Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT ||
00749         Option::mkfile::do_deps || Option::mkfile::do_mocs) && !noIO()) {
00750         QPtrList<MakefileDependDir> deplist;
00751         deplist.setAutoDelete(TRUE);
00752         if((Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT || Option::mkfile::do_deps) &&
00753            doDepends()) {
00754             QStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"];
00755             if(project->isActiveConfig("depend_includepath"))
00756                 incDirs += v["INCLUDEPATH"];
00757             for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it) {
00758                 QString r = (*it), l = Option::fixPathToLocalOS((*it));
00759                 deplist.append(new MakefileDependDir(r.replace("\"",""),
00760                                                      l.replace("\"","")));
00761             }
00762             debug_msg(1, "Dependency Directories: %s", incDirs.join(" :: ").latin1());
00763             if(Option::output.name() != "-" && project->isActiveConfig("qmake_cache")) {
00764                 QFile cachef(cache_file);
00765                 if(cachef.open(IO_ReadOnly | IO_Translate)) {
00766                     QFileInfo cachefi(cache_file);
00767                     debug_msg(2, "Trying internal cache information: %s", cache_file.latin1());
00768                     QTextStream cachet(&cachef);
00769                     QString line, file;
00770                     enum { CacheInfo, CacheDepend, CacheMoc } state = CacheInfo;
00771                     while (!cachet.eof()) {
00772                         line = cachet.readLine().stripWhiteSpace();
00773                         int sep = line.find('=');
00774                         if(line == "[depend]") {
00775                             state = CacheDepend;
00776                         } else if(line == "[mocable]") {
00777                             state = CacheMoc;
00778                         } else if(line == "[check]") {
00779                             state = CacheInfo;
00780                         } else if(!line.isEmpty() && sep != -1) {
00781                             file = line.left(sep).stripWhiteSpace();
00782                             line = line.right(line.length() - sep - 1).stripWhiteSpace();
00783                             if(state == CacheInfo) {
00784                                 if(file == "QMAKE_CACHE_VERSION") {
00785                                     if(line != qmake_version())
00786                                         break;
00787                                 } else {
00788                                     const QStringList &l = project->variables()[file];
00789                                     if(!l.isEmpty() && !line.isEmpty() && l.join(" ") != line)
00790                                         break;
00791                                 }
00792                             } else if(state == CacheDepend) {
00793                                 bool found = (bool)cache_found_files[file];
00794                                 QStringList files = QStringList::split(" ", line);
00795                                 if(!found) {
00796                                     QFileInfo fi(fileFixify(file, QDir::currentDirPath(), Option::output_dir));
00797                                     if(fi.exists() && fi.lastModified() < cachefi.lastModified()) {
00798                                         cache_found_files.insert(file, (void *)1);
00799                                         found = TRUE;
00800                                     }
00801                                 }
00802                                 if(found) {
00803                                     for(QStringList::Iterator dep_it = files.begin();
00804                                         dep_it != files.end(); ++dep_it) {
00805                                         if(!cache_found_files[(*dep_it)]) {
00806                                             QFileInfo fi(fileFixify((*dep_it), QDir::currentDirPath(), Option::output_dir));
00807                                             if(fi.exists() &&
00808                                                fi.lastModified() < cachefi.lastModified()) {
00809                                                 cache_found_files.insert((*dep_it), (void *)1);
00810                                             } else {
00811                                                 found = FALSE;
00812                                                 break;
00813                                             }
00814                                         }
00815                                     }
00816                                     if(found) {
00817                                         debug_msg(2, "Dependencies (cached): %s -> %s", file.latin1(),
00818                                                   files.join(" :: ").latin1());
00819                                         findDependencies(file) = files;
00820                                         setProcessedDependencies(file, TRUE);
00821                                     }
00822                                 }
00823                             } else {
00824                                 void *found = cache_found_files[file];
00825                                 if(found != (void *)2) {
00826                                     if(found) {
00827                                         cache_found_files.replace(file, (void *)2);
00828                                     } else {
00829                                         QFileInfo fi(fileFixify(file, QDir::currentDirPath(), Option::output_dir));
00830                                         if(fi.exists() && fi.lastModified() < cachefi.lastModified()) {
00831                                             cache_found_files.insert(file, (void *)2);
00832                                             found = (void*)1;
00833                                         }
00834                                     }
00835                                 }
00836                                 if(found && line != "*qmake_ignore*") {
00837                                     int ext_len = file.length() - file.findRev('.');
00838                                     bool cpp_ext = FALSE;
00839                                     for(QStringList::Iterator cppit = Option::cpp_ext.begin();
00840                                         cppit != Option::cpp_ext.end(); ++cppit) {
00841                                         if((cpp_ext = (file.right(ext_len) == (*cppit))))
00842                                             break;
00843                                     }
00844                                     if(cpp_ext) {
00845                                         project->variables()["_SRCMOC"].append(line);
00846                                     } else if(project->variables()["HEADERS"].findIndex(file) != -1) {
00847                                         for(QStringList::Iterator hit = Option::h_ext.begin();
00848                                             hit != Option::h_ext.end(); ++hit) {
00849                                             if((file.right(ext_len) == (*hit))) {
00850                                                 project->variables()["_HDRMOC"].append(line);
00851                                                 break;
00852                                             }
00853                                         }
00854                                     }
00855                                     debug_msg(2, "Mocgen (cached): %s -> %s", file.latin1(),
00856                                               line.latin1());
00857                                     mocablesToMOC[file] = line;
00858                                     mocablesFromMOC[line] = file;
00859                                 }
00860                             }
00861                         }
00862                     }
00863                     cachef.close();
00864                 }
00865             }
00866         }
00867         if(!noIO()) {
00868             QString sources[] = { QString("OBJECTS"), QString("LEXSOURCES"), QString("YACCSOURCES"),
00869                                   QString("HEADERS"), QString("SOURCES"), QString("FORMS"), 
00870                                   QString("PRECOMPILED_HEADER"), QString::null };
00871             depHeuristics.clear();
00872             bool write_cache = FALSE, read_cache = QFile::exists(cache_file);
00873             int x;
00874             for(x = 0; sources[x] != QString::null; x++) {
00875                 QStringList vpath, &l = v[sources[x]];
00876                 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
00877                     if(!(*val_it).isEmpty()) {
00878                         QString file = fileFixify((*val_it), QDir::currentDirPath(), Option::output_dir);
00879                         if(!QFile::exists(file)) {
00880                             bool found = FALSE;
00881                             if(QDir::isRelativePath((*val_it))) {
00882                                 if(vpath.isEmpty())
00883                                     vpath = v["VPATH_" + sources[x]] + v["VPATH"] +
00884                                             v["QMAKE_ABSOLUTE_SOURCE_PATH"] + v["DEPENDPATH"];
00885 
00886                                 for(QStringList::Iterator vpath_it = vpath.begin();
00887                                     vpath_it != vpath.end(); ++vpath_it) {
00888                                     QString real_dir = Option::fixPathToLocalOS((*vpath_it));
00889                                     if(QFile::exists(real_dir + QDir::separator() + (*val_it))) {
00890                                         QString dir = (*vpath_it);
00891                                         if(dir.right(Option::dir_sep.length()) != Option::dir_sep)
00892                                             dir += Option::dir_sep;
00893                                         (*val_it) = fileFixify(dir + (*val_it));
00894                                         found = TRUE;
00895                                         debug_msg(1, "Found file through vpath %s -> %s",
00896                                                   file.latin1(), (*val_it).latin1());
00897                                         break;
00898                                     }
00899                                 }
00900                             }
00901                             if(!found) {
00902                                 QString dir, regex = (*val_it), real_dir;
00903                                 if(regex.findRev(Option::dir_sep) != -1) {
00904                                     dir = regex.left(regex.findRev(Option::dir_sep) + 1);
00905                                     real_dir = fileFixify(Option::fixPathToLocalOS(dir),
00906                                                           QDir::currentDirPath(), Option::output_dir);
00907                                     regex = regex.right(regex.length() - dir.length());
00908                                 }
00909                                 if(real_dir.isEmpty() || QFile::exists(real_dir)) {
00910                                     QDir d(real_dir, regex);
00911                                     if(!d.count()) {
00912                                         debug_msg(1, "%s:%d Failure to find %s in vpath (%s)",
00913                                                   __FILE__, __LINE__,
00914                                                   (*val_it).latin1(), vpath.join("::").latin1());
00915                                         warn_msg(WarnLogic, "Failure to find: %s", (*val_it).latin1());
00916                                         continue;
00917                                     } else {
00918                                         for(int i = 0; i < (int)d.count(); i++) {
00919                                             QString file = fileFixify(dir + d[i]);
00920                                             if(i == (int)d.count() - 1)
00921                                                 (*val_it) = file;
00922                                             else
00923                                                 l.insert(val_it, file);
00924                                         }
00925                                     }
00926                                 } else {
00927                                     debug_msg(1, "%s:%d Cannot match %s%c%s, as %s does not exist.",
00928                                               __FILE__, __LINE__,
00929                                               real_dir.latin1(), QDir::separator(), regex.latin1(),
00930                                               real_dir.latin1());
00931                                     warn_msg(WarnLogic, "Failure to find: %s", (*val_it).latin1());
00932                                 }
00933                             }
00934                         }
00935                     }
00936                 }
00937             }
00938             for(x = 0; sources[x] != QString::null; x++) {
00939                 QStringList &l = v[sources[x]];
00940                 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
00941                     bool found_cache_moc = FALSE, found_cache_dep = FALSE;
00942                     if(read_cache && Option::output.name() != "-" &&
00943                             project->isActiveConfig("qmake_cache")) {
00944                         if(processedDependencies((*val_it)))
00945                             found_cache_dep = TRUE;
00946                         if(cache_found_files[(*val_it)] == (void *)2)
00947                             found_cache_moc = TRUE;
00948                         if(!found_cache_moc || !found_cache_dep)
00949                             write_cache = TRUE;
00950                     }
00951                     /* Do moc before dependency checking since some includes can come from
00952                        moc_*.cpp files */
00953                     if(found_cache_moc) {
00954                         QString fixed_file(fileFixify((*val_it), QDir::currentDirPath(), Option::output_dir));
00955                         QString moc = findMocDestination(fixed_file);
00956                         if(!moc.isEmpty()) {
00957                             for(QStringList::Iterator cppit = Option::cpp_ext.begin();
00958                                     cppit != Option::cpp_ext.end(); ++cppit) {
00959                                 if(fixed_file.endsWith((*cppit))) {
00960                                     QStringList &deps = findDependencies(fixed_file);
00961                                     if(!deps.contains(moc))
00962                                         deps.append(moc);
00963                                     break;
00964                                 }
00965                             }
00966                         }
00967                     } else if(mocAware() && (sources[x] == "SOURCES" || sources[x] == "HEADERS") &&
00968                             (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT ||
00969                              Option::mkfile::do_mocs)) {
00970                         generateMocList((*val_it));
00971                     }
00972                     if(!found_cache_dep && sources[x] != "OBJECTS") {
00973                         debug_msg(5, "Looking for dependencies for %s", (*val_it).latin1());
00974                         generateDependencies(deplist, (*val_it), doDepends());
00975                     }
00976                 }
00977             }
00978             if(project->isActiveConfig("qmake_cache") && (write_cache || !read_cache)) {
00979                 QFile cachef(cache_file);
00980                 if(cachef.open(IO_WriteOnly | IO_Translate)) {
00981                     debug_msg(2, "Writing internal cache information: %s", cache_file.latin1());
00982                     QTextStream cachet(&cachef);
00983                     cachet << "[check]" << "\n"
00984                            << "QMAKE_CACHE_VERSION = " << qmake_version() << "\n"
00985                            << "QMAKE_ABSOLUTE_SOURCE_PATH = " << var("QMAKE_ABSOLUTE_SOURCE_PATH") << "\n"
00986                            << "MOC_DIR = " << var("MOC_DIR") << "\n"
00987                            << "UI_DIR = " <<  var("UI_DIR") << "\n"
00988                            << "UI_HEADERS_DIR = " <<  var("UI_HEADERS_DIR") << "\n"
00989                            << "UI_SOURCES_DIR = " <<  var("UI_SOURCES_DIR") << "\n";
00990                     cachet << "[depend]" << endl;
00991                     for(QMap<QString, QStringList>::Iterator it = depends.begin();
00992                         it != depends.end(); ++it)
00993                         cachet << dependencyKey(it.key()) << " = " << it.data().join(" ") << endl;
00994                     cachet << "[mocable]" << endl;
00995                     QString mc, moc_sources[] = { QString("HEADERS"), QString("SOURCES"), QString::null };
00996                     for(int x = 0; moc_sources[x] != QString::null; x++) {
00997                         QStringList &l = v[moc_sources[x]];
00998                         for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
00999                             QString f = fileFixify((*val_it));
01000                             if(!f.isEmpty()) {
01001                                 mc = mocablesToMOC[f];
01002                                 if(mc.isEmpty())
01003                                     mc = "*qmake_ignore*";
01004                                 cachet << f << " = " << mc << endl;
01005                             }
01006                         }
01007                     }
01008                     cachef.close();
01009                 }
01010             }
01011         }
01012     }
01013     v["OBJECTS"] = createObjectList("SOURCES") + v["OBJECTS"]; // init variables
01014 
01015     //lex files
01016     {
01017         QStringList &impls = v["LEXIMPLS"];
01018         QStringList &l = v["LEXSOURCES"];
01019         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01020             QString dir;
01021             QFileInfo fi((*it));
01022             if(fi.dirPath() != ".")
01023                 dir = fi.dirPath() + Option::dir_sep;
01024             dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
01025             if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
01026                 dir += Option::dir_sep;
01027             QString impl = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
01028             logicWarn(impl, "SOURCES");
01029             logicWarn(impl, "SOURCES");
01030             impls.append(impl);
01031             if( ! project->isActiveConfig("lex_included")) {
01032                 v["SOURCES"].append(impl);
01033                 // attribute deps of lex file to impl file
01034                 QStringList &lexdeps = findDependencies((*it));
01035                 QStringList &impldeps = findDependencies(impl);
01036                 for(QStringList::ConstIterator d = lexdeps.begin(); d != lexdeps.end(); ++d) {
01037                     if(!impldeps.contains(*d))
01038                         impldeps.append(*d);
01039                 }
01040                 lexdeps.clear();
01041             }
01042         }
01043         if( ! project->isActiveConfig("lex_included"))
01044             v["OBJECTS"] += (v["LEXOBJECTS"] = createObjectList("LEXIMPLS"));
01045     }
01046     //yacc files
01047     {
01048         QStringList &decls = v["YACCCDECLS"], &impls = v["YACCIMPLS"];
01049         QStringList &l = v["YACCSOURCES"];
01050         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01051             QString dir;
01052             QFileInfo fi((*it));
01053             if(fi.dirPath() != ".")
01054                 dir = fi.dirPath() + Option::dir_sep;
01055             dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
01056             if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
01057                 dir += Option::dir_sep;
01058             QString impl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::cpp_ext.first();
01059             logicWarn(impl, "SOURCES");
01060             QString decl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::h_ext.first();
01061             logicWarn(decl, "HEADERS");
01062 
01063             decls.append(decl);
01064             impls.append(impl);
01065             v["SOURCES"].append(impl);
01066             QStringList &impldeps = findDependencies(impl);
01067             impldeps.append(decl);
01068             // attribute deps of yacc file to impl file
01069             QStringList &yaccdeps = findDependencies((*it));
01070             for(QStringList::ConstIterator d = yaccdeps.begin(); d != yaccdeps.end(); ++d) {
01071                 if(!impldeps.contains(*d))
01072                     impldeps.append(*d);
01073             }
01074             if( project->isActiveConfig("lex_included")) {
01075                 // is there a matching lex file ? Transfer its dependencies.
01076                 QString lexsrc = fi.baseName(TRUE) + Option::lex_ext;
01077                 if(fi.dirPath() != ".")
01078                     lexsrc.prepend(fi.dirPath() + Option::dir_sep);
01079                 if(v["LEXSOURCES"].findIndex(lexsrc) != -1) {
01080                     QString trg = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
01081                     impldeps.append(trg);
01082                     impldeps += findDependencies(lexsrc);
01083                     depends[lexsrc].clear();
01084                 }
01085             }
01086             yaccdeps.clear();
01087         }
01088         v["OBJECTS"] += (v["YACCOBJECTS"] = createObjectList("YACCIMPLS"));
01089     }
01090 
01091     //UI files
01092     {
01093         QStringList &includepath = project->variables()["INCLUDEPATH"];
01094         if(!project->isEmpty("UI_DIR"))
01095             includepath.append(project->first("UI_DIR"));
01096         else if(!project->isEmpty("UI_HEADERS_DIR"))
01097             includepath.append(project->first("UI_HEADERS_DIR"));
01098         QStringList &decls = v["UICDECLS"], &impls = v["UICIMPLS"];
01099         QStringList &l = v["FORMS"];
01100         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01101             QString impl, decl;
01102             QFileInfo fi(Option::fixPathToLocalOS((*it)));
01103             if ( !project->isEmpty("UI_DIR") ) {
01104                 impl = decl = project->first("UI_DIR");
01105                 QString d = fi.dirPath();
01106                 if( d == ".")
01107                     d = QDir::currentDirPath();
01108                 d = fileFixify(d, QDir::currentDirPath(), Option::output_dir);
01109                 if(!includepath.contains(d))
01110                     includepath.append(d);
01111             } else {
01112                 if(decl.isEmpty() && !project->isEmpty("UI_HEADERS_DIR"))
01113                     decl = project->first("UI_HEADERS_DIR");
01114                 if(!decl.isEmpty() || (project->isEmpty("UI_HEADERS_DIR") &&
01115                                        !project->isEmpty("UI_SOURCES_DIR")) ) {
01116                     QString d = fi.dirPath();
01117                     if( d == ".")
01118                         d = QDir::currentDirPath();
01119                     d = fileFixify(d, QDir::currentDirPath(), Option::output_dir);
01120                     if(includepath.contains(d))
01121                         includepath.append(d);
01122                 }
01123                 if(impl.isEmpty() && !project->isEmpty("UI_SOURCES_DIR"))
01124                     impl = project->first("UI_SOURCES_DIR");
01125                 if(fi.dirPath() != ".") {
01126                     if(impl.isEmpty())
01127                         impl = fi.dirPath() + Option::dir_sep;
01128                     if(decl.isEmpty())
01129                         decl = fi.dirPath() + Option::dir_sep;
01130                 }
01131             }
01132             impl = fileFixify(impl, QDir::currentDirPath(), Option::output_dir);
01133             if(!impl.isEmpty() && !impl.endsWith(Option::dir_sep))
01134                 impl += Option::dir_sep;
01135             impl += fi.baseName(TRUE) + Option::cpp_ext.first();
01136             if(Option::output_dir != QDir::currentDirPath() &&
01137                project->isEmpty("UI_DIR") && project->isEmpty("UI_HEADERS_DIR")) {
01138                 QString decl_fixed = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
01139                 if(!includepath.contains(decl_fixed))
01140                     includepath.append(decl_fixed);
01141                 if(!includepath.contains(decl))
01142                     project->variables()["INCLUDEPATH"].append(decl);
01143             }
01144             decl = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
01145             if(!decl.isEmpty() && !decl.endsWith(Option::dir_sep))
01146                 decl += Option::dir_sep;
01147             decl += fi.baseName(TRUE) + Option::h_ext.first();
01148             logicWarn(impl, "SOURCES");
01149             logicWarn(decl, "HEADERS");
01150             decls.append(decl);
01151             impls.append(impl);
01152             findDependencies(impl).append(decl);
01153 
01154             QString mocable = Option::h_moc_mod + fi.baseName(TRUE) + Option::h_moc_ext;
01155             if(!v["MOC_DIR"].isEmpty())
01156                 mocable.prepend(v["MOC_DIR"].first());
01157             else if(fi.dirPath() != ".")
01158                 mocable.prepend(fi.dirPath() + Option::dir_sep);
01159             logicWarn(mocable, "SOURCES");
01160             mocablesToMOC[cleanFilePath(decl)] = mocable;
01161             mocablesFromMOC[cleanFilePath(mocable)] = decl;
01162             v["_UIMOC"].append(mocable);
01163         }
01164         v["OBJECTS"] += (v["UICOBJECTS"] = createObjectList("UICDECLS"));
01165     }
01166 
01167     //Translation files
01168     if(!project->isEmpty("TRANSLATIONS")) {
01169         QStringList &trf = project->variables()["TRANSLATIONS"];
01170         for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it) {
01171             (*it) = Option::fixPathToLocalOS((*it));
01172         }
01173     }
01174 
01175     //Image files
01176     if(!project->isEmpty("IMAGES")) {
01177         if(project->isEmpty("QMAKE_IMAGE_COLLECTION"))
01178             v["QMAKE_IMAGE_COLLECTION"].append("qmake_image_collection" + Option::cpp_ext.first());
01179         QString imgfile = project->first("QMAKE_IMAGE_COLLECTION");
01180         Option::fixPathToTargetOS(imgfile);
01181         if(!project->isEmpty("UI_DIR") || !project->isEmpty("UI_SOURCES_DIR")) {
01182             if(imgfile.find(Option::dir_sep) != -1)
01183                 imgfile = imgfile.right(imgfile.findRev(Option::dir_sep) + 1);
01184             imgfile.prepend( (project->isEmpty("UI_DIR") ? project->first("UI_SOURCES_DIR") :
01185                             project->first("UI_DIR")) );
01186             v["QMAKE_IMAGE_COLLECTION"] = QStringList(imgfile);
01187         }
01188         logicWarn(imgfile, "SOURCES");
01189         if(!noIO()) {
01190             QStringList &l = v["IMAGES"];
01191             for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01192                 if(!QFile::exists((*it))) {
01193                     warn_msg(WarnLogic, "Failure to open: %s", (*it).latin1());
01194                     continue;
01195                 }
01196                 findDependencies(imgfile).append(fileFixify((*it)));
01197             }
01198         }
01199         v["OBJECTS"] += (v["IMAGEOBJECTS"] = createObjectList("QMAKE_IMAGE_COLLECTION"));
01200     }
01201     if(Option::output_dir != QDir::currentDirPath())
01202         project->variables()["INCLUDEPATH"].append(fileFixify(Option::output_dir, Option::output_dir,
01203                                                               Option::output_dir));
01204 
01205     //moc files
01206     if ( mocAware() ) {
01207         if(!project->isEmpty("MOC_DIR"))
01208             project->variables()["INCLUDEPATH"].append(project->first("MOC_DIR"));
01209         if ( Option::h_moc_ext == Option::cpp_ext.first() )
01210             v["OBJMOC"] = createObjectList("_HDRMOC") + createObjectList("_UIMOC");
01211 
01212         QStringList &l = v["SRCMOC"];
01213         l = v["_HDRMOC"] + v["_UIMOC"] + v["_SRCMOC"];
01214         for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
01215             if(!(*val_it).isEmpty())
01216                 (*val_it) = Option::fixPathToTargetOS((*val_it), FALSE);
01217         }
01218     }
01219 
01220     QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString("POST_TARGETDEPS"), QString::null };
01221     for(int path = 0; !fixpaths[path].isNull(); path++) {
01222         QStringList &l = v[fixpaths[path]];
01223         for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
01224             if(!(*val_it).isEmpty())
01225                 (*val_it) = Option::fixPathToTargetOS((*val_it), FALSE);
01226         }
01227     }
01228 
01229     // Make sure the INCLUDEPATH doesn't contain any empty(/null) entries
01230     QStringList &ipl = project->variables()["INCLUDEPATH"];
01231     for(QStringList::Iterator ipl_it = ipl.begin(); ipl_it != ipl.end();) {
01232         if ((*ipl_it).isEmpty())
01233             ipl_it = ipl.remove(ipl_it);
01234         else
01235             ++ipl_it;
01236     }
01237 }
01238 
01239 bool
01240 MakefileGenerator::processPrlFile(QString &file)
01241 {
01242     bool ret = FALSE, try_replace_file=FALSE;
01243     QString meta_file, orig_file = file;
01244     if(QMakeMetaInfo::libExists(file)) {
01245         try_replace_file = TRUE;
01246         meta_file = file;
01247         file = "";
01248     } else {
01249         QString tmp = file;
01250         int ext = tmp.findRev('.');
01251         if(ext != -1)
01252             tmp = tmp.left(ext);
01253         meta_file = tmp;
01254     }
01255     meta_file = fileFixify(meta_file);
01256     if(!QMakeMetaInfo::libExists(fileFixify(meta_file, QDir::currentDirPath(), Option::output_dir)) &&
01257        project->isActiveConfig("qt")) {
01258         QString stem = meta_file, dir, extn;
01259         int slsh = stem.findRev('/'), hadlib = 0;
01260         if(slsh != -1) {
01261             dir = stem.left(slsh + 1);
01262             stem = stem.right(stem.length() - slsh - 1);
01263         }
01264         if(stem.startsWith("lib")) {
01265             hadlib = 1;
01266             stem = stem.right(stem.length() - 3);
01267         }
01268         int dot = stem.find('.');
01269         if(dot != -1) {
01270             extn = stem.right(stem.length() - dot);
01271             stem = stem.left(dot);
01272         }
01273         if(stem == "qt" || stem == "qte" || stem == "qte-mt" || stem == "qt-mt") {
01274             if(stem.endsWith("-mt"))
01275                 stem = stem.left(stem.length() - 3); //lose the -mt
01276             else
01277                 stem += "-mt"; //try the thread case
01278             meta_file = dir;
01279             if(hadlib)
01280                 meta_file += "lib";
01281             meta_file += stem + extn;
01282             try_replace_file = TRUE;
01283         }
01284     }
01285     QString real_meta_file = Option::fixPathToLocalOS(meta_file);
01286     if(project->variables()["QMAKE_PRL_INTERNAL_FILES"].findIndex(QMakeMetaInfo::findLib(meta_file)) != -1) {
01287         ret = TRUE;
01288     } else if(!meta_file.isEmpty()) {
01289         QString f = fileFixify(real_meta_file, QDir::currentDirPath(), Option::output_dir);
01290         if(QMakeMetaInfo::libExists(f)) {
01291             QMakeMetaInfo libinfo;
01292             debug_msg(1, "Processing PRL file: %s", real_meta_file.latin1());
01293             if(!libinfo.readLib(f)) {
01294                 fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.latin1());
01295             } else if(project->isActiveConfig("no_read_prl_" + libinfo.type().lower())) {
01296                 debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.latin1(), libinfo.type().latin1()); 
01297             } else {
01298                 ret = TRUE;
01299                 QMap<QString, QStringList> &vars = libinfo.variables();
01300                 for( QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it)
01301                     processPrlVariable(it.key(), it.data());
01302                 if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) {
01303                     QString dir;
01304                     int slsh = real_meta_file.findRev(Option::dir_sep);
01305                     if(slsh != -1)
01306                         dir = real_meta_file.left(slsh+1);
01307                     file = libinfo.first("QMAKE_PRL_TARGET");
01308                     if(QDir::isRelativePath(file))
01309                         file.prepend(dir);
01310                 }
01311             }
01312         }
01313         if(ret) {
01314             QString mf = QMakeMetaInfo::findLib(meta_file);
01315             project->variables()["QMAKE_PRL_INTERNAL_FILES"].append(mf);
01316             project->variables()["QMAKE_INTERNAL_INCLUDED_FILES"].append(mf);
01317         }
01318     }
01319     if(try_replace_file && file.isEmpty()) {
01320 #if 0
01321         warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.latin1(),
01322                  orig_file.latin1());
01323 #endif
01324         file = orig_file;
01325     }
01326     return ret;
01327 }
01328 
01329 void
01330 MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
01331 {
01332     if(var == "QMAKE_PRL_LIBS") {
01333         QString where = "QMAKE_LIBS";
01334         if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
01335             where = project->first("QMAKE_INTERNAL_PRL_LIBS");
01336         QStringList &out = project->variables()[where];
01337         for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
01338             if( out.findIndex((*it)) == -1)
01339                 out.append((*it));
01340         }
01341     } else if(var == "QMAKE_PRL_DEFINES") {
01342         QStringList &out = project->variables()["DEFINES"];
01343         for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
01344             if(out.findIndex((*it)) == -1 &&
01345                project->variables()["PRL_EXPORT_DEFINES"].findIndex((*it)) == -1)
01346                 out.append((*it));
01347         }
01348     }
01349 }
01350 
01351 void
01352 MakefileGenerator::processPrlFiles()
01353 {
01354     QDict<void> processed;
01355     for(bool ret = FALSE; TRUE; ret = FALSE) {
01356         //read in any prl files included..
01357         QStringList l_out;
01358         QString where = "QMAKE_LIBS";
01359         if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
01360             where = project->first("QMAKE_INTERNAL_PRL_LIBS");
01361         QStringList &l = project->variables()[where];
01362         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01363             QString file = (*it);
01364             if(!processed[file] && processPrlFile(file)) {
01365                 processed.insert(file, (void*)1);
01366                 ret = TRUE;
01367             }
01368             if(!file.isEmpty())
01369                 l_out.append(file);
01370         }
01371         if(ret)
01372             l = l_out;
01373         else
01374             break;
01375     }
01376 }
01377 
01378 void
01379 MakefileGenerator::writePrlFile(QTextStream &t)
01380 {
01381     QString target = project->first("TARGET");
01382     int slsh = target.findRev(Option::dir_sep);
01383     if(slsh != -1)
01384         target = target.right(target.length() - slsh - 1);
01385     QString bdir = Option::output_dir;
01386     if(bdir.isEmpty())
01387         bdir = QDir::currentDirPath();
01388     t << "QMAKE_PRL_BUILD_DIR = " << bdir << endl;
01389 
01390     if(!project->projectFile().isEmpty() && project->projectFile() != "-")
01391         t << "QMAKE_PRO_INPUT = " << project->projectFile().section('/', -1) << endl;
01392 
01393     if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
01394         t << "QMAKE_PRL_SOURCE_DIR = " << project->first("QMAKE_ABSOLUTE_SOURCE_PATH") << endl;
01395     t << "QMAKE_PRL_TARGET = " << target << endl;
01396     if(!project->isEmpty("PRL_EXPORT_DEFINES"))
01397         t << "QMAKE_PRL_DEFINES = " << project->variables()["PRL_EXPORT_DEFINES"].join(" ") << endl;
01398     if(!project->isEmpty("PRL_EXPORT_CFLAGS"))
01399         t << "QMAKE_PRL_CFLAGS = " << project->variables()["PRL_EXPORT_CFLAGS"].join(" ") << endl;
01400     if(!project->isEmpty("PRL_EXPORT_CXXFLAGS"))
01401         t << "QMAKE_PRL_CXXFLAGS = " << project->variables()["PRL_EXPORT_CXXFLAGS"].join(" ") << endl;
01402     if(!project->isEmpty("CONFIG"))
01403         t << "QMAKE_PRL_CONFIG = " << project->variables()["CONFIG"].join(" ") << endl;
01404     if(!project->isEmpty("VERSION"))
01405         t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl;
01406     if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) {
01407         QStringList libs;
01408         if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
01409             libs = project->variables()["QMAKE_INTERNAL_PRL_LIBS"];
01410         else
01411             libs << "QMAKE_LIBS"; //obvious one
01412         t << "QMAKE_PRL_LIBS = ";
01413         for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it)
01414             t << project->variables()[(*it)].join(" ") << " ";
01415         t << endl;
01416     }
01417 }
01418 
01419 bool
01420 MakefileGenerator::write()
01421 {
01422     usePlatformDir();
01423     init();
01424     findLibraries();
01425     if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write prl
01426        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) &&
01427        project->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty() &&
01428        project->isActiveConfig("create_prl") && project->first("TEMPLATE") == "lib" &&
01429        !project->isActiveConfig("plugin")) {
01430         QString prl = var("TARGET");
01431         int slsh = prl.findRev(Option::dir_sep);
01432         if(slsh != -1)
01433             prl = prl.right(prl.length() - slsh);
01434         int dot = prl.find('.');
01435         if(dot != -1)
01436             prl = prl.left(dot);
01437         prl += Option::prl_ext;
01438         if(!project->isEmpty("DESTDIR"))
01439             prl.prepend(var("DESTDIR"));
01440         QString local_prl = Option::fixPathToLocalOS(fileFixify(prl, QDir::currentDirPath(), Option::output_dir));
01441         QFile ft(local_prl);
01442         if(ft.open(IO_WriteOnly)) {
01443             project->variables()["ALL_DEPS"].append(prl);
01444             project->variables()["QMAKE_INTERNAL_PRL_FILE"].append(prl);
01445             QTextStream t(&ft);
01446             writePrlFile(t);
01447             ft.close();
01448         }
01449     }
01450     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE &&
01451        project->isActiveConfig("link_prl")) //load up prl's'
01452         processPrlFiles();
01453 
01454     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write prl file
01455        Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
01456         QTextStream t(&Option::output);
01457         writeMakefile(t);
01458     }
01459     return TRUE;
01460 }
01461 
01462 // Manipulate directories, so it's possible to build
01463 // several cross-platform targets concurrently
01464 void
01465 MakefileGenerator::usePlatformDir()
01466 {
01467     QString pltDir(project->first("QMAKE_PLATFORM_DIR"));
01468     if(pltDir.isEmpty())
01469         return;
01470     char sep = QDir::separator();
01471     QString slashPltDir = sep + pltDir;
01472 
01473     QString filePath = project->first("DESTDIR");
01474     project->variables()["DESTDIR"] = filePath 
01475                                     + (filePath.isEmpty() ? pltDir : slashPltDir);
01476 
01477     filePath = project->first("DLLDESTDIR");
01478     project->variables()["DLLDESTDIR"] = filePath 
01479                                        + (filePath.isEmpty() ? pltDir : slashPltDir);
01480 
01481     filePath = project->first("OBJECTS_DIR");
01482     project->variables()["OBJECTS_DIR"] = filePath 
01483                                         + (filePath.isEmpty() ? pltDir : slashPltDir);
01484 
01485     filePath = project->first("QMAKE_LIBDIR_QT");
01486     project->variables()["QMAKE_LIBDIR_QT"] = filePath 
01487                                             + (filePath.isEmpty() ? pltDir : slashPltDir);
01488 
01489     filePath = project->first("QMAKE_LIBS_QT");
01490     int fpi = filePath.findRev(sep);
01491     if (fpi == -1)
01492         project->variables()["QMAKE_LIBS_QT"].prepend(pltDir + sep);
01493     else
01494         project->variables()["QMAKE_LIBS_QT"] = filePath.left(fpi)
01495                                               + slashPltDir
01496                                               + filePath.mid(fpi);
01497     
01498     filePath = project->first("QMAKE_LIBS_QT_THREAD");
01499     fpi = filePath.findRev(sep);
01500     if (fpi == -1)
01501         project->variables()["QMAKE_LIBS_QT_THREAD"].prepend(pltDir + sep);
01502     else
01503         project->variables()["QMAKE_LIBS_QT_THREAD"] = filePath.left(fpi)
01504                                                      + slashPltDir
01505                                                      + filePath.mid(fpi);
01506 
01507     filePath = project->first("QMAKE_LIBS_QT_ENTRY");
01508     fpi = filePath.findRev(sep);
01509     if (fpi == -1)
01510         project->variables()["QMAKE_LIBS_QT_ENTRY"].prepend(pltDir + sep);
01511     else
01512         project->variables()["QMAKE_LIBS_QT_ENTRY"] = filePath.left(fpi)
01513                                                     + slashPltDir
01514                                                     + filePath.mid(fpi);
01515 }
01516 
01517 void
01518 MakefileGenerator::writeObj(QTextStream &t, const QString &obj, const QString &src)
01519 {
01520     QStringList &objl = project->variables()[obj];
01521     QStringList &srcl = project->variables()[src];
01522 
01523     QStringList::Iterator oit = objl.begin();
01524     QStringList::Iterator sit = srcl.begin();
01525     QString stringSrc("$src");
01526     QString stringObj("$obj");
01527     for( ;sit != srcl.end() && oit != objl.end(); oit++, sit++) {
01528         if((*sit).isEmpty())
01529             continue;
01530 
01531         if(!doDepends()) {
01532             QString sdep, odep = (*sit) + " ";
01533             QStringList deps = findDependencies((*sit));
01534             for(QStringList::Iterator dit = deps.begin(); dit != deps.end(); dit++) {
01535                 if((*dit).endsWith(Option::cpp_moc_ext))
01536                     odep += (*dit) + " ";
01537                 else
01538                     sdep += (*dit) + " ";
01539             }
01540             t << (*sit) << ": " << sdep << endl
01541               << (*oit) << ": " << odep ;
01542         } else {
01543             t << (*oit) << ": " << (*sit) << " " << findDependencies((*sit)).join(" \\\n\t\t");
01544         }
01545 
01546         QString comp, cimp;
01547         for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
01548             if((*sit).endsWith((*cppit))) {
01549                 comp = "QMAKE_RUN_CXX";
01550                 cimp = "QMAKE_RUN_CXX_IMP";
01551                 break;
01552             }
01553         }
01554         if(comp.isEmpty()) {
01555             comp = "QMAKE_RUN_CC";
01556             cimp = "QMAKE_RUN_CC_IMP";
01557         }
01558         bool use_implicit_rule = !project->isEmpty(cimp);
01559         if(use_implicit_rule) {
01560             if(!project->isEmpty("OBJECTS_DIR")) {
01561                 use_implicit_rule = FALSE;
01562             } else {
01563                 int dot = (*sit).findRev('.');
01564                 if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
01565                     use_implicit_rule = FALSE;
01566             }
01567         }
01568         if (!use_implicit_rule && !project->isEmpty(comp)) {
01569             QString p = var(comp), srcf(*sit);
01570             p.replace(stringSrc, srcf);
01571             p.replace(stringObj, (*oit));
01572             t << "\n\t" << p;
01573         }
01574         t << endl << endl;
01575     }
01576 }
01577 
01578 
01579 void
01580 MakefileGenerator::writeUicSrc(QTextStream &t, const QString &ui)
01581 {
01582     QStringList &uil = project->variables()[ui];
01583     for(QStringList::Iterator it = uil.begin(); it != uil.end(); it++) {
01584         QString decl, impl;
01585         {
01586             QString tmp = (*it), impl_dir, decl_dir;
01587             decl = tmp.replace(QRegExp("\\" + Option::ui_ext + "$"), Option::h_ext.first());
01588             int dlen = decl.findRev(Option::dir_sep) + 1;
01589             tmp = (*it);
01590             impl = tmp.replace(QRegExp("\\" + Option::ui_ext + "$"), Option::cpp_ext.first());
01591             int ilen = decl.findRev(Option::dir_sep) + 1;
01592             if(!project->isEmpty("UI_DIR")) {
01593                 impl_dir = project->first("UI_DIR");
01594                 decl = project->first("UI_DIR") + decl.right(decl.length() - dlen);
01595                 impl = project->first("UI_DIR") + impl.right(impl.length() - ilen);
01596             } else {
01597                 if(!project->isEmpty("UI_HEADERS_DIR")) {
01598                     decl_dir = project->first("UI_HEADERS_DIR");
01599                     decl = project->first("UI_HEADERS_DIR") + decl.right(decl.length() - dlen);
01600                 }
01601                 if(!project->isEmpty("UI_SOURCES_DIR")) {
01602                     impl_dir = project->first("UI_SOURCES_DIR");
01603                     impl = project->first("UI_SOURCES_DIR") + impl.right(impl.length() - ilen);
01604                 }
01605             }
01606             impl = fileFixify(impl, QDir::currentDirPath(), Option::output_dir);
01607             decl = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
01608             if(decl_dir.isEmpty())
01609                 decl_dir = decl.section(Option::dir_sep,0,-2);
01610             if(impl_dir.isEmpty())
01611                 impl_dir = impl.section(Option::dir_sep,0,-2);
01612             if (QDir::isRelativePath(impl_dir))
01613                 impl_dir.prepend(Option::output_dir + Option::dir_sep);
01614             if (QDir::isRelativePath(decl_dir))
01615                 decl_dir.prepend(Option::output_dir + Option::dir_sep);
01616             createDir(impl_dir);
01617             createDir(decl_dir);
01618         }
01619         QStringList deps = findDependencies((*it));
01620         deps.remove(decl); //avoid circular dependencies..
01621         t << decl << ": " << (*it) << " " << deps.join(" \\\n\t\t") << "\n\t"
01622           << "$(UIC) " << (*it) << " -o " << decl << endl << endl;
01623 
01624         QString mildDecl = decl;
01625         int k = mildDecl.findRev(Option::dir_sep);
01626         if ( k != -1 )
01627             mildDecl = mildDecl.mid( k + 1 );
01628         t << impl << ": " << decl << " " << (*it) << " " << deps.join(" \\\n\t\t") << "\n\t"
01629           << "$(UIC)";
01630         t << " " << (*it) << " -i " << mildDecl << " -o " << impl << endl << endl;
01631     }
01632 }
01633 
01634 
01635 void
01636 MakefileGenerator::writeMocObj(QTextStream &t, const QString &obj, const QString &src)
01637 {
01638     QStringList &objl = project->variables()[obj],
01639                 &srcl = project->variables()[src];
01640     QStringList::Iterator oit = objl.begin(), sit = srcl.begin();
01641     QString stringSrc("$src"), stringObj("$obj");
01642     for( ;sit != srcl.end() && oit != objl.end(); oit++, sit++) {
01643         QString hdr = findMocSource((*sit));
01644         t << (*oit) << ": " 
01645           << (*sit) << " " << findDependencies((*sit)).join(" \\\n\t\t") << " "
01646           << hdr << " " << findDependencies(hdr).join(" \\\n\t\t");
01647         bool use_implicit_rule = !project->isEmpty("QMAKE_RUN_CXX_IMP");
01648         if(use_implicit_rule) {
01649             if(!project->isEmpty("OBJECTS_DIR") || !project->isEmpty("MOC_DIR")) {
01650                 use_implicit_rule = FALSE;
01651             } else {
01652                 int dot = (*sit).findRev('.');
01653                 if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
01654                     use_implicit_rule = FALSE;
01655             }
01656         }
01657         if (!use_implicit_rule && !project->isEmpty("QMAKE_RUN_CXX")) {
01658             QString p = var("QMAKE_RUN_CXX"), srcf(*sit);
01659             p.replace(stringSrc, srcf);
01660             p.replace(stringObj, (*oit));
01661             t << "\n\t" << p;
01662         }
01663         t << endl << endl;
01664     }
01665 }
01666 
01667 
01668 void
01669 MakefileGenerator::writeMocSrc(QTextStream &t, const QString &src)
01670 {
01671     QStringList &l = project->variables()[src];
01672     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01673         QString m = Option::fixPathToTargetOS(findMocDestination(*it));
01674         if ( !m.isEmpty()) {
01675             QString deps;
01676             if(!project->isActiveConfig("no_mocdepend"))
01677                 deps += "$(MOC) ";
01678             deps += (*it);
01679             t << m << ": " << deps << "\n\t"
01680               << "$(MOC)";
01681             t << " " << (*it) << " -o " << m << endl << endl;
01682         }
01683     }
01684 }
01685 
01686 void
01687 MakefileGenerator::writeYaccSrc(QTextStream &t, const QString &src)
01688 {
01689     QStringList &l = project->variables()[src];
01690     if(project->isActiveConfig("yacc_no_name_mangle") && l.count() > 1)
01691         warn_msg(WarnLogic, "yacc_no_name_mangle specified, but multiple parsers expected."
01692                  "This can lead to link problems.\n");
01693     QString default_out_h = "y.tab.h", default_out_c = "y.tab.c";
01694     if(!project->isEmpty("QMAKE_YACC_HEADER"))
01695         default_out_h = project->first("QMAKE_YACC_HEADER");
01696     if(!project->isEmpty("QMAKE_YACC_SOURCE"))
01697         default_out_c = project->first("QMAKE_YACC_SOURCE");
01698     QString stringBase("$base");
01699     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01700         QFileInfo fi((*it));
01701         QString dir;
01702         if(fi.dirPath() != ".")
01703             dir = fi.dirPath() + Option::dir_sep;
01704         dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
01705         if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
01706             dir += Option::dir_sep;
01707 
01708         QString impl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::cpp_ext.first();
01709         QString decl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::h_ext.first();
01710 
01711         QString yaccflags = "$(YACCFLAGS)", mangle = "y";
01712         if(!project->isActiveConfig("yacc_no_name_mangle")) {
01713             mangle = fi.baseName(TRUE);
01714             if(!project->isEmpty("QMAKE_YACCFLAGS_MANGLE")) 
01715                 yaccflags += " " + var("QMAKE_YACCFLAGS_MANGLE").replace(stringBase, mangle);
01716             else
01717                 yaccflags += " -p " + mangle;
01718         }
01719         QString out_h = default_out_h, out_c = default_out_c;
01720         if(!mangle.isEmpty()) {
01721             out_h.replace(stringBase, mangle);
01722             out_c.replace(stringBase, mangle);
01723         }
01724 
01725         t << impl << ": " << (*it) << "\n\t"
01726           << "$(YACC) " << yaccflags << " " << (*it) << "\n\t"
01727           << "-$(DEL_FILE) " << impl << " " << decl << "\n\t"
01728           << "-$(MOVE) " << out_h << " " << decl << "\n\t"
01729           << "-$(MOVE) " << out_c << " " << impl << endl << endl;
01730         t << decl << ": " << impl << endl << endl;
01731     }
01732 }
01733 
01734 void
01735 MakefileGenerator::writeLexSrc(QTextStream &t, const QString &src)
01736 {
01737     QStringList &l = project->variables()[src];
01738     if(project->isActiveConfig("yacc_no_name_mangle") && l.count() > 1)
01739         warn_msg(WarnLogic, "yacc_no_name_mangle specified, but multiple parsers expected.\n"
01740                  "This can lead to link problems.\n");
01741     QString default_out_c = "lex.$base.c";
01742     if(!project->isEmpty("QMAKE_LEX_SOURCE"))
01743         default_out_c = project->first("QMAKE_LEX_SOURCE");
01744     QString stringBase("$base");
01745     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01746         QFileInfo fi((*it));
01747         QString dir;
01748         if(fi.dirPath() != ".")
01749             dir = fi.dirPath() + Option::dir_sep;
01750         dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
01751         if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
01752             dir += Option::dir_sep;
01753         QString impl = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
01754 
01755         QString lexflags = "$(LEXFLAGS)", stub="yy";
01756         if(!project->isActiveConfig("yacc_no_name_mangle")) {
01757             stub = fi.baseName(TRUE);
01758             lexflags += " -P" + stub;
01759         }
01760         QString out_c = default_out_c;
01761         if(!stub.isEmpty())
01762             out_c.replace(stringBase, stub);
01763 
01764         t << impl << ": " << (*it) << " " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
01765           << ( "$(LEX) " + lexflags + " " ) << (*it) << "\n\t"
01766           << "-$(DEL_FILE) " << impl << " " << "\n\t"
01767           << "-$(MOVE) " << out_c << " " << impl << endl << endl;
01768     }
01769 }
01770 
01771 void
01772 MakefileGenerator::writeImageObj(QTextStream &t, const QString &obj)
01773 {
01774     QStringList &objl = project->variables()[obj];
01775     QString stringSrc("$src");
01776     QString stringObj("$obj");
01777 
01778     QString uidir;
01779     for(QStringList::Iterator oit = objl.begin(); oit != objl.end(); oit++) {
01780         QString src(project->first("QMAKE_IMAGE_COLLECTION"));
01781         t << (*oit) << ": " << src;
01782         bool use_implicit_rule = !project->isEmpty("QMAKE_RUN_CXX_IMP");
01783         if(use_implicit_rule) {
01784             if(!project->isEmpty("OBJECTS_DIR") || !project->isEmpty("UI_DIR") || !project->isEmpty("UI_SOURCES_DIR")) {
01785                 use_implicit_rule = FALSE;
01786             } else {
01787                 int dot = src.findRev('.');
01788                 if(dot == -1 || (src.left(dot) + Option::obj_ext != (*oit)))
01789                     use_implicit_rule = FALSE;
01790             }
01791         }
01792         if(!use_implicit_rule && !project->isEmpty("QMAKE_RUN_CXX")) {
01793             QString p = var("QMAKE_RUN_CXX"), srcf(src);
01794             p.replace(stringSrc, srcf);
01795             p.replace(stringObj, (*oit));
01796             t << "\n\t" << p;
01797         }
01798         t << endl << endl;
01799     }
01800 }
01801 
01802 
01803 void
01804 MakefileGenerator::writeImageSrc(QTextStream &t, const QString &src)
01805 {
01806     QStringList &l = project->variables()[src];
01807     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01808         QString gen = project->first("MAKEFILE_GENERATOR");
01809         if ( gen == "MSVC" ) {
01810             t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
01811                 << "$(UIC)  -o " << (*it) << " -embed " << project->first("QMAKE_ORIG_TARGET")
01812                 << " -f <<\n" << findDependencies((*it)).join(" ") << "\n<<" << endl << endl;
01813         } else if ( gen == "BMAKE" ) {
01814             t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
01815                 << "$(UIC) " << " -embed " << project->first("QMAKE_ORIG_TARGET")
01816                 << " -f &&|\n" << findDependencies((*it)).join(" ") << "\n| -o " << (*it) << endl << endl;
01817         } else {
01818             t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
01819                 << "$(UIC) " << " -embed " << project->first("QMAKE_ORIG_TARGET")
01820                 << " " << findDependencies((*it)).join(" ") << " -o " << (*it) << endl << endl;
01821         }
01822     }
01823 }
01824 
01825 
01826 void
01827 MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs)
01828 {
01829     QString all_installs, all_uninstalls;
01830     QStringList &l = project->variables()[installs];
01831     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
01832         QString pvar = (*it) + ".path";
01833         if(project->variables()[(*it) + ".CONFIG"].findIndex("no_path") == -1 &&
01834            project->variables()[pvar].isEmpty()) {
01835             warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.latin1());
01836             continue;
01837         }
01838 
01839         bool do_default = TRUE;
01840         const QString root = "$(INSTALL_ROOT)";
01841         QString target, dst= fileFixify(project->variables()[pvar].first());
01842         if(dst.right(1) != Option::dir_sep)
01843             dst += Option::dir_sep;
01844         QStringList tmp, uninst = project->variables()[(*it) + ".uninstall"];
01845         //other
01846         tmp = project->variables()[(*it) + ".extra"];
01847         if(tmp.isEmpty())
01848             tmp = project->variables()[(*it) + ".commands"]; //to allow compatible name
01849         if(!tmp.isEmpty()) {
01850             do_default = FALSE;
01851             if(!target.isEmpty())
01852                 target += "\n\t";
01853             target += tmp.join(" ");
01854         }
01855         //masks
01856         tmp = project->variables()[(*it) + ".files"];
01857         if(!tmp.isEmpty()) {
01858             if(!target.isEmpty())
01859                 target += "\n";
01860             do_default = FALSE;
01861             for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) {
01862                 QString wild = Option::fixPathToLocalOS((*wild_it), FALSE), wild_var = fileFixify(wild);
01863                 QString dirstr = QDir::currentDirPath(), filestr = wild;
01864                 int slsh = filestr.findRev(Option::dir_sep);
01865                 if(slsh != -1) {
01866                     dirstr = filestr.left(slsh+1);
01867                     filestr = filestr.right(filestr.length() - slsh - 1);
01868                 }
01869                 if(dirstr.right(Option::dir_sep.length()) != Option::dir_sep)
01870                     dirstr += Option::dir_sep;
01871                 if(QFile::exists(wild)) { //real file
01872                     QString file = wild;
01873                     QFileInfo fi(wild);
01874                     if(!target.isEmpty())
01875                         target += "\t";
01876                     QString cmd =  QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " \"" +
01877                                    Option::fixPathToTargetOS(fileFixify(wild, QString::null,
01878                                                                         QString::null, FALSE, FALSE), FALSE) +
01879                                    "\" \"" + root + dst + "\"\n";
01880                     target += cmd;
01881                     if(!project->isActiveConfig("debug") &&
01882                        !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
01883                         target += QString("\t-") + var("QMAKE_STRIP") + " \"" +
01884                                   root + fileFixify(dst + filestr, QString::null, QString::null, FALSE, FALSE) +
01885                                   "\"\n";
01886                     if(!uninst.isEmpty())
01887                         uninst.append("\n\t");
01888                     uninst.append(
01889 #ifdef Q_WS_WIN
01890                     QString("-$(DEL_FILE)")
01891 #else
01892                     QString("-$(DEL_FILE) -r")
01893 #endif
01894                     + " \"" + root + fileFixify(dst + filestr, QString::null, QString::null, FALSE, FALSE) + "\"");
01895                     continue;
01896                 }
01897                 fixEnvVariables(dirstr);
01898                 QDir dir(dirstr, filestr);                  //wild
01899                 for(uint x = 0; x < dir.count(); x++) {
01900                     QString file = dir[x];
01901                     if(file == "." || file == "..") //blah
01902                         continue;
01903                     if(!uninst.isEmpty())
01904                         uninst.append("\n\t");
01905                     uninst.append(
01906 #ifdef Q_WS_WIN
01907                         QString("-$(DEL_FILE)")
01908 #else
01909                         QString("-$(DEL_FILE) -r")
01910 #endif
01911                         + " \"" + root + fileFixify(dst + file, QString::null, QString::null, FALSE, FALSE) +
01912                         "\"");
01913                     QFileInfo fi(Option::fixPathToTargetOS(fileFixify(dirstr + file), TRUE));
01914                     if(!target.isEmpty())
01915                         target += "\t";
01916                     QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " \"" +
01917                                   Option::fixPathToTargetOS(fileFixify(dirstr + file, QString::null,
01918                                                                        QString::null, FALSE, FALSE), FALSE) +
01919                                   "\" \"" + root + dst + "\"\n";
01920                     target += cmd;
01921                     if(!project->isActiveConfig("debug") &&
01922                        !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
01923                         target += QString("\t-") + var("QMAKE_STRIP") + " \"" +
01924                                   root + fileFixify(dst + file, QString::null, QString::null, FALSE, FALSE) +
01925                                   "\"\n";
01926                 }
01927             }
01928         }
01929         //default?
01930         if(do_default) {
01931             target = defaultInstall((*it));
01932             uninst = project->variables()[(*it) + ".uninstall"];
01933         }
01934 
01935         if(!target.isEmpty()) {
01936             t << "install_" << (*it) << ": all ";
01937             const QStringList &deps = project->variables()[(*it) + ".depends"];
01938             if(!deps.isEmpty()) {
01939                 for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) {
01940                     QString targ = var((*dep_it) + ".target");
01941                     if(targ.isEmpty())
01942                         targ = (*dep_it);
01943                     t << targ;
01944                 }
01945             }
01946             t << "\n\t";
01947             const QStringList &dirs = project->variables()[pvar];
01948             for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) {
01949                 QString tmp_dst = fileFixify((*pit));
01950 #ifndef Q_WS_WIN
01951                 if(tmp_dst.right(1) != Option::dir_sep)
01952                     tmp_dst += Option::dir_sep;
01953 #endif
01954                 t << mkdir_p_asstring(root+tmp_dst) << "\n\t";
01955             }
01956             t << target << endl << endl;
01957             if(!uninst.isEmpty()) {
01958                 t << "uninstall_" << (*it) << ": " << "\n\t"
01959                   << uninst.join("") << "\n\t"
01960                   << "-$(DEL_DIR) \"" << ( root + dst ) << "\"" << endl << endl;
01961             }
01962             t << endl;
01963 
01964             if(project->variables()[(*it) + ".CONFIG"].findIndex("no_default_install") == -1) {
01965                 all_installs += QString("install_") + (*it) + " ";
01966                 if(!uninst.isEmpty())
01967                     all_uninstalls += "uninstall_" + (*it) + " ";
01968             }
01969         }   else {
01970             debug_msg(1, "no definition for install %s: install target not created",(*it).latin1());
01971         }
01972     }
01973     t << "install: " << all_installs << " " << var("INSTALLDEPS")   << "\n\n";
01974     t << "uninstall: " << all_uninstalls << " " << var("UNINSTALLDEPS") << "\n\n";
01975 }
01976 
01977 QString
01978 MakefileGenerator::var(const QString &var)
01979 {
01980     return val(project->variables()[var]);
01981 }
01982 
01983 QString
01984 MakefileGenerator::val(const QStringList &varList)
01985 {
01986     return valGlue(varList, "", " ", "");
01987 }
01988 
01989 QString
01990 MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after)
01991 {
01992     return valGlue(project->variables()[var], before, glue, after);
01993 }
01994 
01995 QString
01996 MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after)
01997 {
01998     QString ret;
01999     for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) {
02000         if(!(*it).isEmpty()) {
02001             if(!ret.isEmpty())
02002                 ret += glue;
02003             ret += (*it);
02004         }
02005     }
02006     return ret.isEmpty() ? QString("") : before + ret + after;
02007 }
02008 
02009 
02010 QString
02011 MakefileGenerator::varList(const QString &var)
02012 {
02013     return valList(project->variables()[var]);
02014 }
02015 
02016 QString
02017 MakefileGenerator::valList(const QStringList &varList)
02018 {
02019     return valGlue(varList, "", " \\\n\t\t", "");
02020 }
02021 
02022 
02023 QStringList
02024 MakefileGenerator::createObjectList(const QString &var)
02025 {
02026     QStringList &l = project->variables()[var], ret;
02027     QString objdir, dir;
02028     if(!project->variables()["OBJECTS_DIR"].isEmpty())
02029         objdir = project->first("OBJECTS_DIR");
02030     for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
02031         QFileInfo fi(Option::fixPathToLocalOS((*it)));
02032         if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) {
02033             QString fName = Option::fixPathToTargetOS((*it), FALSE);
02034             int dl = fName.findRev(Option::dir_sep);
02035             if(dl != -1)
02036                 dir = fName.left(dl + 1);
02037         } else {
02038             dir = objdir;
02039         }
02040         ret.append(dir + fi.baseName(TRUE) + Option::obj_ext);
02041     }
02042     return ret;
02043 }
02044 
02045 bool
02046 MakefileGenerator::writeMakefile(QTextStream &t)
02047 {
02048     t << "####### Compile" << endl << endl;
02049     writeObj(t, "OBJECTS", "SOURCES");
02050     writeUicSrc(t, "FORMS");
02051     writeObj(t, "UICOBJECTS", "UICIMPLS");
02052     writeMocObj(t, "OBJMOC", "SRCMOC" );
02053     writeMocSrc(t, "HEADERS");
02054     writeMocSrc(t, "SOURCES");
02055     writeMocSrc(t, "UICDECLS");
02056     writeYaccSrc(t, "YACCSOURCES");
02057     writeLexSrc(t, "LEXSOURCES");
02058     writeImageObj(t, "IMAGEOBJECTS");
02059     writeImageSrc(t, "QMAKE_IMAGE_COLLECTION");
02060 
02061     t << "####### Install" << endl << endl;
02062     writeInstalls(t, "INSTALLS");
02063     return TRUE;
02064 }
02065 
02066 QString MakefileGenerator::buildArgs()
02067 {
02068     static QString ret;
02069     if(ret.isEmpty()) {
02070         //special variables
02071         if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
02072             ret += " QMAKE_ABSOLUTE_SOURCE_PATH=\"" + project->first("QMAKE_ABSOLUTE_SOURCE_PATH") + "\"";
02073 
02074         //warnings
02075         else if(Option::warn_level == WarnNone)
02076             ret += " -Wnone";
02077         else if(Option::warn_level == WarnAll)
02078             ret += " -Wall";
02079         else if(Option::warn_level & WarnParser)
02080                 ret += " -Wparser";
02081         //other options
02082         if(!Option::user_template.isEmpty())
02083             ret += " -t " + Option::user_template;
02084         if(!Option::mkfile::do_cache)
02085             ret += " -nocache";
02086         if(!Option::mkfile::do_deps)
02087             ret += " -nodepend";
02088         if(!Option::mkfile::do_mocs)
02089             ret += " -nomoc";
02090         if(!Option::mkfile::do_dep_heuristics)
02091             ret += " -nodependheuristics";
02092         if(!Option::mkfile::qmakespec_commandline.isEmpty())
02093             ret += " -spec " + Option::mkfile::qmakespec_commandline;
02094 
02095         //arguments
02096         for(QStringList::Iterator it = Option::before_user_vars.begin();
02097             it != Option::before_user_vars.end(); ++it) {
02098             if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
02099                 ret += " \"" + (*it) + "\"";
02100         }
02101         if(Option::after_user_vars.count()) {
02102             ret += " -after ";
02103             for(QStringList::Iterator it = Option::after_user_vars.begin();
02104                 it != Option::after_user_vars.end(); ++it) {
02105                 if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
02106                     ret += " \"" + (*it) + "\"";
02107             }
02108         }
02109     }
02110     return ret;
02111 }
02112 
02113 //could get stored argv, but then it would have more options than are
02114 //probably necesary this will try to guess the bare minimum..
02115 QString MakefileGenerator::build_args()
02116 {
02117     static QString ret;
02118     if(ret.isEmpty()) {
02119         ret = "$(QMAKE)";
02120 
02121         // general options and arguments
02122         ret += buildArgs();
02123 
02124         //output
02125         QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.name()));
02126         if (!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE"))
02127             ret += " -o " + ofile;
02128 
02129         //inputs
02130         QStringList files = fileFixify(Option::mkfile::project_files);
02131         ret += " " + files.join(" ");
02132     }
02133     return ret;
02134 }
02135 
02136 bool
02137 MakefileGenerator::writeHeader(QTextStream &t)
02138 {
02139     time_t foo = time(NULL);
02140     t << "#############################################################################" << endl;
02141     t << "# Makefile for building: " << var("TARGET") << endl;
02142     t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: " << ctime(&foo);
02143     t << "# Project:  " << fileFixify(project->projectFile()) << endl;
02144     t << "# Template: " << var("TEMPLATE") << endl;
02145     t << "# Command: " << build_args() << endl;
02146     t << "#############################################################################" << endl;
02147     t << endl;
02148     return TRUE;
02149 }
02150 
02151 
02152 //makes my life easier..
02153 bool
02154 MakefileGenerator::writeMakeQmake(QTextStream &t)
02155 {
02156     QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.name()));
02157     if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig("no_autoqmake") &&
02158        !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
02159         QStringList files = fileFixify(Option::mkfile::project_files);
02160         t << project->first("QMAKE_INTERNAL_PRL_FILE") << ": " << "\n\t"
02161           << "@$(QMAKE) -prl " << buildArgs() << " " << files.join(" ") << endl;
02162     }
02163 
02164     QString pfile = project->projectFile();
02165     if(pfile != "(stdin)") {
02166         QString qmake = build_args();
02167         if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
02168             t << ofile << ": " << fileFixify(pfile) << " ";
02169             if(Option::mkfile::do_cache)
02170                 t <<  fileFixify(Option::mkfile::cachefile) << " ";
02171             if(!specdir().isEmpty()) {
02172                 if (QFile::exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf")))
02173                     t << specdir() << Option::dir_sep << "qmake.conf" << " ";
02174                 else if (QFile::exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"tmake.conf")))
02175                     t << specdir() << Option::dir_sep << "tmake.conf" << " ";
02176             }
02177             t << project->variables()["QMAKE_INTERNAL_INCLUDED_FILES"].join(" \\\n\t\t") << "\n\t"
02178               << qmake <<endl;
02179         }
02180         if(project->first("QMAKE_ORIG_TARGET") != "qmake") {
02181             t << "qmake: " <<
02182                 project->variables()["QMAKE_INTERNAL_QMAKE_DEPS"].join(" \\\n\t\t") << "\n\t"
02183               << "@" << qmake << endl << endl;
02184         }
02185     }
02186     return TRUE;
02187 }
02188 
02189 QStringList
02190 MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir,
02191                               bool force_fix, bool canon) const
02192 {
02193     if(files.isEmpty())
02194         return files;
02195     QStringList ret;
02196     for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
02197         if(!(*it).isEmpty())
02198             ret << fileFixify((*it), out_dir, in_dir, force_fix, canon);
02199     }
02200     return ret;
02201 }
02202 
02203 QString
02204 MakefileGenerator::fileFixify(const QString& file0, const QString &out_d,
02205                               const QString &in_d, bool force_fix, bool canon) const
02206 {
02207     if(file0.isEmpty())
02208         return file0;
02209     QString key = file0;
02210     if(QDir::isRelativePath(file0))
02211         key.prepend(QDir::currentDirPath() + "--");
02212     if(!in_d.isEmpty() || !out_d.isEmpty() || force_fix || !canon)
02213         key.prepend(in_d + "--" + out_d + "--" + QString::number((int)force_fix) + "--" +
02214                     QString::number((int)canon) + "-");
02215     if(fileFixed.contains(key))
02216         return fileFixed[key];
02217 
02218     QString file = file0;
02219     int depth = 4;
02220     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
02221        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
02222         if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH"))
02223             depth = project->first("QMAKE_PROJECT_DEPTH").toInt();
02224         else if(Option::mkfile::cachefile_depth != -1)
02225             depth = Option::mkfile::cachefile_depth;
02226     }
02227 
02228     QChar quote;
02229     if((file.startsWith("'") || file.startsWith("\"")) && file.startsWith(file.right(1))) {
02230         quote = file.at(0);
02231         file = file.mid(1, file.length() - 2);
02232     }
02233     QString orig_file = file;
02234     if(!force_fix && project->isActiveConfig("no_fixpath")) {
02235         if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) { //absoluteify it
02236             QString qfile = Option::fixPathToLocalOS(file, TRUE, canon);
02237             if(QDir::isRelativePath(file)) { //already absolute
02238                 QFileInfo fi(qfile);
02239                 if(!fi.convertToAbs()) //strange
02240                     file = fi.filePath();
02241             }
02242         }
02243     } else { //fix it..
02244         QString qfile(Option::fixPathToLocalOS(file, TRUE, canon)), in_dir(in_d), out_dir(out_d);
02245         {
02246             if(out_dir.isNull() || QDir::isRelativePath(out_dir))
02247                 out_dir.prepend(Option::output_dir + QDir::separator());
02248             if(out_dir == ".")
02249                 out_dir = QDir::currentDirPath();
02250             if(in_dir.isEmpty() || QDir::isRelativePath(in_dir))
02251                 in_dir.prepend(QDir::currentDirPath() + QDir::separator());
02252             if(in_dir == ".")
02253                 in_dir = QDir::currentDirPath();
02254 
02255             if(!QDir::isRelativePath(in_dir) || !QDir::isRelativePath(out_dir)) {
02256                 QFileInfo in_fi(in_dir);
02257                 if(!in_fi.convertToAbs())
02258                     in_dir = in_fi.filePath();
02259                 QFileInfo out_fi(out_dir);
02260                 if(!out_fi.convertToAbs())
02261                     out_dir = out_fi.filePath();
02262             }
02263             QString in_canonical_dir = QDir(in_dir).canonicalPath(),
02264                    out_canonical_dir = QDir(out_dir).canonicalPath();
02265             if(!in_canonical_dir.isEmpty())
02266                 in_dir = in_canonical_dir;
02267             if(!out_canonical_dir.isEmpty())
02268                 out_dir = out_canonical_dir;
02269         }
02270         if(out_dir != in_dir || !QDir::isRelativePath(qfile)) {
02271             if(QDir::isRelativePath(qfile)) {
02272                 if(file.left(Option::dir_sep.length()) != Option::dir_sep &&
02273                    in_dir.right(Option::dir_sep.length()) != Option::dir_sep)
02274                     file.prepend(Option::dir_sep);
02275                 file.prepend(in_dir);
02276             }
02277             file = Option::fixPathToTargetOS(file, FALSE, canon);
02278             if(canon && QFile::exists(file) && file == Option::fixPathToTargetOS(file, TRUE, canon)) {
02279                 QString real_file = QDir(file).canonicalPath();
02280                 if(!real_file.isEmpty())
02281                     file = real_file;
02282             }
02283             QString match_dir = Option::fixPathToTargetOS(out_dir, FALSE, canon);
02284             if(file == match_dir) {
02285                 file = "";
02286             } else if(file.startsWith(match_dir) &&
02287                file.mid(match_dir.length(), Option::dir_sep.length()) == Option::dir_sep) {
02288                 file = file.right(file.length() - (match_dir.length() + 1));
02289             } else {
02290                 for(int i = 1; i <= depth; i++) {
02291                     int sl = match_dir.findRev(Option::dir_sep);
02292                     if(sl == -1)
02293                         break;
02294                     match_dir = match_dir.left(sl);
02295                     if(match_dir.isEmpty())
02296                         break;
02297                     if(file.startsWith(match_dir) &&
02298                        file.mid(match_dir.length(), Option::dir_sep.length()) == Option::dir_sep) {
02299                         //concat
02300                         int remlen = file.length() - (match_dir.length() + 1);
02301                         if (remlen < 0)
02302                             remlen = 0;
02303                         file = file.right(remlen);
02304                         //prepend
02305                         for(int o = 0; o < i; o++)
02306                             file.prepend(".." + Option::dir_sep);
02307                     }
02308                 }
02309             }
02310         }
02311     }
02312     file = Option::fixPathToTargetOS(file, FALSE, canon);
02313     if(file.isEmpty())
02314         file = ".";
02315     if(!quote.isNull())
02316         file = quote + file + quote;
02317     debug_msg(3, "Fixed %s :: to :: %s (%d) [%s::%s]", orig_file.latin1(), file.latin1(), depth,
02318               in_d.latin1(), out_d.latin1());
02319     ((MakefileGenerator*)this)->fileFixed.insert(key, file);
02320     return file;
02321 }
02322 
02323 QString
02324 MakefileGenerator::cleanFilePath(const QString &file) const
02325 {
02326     return fileFixify(Option::fixPathToTargetOS(file));
02327 }
02328 
02329 void MakefileGenerator::logicWarn(const QString &f, const QString &w)
02330 {
02331     if(!(Option::warn_level & WarnLogic))
02332         return;
02333     QString file = f;
02334     int slsh = f.findRev(Option::dir_sep);
02335     if(slsh != -1)
02336         file = file.right(file.length() - slsh - 1);
02337     QStringList &l = project->variables()[w];
02338     for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
02339         QString file2((*val_it));
02340         slsh = file2.findRev(Option::dir_sep);
02341         if(slsh != -1)
02342             file2 = file2.right(file2.length() - slsh - 1);
02343         if(file2 == file) {
02344             warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s",
02345                      file.latin1(), (*val_it).latin1(), w.latin1());
02346             break;
02347         }
02348     }
02349 }
02350 
02351 QString 
02352 MakefileGenerator::dependencyKey(const QString &file) const
02353 {
02354      QString key = file;
02355      Option::fixPathToTargetOS(key);
02356      if(key.find(Option::dir_sep))
02357         key = key.right(key.length() - key.findRev(Option::dir_sep) - 1);
02358      return key;
02359 }
02360 
02361 void 
02362 MakefileGenerator::setProcessedDependencies(const QString &file, bool b)
02363 {
02364     depProcessed[dependencyKey(file)] = b;
02365 }
02366 
02367 bool 
02368 MakefileGenerator::processedDependencies(const QString &file)
02369 {
02370     QString key = dependencyKey(file);
02371     if(!depProcessed.contains(key))
02372         return FALSE;
02373     return depProcessed[key];
02374 }
02375 
02376 QStringList
02377 &MakefileGenerator::findDependencies(const QString &file)
02378 {
02379     return depends[dependencyKey(file)];
02380 }
02381 
02382 
02383 QString
02384 MakefileGenerator::specdir()
02385 {
02386     if(!spec.isEmpty())
02387         return spec;
02388     spec = Option::mkfile::qmakespec;
02389 #if 0
02390     if(const char *d = getenv("QTDIR")) {
02391         QString qdir = Option::fixPathToTargetOS(QString(d));
02392         if(qdir.endsWith(QString(QChar(QDir::separator()))))
02393             qdir.truncate(qdir.length()-1);
02394         //fix path
02395         QFileInfo fi(spec);
02396         QString absSpec(fi.absFilePath());
02397         absSpec = Option::fixPathToTargetOS(absSpec);
02398         //replace what you can
02399         if(absSpec.startsWith(qdir)) {
02400             absSpec.replace(0, qdir.length(), "$(QTDIR)");
02401             spec = absSpec;
02402         }
02403     }
02404 #else
02405     spec = Option::fixPathToTargetOS(spec);
02406 #endif
02407     return spec;
02408 }
02409 
02410 bool
02411 MakefileGenerator::openOutput(QFile &file) const
02412 {
02413     {
02414         QString outdir;
02415         if(!file.name().isEmpty()) {
02416             if(QDir::isRelativePath(file.name()))
02417                 file.setName(Option::output_dir + file.name()); //pwd when qmake was run
02418             QFileInfo fi(file);
02419             if(fi.isDir())
02420                 outdir = file.name() + QDir::separator();
02421         }
02422         if(!outdir.isEmpty() || file.name().isEmpty()) {
02423             QString fname = "Makefile";
02424             if(!project->isEmpty("MAKEFILE"))
02425                fname = project->first("MAKEFILE");
02426             file.setName(outdir + fname);
02427         }
02428     }
02429     if(QDir::isRelativePath(file.name()))
02430         file.setName(Option::output_dir + file.name()); //pwd when qmake was run
02431     if(project->isEmpty("QMAKE_MAKEFILE"))
02432         project->variables()["QMAKE_MAKEFILE"].append(file.name());
02433     int slsh = file.name().findRev(Option::dir_sep);
02434     if(slsh != -1)
02435         createDir(file.name().left(slsh));
02436     if(file.open(IO_WriteOnly | IO_Translate)) {
02437         QFileInfo fi(Option::output);
02438         QString od = Option::fixPathToTargetOS((fi.isSymLink() ? fi.readLink() : fi.dirPath()) );
02439         if(QDir::isRelativePath(od))
02440             od.prepend(Option::output_dir);
02441         Option::output_dir = od;
02442         return TRUE;
02443     }
02444     return FALSE;
02445 }
02446 
02447 
02448 
02449 //Factory thing
02450 #include "unixmake.h"
02451 #include "msvc_nmake.h"
02452 #include "borland_bmake.h"
02453 #include "mingw_make.h"
02454 #include "msvc_dsp.h"
02455 #include "msvc_vcproj.h"
02456 #include "metrowerks_xml.h"
02457 #include "pbuilder_pbx.h"
02458 #include "projectgenerator.h"
02459 
02460 MakefileGenerator *
02461 MakefileGenerator::create(QMakeProject *proj)
02462 {
02463     if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
02464         return new ProjectGenerator(proj);
02465 
02466     MakefileGenerator *mkfile = NULL;
02467     QString gen = proj->first("MAKEFILE_GENERATOR");
02468     if(gen.isEmpty()) {
02469         fprintf(stderr, "No generator specified in config file: %s\n",
02470                 proj->projectFile().latin1());
02471     } else if(gen == "UNIX") {
02472         mkfile = new UnixMakefileGenerator(proj);
02473     } else if(gen == "MSVC") {
02474         // Visual Studio =< v6.0
02475         if(proj->first("TEMPLATE").find(QRegExp("^vc.*")) != -1)
02476             mkfile = new DspMakefileGenerator(proj);
02477         else
02478             mkfile = new NmakeMakefileGenerator(proj);
02479     } else if(gen == "MSVC.NET") {
02480         // Visual Studio >= v7.0
02481         if(proj->first("TEMPLATE").find(QRegExp("^vc.*")) != -1)
02482             mkfile = new VcprojGenerator(proj);
02483         else
02484             mkfile = new NmakeMakefileGenerator(proj);
02485     } else if(gen == "BMAKE") {
02486         mkfile = new BorlandMakefileGenerator(proj);
02487     } else if(gen == "MINGW") {
02488         mkfile = new MingwMakefileGenerator(proj);
02489     } else if(gen == "METROWERKS") {
02490         mkfile = new MetrowerksMakefileGenerator(proj);
02491     } else if(gen == "PROJECTBUILDER") {
02492         mkfile = new ProjectBuilderMakefileGenerator(proj);
02493     } else {
02494         fprintf(stderr, "Unknown generator specified: %s\n", gen.latin1());
02495     }
02496     return mkfile;
02497 }

Generated on Sat Nov 5 16:18:19 2005 for OPIE by  doxygen 1.4.2