1/**************************************************************************** 2** 3** Copyright (C) 2015 The Qt Company Ltd. 4** Contact: http://www.qt.io/licensing/ 5** 6** This file is part of the qmake application of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see http://www.qt.io/terms-conditions. For further 15** information use the contact form at http://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 2.1 or version 3 as published by the Free 20** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22** following information to ensure the GNU Lesser General Public License 23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25** 26** As a special exception, The Qt Company gives you certain additional 27** rights. These rights are described in The Qt Company LGPL Exception 28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29** 30** GNU General Public License Usage 31** Alternatively, this file may be used under the terms of the GNU 32** General Public License version 3.0 as published by the Free Software 33** Foundation and appearing in the file LICENSE.GPL included in the 34** packaging of this file. Please review the following information to 35** ensure the GNU General Public License version 3.0 requirements will be 36** met: http://www.gnu.org/copyleft/gpl.html. 37** 38** $QT_END_LICENSE$ 39** 40****************************************************************************/ 41 42#include "makefile.h" 43#include "option.h" 44#include "cachekeys.h" 45#include "meta.h" 46#include <qdir.h> 47#include <qfile.h> 48#include <qtextstream.h> 49#include <qregexp.h> 50#include <qhash.h> 51#include <qdebug.h> 52#include <qbuffer.h> 53#include <qsettings.h> 54#include <qdatetime.h> 55#if defined(Q_OS_UNIX) 56#include <unistd.h> 57#else 58#include <io.h> 59#endif 60#include <qdebug.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <time.h> 64#include <fcntl.h> 65#include <sys/types.h> 66#include <sys/stat.h> 67 68QT_BEGIN_NAMESPACE 69 70// Well, Windows doesn't have this, so here's the macro 71#ifndef S_ISDIR 72# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 73#endif 74 75bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const 76{ 77 int argv0 = -1; 78 for(int i = 0; i < cmdline.count(); ++i) { 79 if(!cmdline.at(i).contains('=')) { 80 argv0 = i; 81 break; 82 } 83 } 84 if(a) 85 *a = argv0; 86 if(argv0 != -1) { 87 const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true); 88 if(exists(c)) 89 return true; 90 } 91 return false; 92} 93 94QString MakefileGenerator::mkdir_p_asstring(const QString &dir, bool escape) const 95{ 96 QString ret = "@$(CHK_DIR_EXISTS) "; 97 if(escape) 98 ret += escapeFilePath(dir); 99 else 100 ret += dir; 101 ret += " "; 102 if(isWindowsShell()) 103 ret += "$(MKDIR)"; 104 else 105 ret += "|| $(MKDIR)"; 106 ret += " "; 107 if(escape) 108 ret += escapeFilePath(dir); 109 else 110 ret += dir; 111 ret += " "; 112 return ret; 113} 114 115bool MakefileGenerator::mkdir(const QString &in_path) const 116{ 117 QString path = Option::fixPathToLocalOS(in_path); 118 if(QFile::exists(path)) 119 return true; 120 121 QDir d; 122 if(path.startsWith(QDir::separator())) { 123 d.cd(QString(QDir::separator())); 124 path.remove(0, 1); 125 } 126 bool ret = true; 127#ifdef Q_OS_WIN 128 bool driveExists = true; 129 if(!QDir::isRelativePath(path)) { 130 if(QFile::exists(path.left(3))) { 131 d.cd(path.left(3)); 132 path.remove(0, 3); 133 } else { 134 warn_msg(WarnLogic, "Cannot access drive '%s' (%s)", 135 path.left(3).toLatin1().data(), path.toLatin1().data()); 136 driveExists = false; 137 } 138 } 139 if(driveExists) 140#endif 141 { 142 QStringList subs = path.split(QDir::separator()); 143 for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) { 144 if(!d.cd(*subit)) { 145 d.mkdir((*subit)); 146 if(d.exists((*subit))) { 147 d.cd((*subit)); 148 } else { 149 ret = false; 150 break; 151 } 152 } 153 } 154 } 155 return ret; 156} 157 158// ** base makefile generator 159MakefileGenerator::MakefileGenerator() : 160 init_opath_already(false), init_already(false), no_io(false), project(0) 161{ 162} 163 164 165void 166MakefileGenerator::verifyCompilers() 167{ 168 QMap<QString, QStringList> &v = project->variables(); 169 QStringList &quc = v["QMAKE_EXTRA_COMPILERS"]; 170 for(int i = 0; i < quc.size(); ) { 171 bool error = false; 172 QString comp = quc.at(i); 173 if(v[comp + ".output"].isEmpty()) { 174 if(!v[comp + ".output_function"].isEmpty()) { 175 v[comp + ".output"].append("${QMAKE_FUNC_FILE_IN_" + v[comp + ".output_function"].first() + "}"); 176 } else { 177 error = true; 178 warn_msg(WarnLogic, "Compiler: %s: No output file specified", comp.toLatin1().constData()); 179 } 180 } else if(v[comp + ".input"].isEmpty()) { 181 error = true; 182 warn_msg(WarnLogic, "Compiler: %s: No input variable specified", comp.toLatin1().constData()); 183 } 184 if(error) 185 quc.removeAt(i); 186 else 187 ++i; 188 } 189} 190 191void 192MakefileGenerator::initOutPaths() 193{ 194 if(init_opath_already) 195 return; 196 verifyCompilers(); 197 init_opath_already = true; 198 QMap<QString, QStringList> &v = project->variables(); 199 //for shadow builds 200 if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) { 201 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() && 202 v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) { 203 QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first(); 204 root = QDir::fromNativeSeparators(root); 205 if(!root.isEmpty()) { 206 QFileInfo fi = fileInfo(Option::mkfile::cachefile); 207 if(!fi.makeAbsolute()) { 208 QString cache_r = fi.path(), pwd = Option::output_dir; 209 if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) { 210 pwd = root + pwd.mid(cache_r.length()); 211 if(exists(pwd)) 212 v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", QStringList(pwd)); 213 } 214 } 215 } 216 } 217 } 218 if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) { 219 QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first(); 220 asp = QDir::fromNativeSeparators(asp); 221 if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother? 222 v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear(); 223 } 224 225 QString currentDir = qmake_getpwd(); //just to go back to 226 227 //some builtin directories 228 if(project->isEmpty("PRECOMPILED_DIR") && !project->isEmpty("OBJECTS_DIR")) 229 v["PRECOMPILED_DIR"] = v["OBJECTS_DIR"]; 230 QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"), 231 QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"), 232 QString("PRECOMPILED_DIR"), QString() }; 233 for(int x = 0; !dirs[x].isEmpty(); x++) { 234 if(v[dirs[x]].isEmpty()) 235 continue; 236 const QString orig_path = v[dirs[x]].first(); 237 238 QString &pathRef = v[dirs[x]].first(); 239 pathRef = fileFixify(pathRef, Option::output_dir, Option::output_dir); 240 241#ifdef Q_OS_WIN 242 // We don't want to add a separator for DLLDESTDIR on Windows (###why?) 243 if(!(dirs[x] == "DLLDESTDIR")) 244#endif 245 { 246 if(!pathRef.endsWith(Option::dir_sep)) 247 pathRef += Option::dir_sep; 248 } 249 250 if(noIO()) 251 continue; 252 253 QString path = project->first(dirs[x]); //not to be changed any further 254 path = fileFixify(path, currentDir, Option::output_dir); 255 debug_msg(3, "Fixed output_dir %s (%s) into %s", dirs[x].toLatin1().constData(), 256 orig_path.toLatin1().constData(), path.toLatin1().constData()); 257 if(!mkdir(path)) 258 warn_msg(WarnLogic, "%s: Cannot access directory '%s'", dirs[x].toLatin1().constData(), 259 path.toLatin1().constData()); 260 } 261 262 //out paths from the extra compilers 263 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); 264 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { 265 QString tmp_out = project->values((*it) + ".output").first(); 266 if(tmp_out.isEmpty()) 267 continue; 268 const QStringList &tmp = project->values((*it) + ".input"); 269 for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { 270 QStringList &inputs = project->values((*it2)); 271 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { 272 (*input) = fileFixify((*input), Option::output_dir, Option::output_dir); 273 QString path = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); 274 path = Option::fixPathToTargetOS(path); 275 int slash = path.lastIndexOf(Option::dir_sep); 276 if(slash != -1) { 277 path = path.left(slash); 278 // Make out path only if it does not contain makefile variables 279 if(!path.contains("${")) 280 if(path != "." && 281 !mkdir(fileFixify(path, qmake_getpwd(), Option::output_dir))) 282 warn_msg(WarnLogic, "%s: Cannot access directory '%s'", 283 (*it).toLatin1().constData(), path.toLatin1().constData()); 284 } 285 } 286 } 287 } 288 289 if(!v["DESTDIR"].isEmpty()) { 290 QDir d(v["DESTDIR"].first()); 291 if(Option::fixPathToLocalOS(d.absolutePath()) == Option::fixPathToLocalOS(Option::output_dir)) 292 v.remove("DESTDIR"); 293 } 294} 295 296QMakeProject 297*MakefileGenerator::projectFile() const 298{ 299 return project; 300} 301 302void 303MakefileGenerator::setProjectFile(QMakeProject *p) 304{ 305 if(project) 306 return; 307 project = p; 308 init(); 309 usePlatformDir(); 310 findLibraries(); 311 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE && 312 project->isActiveConfig("link_prl")) //load up prl's' 313 processPrlFiles(); 314} 315 316QStringList 317MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &vpath_var) 318{ 319 QStringList vpath; 320 QMap<QString, QStringList> &v = project->variables(); 321 for(int val_it = 0; val_it < l.count(); ) { 322 bool remove_file = false; 323 QString &val = l[val_it]; 324 if(!val.isEmpty()) { 325 QString file = fixEnvVariables(val); 326 if(!(flags & VPATH_NoFixify)) 327 file = fileFixify(file, qmake_getpwd(), Option::output_dir); 328 if (file.at(0) == '\"' && file.at(file.length() - 1) == '\"') 329 file = file.mid(1, file.length() - 2); 330 331 if(exists(file)) { 332 ++val_it; 333 continue; 334 } 335 bool found = false; 336 if(QDir::isRelativePath(val)) { 337 if(vpath.isEmpty()) { 338 if(!vpath_var.isEmpty()) 339 vpath = v[vpath_var]; 340 vpath += v["VPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"] + v["DEPENDPATH"]; 341 if(Option::output_dir != qmake_getpwd()) 342 vpath += Option::output_dir; 343 } 344 for(QStringList::Iterator vpath_it = vpath.begin(); 345 vpath_it != vpath.end(); ++vpath_it) { 346 QString real_dir = Option::fixPathToLocalOS((*vpath_it)); 347 if(exists(real_dir + QDir::separator() + val)) { 348 QString dir = (*vpath_it); 349 if(!dir.endsWith(Option::dir_sep)) 350 dir += Option::dir_sep; 351 val = dir + val; 352 if(!(flags & VPATH_NoFixify)) 353 val = fileFixify(val); 354 found = true; 355 debug_msg(1, "Found file through vpath %s -> %s", 356 file.toLatin1().constData(), val.toLatin1().constData()); 357 break; 358 } 359 } 360 } 361 if(!found) { 362 QString dir, regex = val, real_dir; 363 if(regex.lastIndexOf(Option::dir_sep) != -1) { 364 dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1); 365 real_dir = dir; 366 if(!(flags & VPATH_NoFixify)) 367 real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir) + '/'; 368 regex.remove(0, dir.length()); 369 } 370 if(real_dir.isEmpty() || exists(real_dir)) { 371 QStringList files = QDir(real_dir).entryList(QStringList(regex)); 372 if(files.isEmpty()) { 373 debug_msg(1, "%s:%d Failure to find %s in vpath (%s)", 374 __FILE__, __LINE__, 375 val.toLatin1().constData(), vpath.join("::").toLatin1().constData()); 376 if(flags & VPATH_RemoveMissingFiles) 377 remove_file = true; 378 else if(flags & VPATH_WarnMissingFiles) 379 warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); 380 } else { 381 l.removeAt(val_it); 382 QString a; 383 for(int i = (int)files.count()-1; i >= 0; i--) { 384 if(files[i] == "." || files[i] == "..") 385 continue; 386 a = real_dir + files[i]; 387 if(!(flags & VPATH_NoFixify)) 388 a = fileFixify(a); 389 l.insert(val_it, a); 390 } 391 } 392 } else { 393 debug_msg(1, "%s:%d Cannot match %s%s, as %s does not exist.", 394 __FILE__, __LINE__, real_dir.toLatin1().constData(), 395 regex.toLatin1().constData(), real_dir.toLatin1().constData()); 396 if(flags & VPATH_RemoveMissingFiles) 397 remove_file = true; 398 else if(flags & VPATH_WarnMissingFiles) 399 warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); 400 } 401 } 402 } 403 if(remove_file) 404 l.removeAt(val_it); 405 else 406 ++val_it; 407 } 408 return l; 409} 410 411void 412MakefileGenerator::initCompiler(const MakefileGenerator::Compiler &comp) 413{ 414 QMap<QString, QStringList> &v = project->variables(); 415 QStringList &l = v[comp.variable_in]; 416 // find all the relevant file inputs 417 if(!init_compiler_already.contains(comp.variable_in)) { 418 init_compiler_already.insert(comp.variable_in, true); 419 if(!noIO()) 420 l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ? 421 VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_" + comp.variable_in); 422 } 423} 424 425void 426MakefileGenerator::init() 427{ 428 initOutPaths(); 429 if(init_already) 430 return; 431 verifyCompilers(); 432 init_already = true; 433 434 QMap<QString, QStringList> &v = project->variables(); 435 QStringList &quc = v["QMAKE_EXTRA_COMPILERS"]; 436 437 //make sure the COMPILERS are in the correct input/output chain order 438 for(int comp_out = 0, jump_count = 0; comp_out < quc.size(); ++comp_out) { 439 continue_compiler_chain: 440 if(jump_count > quc.size()) //just to avoid an infinite loop here 441 break; 442 if(project->variables().contains(quc.at(comp_out) + ".variable_out")) { 443 const QStringList &outputs = project->variables().value(quc.at(comp_out) + ".variable_out"); 444 for(int out = 0; out < outputs.size(); ++out) { 445 for(int comp_in = 0; comp_in < quc.size(); ++comp_in) { 446 if(comp_in == comp_out) 447 continue; 448 if(project->variables().contains(quc.at(comp_in) + ".input")) { 449 const QStringList &inputs = project->variables().value(quc.at(comp_in) + ".input"); 450 for(int in = 0; in < inputs.size(); ++in) { 451 if(inputs.at(in) == outputs.at(out) && comp_out > comp_in) { 452 ++jump_count; 453 //move comp_out to comp_in and continue the compiler chain 454 quc.move(comp_out, comp_in); 455 comp_out = comp_in; 456 goto continue_compiler_chain; 457 } 458 } 459 } 460 } 461 } 462 } 463 } 464 465 if(!project->isEmpty("QMAKE_SUBSTITUTES")) { 466 const QStringList &subs = v["QMAKE_SUBSTITUTES"]; 467 for(int i = 0; i < subs.size(); ++i) { 468 QString inn = subs.at(i) + ".input", outn = subs.at(i) + ".output"; 469 if (v.contains(inn) || v.contains(outn)) { 470 if (!v.contains(inn) || !v.contains(outn)) { 471 warn_msg(WarnLogic, "Substitute '%s' has only one of .input and .output", 472 subs.at(i).toLatin1().constData()); 473 continue; 474 } 475 const QStringList &tinn = v[inn], &toutn = v[outn]; 476 if (tinn.length() != 1) { 477 warn_msg(WarnLogic, "Substitute '%s.input' does not have exactly one value", 478 subs.at(i).toLatin1().constData()); 479 continue; 480 } 481 if (toutn.length() != 1) { 482 warn_msg(WarnLogic, "Substitute '%s.output' does not have exactly one value", 483 subs.at(i).toLatin1().constData()); 484 continue; 485 } 486 inn = fileFixify(tinn.first(), qmake_getpwd()); 487 outn = fileFixify(toutn.first(), qmake_getpwd(), Option::output_dir); 488 } else { 489 inn = fileFixify(subs.at(i), qmake_getpwd()); 490 if (!QFile::exists(inn)) { 491 // random insanity for backwards compat: .in file specified with absolute out dir 492 inn = fileFixify(subs.at(i)); 493 } 494 if(!inn.endsWith(".in")) { 495 warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'", 496 inn.toLatin1().constData()); 497 continue; 498 } 499 outn = fileFixify(inn.left(inn.length()-3), qmake_getpwd(), Option::output_dir); 500 } 501 QFile in(inn); 502 if(in.open(QFile::ReadOnly)) { 503 QString contents; 504 QStack<int> state; 505 enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION }; 506 for(int count = 1; !in.atEnd(); ++count) { 507 QString line = QString::fromUtf8(in.readLine()); 508 if(line.startsWith("!!IF ")) { 509 if(state.isEmpty() || state.top() == IN_CONDITION) { 510 QString test = line.mid(5, line.length()-(5+1)); 511 if(project->test(test)) 512 state.push(IN_CONDITION); 513 else 514 state.push(PENDING_CONDITION); 515 } else { 516 state.push(MET_CONDITION); 517 } 518 } else if(line.startsWith("!!ELIF ")) { 519 if(state.isEmpty()) { 520 warn_msg(WarnLogic, "(%s:%d): Unexpected else condition", 521 in.fileName().toLatin1().constData(), count); 522 } else if(state.top() == PENDING_CONDITION) { 523 QString test = line.mid(7, line.length()-(7+1)); 524 if(project->test(test)) { 525 state.pop(); 526 state.push(IN_CONDITION); 527 } 528 } else if(state.top() == IN_CONDITION) { 529 state.pop(); 530 state.push(MET_CONDITION); 531 } 532 } else if(line.startsWith("!!ELSE")) { 533 if(state.isEmpty()) { 534 warn_msg(WarnLogic, "(%s:%d): Unexpected else condition", 535 in.fileName().toLatin1().constData(), count); 536 } else if(state.top() == PENDING_CONDITION) { 537 state.pop(); 538 state.push(IN_CONDITION); 539 } else if(state.top() == IN_CONDITION) { 540 state.pop(); 541 state.push(MET_CONDITION); 542 } 543 } else if(line.startsWith("!!ENDIF")) { 544 if(state.isEmpty()) 545 warn_msg(WarnLogic, "(%s:%d): Unexpected endif", 546 in.fileName().toLatin1().constData(), count); 547 else 548 state.pop(); 549 } else if(state.isEmpty() || state.top() == IN_CONDITION) { 550 contents += project->expand(line, in.fileName(), count); 551 } 552 } 553 QFile out(outn); 554 if(out.exists() && out.open(QFile::ReadOnly)) { 555 QString old = QString::fromUtf8(out.readAll()); 556 if(contents == old) { 557 v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName()); 558 continue; 559 } 560 out.close(); 561 if(!out.remove()) { 562 warn_msg(WarnLogic, "Cannot clear substitute '%s'", 563 out.fileName().toLatin1().constData()); 564 continue; 565 } 566 } 567 mkdir(QFileInfo(out).absolutePath()); 568 if(out.open(QFile::WriteOnly)) { 569 v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName()); 570 out.write(contents.toUtf8()); 571 } else { 572 warn_msg(WarnLogic, "Cannot open substitute for output '%s'", 573 out.fileName().toLatin1().constData()); 574 } 575 } else { 576 warn_msg(WarnLogic, "Cannot open substitute for input '%s'", 577 in.fileName().toLatin1().constData()); 578 } 579 } 580 } 581 582 int x; 583 584 //build up a list of compilers 585 QList<Compiler> compilers; 586 { 587 const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", 0 }; 588 for(x = 0; builtins[x]; ++x) { 589 Compiler compiler; 590 compiler.variable_in = builtins[x]; 591 compiler.flags = Compiler::CompilerBuiltin; 592 compiler.type = QMakeSourceFileInfo::TYPE_C; 593 if(!strcmp(builtins[x], "OBJECTS")) 594 compiler.flags |= Compiler::CompilerNoCheckDeps; 595 compilers.append(compiler); 596 } 597 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { 598 const QStringList &inputs = v[(*it) + ".input"]; 599 for(x = 0; x < inputs.size(); ++x) { 600 Compiler compiler; 601 compiler.variable_in = inputs.at(x); 602 compiler.flags = Compiler::CompilerNoFlags; 603 if(v[(*it) + ".CONFIG"].indexOf("ignore_no_exist") != -1) 604 compiler.flags |= Compiler::CompilerRemoveNoExist; 605 if(v[(*it) + ".CONFIG"].indexOf("no_dependencies") != -1) 606 compiler.flags |= Compiler::CompilerNoCheckDeps; 607 608 QString dep_type; 609 if(!project->isEmpty((*it) + ".dependency_type")) 610 dep_type = project->first((*it) + ".dependency_type"); 611 if (dep_type.isEmpty()) 612 compiler.type = QMakeSourceFileInfo::TYPE_UNKNOWN; 613 else if(dep_type == "TYPE_UI") 614 compiler.type = QMakeSourceFileInfo::TYPE_UI; 615 else 616 compiler.type = QMakeSourceFileInfo::TYPE_C; 617 compilers.append(compiler); 618 } 619 } 620 } 621 { //do the path fixifying 622 QStringList paths; 623 for(x = 0; x < compilers.count(); ++x) { 624 if(!paths.contains(compilers.at(x).variable_in)) 625 paths << compilers.at(x).variable_in; 626 } 627 paths << "INCLUDEPATH" << "QMAKE_INTERNAL_INCLUDED_FILES" << "PRECOMPILED_HEADER"; 628 for(int y = 0; y < paths.count(); y++) { 629 QStringList &l = v[paths[y]]; 630 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { 631 if((*it).isEmpty()) 632 continue; 633 if(exists((*it))) 634 (*it) = fileFixify((*it)); 635 } 636 } 637 } 638 639 if(noIO() || !doDepends()) 640 QMakeSourceFileInfo::setDependencyMode(QMakeSourceFileInfo::NonRecursive); 641 for(x = 0; x < compilers.count(); ++x) 642 initCompiler(compilers.at(x)); 643 644 //merge actual compiler outputs into their variable_out. This is done last so that 645 //files are already properly fixified. 646 for(QStringList::Iterator it = quc.begin(); it != quc.end(); ++it) { 647 QString tmp_out = project->values((*it) + ".output").first(); 648 if(tmp_out.isEmpty()) 649 continue; 650 if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) { 651 QStringList &compilerInputs = project->values((*it) + ".input"); 652 // Don't generate compiler output if it doesn't have input. 653 if (compilerInputs.isEmpty() || project->values(compilerInputs.first()).isEmpty()) 654 continue; 655 if(tmp_out.indexOf("$") == -1) { 656 if(!verifyExtraCompiler((*it), QString())) //verify 657 continue; 658 QString out = fileFixify(tmp_out, Option::output_dir, Option::output_dir); 659 bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1); 660 if(project->variables().contains((*it) + ".variable_out")) { 661 const QStringList &var_out = project->variables().value((*it) + ".variable_out"); 662 for(int i = 0; i < var_out.size(); ++i) { 663 QString v = var_out.at(i); 664 if(v == QLatin1String("SOURCES")) 665 v = "GENERATED_SOURCES"; 666 else if(v == QLatin1String("OBJECTS")) 667 pre_dep = false; 668 QStringList &list = project->values(v); 669 if(!list.contains(out)) 670 list.append(out); 671 } 672 } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) { 673 QStringList &list = project->values("OBJECTS"); 674 pre_dep = false; 675 if(!list.contains(out)) 676 list.append(out); 677 } else { 678 QStringList &list = project->values("UNUSED_SOURCES"); 679 if(!list.contains(out)) 680 list.append(out); 681 } 682 if(pre_dep) { 683 QStringList &list = project->variables()["PRE_TARGETDEPS"]; 684 if(!list.contains(out)) 685 list.append(out); 686 } 687 } 688 } else { 689 QStringList &tmp = project->values((*it) + ".input"); 690 for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { 691 const QStringList inputs = project->values((*it2)); 692 for(QStringList::ConstIterator input = inputs.constBegin(); input != inputs.constEnd(); ++input) { 693 if((*input).isEmpty()) 694 continue; 695 QString in = Option::fixPathToTargetOS((*input), false); 696 if(!verifyExtraCompiler((*it), in)) //verify 697 continue; 698 QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString()); 699 out = fileFixify(out, Option::output_dir, Option::output_dir); 700 bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1); 701 if(project->variables().contains((*it) + ".variable_out")) { 702 const QStringList &var_out = project->variables().value((*it) + ".variable_out"); 703 for(int i = 0; i < var_out.size(); ++i) { 704 QString v = var_out.at(i); 705 if(v == QLatin1String("SOURCES")) 706 v = "GENERATED_SOURCES"; 707 else if(v == QLatin1String("OBJECTS")) 708 pre_dep = false; 709 QStringList &list = project->values(v); 710 if(!list.contains(out)) 711 list.append(out); 712 } 713 } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) { 714 pre_dep = false; 715 QStringList &list = project->values("OBJECTS"); 716 if(!list.contains(out)) 717 list.append(out); 718 } else { 719 QStringList &list = project->values("UNUSED_SOURCES"); 720 if(!list.contains(out)) 721 list.append(out); 722 } 723 if(pre_dep) { 724 QStringList &list = project->variables()["PRE_TARGETDEPS"]; 725 if(!list.contains(out)) 726 list.append(out); 727 } 728 } 729 } 730 } 731 } 732 733 //handle dependencies 734 depHeuristicsCache.clear(); 735 if(!noIO()) { 736 // dependency paths 737 QStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"]; 738 if(project->isActiveConfig("depend_includepath")) 739 incDirs += v["INCLUDEPATH"]; 740 if(!project->isActiveConfig("no_include_pwd")) { 741 QString pwd = qmake_getpwd(); 742 if(pwd.isEmpty()) 743 pwd = "."; 744 incDirs += pwd; 745 } 746 QList<QMakeLocalFileName> deplist; 747 for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it) 748 deplist.append(QMakeLocalFileName(unescapeFilePath((*it)))); 749 QMakeSourceFileInfo::setDependencyPaths(deplist); 750 debug_msg(1, "Dependency Directories: %s", incDirs.join(" :: ").toLatin1().constData()); 751 //cache info 752 if(project->isActiveConfig("qmake_cache")) { 753 QString cache_file; 754 if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE")) { 755 cache_file = QDir::fromNativeSeparators(project->first("QMAKE_INTERNAL_CACHE_FILE")); 756 } else { 757 cache_file = ".qmake.internal.cache"; 758 if(project->isActiveConfig("build_pass")) 759 cache_file += ".BUILD." + project->first("BUILD_PASS"); 760 } 761 if(cache_file.indexOf('/') == -1) 762 cache_file.prepend(Option::output_dir + '/'); 763 QMakeSourceFileInfo::setCacheFile(cache_file); 764 } 765 766 //add to dependency engine 767 for(x = 0; x < compilers.count(); ++x) { 768 const MakefileGenerator::Compiler &comp = compilers.at(x); 769 if(!(comp.flags & Compiler::CompilerNoCheckDeps)) 770 addSourceFiles(v[comp.variable_in], QMakeSourceFileInfo::SEEK_DEPS, 771 (QMakeSourceFileInfo::SourceFileType)comp.type); 772 } 773 } 774 775 processSources(); //remove anything in SOURCES which is included (thus it need not be linked in) 776 777 //all sources and generated sources must be turned into objects at some point (the one builtin compiler) 778 v["OBJECTS"] += createObjectList(v["SOURCES"]) + createObjectList(v["GENERATED_SOURCES"]); 779 780 //Translation files 781 if(!project->isEmpty("TRANSLATIONS")) { 782 QStringList &trf = project->values("TRANSLATIONS"); 783 for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it) 784 (*it) = Option::fixPathToLocalOS((*it)); 785 } 786 787 if(!project->isActiveConfig("no_include_pwd")) { //get the output_dir into the pwd 788 if(Option::output_dir != qmake_getpwd()) 789 project->values("INCLUDEPATH").append("."); 790 } 791 792 //fix up the target deps 793 QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString("POST_TARGETDEPS"), QString() }; 794 for(int path = 0; !fixpaths[path].isNull(); path++) { 795 QStringList &l = v[fixpaths[path]]; 796 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { 797 if(!(*val_it).isEmpty()) 798 (*val_it) = escapeDependencyPath(Option::fixPathToTargetOS((*val_it), false, false)); 799 } 800 } 801 802 //extra depends 803 if(!project->isEmpty("DEPENDS")) { 804 QStringList &l = v["DEPENDS"]; 805 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { 806 QStringList files = v[(*it) + ".file"] + v[(*it) + ".files"]; //why do I support such evil things? 807 for(QStringList::Iterator file_it = files.begin(); file_it != files.end(); ++file_it) { 808 QStringList &out_deps = findDependencies(*file_it); 809 QStringList &in_deps = v[(*it) + ".depends"]; //even more evilness.. 810 for(QStringList::Iterator dep_it = in_deps.begin(); dep_it != in_deps.end(); ++dep_it) { 811 if(exists(*dep_it)) { 812 out_deps.append(*dep_it); 813 } else { 814 QString dir, regex = Option::fixPathToLocalOS((*dep_it)); 815 if(regex.lastIndexOf(Option::dir_sep) != -1) { 816 dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1); 817 regex.remove(0, dir.length()); 818 } 819 QStringList files = QDir(dir).entryList(QStringList(regex)); 820 if(files.isEmpty()) { 821 warn_msg(WarnLogic, "Dependency for [%s]: Not found %s", (*file_it).toLatin1().constData(), 822 (*dep_it).toLatin1().constData()); 823 } else { 824 for(int i = 0; i < files.count(); i++) 825 out_deps.append(dir + files[i]); 826 } 827 } 828 } 829 } 830 } 831 } 832 833 // escape qmake command 834 QStringList &qmk = project->values("QMAKE_QMAKE"); 835 qmk = escapeFilePaths(qmk); 836} 837 838bool 839MakefileGenerator::processPrlFile(QString &file) 840{ 841 bool ret = false, try_replace_file=false; 842 QString meta_file, orig_file = file; 843 if(QMakeMetaInfo::libExists(file)) { 844 try_replace_file = true; 845 meta_file = file; 846 file = ""; 847 } else { 848 QString tmp = file; 849 int ext = tmp.lastIndexOf('.'); 850 if(ext != -1) 851 tmp = tmp.left(ext); 852 meta_file = tmp; 853 } 854// meta_file = fileFixify(meta_file); 855 QString real_meta_file = Option::fixPathToLocalOS(meta_file); 856 if(!meta_file.isEmpty()) { 857 QString f = fileFixify(real_meta_file, qmake_getpwd(), Option::output_dir); 858 if(QMakeMetaInfo::libExists(f)) { 859 QMakeMetaInfo libinfo; 860 debug_msg(1, "Processing PRL file: %s", real_meta_file.toLatin1().constData()); 861 if(!libinfo.readLib(f)) { 862 fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.toLatin1().constData()); 863 } else if(project->isActiveConfig("no_read_prl_" + libinfo.type().toLower())) { 864 debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.toLatin1().constData(), libinfo.type().toLatin1().constData()); 865 } else { 866 ret = true; 867 QMap<QString, QStringList> &vars = libinfo.variables(); 868 for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) 869 processPrlVariable(it.key(), it.value()); 870 if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) { 871 QString dir; 872 int slsh = real_meta_file.lastIndexOf(Option::dir_sep); 873 if(slsh != -1) 874 dir = real_meta_file.left(slsh+1); 875 file = libinfo.first("QMAKE_PRL_TARGET"); 876 if(QDir::isRelativePath(file)) 877 file.prepend(dir); 878 } 879 } 880 } 881 if(ret) { 882 QString mf = QMakeMetaInfo::findLib(meta_file); 883 if(project->values("QMAKE_PRL_INTERNAL_FILES").indexOf(mf) == -1) 884 project->values("QMAKE_PRL_INTERNAL_FILES").append(mf); 885 if(project->values("QMAKE_INTERNAL_INCLUDED_FILES").indexOf(mf) == -1) 886 project->values("QMAKE_INTERNAL_INCLUDED_FILES").append(mf); 887 } 888 } 889 if(try_replace_file && file.isEmpty()) { 890#if 0 891 warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.toLatin1().constData(), 892 orig_file.toLatin1().constData()); 893#endif 894 file = orig_file; 895 } 896 return ret; 897} 898 899void 900MakefileGenerator::filterIncludedFiles(const QString &var) 901{ 902 QStringList &inputs = project->values(var); 903 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ) { 904 if(QMakeSourceFileInfo::included((*input)) > 0) 905 input = inputs.erase(input); 906 else 907 ++input; 908 } 909} 910 911void 912MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l) 913{ 914 if(var == "QMAKE_PRL_LIBS") { 915 QString where = "QMAKE_LIBS"; 916 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) 917 where = project->first("QMAKE_INTERNAL_PRL_LIBS"); 918 QStringList &out = project->values(where); 919 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { 920 if(out.indexOf((*it)) == -1) 921 out.append((*it)); 922 } 923 } else if(var == "QMAKE_PRL_DEFINES") { 924 QStringList &out = project->values("DEFINES"); 925 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { 926 if(out.indexOf((*it)) == -1 && 927 project->values("PRL_EXPORT_DEFINES").indexOf((*it)) == -1) 928 out.append((*it)); 929 } 930 } 931} 932 933void 934MakefileGenerator::processPrlFiles() 935{ 936 QHash<QString, bool> processed; 937 for(bool ret = false; true; ret = false) { 938 //read in any prl files included.. 939 QStringList l_out; 940 QString where = "QMAKE_LIBS"; 941 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) 942 where = project->first("QMAKE_INTERNAL_PRL_LIBS"); 943 QStringList &l = project->values(where); 944 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { 945 QString file = (*it); 946 if(!processed.contains(file) && processPrlFile(file)) { 947 processed.insert(file, true); 948 ret = true; 949 } 950 if(!file.isEmpty()) 951 l_out.append(file); 952 } 953 if(ret) 954 l = l_out; 955 else 956 break; 957 } 958} 959 960void 961MakefileGenerator::writePrlFile(QTextStream &t) 962{ 963 QString target = project->first("TARGET"); 964 int slsh = target.lastIndexOf(Option::dir_sep); 965 if(slsh != -1) 966 target.remove(0, slsh + 1); 967 QString bdir = Option::output_dir; 968 if(bdir.isEmpty()) 969 bdir = qmake_getpwd(); 970 t << "QMAKE_PRL_BUILD_DIR = " << bdir << endl; 971 972 if(!project->projectFile().isEmpty() && project->projectFile() != "-") 973 t << "QMAKE_PRO_INPUT = " << project->projectFile().section('/', -1) << endl; 974 975 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) 976 t << "QMAKE_PRL_SOURCE_DIR = " << project->first("QMAKE_ABSOLUTE_SOURCE_PATH") << endl; 977 t << "QMAKE_PRL_TARGET = " << target << endl; 978 if(!project->isEmpty("PRL_EXPORT_DEFINES")) 979 t << "QMAKE_PRL_DEFINES = " << project->values("PRL_EXPORT_DEFINES").join(" ") << endl; 980 if(!project->isEmpty("PRL_EXPORT_CFLAGS")) 981 t << "QMAKE_PRL_CFLAGS = " << project->values("PRL_EXPORT_CFLAGS").join(" ") << endl; 982 if(!project->isEmpty("PRL_EXPORT_CXXFLAGS")) 983 t << "QMAKE_PRL_CXXFLAGS = " << project->values("PRL_EXPORT_CXXFLAGS").join(" ") << endl; 984 if(!project->isEmpty("CONFIG")) 985 t << "QMAKE_PRL_CONFIG = " << project->values("CONFIG").join(" ") << endl; 986 if(!project->isEmpty("TARGET_VERSION_EXT")) 987 t << "QMAKE_PRL_VERSION = " << project->first("TARGET_VERSION_EXT") << endl; 988 else if(!project->isEmpty("VERSION")) 989 t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl; 990 if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) { 991 QStringList libs; 992 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) 993 libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); 994 else 995 libs << "QMAKE_LIBS"; //obvious one 996 if(project->isActiveConfig("staticlib")) 997 libs << "QMAKE_LIBS_PRIVATE"; 998 t << "QMAKE_PRL_LIBS = "; 999 for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it) 1000 t << project->values((*it)).join(" ").replace('\\', "\\\\") << " "; 1001 t << endl; 1002 } 1003} 1004 1005bool 1006MakefileGenerator::writeProjectMakefile() 1007{ 1008 usePlatformDir(); 1009 QTextStream t(&Option::output); 1010 1011 //header 1012 writeHeader(t); 1013 1014 QList<SubTarget*> targets; 1015 { 1016 QStringList builds = project->values("BUILDS"); 1017 for(QStringList::Iterator it = builds.begin(); it != builds.end(); ++it) { 1018 SubTarget *st = new SubTarget; 1019 targets.append(st); 1020 st->makefile = "$(MAKEFILE)." + (*it); 1021 st->name = (*it); 1022 st->target = project->isEmpty((*it) + ".target") ? (*it) : project->first((*it) + ".target"); 1023 } 1024 } 1025 if(project->isActiveConfig("build_all")) { 1026 t << "first: all" << endl; 1027 QList<SubTarget*>::Iterator it; 1028 1029 //install 1030 t << "install: "; 1031 for(it = targets.begin(); it != targets.end(); ++it) 1032 t << (*it)->target << "-install "; 1033 t << endl; 1034 1035 //uninstall 1036 t << "uninstall: "; 1037 for(it = targets.begin(); it != targets.end(); ++it) 1038 t << (*it)->target << "-uninstall "; 1039 t << endl; 1040 } else { 1041 t << "first: " << targets.first()->target << endl 1042 << "install: " << targets.first()->target << "-install" << endl 1043 << "uninstall: " << targets.first()->target << "-uninstall" << endl; 1044 } 1045 1046 writeSubTargets(t, targets, SubTargetsNoFlags); 1047 if(!project->isActiveConfig("no_autoqmake")) { 1048 for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) 1049 t << (*it)->makefile << ": " << 1050 Option::fixPathToTargetOS(fileFixify(Option::output.fileName())) << endl; 1051 } 1052 qDeleteAll(targets); 1053 return true; 1054} 1055 1056bool 1057MakefileGenerator::write() 1058{ 1059 if(!project) 1060 return false; 1061 writePrlFile(); 1062 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write makefile 1063 Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { 1064 QTextStream t(&Option::output); 1065 if(!writeMakefile(t)) { 1066#if 1 1067 warn_msg(WarnLogic, "Unable to generate output for: %s [TEMPLATE %s]", 1068 Option::output.fileName().toLatin1().constData(), 1069 project->first("TEMPLATE").toLatin1().constData()); 1070 if(Option::output.exists()) 1071 Option::output.remove(); 1072#endif 1073 } 1074 } 1075 return true; 1076} 1077 1078QString 1079MakefileGenerator::prlFileName(bool fixify) 1080{ 1081 QString ret = project->first("TARGET_PRL");; 1082 if(ret.isEmpty()) 1083 ret = project->first("TARGET"); 1084 int slsh = ret.lastIndexOf(Option::dir_sep); 1085 if(slsh != -1) 1086 ret.remove(0, slsh); 1087 if(!ret.endsWith(Option::prl_ext)) { 1088 int dot = ret.indexOf('.'); 1089 if(dot != -1) 1090 ret.truncate(dot); 1091 ret += Option::prl_ext; 1092 } 1093 if(!project->isEmpty("QMAKE_BUNDLE")) 1094 ret.prepend(project->first("QMAKE_BUNDLE") + Option::dir_sep); 1095 if(fixify) { 1096 if(!project->isEmpty("DESTDIR")) 1097 ret.prepend(project->first("DESTDIR")); 1098 ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir)); 1099 } 1100 return ret; 1101} 1102 1103void 1104MakefileGenerator::writePrlFile() 1105{ 1106 if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || 1107 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) 1108 && project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty() 1109 && project->isActiveConfig("create_prl") 1110 && (project->first("TEMPLATE") == "lib" 1111 || project->first("TEMPLATE") == "vclib") 1112 && (!project->isActiveConfig("plugin") || project->isActiveConfig("static"))) { //write prl file 1113 QString local_prl = prlFileName(); 1114 QString prl = fileFixify(local_prl); 1115 mkdir(fileInfo(local_prl).path()); 1116 QFile ft(local_prl); 1117 if(ft.open(QIODevice::WriteOnly)) { 1118 project->values("ALL_DEPS").append(prl); 1119 project->values("QMAKE_INTERNAL_PRL_FILE").append(prl); 1120 QTextStream t(&ft); 1121 writePrlFile(t); 1122 } 1123 } 1124} 1125 1126// Manipulate directories, so it's possible to build 1127// several cross-platform targets concurrently 1128void 1129MakefileGenerator::usePlatformDir() 1130{ 1131 QString pltDir(project->first("QMAKE_PLATFORM_DIR")); 1132 if(pltDir.isEmpty()) 1133 return; 1134 QChar sep = QDir::separator(); 1135 QString slashPltDir = sep + pltDir; 1136 1137 QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"), 1138 QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"), 1139 QString("PRECOMPILED_DIR"), QString("QMAKE_LIBDIR_QT"), QString() }; 1140 for(int i = 0; !dirs[i].isEmpty(); ++i) { 1141 QString filePath = project->first(dirs[i]); 1142 project->values(dirs[i]) = QStringList(filePath + (filePath.isEmpty() ? pltDir : slashPltDir)); 1143 } 1144 1145 QString libs[] = { QString("QMAKE_LIBS_QT"), QString("QMAKE_LIBS_QT_THREAD"), QString("QMAKE_LIBS_QT_ENTRY"), QString() }; 1146 for(int i = 0; !libs[i].isEmpty(); ++i) { 1147 QString filePath = project->first(libs[i]); 1148 int fpi = filePath.lastIndexOf(sep); 1149 if(fpi == -1) 1150 project->values(libs[i]).prepend(pltDir + sep); 1151 else 1152 project->values(libs[i]) = QStringList(filePath.left(fpi) + slashPltDir + filePath.mid(fpi)); 1153 } 1154} 1155 1156void 1157MakefileGenerator::writeObj(QTextStream &t, const QString &src) 1158{ 1159 QStringList &srcl = project->values(src); 1160 QStringList objl = createObjectList(srcl); 1161 1162 QStringList::Iterator oit = objl.begin(); 1163 QStringList::Iterator sit = srcl.begin(); 1164 QString stringSrc("$src"); 1165 QString stringObj("$obj"); 1166 for(;sit != srcl.end() && oit != objl.end(); ++oit, ++sit) { 1167 if((*sit).isEmpty()) 1168 continue; 1169 1170 t << escapeDependencyPath((*oit)) << ": " << escapeDependencyPath((*sit)) << " " << escapeDependencyPaths(findDependencies((*sit))).join(" \\\n\t\t"); 1171 1172 QString comp, cimp; 1173 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) { 1174 if((*sit).endsWith((*cppit))) { 1175 comp = "QMAKE_RUN_CXX"; 1176 cimp = "QMAKE_RUN_CXX_IMP"; 1177 break; 1178 } 1179 } 1180 if(comp.isEmpty()) { 1181 comp = "QMAKE_RUN_CC"; 1182 cimp = "QMAKE_RUN_CC_IMP"; 1183 } 1184 bool use_implicit_rule = !project->isEmpty(cimp); 1185 use_implicit_rule = false; 1186 if(use_implicit_rule) { 1187 if(!project->isEmpty("OBJECTS_DIR")) { 1188 use_implicit_rule = false; 1189 } else { 1190 int dot = (*sit).lastIndexOf('.'); 1191 if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit))) 1192 use_implicit_rule = false; 1193 } 1194 } 1195 if (!use_implicit_rule && !project->isEmpty(comp)) { 1196 QString p = var(comp), srcf(*sit); 1197 p.replace(stringSrc, escapeFilePath(srcf)); 1198 p.replace(stringObj, escapeFilePath((*oit))); 1199 t << "\n\t" << p; 1200 } 1201 t << endl << endl; 1202 } 1203} 1204 1205QString 1206MakefileGenerator::filePrefixRoot(const QString &root, const QString &path) 1207{ 1208 QString ret(root + path); 1209 if(path.length() > 2 && path[1] == ':') //c:\foo 1210 ret = QString(path.mid(0, 2) + root + path.mid(2)); 1211 while(ret.endsWith("\\")) 1212 ret = ret.left(ret.length()-1); 1213 return ret; 1214} 1215 1216void 1217MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs, bool noBuild) 1218{ 1219 QString rm_dir_contents("-$(DEL_FILE)"); 1220 if (!isWindowsShell()) //ick 1221 rm_dir_contents = "-$(DEL_FILE) -r"; 1222 1223 QString all_installs, all_uninstalls; 1224 QStringList &l = project->values(installs); 1225 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { 1226 QString pvar = (*it) + ".path"; 1227 if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 && 1228 project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1 && 1229 project->values(pvar).isEmpty()) { 1230 warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.toLatin1().constData()); 1231 continue; 1232 } 1233 1234 bool do_default = true; 1235 const QString root = "$(INSTALL_ROOT)"; 1236 QString target, dst; 1237 if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 && 1238 project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1) { 1239 dst = fileFixify(unescapeFilePath(project->values(pvar).first()), FileFixifyAbsolute, false); 1240 if(!dst.endsWith(Option::dir_sep)) 1241 dst += Option::dir_sep; 1242 } 1243 dst = escapeFilePath(dst); 1244 1245 QStringList tmp, uninst = project->values((*it) + ".uninstall"); 1246 //other 1247 tmp = project->values((*it) + ".extra"); 1248 if(tmp.isEmpty()) 1249 tmp = project->values((*it) + ".commands"); //to allow compatible name 1250 if(!tmp.isEmpty()) { 1251 do_default = false; 1252 if(!target.isEmpty()) 1253 target += "\n\t"; 1254 target += tmp.join(" "); 1255 } 1256 //masks 1257 tmp = findFilesInVPATH(project->values((*it) + ".files"), VPATH_NoFixify); 1258 tmp = fileFixify(tmp, FileFixifyAbsolute); 1259 if(!tmp.isEmpty()) { 1260 if(!target.isEmpty()) 1261 target += "\n"; 1262 do_default = false; 1263 for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) { 1264 QString wild = Option::fixPathToTargetOS((*wild_it), false, false); 1265 QString dirstr = qmake_getpwd(), filestr = wild; 1266 int slsh = filestr.lastIndexOf(Option::dir_sep); 1267 if(slsh != -1) { 1268 dirstr = filestr.left(slsh+1); 1269 filestr.remove(0, slsh+1); 1270 } 1271 if(!dirstr.endsWith(Option::dir_sep)) 1272 dirstr += Option::dir_sep; 1273 bool is_target = (wild == fileFixify(var("TARGET"), FileFixifyAbsolute)); 1274 if(is_target || exists(wild)) { //real file or target 1275 QString file = wild; 1276 QFileInfo fi(fileInfo(wild)); 1277 if(!target.isEmpty()) 1278 target += "\t"; 1279 QString dst_file = filePrefixRoot(root, dst); 1280 if(fi.isDir() && project->isActiveConfig("copy_dir_files")) { 1281 if(!dst_file.endsWith(Option::dir_sep)) 1282 dst_file += Option::dir_sep; 1283 dst_file += fi.fileName(); 1284 } 1285 QString cmd; 1286 if (fi.isDir()) 1287 cmd = "-$(INSTALL_DIR)"; 1288 else if (is_target || fi.isExecutable()) 1289 cmd = "-$(INSTALL_PROGRAM)"; 1290 else 1291 cmd = "-$(INSTALL_FILE)"; 1292 cmd += " " + escapeFilePath(wild) + " " + dst_file + "\n"; 1293 target += cmd; 1294 if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") && 1295 !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP")) 1296 target += QString("\t-") + var("QMAKE_STRIP") + " " + 1297 filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)) + "\n"; 1298 if(!uninst.isEmpty()) 1299 uninst.append("\n\t"); 1300 uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false))); 1301 continue; 1302 } 1303 QString local_dirstr = Option::fixPathToLocalOS(dirstr, true); 1304 QStringList files = QDir(local_dirstr).entryList(QStringList(filestr)); 1305 const QStringList &installConfigValues = project->values((*it) + ".CONFIG"); 1306 if (installConfigValues.contains("no_check_exist") && files.isEmpty()) { 1307 if(!target.isEmpty()) 1308 target += "\t"; 1309 QString dst_file = filePrefixRoot(root, dst); 1310 QFileInfo fi(fileInfo(wild)); 1311 QString cmd; 1312 if (installConfigValues.contains("directory")) { 1313 cmd = QLatin1String("-$(INSTALL_DIR)"); 1314 if (!dst_file.endsWith(Option::dir_sep)) 1315 dst_file += Option::dir_sep; 1316 dst_file += fi.fileName(); 1317 } else if (installConfigValues.contains("executable")) { 1318 cmd = QLatin1String("-$(INSTALL_PROGRAM)"); 1319 } else if (installConfigValues.contains("data")) { 1320 cmd = QLatin1String("-$(INSTALL_FILE)"); 1321 } else { 1322 cmd = QString(fi.isExecutable() ? "-$(INSTALL_PROGRAM)" : "-$(INSTALL_FILE)"); 1323 } 1324 cmd += " " + wild + " " + dst_file + "\n"; 1325 target += cmd; 1326 if(!uninst.isEmpty()) 1327 uninst.append("\n\t"); 1328 uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false))); 1329 } 1330 for(int x = 0; x < files.count(); x++) { 1331 QString file = files[x]; 1332 if(file == "." || file == "..") //blah 1333 continue; 1334 if(!uninst.isEmpty()) 1335 uninst.append("\n\t"); 1336 uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false))); 1337 QFileInfo fi(fileInfo(dirstr + file)); 1338 if(!target.isEmpty()) 1339 target += "\t"; 1340 QString dst_file = filePrefixRoot(root, fileFixify(dst, FileFixifyAbsolute, false)); 1341 if(fi.isDir() && project->isActiveConfig("copy_dir_files")) { 1342 if(!dst_file.endsWith(Option::dir_sep)) 1343 dst_file += Option::dir_sep; 1344 dst_file += fi.fileName(); 1345 } 1346 QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " " + 1347 dirstr + file + " " + dst_file + "\n"; 1348 target += cmd; 1349 if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") && 1350 !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP")) 1351 target += QString("\t-") + var("QMAKE_STRIP") + " " + 1352 filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)) + 1353 "\n"; 1354 } 1355 } 1356 } 1357 //default? 1358 if(do_default) { 1359 target = defaultInstall((*it)); 1360 uninst = project->values((*it) + ".uninstall"); 1361 } 1362 1363 if(!target.isEmpty() || project->values((*it) + ".CONFIG").indexOf("dummy_install") != -1) { 1364 if(noBuild || project->values((*it) + ".CONFIG").indexOf("no_build") != -1) 1365 t << "install_" << (*it) << ":"; 1366 else if(project->isActiveConfig("build_all")) 1367 t << "install_" << (*it) << ": all"; 1368 else 1369 t << "install_" << (*it) << ": first"; 1370 const QStringList &deps = project->values((*it) + ".depends"); 1371 if(!deps.isEmpty()) { 1372 for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) { 1373 QString targ = var((*dep_it) + ".target"); 1374 if(targ.isEmpty()) 1375 targ = (*dep_it); 1376 t << " " << escapeDependencyPath(targ); 1377 } 1378 } 1379 if(project->isEmpty("QMAKE_NOFORCE")) 1380 t << " FORCE"; 1381 t << "\n\t"; 1382 const QStringList &dirs = project->values(pvar); 1383 for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) { 1384 QString tmp_dst = fileFixify((*pit), FileFixifyAbsolute, false); 1385 if (!isWindowsShell() && !tmp_dst.endsWith(Option::dir_sep)) 1386 tmp_dst += Option::dir_sep; 1387 t << mkdir_p_asstring(filePrefixRoot(root, tmp_dst)) << "\n\t"; 1388 } 1389 t << target << endl << endl; 1390 if(!uninst.isEmpty()) { 1391 t << "uninstall_" << (*it) << ": "; 1392 if(project->isEmpty("QMAKE_NOFORCE")) 1393 t << " FORCE"; 1394 t << "\n\t" 1395 << uninst.join(" ") << "\n\t" 1396 << "-$(DEL_DIR) " << filePrefixRoot(root, dst) << " " << endl << endl; 1397 } 1398 t << endl; 1399 1400 if(project->values((*it) + ".CONFIG").indexOf("no_default_install") == -1) { 1401 all_installs += QString("install_") + (*it) + " "; 1402 if(!uninst.isEmpty()) 1403 all_uninstalls += "uninstall_" + (*it) + " "; 1404 } 1405 } else { 1406 debug_msg(1, "no definition for install %s: install target not created",(*it).toLatin1().constData()); 1407 } 1408 } 1409 t << "install: " << var("INSTALLDEPS") << " " << all_installs; 1410 if(project->isEmpty("QMAKE_NOFORCE")) 1411 t << " FORCE"; 1412 t << "\n\n"; 1413 t << "uninstall: " << all_uninstalls << " " << var("UNINSTALLDEPS"); 1414 if(project->isEmpty("QMAKE_NOFORCE")) 1415 t << " FORCE"; 1416 t << "\n\n"; 1417} 1418 1419QString 1420MakefileGenerator::var(const QString &var) 1421{ 1422 return val(project->values(var)); 1423} 1424 1425QString 1426MakefileGenerator::val(const QStringList &varList) 1427{ 1428 return valGlue(varList, "", " ", ""); 1429} 1430 1431QString 1432MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after) 1433{ 1434 return valGlue(project->values(var), before, glue, after); 1435} 1436 1437QString 1438MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after) 1439{ 1440 QString ret; 1441 for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) { 1442 if(!(*it).isEmpty()) { 1443 if(!ret.isEmpty()) 1444 ret += glue; 1445 ret += (*it); 1446 } 1447 } 1448 return ret.isEmpty() ? QString("") : before + ret + after; 1449} 1450 1451 1452QString 1453MakefileGenerator::varList(const QString &var) 1454{ 1455 return valList(project->values(var)); 1456} 1457 1458QString 1459MakefileGenerator::valList(const QStringList &varList) 1460{ 1461 return valGlue(varList, "", " \\\n\t\t", ""); 1462} 1463 1464QStringList 1465MakefileGenerator::createObjectList(const QStringList &sources) 1466{ 1467 QStringList ret; 1468 QString objdir; 1469 if(!project->values("OBJECTS_DIR").isEmpty()) 1470 objdir = project->first("OBJECTS_DIR"); 1471 for(QStringList::ConstIterator it = sources.begin(); it != sources.end(); ++it) { 1472 QFileInfo fi(fileInfo(Option::fixPathToLocalOS((*it)))); 1473 QString dir; 1474 if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) { 1475 QString fName = Option::fixPathToTargetOS((*it), false); 1476 int dl = fName.lastIndexOf(Option::dir_sep); 1477 if(dl != -1) 1478 dir = fName.left(dl + 1); 1479 } else if (project->isActiveConfig("object_parallel_to_source")) { 1480 // The source paths are relative to the output dir, but we need source-relative paths 1481 QString sourceRelativePath = fileFixify(*it, qmake_getpwd(), Option::output_dir); 1482 sourceRelativePath = Option::fixPathToTargetOS(sourceRelativePath, false); 1483 1484 if (sourceRelativePath.startsWith(".." + Option::dir_sep)) 1485 sourceRelativePath = fileFixify(sourceRelativePath, FileFixifyAbsolute); 1486 1487 if (QDir::isAbsolutePath(sourceRelativePath)) 1488 sourceRelativePath.remove(0, sourceRelativePath.indexOf(Option::dir_sep) + 1); 1489 1490 dir = objdir; // We still respect OBJECTS_DIR 1491 1492 int lastDirSepPosition = sourceRelativePath.lastIndexOf(Option::dir_sep); 1493 if (lastDirSepPosition != -1) 1494 dir += sourceRelativePath.leftRef(lastDirSepPosition + 1); 1495 1496 if (!noIO()) { 1497 // Ensure that the final output directory of each object exists 1498 QString outRelativePath = fileFixify(dir, qmake_getpwd(), Option::output_dir); 1499 if (!mkdir(outRelativePath)) 1500 warn_msg(WarnLogic, "Cannot create directory '%s'", outRelativePath.toLatin1().constData()); 1501 } 1502 } else { 1503 dir = objdir; 1504 } 1505 ret.append(dir + fi.completeBaseName() + Option::obj_ext); 1506 } 1507 return ret; 1508} 1509 1510ReplaceExtraCompilerCacheKey::ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o) 1511{ 1512 static QString doubleColon = QLatin1String("::"); 1513 1514 hash = 0; 1515 pwd = qmake_getpwd(); 1516 var = v; 1517 { 1518 QStringList il = i; 1519 il.sort(); 1520 in = il.join(doubleColon); 1521 } 1522 { 1523 QStringList ol = o; 1524 ol.sort(); 1525 out = ol.join(doubleColon); 1526 } 1527} 1528 1529bool ReplaceExtraCompilerCacheKey::operator==(const ReplaceExtraCompilerCacheKey &f) const 1530{ 1531 return (hashCode() == f.hashCode() && 1532 f.in == in && 1533 f.out == out && 1534 f.var == var && 1535 f.pwd == pwd); 1536} 1537 1538 1539QString 1540MakefileGenerator::replaceExtraCompilerVariables(const QString &orig_var, const QStringList &in, const QStringList &out) 1541{ 1542 //lazy cache 1543 ReplaceExtraCompilerCacheKey cacheKey(orig_var, in, out); 1544 QString cacheVal = extraCompilerVariablesCache.value(cacheKey); 1545 if(!cacheVal.isNull()) 1546 return cacheVal; 1547 1548 //do the work 1549 QString ret = orig_var; 1550 QRegExp reg_var("\\$\\{.*\\}"); 1551 reg_var.setMinimal(true); 1552 for(int rep = 0; (rep = reg_var.indexIn(ret, rep)) != -1; ) { 1553 QStringList val; 1554 const QString var = ret.mid(rep + 2, reg_var.matchedLength() - 3); 1555 bool filePath = false; 1556 if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_"))) { 1557 const QString varname = var.mid(10); 1558 val += project->values(varname); 1559 } 1560 if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_FIRST_"))) { 1561 const QString varname = var.mid(16); 1562 val += project->first(varname); 1563 } 1564 1565 if(val.isEmpty() && !in.isEmpty()) { 1566 if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_IN_"))) { 1567 filePath = true; 1568 const QString funcname = var.mid(19); 1569 val += project->expand(funcname, QList<QStringList>() << in); 1570 } else if(var == QLatin1String("QMAKE_FILE_BASE") || var == QLatin1String("QMAKE_FILE_IN_BASE")) { 1571 //filePath = true; 1572 for(int i = 0; i < in.size(); ++i) { 1573 QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i)))); 1574 QString base = fi.completeBaseName(); 1575 if(base.isNull()) 1576 base = fi.fileName(); 1577 val += base; 1578 } 1579 } else if(var == QLatin1String("QMAKE_FILE_EXT")) { 1580 filePath = true; 1581 for(int i = 0; i < in.size(); ++i) { 1582 QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i)))); 1583 QString ext; 1584 // Ensure complementarity with QMAKE_FILE_BASE 1585 int baseLen = fi.completeBaseName().length(); 1586 if(baseLen == 0) 1587 ext = fi.fileName(); 1588 else 1589 ext = fi.fileName().remove(0, baseLen); 1590 val += ext; 1591 } 1592 } else if(var == QLatin1String("QMAKE_FILE_PATH") || var == QLatin1String("QMAKE_FILE_IN_PATH")) { 1593 filePath = true; 1594 for(int i = 0; i < in.size(); ++i) 1595 val += fileInfo(Option::fixPathToLocalOS(in.at(i))).path(); 1596 } else if(var == QLatin1String("QMAKE_FILE_NAME") || var == QLatin1String("QMAKE_FILE_IN")) { 1597 filePath = true; 1598 for(int i = 0; i < in.size(); ++i) 1599 val += fileInfo(Option::fixPathToLocalOS(in.at(i))).filePath(); 1600 1601 } 1602 } 1603 if(val.isEmpty() && !out.isEmpty()) { 1604 if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_OUT_"))) { 1605 filePath = true; 1606 const QString funcname = var.mid(20); 1607 val += project->expand(funcname, QList<QStringList>() << out); 1608 } else if(var == QLatin1String("QMAKE_FILE_OUT")) { 1609 filePath = true; 1610 for(int i = 0; i < out.size(); ++i) 1611 val += fileInfo(Option::fixPathToLocalOS(out.at(i))).filePath(); 1612 } else if(var == QLatin1String("QMAKE_FILE_OUT_BASE")) { 1613 //filePath = true; 1614 for(int i = 0; i < out.size(); ++i) { 1615 QFileInfo fi(fileInfo(Option::fixPathToLocalOS(out.at(i)))); 1616 QString base = fi.completeBaseName(); 1617 if(base.isNull()) 1618 base = fi.fileName(); 1619 val += base; 1620 } 1621 } 1622 } 1623 if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_FUNC_"))) { 1624 const QString funcname = var.mid(11); 1625 val += project->expand(funcname, QList<QStringList>() << in << out); 1626 } 1627 1628 if(!val.isEmpty()) { 1629 QString fullVal; 1630 if(filePath) { 1631 for(int i = 0; i < val.size(); ++i) { 1632 const QString file = Option::fixPathToTargetOS(unescapeFilePath(val.at(i)), false); 1633 if(!fullVal.isEmpty()) 1634 fullVal += " "; 1635 fullVal += escapeFilePath(file); 1636 } 1637 } else { 1638 fullVal = val.join(" "); 1639 } 1640 ret.replace(rep, reg_var.matchedLength(), fullVal); 1641 rep += fullVal.length(); 1642 } else { 1643 rep += reg_var.matchedLength(); 1644 } 1645 } 1646 1647 //cache the value 1648 extraCompilerVariablesCache.insert(cacheKey, ret); 1649 return ret; 1650} 1651 1652bool 1653MakefileGenerator::verifyExtraCompiler(const QString &comp, const QString &file_unfixed) 1654{ 1655 if(noIO()) 1656 return false; 1657 const QString file = Option::fixPathToLocalOS(file_unfixed); 1658 1659 if(project->values(comp + ".CONFIG").indexOf("moc_verify") != -1) { 1660 if(!file.isNull()) { 1661 QMakeSourceFileInfo::addSourceFile(file, QMakeSourceFileInfo::SEEK_MOCS); 1662 if(!mocable(file)) { 1663 return false; 1664 } else { 1665 project->values("MOCABLES").append(file); 1666 } 1667 } 1668 } else if(project->values(comp + ".CONFIG").indexOf("function_verify") != -1) { 1669 QString tmp_out = project->values(comp + ".output").first(); 1670 if(tmp_out.isEmpty()) 1671 return false; 1672 QStringList verify_function = project->values(comp + ".verify_function"); 1673 if(verify_function.isEmpty()) 1674 return false; 1675 1676 for(int i = 0; i < verify_function.size(); ++i) { 1677 bool invert = false; 1678 QString verify = verify_function.at(i); 1679 if(verify.at(0) == QLatin1Char('!')) { 1680 invert = true; 1681 verify = verify.mid(1); 1682 } 1683 1684 if(project->values(comp + ".CONFIG").indexOf("combine") != -1) { 1685 bool pass = project->test(verify, QList<QStringList>() << QStringList(tmp_out) << QStringList(file)); 1686 if(invert) 1687 pass = !pass; 1688 if(!pass) 1689 return false; 1690 } else { 1691 QStringList &tmp = project->values(comp + ".input"); 1692 for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) { 1693 QStringList &inputs = project->values((*it)); 1694 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { 1695 if((*input).isEmpty()) 1696 continue; 1697 QString in = fileFixify(Option::fixPathToTargetOS((*input), false)); 1698 if(in == file) { 1699 bool pass = project->test(verify, 1700 QList<QStringList>() << QStringList(replaceExtraCompilerVariables(tmp_out, (*input), QString())) << 1701 QStringList(file)); 1702 if(invert) 1703 pass = !pass; 1704 if(!pass) 1705 return false; 1706 break; 1707 } 1708 } 1709 } 1710 } 1711 } 1712 } else if(project->values(comp + ".CONFIG").indexOf("verify") != -1) { 1713 QString tmp_out = project->values(comp + ".output").first(); 1714 if(tmp_out.isEmpty()) 1715 return false; 1716 QString tmp_cmd; 1717 if(!project->isEmpty(comp + ".commands")) { 1718 int argv0 = -1; 1719 QStringList cmdline = project->values(comp + ".commands"); 1720 for(int i = 0; i < cmdline.count(); ++i) { 1721 if(!cmdline.at(i).contains('=')) { 1722 argv0 = i; 1723 break; 1724 } 1725 } 1726 if(argv0 != -1) { 1727 cmdline[argv0] = Option::fixPathToTargetOS(cmdline.at(argv0), false); 1728 tmp_cmd = cmdline.join(" "); 1729 } 1730 } 1731 1732 if(project->values(comp + ".CONFIG").indexOf("combine") != -1) { 1733 QString cmd = replaceExtraCompilerVariables(tmp_cmd, QString(), tmp_out); 1734 if(system(cmd.toLatin1().constData())) 1735 return false; 1736 } else { 1737 QStringList &tmp = project->values(comp + ".input"); 1738 for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) { 1739 QStringList &inputs = project->values((*it)); 1740 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { 1741 if((*input).isEmpty()) 1742 continue; 1743 QString in = fileFixify(Option::fixPathToTargetOS((*input), false)); 1744 if(in == file) { 1745 QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString()); 1746 QString cmd = replaceExtraCompilerVariables(tmp_cmd, in, out); 1747 if(system(cmd.toLatin1().constData())) 1748 return false; 1749 break; 1750 } 1751 } 1752 } 1753 } 1754 } 1755 return true; 1756} 1757 1758void 1759MakefileGenerator::writeExtraTargets(QTextStream &t) 1760{ 1761 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); 1762 for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) { 1763 QString targ = var((*it) + ".target"), 1764 cmd = var((*it) + ".commands"), deps; 1765 if(targ.isEmpty()) 1766 targ = (*it); 1767 QStringList &deplist = project->values((*it) + ".depends"); 1768 for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) { 1769 QString dep = var((*dep_it) + ".target"); 1770 if(dep.isEmpty()) 1771 dep = (*dep_it); 1772 deps += " " + escapeDependencyPath(dep); 1773 } 1774 if(project->values((*it) + ".CONFIG").indexOf("fix_target") != -1) 1775 targ = fileFixify(targ, Option::output_dir, Option::output_dir); 1776 if(project->isEmpty("QMAKE_NOFORCE") && 1777 project->values((*it) + ".CONFIG").indexOf("phony") != -1) 1778 deps += QString(" ") + "FORCE"; 1779 t << escapeDependencyPath(targ) << ":" << deps; 1780 if(!cmd.isEmpty()) 1781 t << "\n\t" << cmd; 1782 t << endl << endl; 1783 1784 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(targ); 1785 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(targ)) << deps.split(" ", QString::SkipEmptyParts); 1786 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(targ)) << cmd; 1787 } 1788} 1789 1790void 1791MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) 1792{ 1793 QString clean_targets; 1794 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); 1795 QDir outputDir(Option::output_dir); 1796 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { 1797 QString tmp_out = fileFixify(project->values((*it) + ".output").first(), 1798 Option::output_dir, Option::output_dir); 1799 QString tmp_cmd; 1800 if(!project->isEmpty((*it) + ".commands")) { 1801 QStringList cmdline = project->values((*it) + ".commands"); 1802 int argv0 = findExecutable(cmdline); 1803 if(argv0 != -1) { 1804 cmdline[argv0] = escapeFilePath(Option::fixPathToTargetOS(cmdline.at(argv0), false)); 1805 tmp_cmd = cmdline.join(" "); 1806 } 1807 } 1808 QStringList tmp_dep = project->values((*it) + ".depends"); 1809 QString tmp_dep_cmd; 1810 QString dep_cd_cmd; 1811 if(!project->isEmpty((*it) + ".depend_command")) { 1812 int argv0 = -1; 1813 QStringList cmdline = project->values((*it) + ".depend_command"); 1814 for(int i = 0; i < cmdline.count(); ++i) { 1815 if(!cmdline.at(i).contains('=')) { 1816 argv0 = i; 1817 break; 1818 } 1819 } 1820 if(argv0 != -1) { 1821 const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true); 1822 if(exists(c)) { 1823 cmdline[argv0] = escapeFilePath(Option::fixPathToLocalOS(cmdline.at(argv0), false)); 1824 } else { 1825 cmdline[argv0] = escapeFilePath(cmdline.at(argv0)); 1826 } 1827 QFileInfo cmdFileInfo(cmdline[argv0]); 1828 if (!cmdFileInfo.isAbsolute() || cmdFileInfo.exists()) 1829 tmp_dep_cmd = cmdline.join(" "); 1830 } 1831 dep_cd_cmd = QLatin1String("cd ") 1832 + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) 1833 + QLatin1String(" && "); 1834 } 1835 QStringList &vars = project->values((*it) + ".variables"); 1836 if(tmp_out.isEmpty() || tmp_cmd.isEmpty()) 1837 continue; 1838 QStringList tmp_inputs; 1839 { 1840 const QStringList &comp_inputs = project->values((*it) + ".input"); 1841 for(QStringList::ConstIterator it2 = comp_inputs.begin(); it2 != comp_inputs.end(); ++it2) { 1842 const QStringList &tmp = project->values((*it2)); 1843 for(QStringList::ConstIterator input = tmp.begin(); input != tmp.end(); ++input) { 1844 QString in = Option::fixPathToTargetOS((*input), false); 1845 if(verifyExtraCompiler((*it), in)) 1846 tmp_inputs.append((*input)); 1847 } 1848 } 1849 } 1850 1851 t << "compiler_" << (*it) << "_make_all:"; 1852 if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) { 1853 // compilers with a combined input only have one output 1854 QString input = project->values((*it) + ".output").first(); 1855 t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, input, QString())); 1856 } else { 1857 for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { 1858 QString in = Option::fixPathToTargetOS((*input), false); 1859 t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); 1860 } 1861 } 1862 t << endl; 1863 1864 if(project->values((*it) + ".CONFIG").indexOf("no_clean") == -1) { 1865 QString tmp_clean = project->values((*it) + ".clean").join(" "); 1866 QString tmp_clean_cmds = project->values((*it) + ".clean_commands").join(" "); 1867 if(!tmp_inputs.isEmpty()) 1868 clean_targets += QString("compiler_" + (*it) + "_clean "); 1869 t << "compiler_" << (*it) << "_clean:"; 1870 bool wrote_clean_cmds = false, wrote_clean = false; 1871 if(tmp_clean_cmds.isEmpty()) { 1872 wrote_clean_cmds = true; 1873 } else if(tmp_clean_cmds.indexOf("${QMAKE_") == -1) { 1874 t << "\n\t" << tmp_clean_cmds; 1875 wrote_clean_cmds = true; 1876 } 1877 if(tmp_clean.isEmpty()) 1878 tmp_clean = tmp_out; 1879 if(tmp_clean.indexOf("${QMAKE_") == -1) { 1880 t << "\n\t" << "-$(DEL_FILE) " << tmp_clean; 1881 wrote_clean = true; 1882 } 1883 if(!wrote_clean_cmds || !wrote_clean) { 1884 QStringList cleans; 1885 const QString del_statement("-$(DEL_FILE)"); 1886 if(!wrote_clean) { 1887 if(project->isActiveConfig("no_delete_multiple_files")) { 1888 for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) 1889 cleans.append(" " + replaceExtraCompilerVariables(tmp_clean, (*input), 1890 replaceExtraCompilerVariables(tmp_out, (*input), QString()))); 1891 } else { 1892 QString files, file; 1893 const int commandlineLimit = 2047; // NT limit, expanded 1894 for(int input = 0; input < tmp_inputs.size(); ++input) { 1895 file = " " + replaceExtraCompilerVariables(tmp_clean, tmp_inputs.at(input), 1896 replaceExtraCompilerVariables(tmp_out, tmp_inputs.at(input), QString())); 1897 if(del_statement.length() + files.length() + 1898 qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) { 1899 cleans.append(files); 1900 files.clear(); 1901 } 1902 files += file; 1903 } 1904 if(!files.isEmpty()) 1905 cleans.append(files); 1906 } 1907 } 1908 if(!cleans.isEmpty()) 1909 t << valGlue(cleans, "\n\t" + del_statement, "\n\t" + del_statement, ""); 1910 if(!wrote_clean_cmds) { 1911 for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { 1912 t << "\n\t" << replaceExtraCompilerVariables(tmp_clean_cmds, (*input), 1913 replaceExtraCompilerVariables(tmp_out, (*input), QString())); 1914 } 1915 } 1916 } 1917 t << endl; 1918 } 1919 if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) { 1920 if(tmp_out.indexOf("${QMAKE_") != -1) { 1921 warn_msg(WarnLogic, "QMAKE_EXTRA_COMPILERS(%s) with combine has variable output.", 1922 (*it).toLatin1().constData()); 1923 continue; 1924 } 1925 QStringList deps, inputs; 1926 if(!tmp_dep.isEmpty()) 1927 deps += fileFixify(tmp_dep, Option::output_dir, Option::output_dir); 1928 for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { 1929 deps += findDependencies((*input)); 1930 inputs += Option::fixPathToTargetOS((*input), false); 1931 if(!tmp_dep_cmd.isEmpty() && doDepends()) { 1932 char buff[256]; 1933 QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), 1934 tmp_out); 1935 dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); 1936 if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { 1937 QString indeps; 1938 while(!feof(proc)) { 1939 int read_in = (int)fread(buff, 1, 255, proc); 1940 if(!read_in) 1941 break; 1942 indeps += QByteArray(buff, read_in); 1943 } 1944 QT_PCLOSE(proc); 1945 if(!indeps.isEmpty()) { 1946 QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' '); 1947 for(int i = 0; i < dep_cmd_deps.count(); ++i) { 1948 QString &file = dep_cmd_deps[i]; 1949 if(!exists(file)) { 1950 QString localFile; 1951 QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); 1952 for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); 1953 it != depdirs.end(); ++it) { 1954 if(exists((*it).real() + Option::dir_sep + file)) { 1955 localFile = (*it).local() + Option::dir_sep + file; 1956 break; 1957 } 1958 } 1959 file = localFile; 1960 } 1961 if(!file.isEmpty()) 1962 file = fileFixify(file); 1963 } 1964 deps += dep_cmd_deps; 1965 } 1966 } 1967 } 1968 } 1969 for(int i = 0; i < inputs.size(); ) { 1970 if(tmp_out == inputs.at(i)) 1971 inputs.removeAt(i); 1972 else 1973 ++i; 1974 } 1975 for(int i = 0; i < deps.size(); ) { 1976 if(tmp_out == deps.at(i)) 1977 deps.removeAt(i); 1978 else 1979 ++i; 1980 } 1981 if (inputs.isEmpty()) 1982 continue; 1983 1984 QString cmd; 1985 if (isForSymbianSbsv2()) { 1986 // In sbsv2 the command inputs and outputs need to use absolute paths 1987 QStringList absoluteInputs; 1988 for (int i = 0; i < inputs.size(); ++i) 1989 absoluteInputs.append(escapeFilePath(outputDir.absoluteFilePath(inputs.at(i)))); 1990 cmd = replaceExtraCompilerVariables(tmp_cmd, absoluteInputs, 1991 QStringList(outputDir.absoluteFilePath(tmp_out))); 1992 } else { 1993 cmd = replaceExtraCompilerVariables(tmp_cmd, escapeFilePaths(inputs), QStringList(tmp_out)); 1994 } 1995 1996 t << escapeDependencyPath(tmp_out) << ":"; 1997 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(tmp_out); 1998 // compiler.CONFIG+=explicit_dependencies means that ONLY compiler.depends gets to cause Makefile dependencies 1999 if(project->values((*it) + ".CONFIG").indexOf("explicit_dependencies") != -1) { 2000 t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, Option::output_dir, Option::output_dir))); 2001 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << tmp_dep; 2002 } else { 2003 t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps)); 2004 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << inputs << deps; 2005 } 2006 t << "\n\t" << cmd << endl << endl; 2007 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(tmp_out)) << cmd; 2008 continue; 2009 } 2010 for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { 2011 QString in = Option::fixPathToTargetOS((*input), false); 2012 QStringList deps = findDependencies((*input)); 2013 deps += escapeDependencyPath(in); 2014 QString out = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); 2015 if(!tmp_dep.isEmpty()) { 2016 QStringList pre_deps = fileFixify(tmp_dep, Option::output_dir, Option::output_dir); 2017 for(int i = 0; i < pre_deps.size(); ++i) 2018 deps += replaceExtraCompilerVariables(pre_deps.at(i), (*input), out); 2019 } 2020 QString cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out); 2021 // NOTE: The var -> QMAKE_COMP_var replace feature is unsupported, do not use! 2022 if (isForSymbianSbsv2()) { 2023 // In sbsv2 the command inputs and outputs need to use absolute paths 2024 cmd = replaceExtraCompilerVariables(tmp_cmd, 2025 outputDir.absoluteFilePath(*input), 2026 outputDir.absoluteFilePath(out)); 2027 } else { 2028 cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out); 2029 } 2030 for(QStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3) 2031 cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")"); 2032 if(!tmp_dep_cmd.isEmpty() && doDepends()) { 2033 char buff[256]; 2034 QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), out); 2035 dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); 2036 if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { 2037 QString indeps; 2038 while(!feof(proc)) { 2039 int read_in = (int)fread(buff, 1, 255, proc); 2040 if(!read_in) 2041 break; 2042 indeps += QByteArray(buff, read_in); 2043 } 2044 QT_PCLOSE(proc); 2045 if(!indeps.isEmpty()) { 2046 QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' '); 2047 for(int i = 0; i < dep_cmd_deps.count(); ++i) { 2048 QString &file = dep_cmd_deps[i]; 2049 if(!exists(file)) { 2050 QString localFile; 2051 QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); 2052 for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); 2053 it != depdirs.end(); ++it) { 2054 if(exists((*it).real() + Option::dir_sep + file)) { 2055 localFile = (*it).local() + Option::dir_sep + file; 2056 break; 2057 } 2058 } 2059 file = localFile; 2060 } 2061 if(!file.isEmpty()) 2062 file = fileFixify(file); 2063 } 2064 deps += dep_cmd_deps; 2065 } 2066 } 2067 //use the depend system to find includes of these included files 2068 QStringList inc_deps; 2069 for(int i = 0; i < deps.size(); ++i) { 2070 const QString dep = deps.at(i); 2071 if(QFile::exists(dep)) { 2072 SourceFileType type = TYPE_UNKNOWN; 2073 if(type == TYPE_UNKNOWN) { 2074 for(QStringList::Iterator cit = Option::c_ext.begin(); 2075 cit != Option::c_ext.end(); ++cit) { 2076 if(dep.endsWith((*cit))) { 2077 type = TYPE_C; 2078 break; 2079 } 2080 } 2081 } 2082 if(type == TYPE_UNKNOWN) { 2083 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); 2084 cppit != Option::cpp_ext.end(); ++cppit) { 2085 if(dep.endsWith((*cppit))) { 2086 type = TYPE_C; 2087 break; 2088 } 2089 } 2090 } 2091 if(type == TYPE_UNKNOWN) { 2092 for(QStringList::Iterator hit = Option::h_ext.begin(); 2093 type == TYPE_UNKNOWN && hit != Option::h_ext.end(); ++hit) { 2094 if(dep.endsWith((*hit))) { 2095 type = TYPE_C; 2096 break; 2097 } 2098 } 2099 } 2100 if(type != TYPE_UNKNOWN) { 2101 if(!QMakeSourceFileInfo::containsSourceFile(dep, type)) 2102 QMakeSourceFileInfo::addSourceFile(dep, type); 2103 inc_deps += QMakeSourceFileInfo::dependencies(dep); 2104 } 2105 } 2106 } 2107 deps += inc_deps; 2108 } 2109 for(int i = 0; i < deps.size(); ) { 2110 QString &dep = deps[i]; 2111 dep = Option::fixPathToTargetOS(unescapeFilePath(dep), false); 2112 if(out == dep) 2113 deps.removeAt(i); 2114 else 2115 ++i; 2116 } 2117 t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t" 2118 << cmd << endl << endl; 2119 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(out); 2120 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(out)) << deps; 2121 project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(out)) << cmd; 2122 } 2123 } 2124 t << "compiler_clean: " << clean_targets << endl << endl; 2125} 2126 2127void 2128MakefileGenerator::writeExtraCompilerVariables(QTextStream &t) 2129{ 2130 bool first = true; 2131 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); 2132 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { 2133 const QStringList &vars = project->values((*it) + ".variables"); 2134 for(QStringList::ConstIterator varit = vars.begin(); varit != vars.end(); ++varit) { 2135 if(first) { 2136 t << "\n####### Custom Compiler Variables" << endl; 2137 first = false; 2138 } 2139 t << "QMAKE_COMP_" << (*varit) << " = " 2140 << valList(project->values((*varit))) << endl; 2141 } 2142 } 2143 if(!first) 2144 t << endl; 2145} 2146 2147void 2148MakefileGenerator::writeExtraVariables(QTextStream &t) 2149{ 2150 bool first = true; 2151 QMap<QString, QStringList> &vars = project->variables(); 2152 QStringList &exports = project->values("QMAKE_EXTRA_VARIABLES"); 2153 for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) { 2154 for(QStringList::Iterator exp_it = exports.begin(); exp_it != exports.end(); ++exp_it) { 2155 QRegExp rx((*exp_it), Qt::CaseInsensitive, QRegExp::Wildcard); 2156 if(rx.exactMatch(it.key())) { 2157 if(first) { 2158 t << "\n####### Custom Variables" << endl; 2159 first = false; 2160 } 2161 t << "EXPORT_" << it.key() << " = " << it.value().join(" ") << endl; 2162 } 2163 } 2164 } 2165 if(!first) 2166 t << endl; 2167} 2168 2169bool 2170MakefileGenerator::writeStubMakefile(QTextStream &t) 2171{ 2172 t << "QMAKE = " << var("QMAKE_QMAKE") << endl; 2173 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); 2174 for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it) 2175 t << *it << " "; 2176 //const QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); 2177 t << "first all clean install distclean uninstall: " << "qmake" << endl 2178 << "qmake_all:" << endl; 2179 writeMakeQmake(t); 2180 if(project->isEmpty("QMAKE_NOFORCE")) 2181 t << "FORCE:" << endl << endl; 2182 return true; 2183} 2184 2185bool 2186MakefileGenerator::writeMakefile(QTextStream &t) 2187{ 2188 t << "####### Compile" << endl << endl; 2189 writeObj(t, "SOURCES"); 2190 writeObj(t, "GENERATED_SOURCES"); 2191 2192 t << "####### Install" << endl << endl; 2193 writeInstalls(t, "INSTALLS"); 2194 2195 if(project->isEmpty("QMAKE_NOFORCE")) 2196 t << "FORCE:" << endl << endl; 2197 return true; 2198} 2199 2200QString MakefileGenerator::buildArgs(const QString &outdir) 2201{ 2202 QString ret; 2203 //special variables 2204 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) 2205 ret += " QMAKE_ABSOLUTE_SOURCE_PATH=" + escapeFilePath(project->first("QMAKE_ABSOLUTE_SOURCE_PATH")); 2206 2207 //warnings 2208 else if(Option::warn_level == WarnNone) 2209 ret += " -Wnone"; 2210 else if(Option::warn_level == WarnAll) 2211 ret += " -Wall"; 2212 else if(Option::warn_level & WarnParser) 2213 ret += " -Wparser"; 2214 //other options 2215 if(!Option::user_template.isEmpty()) 2216 ret += " -t " + Option::user_template; 2217 if(!Option::user_template_prefix.isEmpty()) 2218 ret += " -tp " + Option::user_template_prefix; 2219 if(!Option::mkfile::do_cache) 2220 ret += " -nocache"; 2221 if(!Option::mkfile::do_deps) 2222 ret += " -nodepend"; 2223 if(!Option::mkfile::do_dep_heuristics) 2224 ret += " -nodependheuristics"; 2225 if(!Option::mkfile::qmakespec_commandline.isEmpty()) 2226 ret += " -spec " + specdir(outdir); 2227 if (Option::target_mode_overridden) { 2228 if (Option::target_mode == Option::TARG_MACX_MODE) 2229 ret += " -macx"; 2230 else if (Option::target_mode == Option::TARG_UNIX_MODE) 2231 ret += " -unix"; 2232 else if (Option::target_mode == Option::TARG_WIN_MODE) 2233 ret += " -win32"; 2234 } 2235 2236 //configs 2237 for(QStringList::Iterator it = Option::user_configs.begin(); 2238 it != Option::user_configs.end(); ++it) 2239 ret += " -config " + (*it); 2240 //arguments 2241 for(QStringList::Iterator it = Option::before_user_vars.begin(); 2242 it != Option::before_user_vars.end(); ++it) { 2243 if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH") 2244 ret += " " + escapeFilePath((*it)); 2245 } 2246 if(Option::after_user_vars.count()) { 2247 ret += " -after "; 2248 for(QStringList::Iterator it = Option::after_user_vars.begin(); 2249 it != Option::after_user_vars.end(); ++it) { 2250 if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH") 2251 ret += " " + escapeFilePath((*it)); 2252 } 2253 } 2254 return ret; 2255} 2256 2257//could get stored argv, but then it would have more options than are 2258//probably necesary this will try to guess the bare minimum.. 2259QString MakefileGenerator::build_args(const QString &outdir) 2260{ 2261 QString ret = "$(QMAKE)"; 2262 2263 // general options and arguments 2264 ret += buildArgs(outdir); 2265 2266 //output 2267 QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); 2268 if(!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE")) 2269 ret += " -o " + escapeFilePath(ofile); 2270 2271 //inputs 2272 ret += " " + escapeFilePath(fileFixify(project->projectFile(), outdir)); 2273 2274 return ret; 2275} 2276 2277void 2278MakefileGenerator::writeHeader(QTextStream &t) 2279{ 2280 t << "#############################################################################" << endl; 2281 t << "# Makefile for building: " << escapeFilePath(var("TARGET")) << endl; 2282 t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: "; 2283 t << QDateTime::currentDateTime().toString() << endl; 2284 t << "# Project: " << fileFixify(project->projectFile()) << endl; 2285 t << "# Template: " << var("TEMPLATE") << endl; 2286 if(!project->isActiveConfig("build_pass")) 2287 t << "# Command: " << build_args().replace("$(QMAKE)", var("QMAKE_QMAKE")) << endl; 2288 t << "#############################################################################" << endl; 2289 t << endl; 2290} 2291 2292QList<MakefileGenerator::SubTarget*> 2293MakefileGenerator::findSubDirsSubTargets() const 2294{ 2295 QList<SubTarget*> targets; 2296 { 2297 const QStringList subdirs = project->values("SUBDIRS"); 2298 for(int subdir = 0; subdir < subdirs.size(); ++subdir) { 2299 QString fixedSubdir = subdirs[subdir]; 2300 fixedSubdir = fixedSubdir.replace(QRegExp("[^a-zA-Z0-9_]"),"-"); 2301 2302 SubTarget *st = new SubTarget; 2303 st->name = subdirs[subdir]; 2304 targets.append(st); 2305 2306 bool fromFile = false; 2307 QString file = subdirs[subdir]; 2308 if(!project->isEmpty(fixedSubdir + ".file")) { 2309 if(!project->isEmpty(fixedSubdir + ".subdir")) 2310 warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s", 2311 subdirs[subdir].toLatin1().constData()); 2312 file = project->first(fixedSubdir + ".file"); 2313 fromFile = true; 2314 } else if(!project->isEmpty(fixedSubdir + ".subdir")) { 2315 file = project->first(fixedSubdir + ".subdir"); 2316 fromFile = false; 2317 } else { 2318 fromFile = file.endsWith(Option::pro_ext); 2319 } 2320 file = Option::fixPathToTargetOS(file); 2321 2322 if(fromFile) { 2323 int slsh = file.lastIndexOf(Option::dir_sep); 2324 if(slsh != -1) { 2325 st->in_directory = file.left(slsh+1); 2326 st->profile = file.mid(slsh+1); 2327 } else { 2328 st->profile = file; 2329 } 2330 } else { 2331 if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro")) 2332 st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext; 2333 st->in_directory = file; 2334 } 2335 while(st->in_directory.endsWith(Option::dir_sep)) 2336 st->in_directory.chop(1); 2337 if(fileInfo(st->in_directory).isRelative()) 2338 st->out_directory = st->in_directory; 2339 else 2340 st->out_directory = fileFixify(st->in_directory, qmake_getpwd(), Option::output_dir); 2341 if(!project->isEmpty(fixedSubdir + ".makefile")) { 2342 st->makefile = project->first(fixedSubdir + ".makefile"); 2343 } else { 2344 st->makefile = "$(MAKEFILE)"; 2345 if(!st->profile.isEmpty()) { 2346 QString basename = st->in_directory; 2347 int new_slsh = basename.lastIndexOf(Option::dir_sep); 2348 if(new_slsh != -1) 2349 basename = basename.mid(new_slsh+1); 2350 if(st->profile != basename + Option::pro_ext) 2351 st->makefile += "." + st->profile.left(st->profile.length() - Option::pro_ext.length()); 2352 } 2353 } 2354 if(!project->isEmpty(fixedSubdir + ".depends")) { 2355 const QStringList depends = project->values(fixedSubdir + ".depends"); 2356 for(int depend = 0; depend < depends.size(); ++depend) { 2357 bool found = false; 2358 for(int subDep = 0; subDep < subdirs.size(); ++subDep) { 2359 if(subdirs[subDep] == depends.at(depend)) { 2360 QString fixedSubDep = subdirs[subDep]; 2361 fixedSubDep = fixedSubDep.replace(QRegExp("[^a-zA-Z0-9_]"),"-"); 2362 if(!project->isEmpty(fixedSubDep + ".target")) { 2363 st->depends += project->first(fixedSubDep + ".target"); 2364 } else { 2365 QString d = Option::fixPathToLocalOS(subdirs[subDep]); 2366 if(!project->isEmpty(fixedSubDep + ".file")) 2367 d = project->first(fixedSubDep + ".file"); 2368 else if(!project->isEmpty(fixedSubDep + ".subdir")) 2369 d = project->first(fixedSubDep + ".subdir"); 2370 st->depends += "sub-" + d.replace(QRegExp("[^a-zA-Z0-9_]"),"-"); 2371 } 2372 found = true; 2373 break; 2374 } 2375 } 2376 if(!found) { 2377 QString depend_str = depends.at(depend); 2378 st->depends += depend_str.replace(QRegExp("[^a-zA-Z0-9_]"),"-"); 2379 } 2380 } 2381 } 2382 if(!project->isEmpty(fixedSubdir + ".target")) { 2383 st->target = project->first(fixedSubdir + ".target"); 2384 } else { 2385 st->target = "sub-" + file; 2386 st->target = st->target.replace(QRegExp("[^a-zA-Z0-9_]"),"-"); 2387 } 2388 } 2389 } 2390 return targets; 2391} 2392 2393void 2394MakefileGenerator::writeSubDirs(QTextStream &t) 2395{ 2396 QList<SubTarget*> targets = findSubDirsSubTargets(); 2397 t << "first: make_default" << endl; 2398 int flags = SubTargetInstalls; 2399 if(project->isActiveConfig("ordered")) 2400 flags |= SubTargetOrdered; 2401 writeSubTargets(t, targets, flags); 2402 qDeleteAll(targets); 2403} 2404 2405void MakefileGenerator::writeSubMakeCall(QTextStream &t, const QString &callPrefix, 2406 const QString &makeArguments, const QString &callPostfix) 2407{ 2408 t << callPrefix 2409 << "$(MAKE)" << makeArguments 2410 << callPostfix << endl; 2411} 2412 2413void 2414MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags) 2415{ 2416 // blasted includes 2417 QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES"); 2418 for(QStringList::Iterator qeui_it = qeui.begin(); qeui_it != qeui.end(); ++qeui_it) 2419 t << "include " << (*qeui_it) << endl; 2420 2421 if (!(flags & SubTargetSkipDefaultVariables)) { 2422 QString ofile = Option::fixPathToTargetOS(Option::output.fileName()); 2423 if(ofile.lastIndexOf(Option::dir_sep) != -1) 2424 ofile.remove(0, ofile.lastIndexOf(Option::dir_sep) +1); 2425 t << "MAKEFILE = " << ofile << endl; 2426 /* Calling Option::fixPathToTargetOS() is necessary for MinGW/MSYS, which requires 2427 * back-slashes to be turned into slashes. */ 2428 t << "QMAKE = " << var("QMAKE_QMAKE") << endl; 2429 t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl; 2430 t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl; 2431 t << "MKDIR = " << var("QMAKE_MKDIR") << endl; 2432 t << "COPY = " << var("QMAKE_COPY") << endl; 2433 t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl; 2434 t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl; 2435 t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl; 2436 t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl; 2437 t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl; 2438 t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl; 2439 t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl; 2440 t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl; 2441 t << "MOVE = " << var("QMAKE_MOVE") << endl; 2442 t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl; 2443 t << "MKDIR = " << var("QMAKE_MKDIR") << endl; 2444 t << "SUBTARGETS = "; // subtargets are sub-directory 2445 for(int target = 0; target < targets.size(); ++target) 2446 t << " \\\n\t\t" << targets.at(target)->target; 2447 t << endl << endl; 2448 } 2449 writeExtraVariables(t); 2450 2451 QStringList targetSuffixes; 2452 const QString abs_source_path = project->first("QMAKE_ABSOLUTE_SOURCE_PATH"); 2453 if (!(flags & SubTargetSkipDefaultTargets)) { 2454 targetSuffixes << "make_default" << "make_first" << "all" << "clean" << "distclean" 2455 << QString((flags & SubTargetInstalls) ? "install_subtargets" : "install") 2456 << QString((flags & SubTargetInstalls) ? "uninstall_subtargets" : "uninstall"); 2457 } 2458 2459 // generate target rules 2460 for(int target = 0; target < targets.size(); ++target) { 2461 SubTarget *subtarget = targets.at(target); 2462 QString in_directory = subtarget->in_directory; 2463 if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep)) 2464 in_directory += Option::dir_sep; 2465 QString out_directory = subtarget->out_directory; 2466 if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) 2467 out_directory += Option::dir_sep; 2468 if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) 2469 out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); 2470 2471 QString mkfile = subtarget->makefile; 2472 if(!in_directory.isEmpty()) 2473 mkfile.prepend(out_directory); 2474 2475 QString in_directory_cdin, in_directory_cdout, out_directory_cdin, out_directory_cdout; 2476#define MAKE_CD_IN_AND_OUT(directory) \ 2477 if(!directory.isEmpty()) { \ 2478 if(project->isActiveConfig("cd_change_global")) { \ 2479 directory ## _cdin = "\n\tcd " + directory + "\n\t"; \ 2480 QDir pwd(Option::output_dir); \ 2481 QStringList in = directory.split(Option::dir_sep), out; \ 2482 for(int i = 0; i < in.size(); i++) { \ 2483 if(in.at(i) == "..") \ 2484 out.prepend(fileInfo(pwd.path()).fileName()); \ 2485 else if(in.at(i) != ".") \ 2486 out.prepend(".."); \ 2487 pwd.cd(in.at(i)); \ 2488 } \ 2489 directory ## _cdout = "\n\t@cd " + out.join(Option::dir_sep); \ 2490 } else { \ 2491 directory ## _cdin = "\n\tcd " + directory + " && "; \ 2492 } \ 2493 } else { \ 2494 directory ## _cdin = "\n\t"; \ 2495 } 2496 MAKE_CD_IN_AND_OUT(in_directory); 2497 MAKE_CD_IN_AND_OUT(out_directory); 2498 2499 //qmake it 2500 if(!subtarget->profile.isEmpty()) { 2501 QString out = subtarget->makefile; 2502 QString in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute)); 2503 if(out.startsWith(in_directory)) 2504 out = out.mid(in_directory.length()); 2505 t << mkfile << ": " << "\n\t"; 2506 if(!in_directory.isEmpty()) { 2507 t << mkdir_p_asstring(out_directory) 2508 << out_directory_cdin 2509 << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out 2510 << in_directory_cdout << endl; 2511 } else { 2512 t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl; 2513 } 2514 t << subtarget->target << "-qmake_all: "; 2515 if(project->isEmpty("QMAKE_NOFORCE")) 2516 t << " FORCE"; 2517 t << "\n\t"; 2518 if(!in_directory.isEmpty()) { 2519 t << mkdir_p_asstring(out_directory) 2520 << out_directory_cdin 2521 << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out 2522 << in_directory_cdout << endl; 2523 } else { 2524 t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl; 2525 } 2526 } 2527 2528 QString makefilein = " -f " + subtarget->makefile; 2529 2530 { //actually compile 2531 t << subtarget->target << ": " << mkfile; 2532 if(!subtarget->depends.isEmpty()) 2533 t << " " << valList(subtarget->depends); 2534 if(project->isEmpty("QMAKE_NOFORCE")) 2535 t << " FORCE"; 2536 writeSubMakeCall(t, out_directory_cdin, makefilein, out_directory_cdout); 2537 } 2538 2539 for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) { 2540 QString s = targetSuffixes.at(suffix); 2541 if(s == "install_subtargets") 2542 s = "install"; 2543 else if(s == "uninstall_subtargets") 2544 s = "uninstall"; 2545 else if(s == "make_first") 2546 s = "first"; 2547 else if(s == "make_default") 2548 s = QString(); 2549 2550 if(flags & SubTargetOrdered) { 2551 t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered: " << mkfile; 2552 if(target) 2553 t << " " << targets.at(target-1)->target << "-" << targetSuffixes.at(suffix) << "-ordered "; 2554 if(project->isEmpty("QMAKE_NOFORCE")) 2555 t << " FORCE"; 2556 writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout); 2557 } 2558 t << subtarget->target << "-" << targetSuffixes.at(suffix) << ": " << mkfile; 2559 if(!subtarget->depends.isEmpty()) 2560 t << " " << valGlue(subtarget->depends, QString(), "-" + targetSuffixes.at(suffix) + " ", 2561 "-"+targetSuffixes.at(suffix)); 2562 if(project->isEmpty("QMAKE_NOFORCE")) 2563 t << " FORCE"; 2564 writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout); 2565 } 2566 } 2567 t << endl; 2568 2569 if (!(flags & SubTargetSkipDefaultTargets)) { 2570 if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1) 2571 project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all"); 2572 2573 writeMakeQmake(t); 2574 2575 t << "qmake_all:"; 2576 if(!targets.isEmpty()) { 2577 for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) { 2578 if(!(*it)->profile.isEmpty()) 2579 t << " " << (*it)->target << "-" << "qmake_all"; 2580 } 2581 } 2582 if(project->isEmpty("QMAKE_NOFORCE")) 2583 t << " FORCE"; 2584 if(project->isActiveConfig("no_empty_targets")) 2585 t << "\n\t" << "@cd ."; 2586 t << endl << endl; 2587 } 2588 2589 for(int s = 0; s < targetSuffixes.size(); ++s) { 2590 QString suffix = targetSuffixes.at(s); 2591 if(!(flags & SubTargetInstalls) && suffix.endsWith("install")) 2592 continue; 2593 2594 t << suffix << ":"; 2595 for(int target = 0; target < targets.size(); ++target) { 2596 SubTarget *subTarget = targets.at(target); 2597 if((suffix == "make_first" || suffix == "make_default") 2598 && project->values(subTarget->name + ".CONFIG").indexOf("no_default_target") != -1) { 2599 continue; 2600 } 2601 QString targetRule = subTarget->target + "-" + suffix; 2602 if(flags & SubTargetOrdered) 2603 targetRule += "-ordered"; 2604 t << " " << targetRule; 2605 } 2606 if(suffix == "all" || suffix == "make_first") 2607 t << varGlue("ALL_DEPS"," "," ",""); 2608 if(suffix == "clean") 2609 t << varGlue("CLEAN_DEPS"," "," ",""); 2610 if(project->isEmpty("QMAKE_NOFORCE")) 2611 t << " FORCE"; 2612 t << endl; 2613 if(suffix == "clean") { 2614 t << varGlue("QMAKE_CLEAN","\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ", "\n"); 2615 } else if(suffix == "distclean") { 2616 QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); 2617 if(!ofile.isEmpty()) 2618 t << "\t-$(DEL_FILE) " << ofile << endl; 2619 t << varGlue("QMAKE_DISTCLEAN","\t-$(DEL_FILE) "," ","\n"); 2620 } else if(project->isActiveConfig("no_empty_targets")) { 2621 t << "\t" << "@cd ." << endl; 2622 } 2623 } 2624 2625 // user defined targets 2626 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); 2627 for(QStringList::Iterator qut_it = qut.begin(); qut_it != qut.end(); ++qut_it) { 2628 QString targ = var((*qut_it) + ".target"), 2629 cmd = var((*qut_it) + ".commands"), deps; 2630 if(targ.isEmpty()) 2631 targ = (*qut_it); 2632 t << endl; 2633 2634 QStringList &deplist = project->values((*qut_it) + ".depends"); 2635 for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) { 2636 QString dep = var((*dep_it) + ".target"); 2637 if(dep.isEmpty()) 2638 dep = Option::fixPathToTargetOS(*dep_it, false); 2639 deps += " " + dep; 2640 } 2641 if(project->values((*qut_it) + ".CONFIG").indexOf("recursive") != -1) { 2642 QSet<QString> recurse; 2643 if(project->isSet((*qut_it) + ".recurse")) { 2644 recurse = project->values((*qut_it) + ".recurse").toSet(); 2645 } else { 2646 for(int target = 0; target < targets.size(); ++target) 2647 recurse.insert(targets.at(target)->name); 2648 } 2649 for(int target = 0; target < targets.size(); ++target) { 2650 SubTarget *subtarget = targets.at(target); 2651 QString in_directory = subtarget->in_directory; 2652 if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep)) 2653 in_directory += Option::dir_sep; 2654 QString out_directory = subtarget->out_directory; 2655 if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) 2656 out_directory += Option::dir_sep; 2657 if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) 2658 out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); 2659 2660 if(!recurse.contains(subtarget->name)) 2661 continue; 2662 QString mkfile = subtarget->makefile; 2663 if(!in_directory.isEmpty()) { 2664 if(!out_directory.endsWith(Option::dir_sep)) 2665 mkfile.prepend(out_directory + Option::dir_sep); 2666 else 2667 mkfile.prepend(out_directory); 2668 } 2669 QString out_directory_cdin, out_directory_cdout; 2670 MAKE_CD_IN_AND_OUT(out_directory); 2671 2672 QString makefilein = " -f " + subtarget->makefile; 2673 2674 //write the rule/depends 2675 if(flags & SubTargetOrdered) { 2676 const QString dep = subtarget->target + "-" + (*qut_it) + "_ordered"; 2677 t << dep << ": " << mkfile; 2678 if(target) 2679 t << " " << targets.at(target-1)->target << "-" << (*qut_it) << "_ordered "; 2680 deps += " " + dep; 2681 } else { 2682 const QString dep = subtarget->target + "-" + (*qut_it); 2683 t << dep << ": " << mkfile; 2684 if(!subtarget->depends.isEmpty()) 2685 t << " " << valGlue(subtarget->depends, QString(), "-" + (*qut_it) + " ", "-" + (*qut_it)); 2686 deps += " " + dep; 2687 } 2688 2689 QString sub_targ = targ; 2690 if(project->isSet((*qut_it) + ".recurse_target")) 2691 sub_targ = project->first((*qut_it) + ".recurse_target"); 2692 2693 //write the commands 2694 if(!out_directory.isEmpty()) { 2695 writeSubMakeCall(t, out_directory_cdin, makefilein + " " + sub_targ, 2696 out_directory_cdout); 2697 } else { 2698 writeSubMakeCall(t, "\n\t", makefilein + " " + sub_targ, QString()); 2699 } 2700 } 2701 } 2702 if(project->isEmpty("QMAKE_NOFORCE") && 2703 project->values((*qut_it) + ".CONFIG").indexOf("phony") != -1) 2704 deps += " FORCE"; 2705 t << targ << ":" << deps << "\n"; 2706 if(!cmd.isEmpty()) 2707 t << "\t" << cmd << endl; 2708 } 2709 2710 if(flags & SubTargetInstalls) { 2711 project->values("INSTALLDEPS") += "install_subtargets"; 2712 project->values("UNINSTALLDEPS") += "uninstall_subtargets"; 2713 writeInstalls(t, "INSTALLS", true); 2714 } 2715 2716 if(project->isEmpty("QMAKE_NOFORCE")) 2717 t << "FORCE:" << endl << endl; 2718} 2719 2720void 2721MakefileGenerator::writeMakeQmake(QTextStream &t) 2722{ 2723 QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); 2724 if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) { 2725 QStringList files = fileFixify(Option::mkfile::project_files); 2726 t << escapeDependencyPath(project->first("QMAKE_INTERNAL_PRL_FILE")) << ": " << "\n\t" 2727 << "@$(QMAKE) -prl " << buildArgs() << " " << files.join(" ") << endl; 2728 } 2729 2730 QString pfile = project->projectFile(); 2731 if(pfile != "(stdin)") { 2732 QString qmake = build_args(); 2733 if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) { 2734 t << escapeFilePath(ofile) << ": " << escapeDependencyPath(fileFixify(pfile)) << " "; 2735 if(Option::mkfile::do_cache) 2736 t << escapeDependencyPath(fileFixify(Option::mkfile::cachefile)) << " "; 2737 if(!specdir().isEmpty()) { 2738 if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf"))) 2739 t << escapeDependencyPath(specdir() + Option::dir_sep + "qmake.conf") << " "; 2740 } 2741 const QStringList &included = project->values("QMAKE_INTERNAL_INCLUDED_FILES"); 2742 t << escapeDependencyPaths(included).join(" \\\n\t\t") << "\n\t" 2743 << qmake << endl; 2744 for(int include = 0; include < included.size(); ++include) { 2745 const QString i(included.at(include)); 2746 if(!i.isEmpty()) 2747 t << i << ":" << endl; 2748 } 2749 } 2750 if(project->first("QMAKE_ORIG_TARGET") != "qmake") { 2751 t << "qmake: " << 2752 project->values("QMAKE_INTERNAL_QMAKE_DEPS").join(" \\\n\t\t"); 2753 if(project->isEmpty("QMAKE_NOFORCE")) 2754 t << " FORCE"; 2755 t << "\n\t" << "@" << qmake << endl << endl; 2756 } 2757 } 2758} 2759 2760QFileInfo 2761MakefileGenerator::fileInfo(QString file) const 2762{ 2763 static QHash<FileInfoCacheKey, QFileInfo> *cache = 0; 2764 static QFileInfo noInfo = QFileInfo(); 2765 if(!cache) { 2766 cache = new QHash<FileInfoCacheKey, QFileInfo>; 2767 qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FileInfoCacheKey, QFileInfo> >, (void**)&cache); 2768 } 2769 FileInfoCacheKey cacheKey(file); 2770 QFileInfo value = cache->value(cacheKey, noInfo); 2771 if (value != noInfo) 2772 return value; 2773 2774 QFileInfo fi(file); 2775 if (fi.exists()) 2776 cache->insert(cacheKey, fi); 2777 return fi; 2778} 2779 2780QString 2781MakefileGenerator::unescapeFilePath(const QString &path) const 2782{ 2783 QString ret = path; 2784 if(!ret.isEmpty()) { 2785 if(ret.contains(QLatin1String("\\ "))) 2786 ret.replace(QLatin1String("\\ "), QLatin1String(" ")); 2787 if(ret.contains(QLatin1Char('\"'))) 2788 ret.remove(QLatin1Char('\"')); 2789 } 2790 return ret; 2791} 2792 2793QStringList 2794MakefileGenerator::escapeFilePaths(const QStringList &paths) const 2795{ 2796 QStringList ret; 2797 for(int i = 0; i < paths.size(); ++i) 2798 ret.append(escapeFilePath(paths.at(i))); 2799 return ret; 2800} 2801 2802QStringList 2803MakefileGenerator::escapeDependencyPaths(const QStringList &paths) const 2804{ 2805 QStringList ret; 2806 for(int i = 0; i < paths.size(); ++i) 2807 ret.append(escapeDependencyPath(paths.at(i))); 2808 return ret; 2809} 2810 2811QStringList 2812MakefileGenerator::unescapeFilePaths(const QStringList &paths) const 2813{ 2814 QStringList ret; 2815 for(int i = 0; i < paths.size(); ++i) 2816 ret.append(unescapeFilePath(paths.at(i))); 2817 return ret; 2818} 2819 2820QStringList 2821MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir, 2822 FileFixifyType fix, bool canon) const 2823{ 2824 if(files.isEmpty()) 2825 return files; 2826 QStringList ret; 2827 for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) { 2828 if(!(*it).isEmpty()) 2829 ret << fileFixify((*it), out_dir, in_dir, fix, canon); 2830 } 2831 return ret; 2832} 2833 2834QString 2835MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const QString &in_d, 2836 FileFixifyType fix, bool canon) const 2837{ 2838 if(file.isEmpty()) 2839 return file; 2840 QString ret = unescapeFilePath(file); 2841 2842 //do the fixin' 2843 QString orig_file = ret; 2844 if(ret.startsWith(QLatin1Char('~'))) { 2845 if(ret.startsWith(QLatin1String("~/"))) 2846 ret = QDir::homePath() + ret.mid(1); 2847 else 2848 warn_msg(WarnLogic, "Unable to expand ~ in %s", ret.toLatin1().constData()); 2849 } 2850 if(fix == FileFixifyAbsolute || (fix == FileFixifyDefault && project->isActiveConfig("no_fixpath"))) { 2851 if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) { //already absolute 2852 QString pwd = qmake_getpwd(); 2853 if (!pwd.endsWith(QLatin1Char('/'))) 2854 pwd += QLatin1Char('/'); 2855 ret.prepend(pwd); 2856 } 2857 ret = Option::fixPathToTargetOS(ret, false, canon); 2858 } else { //fix it.. 2859 QString out_dir = QDir(Option::output_dir).absoluteFilePath(out_d); 2860 QString in_dir = QDir(qmake_getpwd()).absoluteFilePath(in_d); 2861 { 2862 QFileInfo in_fi(fileInfo(in_dir)); 2863 if(in_fi.exists()) 2864 in_dir = in_fi.canonicalFilePath(); 2865 QFileInfo out_fi(fileInfo(out_dir)); 2866 if(out_fi.exists()) 2867 out_dir = out_fi.canonicalFilePath(); 2868 } 2869 2870 QString qfile(Option::fixPathToLocalOS(ret, true, canon)); 2871 QFileInfo qfileinfo(fileInfo(qfile)); 2872 if(out_dir != in_dir || !qfileinfo.isRelative()) { 2873 if(qfileinfo.isRelative()) { 2874 ret = in_dir + "/" + qfile; 2875 qfileinfo.setFile(ret); 2876 } 2877 ret = Option::fixPathToTargetOS(ret, false, canon); 2878 if(canon && qfileinfo.exists() && 2879 file == Option::fixPathToTargetOS(ret, true, canon)) 2880 ret = Option::fixPathToTargetOS(qfileinfo.canonicalFilePath()); 2881 QString match_dir = Option::fixPathToTargetOS(out_dir, false, canon); 2882 if(ret == match_dir) { 2883 ret = ""; 2884 } else if(ret.startsWith(match_dir + Option::dir_sep)) { 2885 ret = ret.mid(match_dir.length() + Option::dir_sep.length()); 2886 } else { 2887 //figure out the depth 2888 int depth = 4; 2889 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || 2890 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { 2891 if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH")) 2892 depth = project->first("QMAKE_PROJECT_DEPTH").toInt(); 2893 else if(Option::mkfile::cachefile_depth != -1) 2894 depth = Option::mkfile::cachefile_depth; 2895 } 2896 //calculate how much can be removed 2897 QString dot_prefix; 2898 for(int i = 1; i <= depth; i++) { 2899 int sl = match_dir.lastIndexOf(Option::dir_sep); 2900 if(sl == -1) 2901 break; 2902 match_dir = match_dir.left(sl); 2903 if(match_dir.isEmpty()) 2904 break; 2905 if(ret.startsWith(match_dir + Option::dir_sep)) { 2906 //concat 2907 int remlen = ret.length() - (match_dir.length() + 1); 2908 if(remlen < 0) 2909 remlen = 0; 2910 ret = ret.right(remlen); 2911 //prepend 2912 for(int o = 0; o < i; o++) 2913 dot_prefix += ".." + Option::dir_sep; 2914 break; 2915 } 2916 } 2917 ret.prepend(dot_prefix); 2918 } 2919 } else { 2920 ret = Option::fixPathToTargetOS(ret, false, canon); 2921 } 2922 } 2923 if(ret.isEmpty()) 2924 ret = "."; 2925 debug_msg(3, "Fixed[%d,%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, canon, orig_file.toLatin1().constData(), 2926 ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(), 2927 qmake_getpwd().toLatin1().constData(), Option::output_dir.toLatin1().constData()); 2928 return ret; 2929} 2930 2931void 2932MakefileGenerator::checkMultipleDefinition(const QString &f, const QString &w) 2933{ 2934 if(!(Option::warn_level & WarnLogic)) 2935 return; 2936 QString file = f; 2937 int slsh = f.lastIndexOf(Option::dir_sep); 2938 if(slsh != -1) 2939 file.remove(0, slsh + 1); 2940 QStringList &l = project->values(w); 2941 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { 2942 QString file2((*val_it)); 2943 slsh = file2.lastIndexOf(Option::dir_sep); 2944 if(slsh != -1) 2945 file2.remove(0, slsh + 1); 2946 if(file2 == file) { 2947 warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s", 2948 file.toLatin1().constData(), (*val_it).toLatin1().constData(), w.toLatin1().constData()); 2949 break; 2950 } 2951 } 2952} 2953 2954QMakeLocalFileName 2955MakefileGenerator::fixPathForFile(const QMakeLocalFileName &file, bool forOpen) 2956{ 2957 if(forOpen) 2958 return QMakeLocalFileName(fileFixify(file.real(), qmake_getpwd(), Option::output_dir)); 2959 return QMakeLocalFileName(fileFixify(file.real())); 2960} 2961 2962QFileInfo 2963MakefileGenerator::findFileInfo(const QMakeLocalFileName &file) 2964{ 2965 return fileInfo(file.local()); 2966} 2967 2968QMakeLocalFileName 2969MakefileGenerator::findFileForDep(const QMakeLocalFileName &dep, const QMakeLocalFileName &file) 2970{ 2971 QMakeLocalFileName ret; 2972 if(!project->isEmpty("SKIP_DEPENDS")) { 2973 bool found = false; 2974 QStringList &nodeplist = project->values("SKIP_DEPENDS"); 2975 for(QStringList::Iterator it = nodeplist.begin(); 2976 it != nodeplist.end(); ++it) { 2977 QRegExp regx((*it)); 2978 if(regx.indexIn(dep.local()) != -1) { 2979 found = true; 2980 break; 2981 } 2982 } 2983 if(found) 2984 return ret; 2985 } 2986 2987 ret = QMakeSourceFileInfo::findFileForDep(dep, file); 2988 if(!ret.isNull()) 2989 return ret; 2990 2991 //these are some "hacky" heuristics it will try to do on an include 2992 //however these can be turned off at runtime, I'm not sure how 2993 //reliable these will be, most likely when problems arise turn it off 2994 //and see if they go away.. 2995 if(Option::mkfile::do_dep_heuristics) { 2996 if(depHeuristicsCache.contains(dep.real())) 2997 return depHeuristicsCache[dep.real()]; 2998 2999 if(Option::output_dir != qmake_getpwd() 3000 && QDir::isRelativePath(dep.real())) { //is it from the shadow tree 3001 QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); 3002 depdirs.prepend(fileInfo(file.real()).absoluteDir().path()); 3003 QString pwd = qmake_getpwd(); 3004 if(pwd.at(pwd.length()-1) != '/') 3005 pwd += '/'; 3006 for(int i = 0; i < depdirs.count(); i++) { 3007 QString dir = depdirs.at(i).real(); 3008 if(!QDir::isRelativePath(dir) && dir.startsWith(pwd)) 3009 dir = dir.mid(pwd.length()); 3010 if(QDir::isRelativePath(dir)) { 3011 if(!dir.endsWith(Option::dir_sep)) 3012 dir += Option::dir_sep; 3013 QString shadow = fileFixify(dir + dep.local(), pwd, Option::output_dir); 3014 if(exists(shadow)) { 3015 ret = QMakeLocalFileName(shadow); 3016 goto found_dep_from_heuristic; 3017 } 3018 } 3019 } 3020 } 3021 { //is it from an EXTRA_TARGET 3022 const QString dep_basename = dep.local().section(Option::dir_sep, -1); 3023 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); 3024 for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) { 3025 QString targ = var((*it) + ".target"); 3026 if(targ.isEmpty()) 3027 targ = (*it); 3028 QString out = Option::fixPathToTargetOS(targ); 3029 if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) { 3030 ret = QMakeLocalFileName(out); 3031 goto found_dep_from_heuristic; 3032 } 3033 } 3034 } 3035 { //is it from an EXTRA_COMPILER 3036 const QString dep_basename = dep.local().section(Option::dir_sep, -1); 3037 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); 3038 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { 3039 QString tmp_out = project->values((*it) + ".output").first(); 3040 if(tmp_out.isEmpty()) 3041 continue; 3042 QStringList &tmp = project->values((*it) + ".input"); 3043 for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { 3044 QStringList &inputs = project->values((*it2)); 3045 for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { 3046 QString out = Option::fixPathToTargetOS(unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString()))); 3047 if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) { 3048 ret = QMakeLocalFileName(fileFixify(out, qmake_getpwd(), Option::output_dir)); 3049 goto found_dep_from_heuristic; 3050 } 3051 } 3052 } 3053 } 3054 } 3055 found_dep_from_heuristic: 3056 depHeuristicsCache.insert(dep.real(), ret); 3057 } 3058 return ret; 3059} 3060 3061QStringList 3062&MakefileGenerator::findDependencies(const QString &file) 3063{ 3064 const QString fixedFile = fileFixify(file); 3065 if(!dependsCache.contains(fixedFile)) { 3066#if 1 3067 QStringList deps = QMakeSourceFileInfo::dependencies(file); 3068 if(file != fixedFile) 3069 deps += QMakeSourceFileInfo::dependencies(fixedFile); 3070#else 3071 QStringList deps = QMakeSourceFileInfo::dependencies(fixedFile); 3072#endif 3073 dependsCache.insert(fixedFile, deps); 3074 } 3075 return dependsCache[fixedFile]; 3076} 3077 3078QString 3079MakefileGenerator::specdir(const QString &outdir) 3080{ 3081#if 0 3082 if(!spec.isEmpty()) 3083 return spec; 3084#endif 3085 spec = fileFixify(Option::mkfile::qmakespec, outdir); 3086 return spec; 3087} 3088 3089bool 3090MakefileGenerator::openOutput(QFile &file, const QString &build) const 3091{ 3092 { 3093 QString outdir; 3094 if(!file.fileName().isEmpty()) { 3095 if(QDir::isRelativePath(file.fileName())) 3096 file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run 3097 QFileInfo fi(fileInfo(file.fileName())); 3098 if(fi.isDir()) 3099 outdir = file.fileName() + '/'; 3100 } 3101 if(!outdir.isEmpty() || file.fileName().isEmpty()) { 3102 QString fname = "Makefile"; 3103 if(!project->isEmpty("MAKEFILE")) 3104 fname = project->first("MAKEFILE"); 3105 file.setFileName(outdir + fname); 3106 } 3107 } 3108 if(QDir::isRelativePath(file.fileName())) { 3109 QString fname = Option::output_dir; //pwd when qmake was run 3110 if(!fname.endsWith("/")) 3111 fname += "/"; 3112 fname += file.fileName(); 3113 file.setFileName(fname); 3114 } 3115 if(!build.isEmpty()) 3116 file.setFileName(file.fileName() + "." + build); 3117 if(project->isEmpty("QMAKE_MAKEFILE")) 3118 project->values("QMAKE_MAKEFILE").append(file.fileName()); 3119 int slsh = file.fileName().lastIndexOf('/'); 3120 if(slsh != -1) 3121 mkdir(file.fileName().left(slsh)); 3122 if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { 3123 QFileInfo fi(fileInfo(Option::output.fileName())); 3124 QString od; 3125 if(fi.isSymLink()) 3126 od = fileInfo(fi.readLink()).absolutePath(); 3127 else 3128 od = fi.path(); 3129 od = QDir::fromNativeSeparators(od); 3130 if(QDir::isRelativePath(od)) { 3131 QString dir = Option::output_dir; 3132 if (!dir.endsWith('/') && !od.isEmpty()) 3133 dir += '/'; 3134 od.prepend(dir); 3135 } 3136 Option::output_dir = od; 3137 return true; 3138 } 3139 return false; 3140} 3141 3142QString 3143MakefileGenerator::pkgConfigFileName(bool fixify) 3144{ 3145 QString ret = var("TARGET"); 3146 int slsh = ret.lastIndexOf(Option::dir_sep); 3147 if(slsh != -1) 3148 ret = ret.right(ret.length() - slsh - 1); 3149 if(ret.startsWith("lib")) 3150 ret = ret.mid(3); 3151 int dot = ret.indexOf('.'); 3152 if(dot != -1) 3153 ret = ret.left(dot); 3154 ret += Option::pkgcfg_ext; 3155 QString subdir = project->first("QMAKE_PKGCONFIG_DESTDIR"); 3156 if(!subdir.isEmpty()) { 3157 // initOutPaths() appends dir_sep, but just to be safe.. 3158 if (!subdir.endsWith(Option::dir_sep)) 3159 ret.prepend(Option::dir_sep); 3160 ret.prepend(subdir); 3161 } 3162 if(fixify) { 3163 if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR")) 3164 ret.prepend(project->first("DESTDIR")); 3165 ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir)); 3166 } 3167 return ret; 3168} 3169 3170QString 3171MakefileGenerator::pkgConfigPrefix() const 3172{ 3173 if(!project->isEmpty("QMAKE_PKGCONFIG_PREFIX")) 3174 return project->first("QMAKE_PKGCONFIG_PREFIX"); 3175 return QLibraryInfo::location(QLibraryInfo::PrefixPath); 3176} 3177 3178QString 3179MakefileGenerator::pkgConfigFixPath(QString path) const 3180{ 3181 QString prefix = pkgConfigPrefix(); 3182 if(path.startsWith(prefix)) 3183 path = path.replace(prefix, "${prefix}"); 3184 return path; 3185} 3186 3187void 3188MakefileGenerator::writePkgConfigFile() 3189{ 3190 QString fname = pkgConfigFileName(), lname = fname; 3191 mkdir(fileInfo(fname).path()); 3192 int slsh = lname.lastIndexOf(Option::dir_sep); 3193 if(slsh != -1) 3194 lname = lname.right(lname.length() - slsh - 1); 3195 QFile ft(fname); 3196 if(!ft.open(QIODevice::WriteOnly)) 3197 return; 3198 project->values("ALL_DEPS").append(fileFixify(fname)); 3199 QTextStream t(&ft); 3200 3201 QString prefix = pkgConfigPrefix(); 3202 QString libDir = project->first("QMAKE_PKGCONFIG_LIBDIR"); 3203 if(libDir.isEmpty()) 3204 libDir = prefix + Option::dir_sep + "lib" + Option::dir_sep; 3205 QString includeDir = project->first("QMAKE_PKGCONFIG_INCDIR"); 3206 if(includeDir.isEmpty()) 3207 includeDir = prefix + "/include"; 3208 3209 t << "prefix=" << prefix << endl; 3210 t << "exec_prefix=${prefix}\n" 3211 << "libdir=" << pkgConfigFixPath(libDir) << "\n" 3212 << "includedir=" << pkgConfigFixPath(includeDir) << endl; 3213 // non-standard entry. Provides useful info normally only 3214 // contained in the internal .qmake.cache file 3215 t << varGlue("CONFIG", "qt_config=", " ", "") << endl; 3216 3217 //extra PKGCONFIG variables 3218 const QStringList &pkgconfig_vars = project->values("QMAKE_PKGCONFIG_VARIABLES"); 3219 for(int i = 0; i < pkgconfig_vars.size(); ++i) { 3220 QString var = project->first(pkgconfig_vars.at(i) + ".name"), 3221 val = project->values(pkgconfig_vars.at(i) + ".value").join(" "); 3222 if(var.isEmpty()) 3223 continue; 3224 if(val.isEmpty()) { 3225 const QStringList &var_vars = project->values(pkgconfig_vars.at(i) + ".variable"); 3226 for(int v = 0; v < var_vars.size(); ++v) { 3227 const QStringList &vars = project->values(var_vars.at(v)); 3228 for(int var = 0; var < vars.size(); ++var) { 3229 if(!val.isEmpty()) 3230 val += " "; 3231 val += pkgConfigFixPath(vars.at(var)); 3232 } 3233 } 3234 } 3235 t << var << "=" << val << endl; 3236 } 3237 3238 t << endl; 3239 3240 QString name = project->first("QMAKE_PKGCONFIG_NAME"); 3241 if(name.isEmpty()) { 3242 name = project->first("QMAKE_ORIG_TARGET").toLower(); 3243 name.replace(0, 1, name[0].toUpper()); 3244 } 3245 t << "Name: " << name << endl; 3246 QString desc = project->values("QMAKE_PKGCONFIG_DESCRIPTION").join(" "); 3247 if(desc.isEmpty()) { 3248 if(name.isEmpty()) { 3249 desc = project->first("QMAKE_ORIG_TARGET").toLower(); 3250 desc.replace(0, 1, desc[0].toUpper()); 3251 } else { 3252 desc = name; 3253 } 3254 if(project->first("TEMPLATE") == "lib") { 3255 if(project->isActiveConfig("plugin")) 3256 desc += " Plugin"; 3257 else 3258 desc += " Library"; 3259 } else if(project->first("TEMPLATE") == "app") { 3260 desc += " Application"; 3261 } 3262 } 3263 t << "Description: " << desc << endl; 3264 t << "Version: " << project->first("VERSION") << endl; 3265 3266 // libs 3267 t << "Libs: "; 3268 QString pkgConfiglibDir; 3269 QString pkgConfiglibName; 3270 if (Option::target_mode == Option::TARG_MACX_MODE && project->isActiveConfig("lib_bundle")) { 3271 pkgConfiglibDir = "-F${libdir}"; 3272 QString bundle; 3273 if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME")) 3274 bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME")); 3275 else 3276 bundle = unescapeFilePath(project->first("TARGET")); 3277 int suffix = bundle.lastIndexOf(".framework"); 3278 if (suffix != -1) 3279 bundle = bundle.left(suffix); 3280 pkgConfiglibName = "-framework " + bundle + " "; 3281 } else { 3282 pkgConfiglibDir = "-L${libdir}"; 3283 pkgConfiglibName = "-l" + lname.left(lname.length()-Option::libtool_ext.length()); 3284 if (project->isActiveConfig("shared")) 3285 pkgConfiglibName += project->first("TARGET_VERSION_EXT"); 3286 } 3287 t << pkgConfiglibDir << " " << pkgConfiglibName << " " << endl; 3288 3289 QStringList libs; 3290 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) { 3291 libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); 3292 } else { 3293 libs << "QMAKE_LIBS"; //obvious one 3294 } 3295 libs << "QMAKE_LIBS_PRIVATE"; 3296 libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? 3297 t << "Libs.private: "; 3298 for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) { 3299 t << project->values((*it)).join(" ") << " "; 3300 } 3301 t << endl; 3302 3303 // flags 3304 // ### too many 3305 t << "Cflags: " 3306 // << var("QMAKE_CXXFLAGS") << " " 3307 << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ") 3308 << project->values("PRL_EXPORT_CXXFLAGS").join(" ") 3309 << project->values("QMAKE_PKGCONFIG_CFLAGS").join(" ") 3310 // << varGlue("DEFINES","-D"," -D"," ") 3311 << " -I${includedir}" << endl; 3312 3313 // requires 3314 const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join(" "); 3315 if (!requires.isEmpty()) { 3316 t << "Requires: " << requires << endl; 3317 } 3318 3319 t << endl; 3320} 3321 3322QT_END_NAMESPACE 3323