qmake: Normalize paths instead of converting to native separators
[profile/ivi/qtbase.git] / qmake / main.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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_OS_WIN
103     if(!(oldpwd.length() == 3 && oldpwd[0].isLetter() && oldpwd.endsWith(":/")))
104 #endif
105     {
106         if(!oldpwd.endsWith(QLatin1Char('/')))
107             oldpwd += QLatin1Char('/');
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::normalizePath(*pfile);
145             if(!QFile::exists(fn)) {
146                 fprintf(stderr, "Cannot find file: %s.\n",
147                         QDir::toNativeSeparators(fn).toLatin1().constData());
148                 exit_val = 2;
149                 continue;
150             }
151
152             //setup pwd properly
153             debug_msg(1, "Resetting dir to: %s",
154                       QDir::toNativeSeparators(oldpwd).toLatin1().constData());
155             qmake_setpwd(oldpwd); //reset the old pwd
156             int di = fn.lastIndexOf(QLatin1Char('/'));
157             if(di != -1) {
158                 debug_msg(1, "Changing dir to: %s",
159                           QDir::toNativeSeparators(fn.left(di)).toLatin1().constData());
160                 if(!qmake_setpwd(fn.left(di)))
161                     fprintf(stderr, "Cannot find directory: %s\n",
162                             QDir::toNativeSeparators(fn.left(di)).toLatin1().constData());
163                 fn = fn.right(fn.length() - di - 1);
164             }
165
166             // read project..
167             if(!project.read(fn)) {
168                 fprintf(stderr, "Error processing project file: %s\n",
169                         fn == QLatin1String("-") ?
170                             "(stdin)" : QDir::toNativeSeparators(*pfile).toLatin1().constData());
171                 exit_val = 3;
172                 continue;
173             }
174             if(Option::mkfile::do_preprocess) //no need to create makefile
175                 continue;
176         }
177
178         bool success = true;
179         MetaMakefileGenerator *mkfile = MetaMakefileGenerator::createMetaGenerator(&project, QString(), false, &success);
180         if (!success)
181             exit_val = 3;
182
183         if(mkfile && !mkfile->write(oldpwd)) {
184             if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
185                 fprintf(stderr, "Unable to generate project file.\n");
186             else
187                 fprintf(stderr, "Unable to generate makefile for: %s\n",
188                         QDir::toNativeSeparators(*pfile).toLatin1().constData());
189             exit_val = 5;
190         }
191         delete mkfile;
192         mkfile = NULL;
193     }
194     qmakeClearCaches();
195     return exit_val;
196 }
197
198 QT_END_NAMESPACE
199
200 int main(int argc, char **argv)
201 {
202     return QT_PREPEND_NAMESPACE(runQMake)(argc, argv);
203 }