Merge remote branch 'staging/master' into refactor
[profile/ivi/qtbase.git] / qmake / main.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 qmake application 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 "project.h"
43 #include "property.h"
44 #include "option.h"
45 #include "cachekeys.h"
46 #include "metamakefile.h"
47 #include <qnamespace.h>
48 #include <qdebug.h>
49 #include <qregexp.h>
50 #include <qdir.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <ctype.h>
54 #include <fcntl.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57
58 QT_BEGIN_NAMESPACE
59
60 // for Borland, main is defined to qMain which breaks qmake
61 #undef main
62 #ifdef Q_OS_MAC
63 #endif
64
65 /* This is to work around lame implementation on Darwin. It has been noted that the getpwd(3) function
66    is much too slow, and called much too often inside of Qt (every fileFixify). With this we use a locally
67    cached copy because I can control all the times it is set (because Qt never sets the pwd under me).
68 */
69 static QString pwd;
70 QString qmake_getpwd()
71 {
72     if(pwd.isNull())
73         pwd = QDir::currentPath();
74     return pwd;
75 }
76 bool qmake_setpwd(const QString &p)
77 {
78     if(QDir::setCurrent(p)) {
79         pwd = QDir::currentPath();
80         return true;
81     }
82     return false;
83 }
84
85 int runQMake(int argc, char **argv)
86 {
87     // stderr is unbuffered by default, but stdout buffering depends on whether
88     // there is a terminal attached. Buffering can make output from stderr and stdout
89     // appear out of sync, so force stdout to be unbuffered as well.
90     // This is particularly important for things like QtCreator and scripted builds.
91     setvbuf(stdout, (char *)NULL, _IONBF, 0);
92
93     // parse command line
94     int ret = Option::init(argc, argv);
95     if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
96         if ((ret & Option::QMAKE_CMDLINE_ERROR) != 0)
97             return 1;
98         return 0;
99     }
100
101     QString oldpwd = qmake_getpwd();
102 #ifdef Q_WS_WIN
103     if(!(oldpwd.length() == 3 && oldpwd[0].isLetter() && oldpwd.endsWith(":/")))
104 #endif
105     {
106         if(oldpwd.right(1) != QString(QChar(QDir::separator())))
107             oldpwd += QDir::separator();
108     }
109     Option::output_dir = oldpwd; //for now this is the output dir
110
111     if(Option::output.fileName() != "-") {
112         QFileInfo fi(Option::output);
113         QString dir;
114         if(fi.isDir()) {
115             dir = fi.filePath();
116         } else {
117             QString tmp_dir = fi.path();
118             if(!tmp_dir.isEmpty() && QFile::exists(tmp_dir))
119                 dir = tmp_dir;
120         }
121         if(!dir.isNull() && dir != ".")
122             Option::output_dir = dir;
123         if(QDir::isRelativePath(Option::output_dir))
124             Option::output_dir.prepend(oldpwd);
125         Option::output_dir = QDir::cleanPath(Option::output_dir);
126     }
127
128     QMakeProperty prop;
129     if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
130        Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
131        Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY)
132         return prop.exec() ? 0 : 101;
133
134     QMakeProject project(&prop);
135     int exit_val = 0;
136     QStringList files;
137     if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
138         files << "(*hack*)"; //we don't even use files, but we do the for() body once
139     else
140         files = Option::mkfile::project_files;
141     for(QStringList::Iterator pfile = files.begin(); pfile != files.end(); pfile++) {
142         if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
143            Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
144             QString fn = Option::fixPathToLocalOS((*pfile));
145             if(!QFile::exists(fn)) {
146                 fprintf(stderr, "Cannot find file: %s.\n", fn.toLatin1().constData());
147                 exit_val = 2;
148                 continue;
149             }
150
151             //setup pwd properly
152             debug_msg(1, "Resetting dir to: %s", oldpwd.toLatin1().constData());
153             qmake_setpwd(oldpwd); //reset the old pwd
154             int di = fn.lastIndexOf(QDir::separator());
155             if(di != -1) {
156                 debug_msg(1, "Changing dir to: %s", fn.left(di).toLatin1().constData());
157                 if(!qmake_setpwd(fn.left(di)))
158                     fprintf(stderr, "Cannot find directory: %s\n", fn.left(di).toLatin1().constData());
159                 fn = fn.right(fn.length() - di - 1);
160             }
161
162             // read project..
163             if(!project.read(fn)) {
164                 fprintf(stderr, "Error processing project file: %s\n",
165                         fn == "-" ? "(stdin)" : (*pfile).toLatin1().constData());
166                 exit_val = 3;
167                 continue;
168             }
169             if(Option::mkfile::do_preprocess) //no need to create makefile
170                 continue;
171         }
172
173         bool success = true;
174         MetaMakefileGenerator *mkfile = MetaMakefileGenerator::createMetaGenerator(&project, QString(), false, &success);
175         if (!success)
176             exit_val = 3;
177
178         if(mkfile && !mkfile->write(oldpwd)) {
179             if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
180                 fprintf(stderr, "Unable to generate project file.\n");
181             else
182                 fprintf(stderr, "Unable to generate makefile for: %s\n", (*pfile).toLatin1().constData());
183             exit_val = 5;
184         }
185         delete mkfile;
186         mkfile = NULL;
187     }
188     qmakeClearCaches();
189     return exit_val;
190 }
191
192 QT_END_NAMESPACE
193
194 int main(int argc, char **argv)
195 {
196     return QT_PREPEND_NAMESPACE(runQMake)(argc, argv);
197 }