source: trunk/tools/configure/environment.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 19.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "environment.h"
43
44#include <process.h>
45#include <iostream>
46#include <qdebug.h>
47#include <QDir>
48#include <QStringList>
49#include <QMap>
50#include <QDir>
51#include <QFile>
52#include <QFileInfo>
53
54//#define CONFIGURE_DEBUG_EXECUTE
55//#define CONFIGURE_DEBUG_CP_DIR
56
57using namespace std;
58
59#ifdef Q_OS_WIN32
60#include <qt_windows.h>
61#endif
62
63#include <symbian/epocroot_p.h> // from tools/shared
64#include <windows/registry_p.h> // from tools/shared
65
66QT_BEGIN_NAMESPACE
67
68struct CompilerInfo{
69 Compiler compiler;
70 const char *compilerStr;
71 const char *regKey;
72 const char *executable;
73} compiler_info[] = {
74 // The compilers here are sorted in a reversed-preferred order
75 {CC_BORLAND, "Borland C++", 0, "bcc32.exe"},
76 {CC_MINGW, "MinGW (Minimalist GNU for Windows)", 0, "g++.exe"},
77 {CC_INTEL, "Intel(R) C++ Compiler for 32-bit applications", 0, "icl.exe"}, // xilink.exe, xilink5.exe, xilink6.exe, xilib.exe
78 {CC_MSVC6, "Microsoft (R) 32-bit C/C++ Optimizing Compiler (6.x)", "Software\\Microsoft\\VisualStudio\\6.0\\Setup\\Microsoft Visual C++\\ProductDir", "cl.exe"}, // link.exe, lib.exe
79 {CC_NET2002, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2002 (7.0)", "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe
80 {CC_NET2003, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2003 (7.1)", "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe
81 {CC_NET2005, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2005 (8.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\8.0", "cl.exe"}, // link.exe, lib.exe
82 {CC_NET2008, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2008 (9.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\9.0", "cl.exe"}, // link.exe, lib.exe
83 {CC_NET2010, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2010 (10.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\10.0", "cl.exe"}, // link.exe, lib.exe
84 {CC_UNKNOWN, "Unknown", 0, 0},
85};
86
87
88// Initialize static variables
89Compiler Environment::detectedCompiler = CC_UNKNOWN;
90
91/*!
92 Returns the pointer to the CompilerInfo for a \a compiler.
93*/
94CompilerInfo *Environment::compilerInfo(Compiler compiler)
95{
96 int i = 0;
97 while(compiler_info[i].compiler != compiler && compiler_info[i].compiler != CC_UNKNOWN)
98 ++i;
99 return &(compiler_info[i]);
100}
101
102/*!
103 Returns the qmakespec for the compiler detected on the system.
104*/
105QString Environment::detectQMakeSpec()
106{
107 QString spec;
108 switch (detectCompiler()) {
109 case CC_NET2010:
110 spec = "win32-msvc2010";
111 break;
112 case CC_NET2008:
113 spec = "win32-msvc2008";
114 break;
115 case CC_NET2005:
116 spec = "win32-msvc2005";
117 break;
118 case CC_NET2003:
119 spec = "win32-msvc2003";
120 break;
121 case CC_NET2002:
122 spec = "win32-msvc2002";
123 break;
124 case CC_MSVC4:
125 case CC_MSVC5:
126 case CC_MSVC6:
127 spec = "win32-msvc";
128 break;
129 case CC_INTEL:
130 spec = "win32-icc";
131 break;
132 case CC_MINGW:
133 spec = "win32-g++";
134 break;
135 case CC_BORLAND:
136 spec = "win32-borland";
137 break;
138 default:
139 break;
140 }
141
142 return spec;
143}
144
145/*!
146 Returns the enum of the compiler which was detected on the system.
147 The compilers are detected in the order as entered into the
148 compiler_info list.
149
150 If more than one compiler is found, CC_UNKNOWN is returned.
151*/
152Compiler Environment::detectCompiler()
153{
154#ifndef Q_OS_WIN32
155 return MSVC6; // Always generate MSVC 6.0 versions on other platforms
156#else
157 if(detectedCompiler != CC_UNKNOWN)
158 return detectedCompiler;
159
160 int installed = 0;
161
162 // Check for compilers in registry first, to see which version is in PATH
163 QString paths = qgetenv("PATH");
164 QStringList pathlist = paths.toLower().split(";");
165 for(int i = 0; compiler_info[i].compiler; ++i) {
166 QString productPath = qt_readRegistryKey(HKEY_LOCAL_MACHINE, compiler_info[i].regKey).toLower();
167 if (productPath.length()) {
168 QStringList::iterator it;
169 for(it = pathlist.begin(); it != pathlist.end(); ++it) {
170 if((*it).contains(productPath)) {
171 ++installed;
172 detectedCompiler = compiler_info[i].compiler;
173 break;
174 }
175 }
176 }
177 }
178
179 // Now just go looking for the executables, and accept any executable as the lowest version
180 if (!installed) {
181 for(int i = 0; compiler_info[i].compiler; ++i) {
182 QString executable = QString(compiler_info[i].executable).toLower();
183 if (executable.length() && Environment::detectExecutable(executable)) {
184 ++installed;
185 detectedCompiler = compiler_info[i].compiler;
186 break;
187 }
188 }
189 }
190
191 if (installed > 1) {
192 cout << "Found more than one known compiler! Using \"" << compilerInfo(detectedCompiler)->compilerStr << "\"" << endl;
193 detectedCompiler = CC_UNKNOWN;
194 }
195 return detectedCompiler;
196#endif
197};
198
199/*!
200 Returns true if the \a executable could be loaded, else false.
201 This means that the executable either is in the current directory
202 or in the PATH.
203*/
204bool Environment::detectExecutable(const QString &executable)
205{
206 PROCESS_INFORMATION procInfo;
207 memset(&procInfo, 0, sizeof(procInfo));
208
209 STARTUPINFO startInfo;
210 memset(&startInfo, 0, sizeof(startInfo));
211 startInfo.cb = sizeof(startInfo);
212
213 bool couldExecute = CreateProcess(0, (wchar_t*)executable.utf16(),
214 0, 0, false,
215 CREATE_NO_WINDOW | CREATE_SUSPENDED,
216 0, 0, &startInfo, &procInfo);
217
218 if (couldExecute) {
219 CloseHandle(procInfo.hThread);
220 TerminateProcess(procInfo.hProcess, 0);
221 CloseHandle(procInfo.hProcess);
222 }
223 return couldExecute;
224}
225
226/*!
227 Creates a commandling from \a program and it \a arguments,
228 escaping characters that needs it.
229*/
230static QString qt_create_commandline(const QString &program, const QStringList &arguments)
231{
232 QString programName = program;
233 if (!programName.startsWith("\"") && !programName.endsWith("\"") && programName.contains(" "))
234 programName = "\"" + programName + "\"";
235 programName.replace("/", "\\");
236
237 QString args;
238 // add the prgram as the first arrg ... it works better
239 args = programName + " ";
240 for (int i=0; i<arguments.size(); ++i) {
241 QString tmp = arguments.at(i);
242 // in the case of \" already being in the string the \ must also be escaped
243 tmp.replace( "\\\"", "\\\\\"" );
244 // escape a single " because the arguments will be parsed
245 tmp.replace( "\"", "\\\"" );
246 if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
247 // The argument must not end with a \ since this would be interpreted
248 // as escaping the quote -- rather put the \ behind the quote: e.g.
249 // rather use "foo"\ than "foo\"
250 QString endQuote("\"");
251 int i = tmp.length();
252 while (i>0 && tmp.at(i-1) == '\\') {
253 --i;
254 endQuote += "\\";
255 }
256 args += QString(" \"") + tmp.left(i) + endQuote;
257 } else {
258 args += ' ' + tmp;
259 }
260 }
261 return args;
262}
263
264/*!
265 Creates a QByteArray of the \a environment.
266*/
267static QByteArray qt_create_environment(const QStringList &environment)
268{
269 QByteArray envlist;
270 if (environment.isEmpty())
271 return envlist;
272
273 int pos = 0;
274 // add PATH if necessary (for DLL loading)
275 QByteArray path = qgetenv("PATH");
276 if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() && !path.isNull()) {
277 QString tmp = QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path));
278 uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
279 envlist.resize(envlist.size() + tmpSize);