Add -nn for .cpp MOC preprocessing for INTEGRITY
[qt:qt.git] / qmake / generators / integrity / gbuild.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "gbuild.h"
43 #include "option.h"
44 #include "meta.h"
45 #include <qdir.h>
46 #include <qregexp.h>
47 #include <qcryptographichash.h>
48 #include <qdebug.h>
49 #include <stdlib.h>
50 #include <time.h>
51 #ifdef Q_OS_UNIX
52 #  include <sys/types.h>
53 #  include <sys/stat.h>
54 #endif
55
56 QT_BEGIN_NAMESPACE
57
58 unsigned int dllbase = 0x01000000;
59 #define DLLOFFSET 0x600000
60
61 GBuildMakefileGenerator::GBuildMakefileGenerator() : MakefileGenerator()
62 {
63     nativebins << "moc" << "rcc" << "uic" << "bootstrap";
64 }
65
66 bool
67 GBuildMakefileGenerator::write()
68 {
69     QStringList tmp;
70     QString filename(Option::output.fileName());
71     QString pathtoremove(qmake_getpwd());
72     QString relpath(pathtoremove);
73     QString strtarget(project->first("TARGET"));
74     bool isnativebin = nativebins.contains(strtarget);
75     relpath.replace(Option::output_dir, "");
76
77     /* correct output for non-prl, non-recursive case */
78     QString outname(qmake_getpwd());
79     outname += QDir::separator();
80     outname += fileInfo(Option::output.fileName()).baseName();
81     outname += projectSuffix();
82     Option::output.close();
83     Option::output.setFileName(outname);
84     MakefileGenerator::openOutput(Option::output, QString());
85
86     if (strtarget != fileInfo(project->projectFile()).baseName()) {
87         QString gpjname(strtarget);
88         QString outputName(qmake_getpwd());
89         outputName += QDir::separator();
90         outputName += fileInfo(project->projectFile()).baseName();
91         outputName += projectSuffix();
92         QFile f(outputName);
93         f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
94         QTextStream t(&f);
95         t << "#!gbuild\n";
96         t << "[Project]\n";
97         t << gpjname << projectSuffix() << "\n";
98         if ((project->first("TEMPLATE") == "lib")
99                 && project->isActiveConfig("shared"))
100             t << gpjname << "_shared" << projectSuffix() << "\n";
101         t.flush();
102         gpjname += projectSuffix();
103         Option::output.close();
104         Option::output.setFileName(gpjname);
105         MakefileGenerator::openOutput(Option::output, QString());
106     }
107
108     if ((project->first("TEMPLATE") == "app")
109             && (!isnativebin)) {
110         QTextStream t(&Option::output);
111         QString intname(strtarget);
112         intname += ".int";
113         /* this is for bulding an INTEGRITY application.
114          * generate the .int integrate file and the .gpj INTEGRITY Application
115          * project file, then go on with regular files */
116         t << "#!gbuild" << "\n";
117         t << "[INTEGRITY Application]" << "\n";
118         t << "\t:binDirRelative=.\n";
119         t << "\t-o " << strtarget << "\n";
120         t << intname << "\n";
121         t << strtarget << "_app" << projectSuffix() << "\n";
122         t.flush();
123
124         /* generate integrate file */
125         QFile f(intname);
126         f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
127         QTextStream ti(&f);
128         ti << "# This is a file automatically generated by qmake" << "\n";
129         ti << "# Modifications will be lost next time you run qmake" << "\n";
130         ti << "Kernel" << "\n";
131         ti << "\tFilename\tDynamicDownload" << "\n";
132         ti << "EndKernel" << "\n" << "\n";
133         ti << "AddressSpace" << "\n";
134         ti << "\tName\t" << strtarget << "\n";
135         ti << "\tFilename\t" << strtarget << "_app" << "\n";
136         ti << "\tMemoryPoolSize\t0x100000" << "\n";
137         ti << "\tLanguage\tC++" << "\n";
138         /* FIXME : heap size is huge to be big enough for every example
139          * it should probably be tailored for each example, btu there is no
140          * good way to guess that */
141         ti << "\tHeapSize\t0x00D00000" << "\n";
142         ti << "\tTask\tInitial" << "\n";
143         ti << "\t\tStackSize\t0x30000" << "\n";
144         ti << "\tEndTask" << "\n";
145         ti << "EndAddressSpace" << "\n";
146         ti.flush();
147
148         /* change current project file to <projectname>_app.gpj and continue
149          * generation */
150         filename.insert(filename.lastIndexOf("."), "_app");
151         Option::output.close();
152         Option::output.setFileName(filename);
153         MakefileGenerator::openOutput(Option::output, QString());
154     } else if ((project->first("TEMPLATE") == "lib")
155             && project->isActiveConfig("shared")) {
156         QString gpjname(strtarget);
157         gpjname += "_shared";
158         gpjname += projectSuffix();
159         QFile f(gpjname);
160         f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
161         QTextStream t(&f);
162         t << "#!gbuild\n"
163             "[Program]\n"
164             "\t-A libINTEGRITY.so\n"
165             "\t-A libc.so\n"
166             "\t-A libscxx.so\n"
167             "\t-A libQtCore.so\n"
168             "\t-e __ghsbegin_text\n"
169             "\t-startfile=-\n"
170             "\t:syslibraries=-\n"
171             "\t-Onolink\n";
172         t << "\t-o lib" << strtarget << ".so\n";
173         t << "\t-l" << strtarget << "\n";
174         t << "\t-extractall=-l" << strtarget << "\n";
175         t << "\t:outputDir=work/" << filename.section(QDir::separator(), 0, -1).remove(".gpj") << "\n";
176         t << strtarget << "_shared.ld\n";
177         t << "$(__OS_DIR)/intlib/sharedobjbssinit.c\n";
178         t.flush();
179
180         QFile fl(strtarget + "_shared.ld");
181         fl.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
182         QTextStream tl(&fl);
183         tl << "CONSTANTS {\n"
184              "    __INTEGRITY_MinPageAlign          = 16K\n"
185              "    __INTEGRITY_MaxPageAlign          = 16K\n"
186              "    __INTEGRITY_LibCBaseAddress       = \n";
187         tl << dllbase << "\n";
188         tl << "}\n"
189              "-sec\n"
190              "{\n"
191              "  .picbase __INTEGRITY_LibCBaseAddress :\n"
192              "        .text :\n"
193              "  .syscall :\n"
194              "        .intercall :\n"
195              "        .interfunc :\n"
196              "  .secinfo :\n"
197              "  .rodata align(16) :\n"
198              "  .fixaddr :\n"
199              "  .fixtype :\n"
200              "        .rombeg :\n"
201              "        .textchecksum :\n"
202              "        // The above sections may be large. Leave a bigger gap for large pages.\n"
203              "  .pidbase align(__INTEGRITY_MaxPageAlign) :\n"
204              "        .sdabase :\n"
205              "        .data :\n"
206              "        .toc :\n"
207              "        .opd :\n"
208              "        .datachecksum :\n"
209              "  .bss align(__INTEGRITY_MinPageAlign) :\n"
210              "        .heap :\n"
211              "}\n";
212         tl.flush();
213         dllbase += DLLOFFSET;
214     }
215
216     warn_msg(WarnParser, Option::output.fileName().toAscii());
217     QTextStream t(&Option::output);
218     QString primaryTarget(project->values("QMAKE_CXX").at(0));
219
220     pathtoremove += QDir::separator();
221     filename.remove(qmake_getpwd());
222
223     //HEADER
224     t << "#!gbuild" << "\n";
225
226     /* find the architecture out of the compiler name */
227     if (filename.endsWith("projects.gpj")) {
228         primaryTarget.remove(0, 5);
229         t << "macro QT_BUILD_DIR=%expand_path(.)\n";
230         t << "macro __OS_DIR=" << project->values("INTEGRITY_DIR").first() << "\n";
231         t << "primaryTarget=" << primaryTarget << "_integrity.tgt" << "\n";
232         t << "customization=util/integrity/qt.bod\n";
233     }
234     /* project type */
235     if (project->first("TEMPLATE") == "app") {
236         t << "[Program]" << "\n";
237         if (isnativebin) {
238             t << "\t:binDir=bin\n";
239             t << "\t-o " << strtarget << "\n";
240         } else {
241             t << "\t:binDirRelative=.\n";
242             t << "\t-o " << strtarget << "_app\n";
243         }
244     } else if (project->first("TEMPLATE") == "lib") {
245         t << "[Library]" << "\n";
246         t << "\t:binDir=lib" << "\n";
247         t << "\t-o lib" << strtarget << ".a" << "\n";
248     } else if (project->first("TEMPLATE") == "subdirs")
249         t << "[Project]" << "\n";
250     else
251         t << project->first("TEMPLATE") << "\n";
252
253     /* compilations options */
254     t << "\t:sourceDir=." << "\n";
255
256     t << "\t:outputDir=work" << relpath << "\n";
257     if (filename.endsWith("projects.gpj")) {
258         t << "\t:sourceDir=work\n";
259         t << "\t-Iwork\n";
260         t << "\t-Llib\n";
261         t << "\t";
262         QStringList &l = project->values("QMAKE_CXXFLAGS");
263         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
264             if ((*it).startsWith("-"))
265                 t << "\n" << "\t" << (*it);
266             else
267                 t << " " << (*it);
268         }
269         t << "\n";
270     }
271     t << "\n";
272
273     t << varGlue("DEFINES", "\t-D", "\n\t-D", "\n");
274
275     t << "\t-I.\n\t-I" << specdir() << "\n";
276     t << varGlue("INCLUDEPATH", "\t-I", "\n\t-I", "\n");
277     t << "\t--cxx_include_directory .\n\t--cxx_include_directory " << specdir() << "\n";
278     t << varGlue("INCLUDEPATH", "\t--cxx_include_directory ", "\n\t--cxx_include_directory ", "\n");
279
280     if (project->first("TEMPLATE") == "app") {
281         /* include linker flags if it's an application */
282         QString src[] = { "QMAKE_LFLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_LIBS", "LIBS", QString() };
283         for (int i = 0; !src[i].isNull(); i++) {
284             /* skip target libraries for native tools */
285             if (isnativebin && (i == 0))
286                 continue;
287             t << "\t";
288             QStringList &l = project->values(src[i]);
289             for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
290                 if ((*it).startsWith("-"))
291                     t << "\n" << "\t" << (*it);
292                 else
293                     t << " " << (*it);
294             }
295             t << "\n";
296         }
297     }
298
299     /* first subdirectories/subprojects */
300     {
301         QStringList &l = project->values("SUBDIRS");
302         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
303             QString gpjname((*it));
304             /* avoid native tools */
305             if (nativebins.contains(gpjname.section("_", -1)))
306                 continue;
307             if (!project->first((*it) + ".subdir").isEmpty())
308                 gpjname = project->first((*it) + ".subdir");
309             else
310                 gpjname.replace("_", QDir::separator());
311             gpjname += QDir::separator() + gpjname.section(QDir::separator(), -1);
312             gpjname += projectSuffix();
313             /* make relative */
314             if (!project->values("QT_SOURCE_TREE").isEmpty()) {
315                 gpjname.replace(project->values("QT_SOURCE_TREE").first() + QDir::separator(), "");
316             }
317             t << gpjname << "\n";
318         }
319     }
320
321     {
322         QStringList &l = project->values("RESOURCES");
323         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
324             QString tmpstr((*it).replace(pathtoremove, ""));
325             t << tmpstr << "\t[Qt Resource]\n";
326             tmpstr = tmpstr.section(".", -2, -1).section(QDir::separator(), -1);
327             tmpstr.remove(".qrc");
328             t << "\t-name " << tmpstr << "\n";
329             tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "qrc_");
330             tmpstr.append(".cpp");
331             t << "\t-o work/" << tmpstr << "\n";
332         }
333     }
334     {
335         QStringList &l = project->values("FORMS");
336         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
337             QString tmpstr((*it).replace(pathtoremove, ""));
338             t << tmpstr << "\t[Qt Dialog]\n";
339             tmpstr = tmpstr.section(".", 0, 0).section(QDir::separator(), -1);
340             tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "ui_");
341             tmpstr.remove(".ui");
342             tmpstr.append(".h");
343             t << "\t-o work/" << tmpstr << "\n";
344         }
345     }
346
347     /* source files for this project */
348     QString src[] = { "HEADERS", "SOURCES", QString() };
349     for (int i = 0; !src[i].isNull(); i++) {
350         QStringList &l = project->values(src[i]);
351         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
352             if ((*it).isEmpty())
353                 continue;
354             /* native tools aren't preprocessed */
355             if (!isnativebin)
356                 t << writeOne((*it), pathtoremove);
357             else
358                 t << (*it).remove(pathtoremove) << "\n";
359         }
360     }
361     t << "\n";
362
363     {
364         QStringList &l = project->values("GENERATED_SOURCES");
365         for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
366             t << "work/" << (*it).section(QDir::separator(), -1) << "\n";
367         }
368     }
369
370     return true;
371 }
372
373 QString GBuildMakefileGenerator::writeOne(QString filename, QString pathtoremove)
374 {
375     QString s("");
376     s += filename.remove(pathtoremove);
377     if (filename.endsWith(Option::h_ext.first())) {
378         QString corename(filename.section(QDir::separator(), -1));
379         corename.remove(Option::h_ext.first());
380         corename.append(Option::cpp_ext.first());
381         corename.prepend(Option::h_moc_mod);
382         s += "\t[MOC/Qt Header]\n";
383         s += "\t-o ";
384         s += "work/";
385         s += corename;
386         s += "\n";
387     } else if (filename.section(QDir::separator(), -1).startsWith("qrc_")) {
388         QString tmpstr(filename.section("/", -1).section(".", 0, -1).remove("qrc_").remove(".cpp"));
389         s += "\n\t:depends=";
390         s += tmpstr;
391         s += ".qrc";
392         s += "\n";
393     } else if (filename.endsWith(Option::cpp_ext.first())) {
394         QString tmpstr(filename.section("/", -1));
395         QString filepath(pathtoremove);
396         if (!project->values("QT_SOURCE_TREE").isEmpty()) {
397             filepath.remove(project->values("QT_SOURCE_TREE").first());
398             filepath.remove(0, 1);
399         }
400         s += "\n\t:preexecShellSafe='${QT_BUILD_DIR}/bin/moc ";
401         s += "-nn ";
402         s += varGlue("DEFINES", "-D", " -D", " ");
403         s += varGlue("INCLUDEPATH", "-I", " -I", " ");
404         s += filepath;
405         s += filename;
406         s += " -o ";
407         tmpstr.replace(Option::cpp_ext.first(), Option::cpp_moc_ext);
408         s += "work/";
409         s += tmpstr;
410         s += "\n";
411     } else
412         s += "\n";
413     return s;
414 }
415
416 bool
417 GBuildMakefileGenerator::openOutput(QFile &file, const QString &build) const
418 {
419     debug_msg(1, "file is %s", file.fileName().toLatin1().constData());
420     QFileInfo fi(file);
421     if (fi.filePath().isEmpty())
422         file.setFileName(qmake_getpwd() + QDir::separator() + file.fileName());
423     if (!file.fileName().endsWith(projectSuffix())) {
424         QString outputName(file.fileName());
425         outputName += QDir::separator();
426         outputName += fileInfo(project->projectFile()).baseName();
427         outputName += projectSuffix();
428         warn_msg(WarnParser, outputName.toAscii());
429         file.setFileName(outputName);
430     }
431     debug_msg(1, "file is %s", file.fileName().toLatin1().constData());
432     bool ret = MakefileGenerator::openOutput(file, QString());
433     return ret;
434 }
435
436 QT_END_NAMESPACE