revamp automatic makefile generation for sub-projects
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>
Fri, 18 May 2012 20:13:51 +0000 (22:13 +0200)
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>
Tue, 19 Jun 2012 14:46:08 +0000 (16:46 +0200)
instead of making the "real" targets depend on the makefiles, add
conditional makefile generation to the targets themselves.
this causes makefile generation to follow the recursion order determined
by the project, which is important when dealing with prl and module pri
files.
a side effect of this is that qmake and make calls are interleaved now,
which is entirely different from a 'qmake -r' run.

on the downside, calling make with multiple targets which operate on the
same subprojects without prior makefile generation will make a mess, as
the qmake calls will be racing. this should be no problem, as qmake does
not generate recursive targets where this would be useful - at least by
default.

it is not sufficient to just order the creation of the makefiles
non-recursively (e.g., by using gnu-specific order-only-prerequisites),
as an interrupted and subsequently resumed build would happily skip the
nested makefiles.
workable alternative approaches would be walking the entire tree in a
pre-pass to ensure makefile presence (which is incredibly slow) or
creating additional stamp files only after recursing and having the
makefiles depend on them (which is ugly).

Task-number: QTBUG-23376
Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
Change-Id: I88d3e7610215677d362026de316513d3bea04b06

mkspecs/common/shell-unix.conf
mkspecs/common/shell-win32.conf
qmake/generators/makefile.cpp
qmake/generators/makefile.h

index 967a658..17c3612 100644 (file)
@@ -8,6 +8,7 @@ QMAKE_MOVE             = mv -f
 QMAKE_DEL_FILE         = rm -f
 QMAKE_DEL_DIR          = rmdir
 QMAKE_CHK_DIR_EXISTS   = test -d
+QMAKE_CHK_FILE_EXISTS  = test -f
 QMAKE_CHK_EXISTS_GLUE  = "|| "
 QMAKE_MKDIR            = mkdir -p
 QMAKE_STREAM_EDITOR    = sed
index 16f86e5..3b2ace7 100644 (file)
@@ -6,5 +6,6 @@ QMAKE_MOVE             = move
 QMAKE_DEL_FILE         = del
 QMAKE_DEL_DIR          = rmdir
 QMAKE_CHK_DIR_EXISTS   = if not exist
+QMAKE_CHK_FILE_EXISTS  = if not exist
 QMAKE_CHK_EXISTS_GLUE  =
 QMAKE_MKDIR            = mkdir
index a14e723..83354b9 100644 (file)
@@ -428,6 +428,9 @@ MakefileGenerator::init()
     QHash<QString, QStringList> &v = project->variables();
 
     chkdir = v["QMAKE_CHK_DIR_EXISTS"].join(" ");
+    chkfile = v["QMAKE_CHK_FILE_EXISTS"].join(" ");
+    if (chkfile.isEmpty()) // Backwards compat with Qt4 specs
+        chkfile = isWindowsShell() ? "if not exist" : "test -f";
     chkglue = v["QMAKE_CHK_EXISTS_GLUE"].join(" ");
     if (chkglue.isEmpty()) // Backwards compat with Qt4 specs
         chkglue = isWindowsShell() ? "" : "|| ";
@@ -2369,6 +2372,22 @@ void MakefileGenerator::writeSubMakeCall(QTextStream &t, const QString &callPref
 }
 
 void
+MakefileGenerator::writeSubTargetCall(QTextStream &t,
+        const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
+        const QString &out_directory_cdin, const QString &makefilein, const QString &out_directory_cdout)
+{
+    QString pfx;
+    if (!in.isEmpty()) {
+        if (!in_directory.isEmpty())
+            t << "\n\t" << mkdir_p_asstring(out_directory);
+        pfx = "( " + chkfile + " " + out + " " + chkglue
+              + "$(QMAKE) " + in + buildArgs(in_directory) + " -o " + out
+              + " ) && ";
+    }
+    writeSubMakeCall(t, out_directory_cdin + pfx, makefilein, out_directory_cdout);
+}
+
+void
 MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags)
 {
     // blasted includes
@@ -2426,10 +2445,6 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
         if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
             out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
 
-        QString mkfile = subtarget->makefile;
-        if(!in_directory.isEmpty())
-            mkfile.prepend(out_directory);
-
 #define MAKE_CD_IN_AND_OUT(directory) \
         if(!directory.isEmpty()) {               \
             if(project->isActiveConfig("cd_change_global")) { \
@@ -2457,20 +2472,13 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
         QString makefilein = " -f " + subtarget->makefile;
 
         //qmake it
+        QString out;
+        QString in;
         if(!subtarget->profile.isEmpty()) {
-            QString out = subtarget->makefile;
-            QString in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
+            out = subtarget->makefile;
+            in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
             if(out.startsWith(in_directory))
                 out = out.mid(in_directory.length());
-            t << mkfile << ": " << "\n\t";
-            if(!in_directory.isEmpty()) {
-                t << mkdir_p_asstring(out_directory)
-                  << out_directory_cdin
-                  << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
-                  << out_directory_cdout << endl;
-            } else {
-                t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
-            }
             t << subtarget->target << "-qmake_all: ";
             if (flags & SubTargetOrdered) {
                 if (target)
@@ -2497,12 +2505,13 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
         }
 
         { //actually compile
-            t << subtarget->target << ": " << mkfile;
+            t << subtarget->target << ":";
             if(!subtarget->depends.isEmpty())
                 t << " " << valList(subtarget->depends);
             if(project->isEmpty("QMAKE_NOFORCE"))
                 t <<  " FORCE";
-            writeSubMakeCall(t, out_directory_cdin, makefilein, out_directory_cdout);
+            writeSubTargetCall(t, in_directory, in, out_directory, out,
+                               out_directory_cdin, makefilein, out_directory_cdout);
         }
 
         for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) {
@@ -2515,20 +2524,22 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
                 s = QString();
 
             if(flags & SubTargetOrdered) {
-                t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered: " << mkfile;
+                t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered:";
                 if(target)
                     t << " " << targets.at(target-1)->target << "-" << targetSuffixes.at(suffix) << "-ordered ";
                 if(project->isEmpty("QMAKE_NOFORCE"))
                     t <<  " FORCE";
-                writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout);
+                writeSubTargetCall(t, in_directory, in, out_directory, out,
+                                   out_directory_cdin, makefilein + " " + s, out_directory_cdout);
             }
-            t << subtarget->target << "-" << targetSuffixes.at(suffix) << ": " << mkfile;
+            t << subtarget->target << "-" << targetSuffixes.at(suffix) << ":";
             if(!subtarget->depends.isEmpty())
                 t << " " << valGlue(subtarget->depends, QString(), "-" + targetSuffixes.at(suffix) + " ",
                                     "-"+targetSuffixes.at(suffix));
             if(project->isEmpty("QMAKE_NOFORCE"))
                 t <<  " FORCE";
-            writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout);
+            writeSubTargetCall(t, in_directory, in, out_directory, out,
+                               out_directory_cdin, makefilein + " " + s, out_directory_cdout);
         }
     }
     t << endl;
@@ -2627,28 +2638,31 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
 
                 if(!recurse.contains(subtarget->name))
                     continue;
-                QString mkfile = subtarget->makefile;
-                if(!in_directory.isEmpty()) {
-                    if(!out_directory.endsWith(Option::dir_sep))
-                        mkfile.prepend(out_directory + Option::dir_sep);
-                    else
-                        mkfile.prepend(out_directory);
-                }
+
                 QString out_directory_cdin, out_directory_cdout;
                 MAKE_CD_IN_AND_OUT(out_directory);
 
                 QString makefilein = " -f " + subtarget->makefile;
 
+                QString out;
+                QString in;
+                if (!subtarget->profile.isEmpty()) {
+                    out = subtarget->makefile;
+                    in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
+                    if (out.startsWith(in_directory))
+                        out = out.mid(in_directory.length());
+                }
+
                 //write the rule/depends
                 if(flags & SubTargetOrdered) {
                     const QString dep = subtarget->target + "-" + (*qut_it) + "_ordered";
-                    t << dep << ": " << mkfile;
+                    t << dep << ":";
                     if(target)
                         t << " " << targets.at(target-1)->target << "-" << (*qut_it) << "_ordered ";
                     deps += " " + dep;
                 } else {
                     const QString dep = subtarget->target + "-" + (*qut_it);
-                    t << dep << ": " << mkfile;
+                    t << dep << ":";
                     if(!subtarget->depends.isEmpty())
                         t << " " << valGlue(subtarget->depends, QString(), "-" + (*qut_it) + " ", "-" + (*qut_it));
                     deps += " " + dep;
@@ -2659,8 +2673,8 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
                     sub_targ = project->first((*qut_it) + ".recurse_target");
 
                 //write the commands
-                writeSubMakeCall(t, out_directory_cdin, makefilein + " " + sub_targ,
-                                 out_directory_cdout);
+                writeSubTargetCall(t, in_directory, in, out_directory, out,
+                                   out_directory_cdin, makefilein + " " + sub_targ, out_directory_cdout);
             }
         }
         if(project->isEmpty("QMAKE_NOFORCE") &&
index 3a41fb4..33602dc 100644 (file)
@@ -81,7 +81,7 @@ class MakefileGenerator : protected QMakeSourceFileInfo
     QString spec;
     bool init_opath_already, init_already, no_io;
     QHash<QString, bool> init_compiler_already;
-    QString chkdir, chkglue;
+    QString chkdir, chkfile, chkglue;
     QString build_args(const QString &outdir=QString());
     void checkMultipleDefinition(const QString &, const QString &);
 
@@ -128,6 +128,9 @@ protected:
         SubTargetsNoFlags=0x00
     };
     QList<MakefileGenerator::SubTarget*> findSubDirsSubTargets() const;
+    void writeSubTargetCall(QTextStream &t,
+            const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
+            const QString &out_directory_cdin, const QString &makefilein, const QString &out_directory_cdout);
     virtual void writeSubMakeCall(QTextStream &t, const QString &outDirectory_cdin,
                                   const QString &makeFileIn, const QString &outDirectory_cdout);
     void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);