00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "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);
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
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
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")) {
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
00179
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
00212
00213 t << "\n\t" << "@cd .";
00214 }
00215 t << endl << endl;
00216 }
00217
00218
00219 project->variables()["INSTALLDEPS"] += "install_subdirs";
00220 project->variables()["UNINSTALLDEPS"] += "uninstall_subdirs";
00221 writeInstalls(t, "INSTALLS");
00222
00223
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;
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;
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
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 }