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

winmakefile.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** 
00003 **
00004 ** Implementation of Win32MakefileGenerator 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 "winmakefile.h"
00037 #include "option.h"
00038 #include "project.h"
00039 #include "meta.h"
00040 #include <qtextstream.h>
00041 #include <qstring.h>
00042 #include <qdict.h>
00043 #include <qregexp.h>
00044 #include <qstringlist.h>
00045 #include <qdir.h>
00046 
00047 
00048 Win32MakefileGenerator::Win32MakefileGenerator(QMakeProject *p) : MakefileGenerator(p)
00049 {
00050 
00051 }
00052 
00053 
00054 struct SubDir
00055 {
00056     QString directory, profile, target, makefile;
00057 };
00058 
00059 void
00060 Win32MakefileGenerator::writeSubDirs(QTextStream &t)
00061 {
00062     QPtrList<SubDir> subdirs;
00063     {
00064         QStringList subdirs_in = project->variables()["SUBDIRS"];
00065         for(QStringList::Iterator it = subdirs_in.begin(); it != subdirs_in.end(); ++it) {
00066             QString file = (*it);
00067             file = fileFixify(file);
00068             SubDir *sd = new SubDir;
00069             subdirs.append(sd);
00070             sd->makefile = "$(MAKEFILE)";
00071             if((*it).right(4) == ".pro") {
00072                 int slsh = file.findRev(Option::dir_sep);
00073                 if(slsh != -1) {
00074                     sd->directory = file.left(slsh+1);
00075                     sd->profile = file.mid(slsh+1);
00076                 } else {
00077                     sd->profile = file;
00078                 }
00079             } else {
00080                 sd->directory = file;
00081             }
00082             while(sd->directory.right(1) == Option::dir_sep)
00083                 sd->directory = sd->directory.left(sd->directory.length() - 1);
00084             if(!sd->profile.isEmpty()) {
00085                 QString basename = sd->directory;
00086                 int new_slsh = basename.findRev(Option::dir_sep);
00087                 if(new_slsh != -1)
00088                     basename = basename.mid(new_slsh+1);
00089                 if(sd->profile != basename + ".pro")
00090                     sd->makefile += "." + sd->profile.left(sd->profile.length() - 4); //no need for the .pro
00091             }
00092             sd->target = "sub-" + (*it);
00093             sd->target.replace('/', '-');
00094             sd->target.replace('.', '_');
00095         }
00096     }
00097     QPtrListIterator<SubDir> it(subdirs);
00098 
00099     t << "MAKEFILE = " << (project->isEmpty("MAKEFILE") ? QString("Makefile") : var("MAKEFILE")) << endl;
00100     t << "QMAKE =       " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
00101     t << "SUBTARGETS    = ";
00102     for( it.toFirst(); it.current(); ++it)
00103         t << " \\\n\t\t" << it.current()->target;
00104     t << endl << endl;
00105     t << "all: $(MAKEFILE) $(SUBTARGETS)" << endl << endl;
00106 
00107     for( it.toFirst(); it.current(); ++it) {
00108         bool have_dir = !(*it)->directory.isEmpty();
00109 
00110         //make the makefile
00111         QString mkfile = (*it)->makefile;
00112         if(have_dir)
00113             mkfile.prepend((*it)->directory + Option::dir_sep);
00114         t << mkfile << ":";
00115         if(have_dir)
00116             t << "\n\t" << "cd " << (*it)->directory;
00117         t << "\n\t" << "$(QMAKE) " << (*it)->profile << " " << buildArgs();
00118         t << " -o " << (*it)->makefile;
00119         if(have_dir) {
00120             int subLevels = it.current()->directory.contains(Option::dir_sep) + 1;
00121             t << "\n\t" << "@cd ..";
00122             for(int i = 1; i < subLevels; i++ )
00123                 t << Option::dir_sep << "..";
00124         }
00125         t << endl;
00126 
00127         //now actually build
00128         t << (*it)->target << ": " << mkfile;
00129         if(project->variables()["QMAKE_NOFORCE"].isEmpty())
00130             t << " FORCE";
00131         if(have_dir)
00132             t << "\n\t" << "cd " << (*it)->directory;
00133         t << "\n\t" << "$(MAKE)";
00134         t << " -f " << (*it)->makefile;
00135         if(have_dir) {
00136             int subLevels = it.current()->directory.contains(Option::dir_sep) + 1;
00137             t << "\n\t" << "@cd ..";
00138             for(int i = 1; i < subLevels; i++ )
00139                 t << Option::dir_sep << "..";
00140         }
00141         t << endl << endl;
00142     }
00143 
00144     if (project->isActiveConfig("ordered")) {   // generate dependencies
00145         for( it.toFirst(); it.current(); ) {
00146             QString tar = it.current()->target;
00147             ++it;
00148             if (it.current())
00149                 t << it.current()->target << ": " << tar << endl;
00150         }
00151         t << endl;
00152     }
00153 
00154     if(project->variables()["QMAKE_INTERNAL_QMAKE_DEPS"].findIndex("qmake_all") == -1)
00155         project->variables()["QMAKE_INTERNAL_QMAKE_DEPS"].append("qmake_all");
00156     writeMakeQmake(t);
00157 
00158     t << "qmake_all:";
00159     if ( !subdirs.isEmpty() ) {
00160         for( it.toFirst(); it.current(); ++it) {
00161             QString subdir = (*it)->directory;
00162             QString profile = (*it)->profile;
00163             int subLevels = subdir.contains(Option::dir_sep) + 1;
00164             t << "\n\t"
00165               << "cd " << subdir << "\n\t";
00166             int lastSlash = subdir.findRev(Option::dir_sep);
00167             if(lastSlash != -1)
00168                 subdir = subdir.mid( lastSlash + 1 );
00169             t << "$(QMAKE) "
00170               << ( !profile.isEmpty() ? profile : subdir + ".pro" )
00171               << " -o " << (*it)->makefile
00172               << " " << buildArgs() << "\n\t"
00173               << "@cd ..";
00174             for(int i = 1; i < subLevels; i++ )
00175                 t << Option::dir_sep << "..";
00176         }
00177     } else {
00178         // Borland make does not like empty an empty command section, so insert
00179         // a dummy command.
00180         t << "\n\t" << "@cd .";
00181     }
00182     t << endl << endl;
00183 
00184     QStringList targs;
00185     targs << "clean" << "install_subdirs" << "mocables" << "uicables" << "uiclean" << "mocclean";
00186     targs += project->values("SUBDIR_TARGETS");
00187     for(QStringList::Iterator targ_it = targs.begin(); targ_it != targs.end(); ++targ_it) {
00188         t << (*targ_it) << ": qmake_all";
00189         QString targ = (*targ_it);
00190         if(targ == "install_subdirs")
00191             targ = "install";
00192         else if(targ == "uninstall_subdirs")
00193             targ = "uninstall";
00194         if(targ == "clean")
00195             t << varGlue("QMAKE_CLEAN","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ", "");
00196         if (!subdirs.isEmpty()) {
00197             for( it.toFirst(); it.current(); ++it) {
00198                 int subLevels = (*it)->directory.contains(Option::dir_sep) + 1;
00199                 bool have_dir = !(*it)->directory.isEmpty();
00200                 if(have_dir)
00201                     t << "\n\t" << "cd " << (*it)->directory;
00202                 QString in_file = " -f " + (*it)->makefile;
00203                 t << "\n\t" << "$(MAKE) " << in_file << " " << targ;
00204                 if(have_dir) {
00205                     t << "\n\t" << "@cd ..";
00206                     for(int i = 1; i < subLevels; i++ )
00207                         t << Option::dir_sep << "..";
00208                 }
00209             }
00210         } else {
00211             // Borland make does not like empty an empty command section, so
00212             // insert a dummy command.
00213             t << "\n\t" << "@cd .";
00214         }
00215         t << endl << endl;
00216     }
00217 
00218     //installations
00219     project->variables()["INSTALLDEPS"]   += "install_subdirs";
00220     project->variables()["UNINSTALLDEPS"] += "uninstall_subdirs";
00221     writeInstalls(t, "INSTALLS");
00222 
00223     // user defined targets
00224     QStringList &qut = project->variables()["QMAKE_EXTRA_WIN_TARGETS"];
00225     for(QStringList::Iterator sit = qut.begin(); sit != qut.end(); ++sit) {
00226         QString targ = var((*sit) + ".target"),
00227                  cmd = var((*sit) + ".commands"), deps;
00228         if(targ.isEmpty())
00229             targ = (*sit);
00230         QStringList &deplist = project->variables()[(*sit) + ".depends"];
00231         for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
00232             QString dep = var((*dep_it) + ".target");
00233             if(dep.isEmpty())
00234                 dep = (*dep_it);
00235             deps += " " + dep;
00236         }
00237         if(!project->variables()["QMAKE_NOFORCE"].isEmpty() && 
00238            project->variables()[(*sit) + ".CONFIG"].findIndex("phony") != -1)
00239             deps += QString(" ") + "FORCE";
00240         t << "\n\n" << targ << ":" << deps << "\n\t"
00241           << cmd;
00242     }
00243 
00244     if(project->variables()["QMAKE_NOFORCE"].isEmpty())
00245         t << "FORCE:" << endl << endl;
00246 }
00247 
00248 
00249 int
00250 Win32MakefileGenerator::findHighestVersion(const QString &d, const QString &stem)
00251 {
00252     QString bd = Option::fixPathToLocalOS(d, TRUE);
00253     if(!QFile::exists(bd))
00254         return -1;
00255     if(!project->variables()["QMAKE_" + stem.upper() + "_VERSION_OVERRIDE"].isEmpty())
00256         return project->variables()["QMAKE_" + stem.upper() + "_VERSION_OVERRIDE"].first().toInt();
00257 
00258     QDir dir(bd);
00259     int biggest=-1;
00260     QStringList entries = dir.entryList();
00261     QString dllStem = stem + QTDLL_POSTFIX;
00262     QRegExp regx( "(" + dllStem + "([0-9]*)).lib", FALSE );
00263     for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
00264         if(regx.exactMatch((*it)))
00265             biggest = QMAX(biggest, (regx.cap(1) == dllStem ||
00266                                      regx.cap(2).isEmpty()) ? -1 : regx.cap(2).toInt());
00267     }
00268     QMakeMetaInfo libinfo;
00269     if(libinfo.readLib(bd + dllStem)) {
00270         if(!libinfo.isEmpty("QMAKE_PRL_VERSION"))
00271             biggest = QMAX(biggest, libinfo.first("QMAKE_PRL_VERSION").replace(".", "").toInt());
00272     }
00273     return biggest;
00274 }
00275 
00276 QString
00277 Win32MakefileGenerator::findDependency(const QString &dep)
00278 {
00279     {
00280         QStringList &qut = project->variables()["QMAKE_EXTRA_WIN_TARGETS"];
00281         for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) {
00282             QString targ = var((*it) + ".target");
00283             if(targ.isEmpty())
00284                 targ = (*it);
00285             if(targ.endsWith(dep)) 
00286                 return targ;
00287         }
00288     }
00289     {
00290         QStringList &quc = project->variables()["QMAKE_EXTRA_WIN_COMPILERS"];
00291         for(QStringList::Iterator it = quc.begin(); it != quc.end(); ++it) {
00292             QString tmp_out = project->variables()[(*it) + ".output"].first();
00293             QString tmp_cmd = project->variables()[(*it) + ".commands"].join(" ");
00294             if(tmp_out.isEmpty() || tmp_cmd.isEmpty())
00295                 continue;
00296             QStringList &tmp = project->variables()[(*it) + ".input"];
00297             for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
00298                 QStringList &inputs = project->variables()[(*it2)];
00299                 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
00300                     QString out = tmp_out;
00301                     QFileInfo fi(Option::fixPathToLocalOS((*input)));
00302                     out.replace("${QMAKE_FILE_BASE}", fi.baseName());
00303                     out.replace("${QMAKE_FILE_NAME}", fi.fileName());
00304                     if(out.endsWith(dep)) 
00305                         return out;
00306                 }
00307             }
00308         }
00309     }
00310     return MakefileGenerator::findDependency(dep);
00311 }
00312 
00313 bool
00314 Win32MakefileGenerator::findLibraries(const QString &where)
00315 {
00316 
00317     QStringList &l = project->variables()[where];
00318     QPtrList<MakefileDependDir> dirs;
00319     {
00320         QStringList &libpaths = project->variables()["QMAKE_LIBDIR"];
00321         for(QStringList::Iterator libpathit = libpaths.begin(); libpathit != libpaths.end(); ++libpathit) {
00322             QString r = (*libpathit), l = r;
00323             fixEnvVariables(l);
00324             dirs.append(new MakefileDependDir(r.replace("\"",""), l.replace("\"","")));
00325         }
00326     }
00327     dirs.setAutoDelete(TRUE);
00328     for(QStringList::Iterator it = l.begin(); it != l.end(); ) {
00329         QChar quote;
00330         bool modified_opt = FALSE, remove = FALSE;
00331         QString opt = (*it).stripWhiteSpace();
00332         if((opt[0] == '\'' || opt[0] == '"') && opt[(int)opt.length()-1] == opt[0]) {
00333             quote = opt[0];
00334             opt = opt.mid(1, opt.length()-2);
00335         }
00336         if(opt.startsWith("/LIBPATH:")) {
00337             QString r = opt.mid(9), l = Option::fixPathToLocalOS(r);
00338             dirs.append(new MakefileDependDir(r.replace("\"",""),
00339                                               l.replace("\"","")));
00340         } else if(opt.startsWith("-L") || opt.startsWith("/L")) {
00341             QString r = opt.mid(2), l = Option::fixPathToLocalOS(r);
00342             dirs.append(new MakefileDependDir(r.replace("\"",""),
00343                                               l.replace("\"","")));
00344             remove = TRUE; //we eat this switch
00345         } else if(opt.startsWith("-l") || opt.startsWith("/l")) {
00346             QString lib = opt.right(opt.length() - 2), out;
00347             if(!lib.isEmpty()) {
00348                 for(MakefileDependDir *mdd = dirs.first(); mdd; mdd = dirs.next() ) {
00349                     QString extension;
00350                     int ver = findHighestVersion(mdd->local_dir, lib);
00351                     if(ver > 0)
00352                         extension += QString::number(ver);
00353                     extension += ".lib";
00354                     if(QMakeMetaInfo::libExists(mdd->local_dir + Option::dir_sep + lib) ||
00355                        QFile::exists(mdd->local_dir + Option::dir_sep + lib + extension)) {
00356                         out = mdd->real_dir + Option::dir_sep + lib + extension;
00357                         break;
00358                     }
00359                 }
00360             }
00361             if(out.isEmpty()) {
00362                 remove = TRUE; //just eat it since we cannot find one..
00363             } else {
00364                 modified_opt = TRUE;
00365                 (*it) = out;
00366             }
00367         } else if(!QFile::exists(Option::fixPathToLocalOS(opt))) {
00368             QPtrList<MakefileDependDir> lib_dirs;
00369             QString file = opt;
00370             int slsh = file.findRev(Option::dir_sep);
00371             if(slsh != -1) {
00372                 QString r = file.left(slsh+1), l = r;
00373                 fixEnvVariables(l);
00374                 lib_dirs.append(new MakefileDependDir(r.replace("\"",""), l.replace("\"","")));
00375                 file = file.right(file.length() - slsh - 1);
00376             } else {
00377                 lib_dirs = dirs;
00378             }
00379             if (!project->variables()["QMAKE_QT_DLL"].isEmpty()) {
00380                 if(file.endsWith(".lib")) {
00381                     file = file.left(file.length() - 4);
00382                     if(!file.at(file.length()-1).isNumber()) {
00383                         for(MakefileDependDir *mdd = lib_dirs.first(); mdd; mdd = lib_dirs.next() ) {
00384                             QString lib_tmpl(file + "%1" + ".lib");
00385                             int ver = findHighestVersion(mdd->local_dir, file);
00386                             if(ver != -1) {
00387                                 if(ver)
00388                                     lib_tmpl = lib_tmpl.arg(ver);
00389                                 else
00390                                      lib_tmpl = lib_tmpl.arg("");
00391                                 if(slsh != -1) {
00392                                     QString dir = mdd->real_dir;
00393                                     if(!dir.endsWith(Option::dir_sep))
00394                                         dir += Option::dir_sep;
00395                                     lib_tmpl.prepend(dir);
00396                                 }
00397                                 modified_opt = TRUE;
00398                                 (*it) = lib_tmpl;
00399                                 break;
00400                             }
00401                         }
00402                     }
00403                 }
00404             }
00405         }
00406         if(remove) {
00407             it = l.remove(it);
00408         } else {
00409             if(!quote.isNull() && modified_opt)
00410                 (*it) = quote + (*it) + quote;
00411             ++it;
00412         }
00413     }
00414     return TRUE;
00415 }
00416 
00417 void
00418 Win32MakefileGenerator::processPrlFiles()
00419 {
00420     QDict<void> processed;
00421     QPtrList<MakefileDependDir> libdirs;
00422     libdirs.setAutoDelete(TRUE);
00423     {
00424         QStringList &libpaths = project->variables()["QMAKE_LIBDIR"];
00425         for(QStringList::Iterator libpathit = libpaths.begin(); libpathit != libpaths.end(); ++libpathit) {
00426             QString r = (*libpathit), l = r;
00427             fixEnvVariables(l);
00428             libdirs.append(new MakefileDependDir(r.replace("\"",""),
00429                                                  l.replace("\"","")));
00430         }
00431     }
00432     for(bool ret = FALSE; TRUE; ret = FALSE) {
00433         //read in any prl files included..
00434         QStringList l_out;
00435         QString where = "QMAKE_LIBS";
00436         if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
00437             where = project->first("QMAKE_INTERNAL_PRL_LIBS");
00438         QStringList &l = project->variables()[where];
00439         for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
00440             QString opt = (*it);
00441             if(opt.startsWith("/")) {
00442                 if(opt.startsWith("/LIBPATH:")) {
00443                     QString r = opt.mid(9), l = r;
00444                     fixEnvVariables(l);
00445                     libdirs.append(new MakefileDependDir(r.replace("\"",""),
00446                                                          l.replace("\"","")));
00447                 }
00448             } else {
00449                 if(!processed[opt]) {
00450                     if(processPrlFile(opt)) {
00451                         processed.insert(opt, (void*)1);
00452                         ret = TRUE;
00453                     } else {
00454                         for(MakefileDependDir *mdd = libdirs.first(); mdd; mdd = libdirs.next() ) {
00455                             QString prl = mdd->local_dir + Option::dir_sep + opt;
00456                             if(processed[prl]) {
00457                                 break;
00458                             } else if(processPrlFile(prl)) {
00459                                 processed.insert(prl, (void*)1);
00460                                 ret = TRUE;
00461                                 break;
00462                             }
00463                         }
00464                     }
00465                 }
00466             }
00467             if(!opt.isEmpty())
00468                 l_out.append(opt);
00469         }
00470         if(ret)
00471             l = l_out;
00472         else
00473             break;
00474     }
00475 }

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