Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "environment.h"
43
44#include <process.h>
45#include <errno.h>
46#include <iostream>
47#include <qdebug.h>
48#include <QDir>
49#include <QStringList>
50#include <QMap>
51#include <QDir>
52#include <QFile>
53#include <QFileInfo>
54
55//#define CONFIGURE_DEBUG_EXECUTE
56//#define CONFIGURE_DEBUG_CP_DIR
57
58using namespace std;
59
60#ifdef Q_OS_WIN32
61#include <qt_windows.h>
62#endif
63
64#include <symbian/epocroot_p.h> // from tools/shared
65#include <windows/registry_p.h> // from tools/shared
66
67QT_BEGIN_NAMESPACE
68
69struct CompilerInfo{
70 Compiler compiler;
71 const char *compilerStr;
72 const char *regKey;
73 const char *executable;
74} compiler_info[] = {
75 // The compilers here are sorted in a reversed-preferred order
76 {CC_BORLAND, "Borland C++", 0, "bcc32.exe"},
77 {CC_MINGW, "MinGW (Minimalist GNU for Windows)", 0, "g++.exe"},
78 {CC_INTEL, "Intel(R) C++ Compiler for 32-bit applications", 0, "icl.exe"}, // xilink.exe, xilink5.exe, xilink6.exe, xilib.exe
79 {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
80 {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
81 {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
82 {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
83 {CC_NET2012, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2012 (11.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\11.0", "cl.exe"}, // link.exe, lib.exe
84 {CC_NET2012, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2012 (11.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\11.0", "cl.exe"}, // link.exe, lib.exe
85 {CC_NET2013, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2013 (12.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0", "cl.exe"}, // link.exe, lib.exe
86 {CC_NET2013, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2013 (12.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0", "cl.exe"}, // link.exe, lib.exe
87 {CC_UNKNOWN, "Unknown", 0, 0},
88};
89
90
91// Initialize static variables
92Compiler Environment::detectedCompiler = CC_UNKNOWN;
93
94/*!
95 Returns the pointer to the CompilerInfo for a \a compiler.
96*/
97CompilerInfo *Environment::compilerInfo(Compiler compiler)
98{
99 int i = 0;
100 while(compiler_info[i].compiler != compiler && compiler_info[i].compiler != CC_UNKNOWN)
101 ++i;
102 return &(compiler_info[i]);
103}
104
105/*!
106 Returns the qmakespec for the compiler detected on the system.
107*/
108QString Environment::detectQMakeSpec()
109{
110 QString spec;
111 switch (detectCompiler()) {
112 case CC_NET2013:
113 spec = "win32-msvc2013";
114 break;
115 case CC_NET2012:
116 spec = "win32-msvc2012";
117 break;
118 case CC_NET2010:
119 spec = "win32-msvc2010";
120 break;
121 case CC_NET2008:
122 spec = "win32-msvc2008";
123 break;
124 case CC_NET2005:
125 spec = "win32-msvc2005";
126 break;
127 case CC_NET2003:
128 spec = "win32-msvc2003";
129 break;
130 case CC_INTEL:
131 spec = "win32-icc";
132 break;
133 case CC_MINGW:
134 spec = "win32-g++-4.6";
135 break;
136 case CC_MINGW_44:
137 spec = "win32-g++";
138 break;
139 case CC_BORLAND:
140 spec = "win32-borland";
141 break;
142 default:
143 break;
144 }
145
146 return spec;
147}
148
149/*!
150 Returns the enum of the compiler which was detected on the system.
151 The compilers are detected in the order as entered into the
152 compiler_info list.
153
154 If more than one compiler is found, CC_UNKNOWN is returned.
155*/
156Compiler Environment::detectCompiler()
157{
158#ifndef Q_OS_WIN32
159 return CC_UNKNOWN; // Always generate CC_UNKNOWN on other platforms
160#else
161 if(detectedCompiler != CC_UNKNOWN)
162 return detectedCompiler;
163
164 int installed = 0;
165
166 // Check for compilers in registry first, to see which version is in PATH
167 QString paths = qgetenv("PATH");
168 QStringList pathlist = paths.toLower().split(";");
169 for(int i = 0; compiler_info[i].compiler; ++i) {
170 QString productPath = qt_readRegistryKey(HKEY_LOCAL_MACHINE, compiler_info[i].regKey).toLower();
171 if (productPath.length()) {
172 QStringList::iterator it;
173 for(it = pathlist.begin(); it != pathlist.end(); ++it) {
174 if((*it).contains(productPath)) {
175 if (detectedCompiler != compiler_info[i].compiler) {
176 ++installed;
177 detectedCompiler = compiler_info[i].compiler;
178 }
179 /* else {
180
181 We detected the same compiler again, which happens when
182 configure is run on a 64 bit Windows. Skip the
183 duplicate so that we don't think it's installed twice.
184
185 }
186 */
187 break;
188 }
189 }
190 }
191 }
192
193 // Now just go looking for the executables, and accept any executable as the lowest version
194 if (!installed) {
195 for(int i = 0; compiler_info[i].compiler; ++i) {
196 QString executable = QString(compiler_info[i].executable).toLower();
197 if (executable.length() && Environment::detectExecutable(executable)) {
198 if (detectedCompiler != compiler_info[i].compiler) {
199 ++installed;
200 detectedCompiler = compiler_info[i].compiler;
201 if (detectedCompiler == CC_MINGW) {
202 const int version = detectGPlusPlusVersion(executable);
203 if (version < 0x040600)
204 detectedCompiler = CC_MINGW_44;
205 }
206 }
207 /* else {
208
209 We detected the same compiler again, which happens when
210 configure is run on a 64 bit Windows. Skip the
211 duplicate so that we don't think it's installed twice.
212
213 }
214 */
215 break;
216 }
217 }
218 }
219
220 if (installed > 1) {
221 cout << "Found more than one known compiler! Using \"" << compilerInfo(detectedCompiler)->compilerStr << "\"" << endl;
222 detectedCompiler = CC_UNKNOWN;
223 }
224 return detectedCompiler;
225#endif
226}
227
228/*!
229 Returns true if the \a executable could be loaded, else false.
230 This means that the executable either is in the current directory
231 or in the PATH.
232*/
233bool Environment::detectExecutable(const QString &executable)
234{
235 PROCESS_INFORMATION procInfo;
236 memset(&procInfo, 0, sizeof(procInfo));
237
238 STARTUPINFO startInfo;
239 memset(&startInfo, 0, sizeof(startInfo));
240 startInfo.cb = sizeof(startInfo);
241
242 bool couldExecute = CreateProcess(0, (wchar_t*)executable.utf16(),
243 0, 0, false,
244 CREATE_NO_WINDOW | CREATE_SUSPENDED,
245 0, 0, &startInfo, &procInfo);
246
247 if (couldExecute) {
248 CloseHandle(procInfo.hThread);
249 TerminateProcess(procInfo.hProcess, 0);
250 CloseHandle(procInfo.hProcess);
251 }
252 return couldExecute;
253}
254
255/*!
256 Determine the g++ version.
257*/
258
259int Environment::detectGPlusPlusVersion(const QString &executable)
260{
261 QRegExp regexp(QLatin1String("[gG]\\+\\+[\\.exEX]{0,4} ([^\\n]+) (\\d+)\\.(\\d+)\\.(\\d+)"));
262 QString stdOut = readProcessStandardOutput(executable + QLatin1String(" --version"));
263 if (regexp.indexIn(stdOut) != -1) {
264 const QString compiler = regexp.cap(1);
265 const int major = regexp.cap(2).toInt();
266 const int minor = regexp.cap(3).toInt();
267 const int patch = regexp.cap(4).toInt();
268 return (major << 16) + (minor << 8) + patch;
269 }
270 return 0;
271}
272
273/*!
274 Run a process and return its standard output.
275*/
276
277QString Environment::readProcessStandardOutput(const QString &commandLine)
278{
279 QString stdOut;
280 TCHAR tempFileName[MAX_PATH];
281 TCHAR tempPathBuffer[MAX_PATH];
282 if (!GetTempPath(MAX_PATH, tempPathBuffer)
283 || !GetTempFileName(tempPathBuffer, TEXT("qtconfigure"), 0, tempFileName))
284 return stdOut;
285
286 STARTUPINFO startInfo;
287 memset(&startInfo, 0, sizeof(startInfo));
288 startInfo.cb = sizeof(startInfo);
289 startInfo.dwFlags |= STARTF_USESTDHANDLES;
290
291 SECURITY_ATTRIBUTES securityAttributes;
292 securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
293 securityAttributes.bInheritHandle = TRUE;
294 securityAttributes.lpSecurityDescriptor = NULL;
295
296 startInfo.hStdOutput = CreateFile(tempFileName, GENERIC_WRITE, 0, &securityAttributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
297 if (startInfo.hStdOutput == INVALID_HANDLE_VALUE)
298 return stdOut;
299
300 PROCESS_INFORMATION procInfo;
301 memset(&procInfo, 0, sizeof(procInfo));
302
303 if (!CreateProcess(0, (wchar_t*)commandLine.utf16(),
304 0, 0, TRUE,
305 0,
306 0, 0, &startInfo, &procInfo)) {
307 CloseHandle(startInfo.hStdOutput);
308 DeleteFile(tempFileName);
309 return stdOut;
310 }
311
312 WaitForSingleObject(procInfo.hProcess, INFINITE);
313 CloseHandle(procInfo.hThread);
314 CloseHandle(procInfo.hProcess);
315 CloseHandle(startInfo.hStdOutput);
316 QFile file(QString::fromWCharArray(tempFileName));
317
318 if (file.open(QIODevice::Text| QIODevice::ReadOnly)) {
319 stdOut = QString::fromLocal8Bit(file.readAll());
320 file.close();
321 }
322 DeleteFile(tempFileName);
323 return stdOut;
324}
325
326/*!
327 Creates a commandling from \a program and it \a arguments,
328 escaping characters that needs it.
329*/
330static QString qt_create_commandline(const QString &program, const QStringList &arguments)
331{
332 QString programName = program;
333 if (!programName.startsWith("\"") && !programName.endsWith("\"") && programName.contains(" "))
334 programName = "\"" + programName + "\"";
335 programName.replace("/", "\\");
336
337 QString args;
338 // add the prgram as the first arrg ... it works better
339 args = programName + " ";
340 for (int i=0; i<arguments.size(); ++i) {
341 QString tmp = arguments.at(i);
342 // in the case of \" already being in the string the \ must also be escaped
343 tmp.replace( "\\\"", "\\\\\"" );
344 // escape a single " because the arguments will be parsed
345 tmp.replace( "\"", "\\\"" );
346 if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
347 // The argument must not end with a \ since this would be interpreted
348 // as escaping the quote -- rather put the \ behind the quote: e.g.
349 // rather use "foo"\ than "foo\"
350 QString endQuote("\"");
351 int i = tmp.length();
352 while (i>0 && tmp.at(i-1) == '\\') {
353 --i;
354 endQuote += "\\";
355 }
356 args += QString(" \"") + tmp.left(i) + endQuote;
357 } else {
358 args += ' ' + tmp;
359 }
360 }
361 return args;
362}
363
364/*!
365 Creates a QByteArray of the \a environment.
366*/
367static QByteArray qt_create_environment(const QStringList &environment)
368{
369 QByteArray envlist;
370 if (environment.isEmpty())
371 return envlist;
372
373 int pos = 0;
374 // add PATH if necessary (for DLL loading)
375 QByteArray path = qgetenv("PATH");
376 if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() && !path.isNull()) {
377 QString tmp = QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path));
378 uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
379 envlist.resize(envlist.size() + tmpSize);
380 memcpy(envlist.data() + pos, tmp.utf16(), tmpSize);
381 pos += tmpSize;
382 }
383 // add the user environment
384 foreach (const QString &tmp, environment) {
385 uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
386 envlist.resize(envlist.size() + tmpSize);
387 memcpy(envlist.data() + pos, tmp.utf16(), tmpSize);
388 pos += tmpSize;
389 }
390 // add the 2 terminating 0 (actually 4, just to be on the safe side)
391 envlist.resize(envlist.size() + 4);
392 envlist[pos++] = 0;
393 envlist[pos++] = 0;
394 envlist[pos++] = 0;
395 envlist[pos++] = 0;
396
397 return envlist;
398}
399
400/*!
401 Executes the command described in \a arguments, in the
402 environment inherited from the parent process, with the
403 \a additionalEnv settings applied.
404 \a removeEnv removes the specified environment variables from
405 the environment of the executed process.
406
407 Returns the exit value of the process, or -1 if the command could
408 not be executed.
409
410 This function uses _(w)spawnvpe to spawn a process by searching
411 through the PATH environment variable.
412*/
413int Environment::execute(QStringList arguments, const QStringList &additionalEnv, const QStringList &removeEnv)
414{
415#ifdef CONFIGURE_DEBUG_EXECUTE
416 qDebug() << "About to Execute: " << arguments;
417 qDebug() << " " << QDir::currentPath();
418 qDebug() << " " << additionalEnv;
419 qDebug() << " " << removeEnv;
420#endif
421 // Create the full environment from the current environment and
422 // the additionalEnv strings, then remove all variables defined
423 // in removeEnv
424 QMap<QString, QString> fullEnvMap;
425 LPWSTR envStrings = GetEnvironmentStrings();
426 if (envStrings) {
427 int strLen = 0;
428 for (LPWSTR envString = envStrings; *(envString); envString += strLen + 1) {
429 strLen = wcslen(envString);
430 QString str = QString((const QChar*)envString, strLen);
431 if (!str.startsWith("=")) { // These are added by the system
432 int sepIndex = str.indexOf('=');
433 fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1));
434 }
435 }
436 }
437 FreeEnvironmentStrings(envStrings);
438
439 // Add additionalEnv variables
440 for (int i = 0; i < additionalEnv.count(); ++i) {
441 const QString &str = additionalEnv.at(i);
442 int sepIndex = str.indexOf('=');
443 fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1));
444 }
445
446 // Remove removeEnv variables
447 for (int j = 0; j < removeEnv.count(); ++j)
448 fullEnvMap.remove(removeEnv.at(j).toUpper());
449
450 // Add all variables to a QStringList
451 QStringList fullEnv;
452 QMapIterator<QString, QString> it(fullEnvMap);
453 while (it.hasNext()) {
454 it.next();
455 fullEnv += QString(it.key() + "=" + it.value());
456 }
457
458 // ----------------------------
459 QString program = arguments.takeAt(0);
460 QString args = qt_create_commandline(program, arguments);
461 QByteArray envlist = qt_create_environment(fullEnv);
462
463 DWORD exitCode = DWORD(-1);
464 PROCESS_INFORMATION procInfo;
465 memset(&procInfo, 0, sizeof(procInfo));
466
467 STARTUPINFO startInfo;
468 memset(&startInfo, 0, sizeof(startInfo));
469 startInfo.cb = sizeof(startInfo);
470
471 bool couldExecute = CreateProcess(0, (wchar_t*)args.utf16(),
472 0, 0, true, CREATE_UNICODE_ENVIRONMENT,
473 envlist.isEmpty() ? 0 : envlist.data(),
474 0, &startInfo, &procInfo);
475
476 if (couldExecute) {
477 WaitForSingleObject(procInfo.hProcess, INFINITE);
478 GetExitCodeProcess(procInfo.hProcess, &exitCode);
479 CloseHandle(procInfo.hThread);
480 CloseHandle(procInfo.hProcess);
481 }
482
483
484 if (exitCode == DWORD(-1)) {
485 switch(GetLastError()) {
486 case E2BIG:
487 cerr << "execute: Argument list exceeds 1024 bytes" << endl;
488 foreach (const QString &arg, arguments)
489 cerr << " (" << arg.toLocal8Bit().constData() << ")" << endl;
490 break;
491 case ENOENT:
492 cerr << "execute: File or path is not found (" << program.toLocal8Bit().constData() << ")" << endl;
493 break;
494 case ENOEXEC:
495 cerr << "execute: Specified file is not executable or has invalid executable-file format (" << program.toLocal8Bit().constData() << ")" << endl;
496 break;
497 case ENOMEM:
498 cerr << "execute: Not enough memory is available to execute new process." << endl;
499 break;
500 default:
501 cerr << "execute: Unknown error" << endl;
502 foreach (const QString &arg, arguments)
503 cerr << " (" << arg.toLocal8Bit().constData() << ")" << endl;
504 break;
505 }
506 }
507 return exitCode;
508}
509
510/*!
511 Copies the \a srcDir contents into \a destDir.
512
513 If \a includeSrcDir is not empty, any files with 'h', 'prf', or 'conf' suffixes
514 will not be copied over from \a srcDir. Instead a new file will be created
515 in \a destDir with the same name and that file will include a file with the
516 same name from the \a includeSrcDir using relative path and appropriate
517 syntax for the file type.
518
519 Returns true if copying was successful.
520*/
521bool Environment::cpdir(const QString &srcDir,
522 const QString &destDir,
523 const QString &includeSrcDir)
524{
525 QString cleanSrcName = QDir::cleanPath(srcDir);
526 QString cleanDstName = QDir::cleanPath(destDir);
527 QString cleanIncludeName = QDir::cleanPath(includeSrcDir);
528
529#ifdef CONFIGURE_DEBUG_CP_DIR
530 qDebug() << "Attempt to cpdir " << cleanSrcName << "->" << cleanDstName;
531#endif
532 if(!QFile::exists(cleanDstName) && !QDir().mkpath(cleanDstName)) {
533 qDebug() << "cpdir: Failure to create " << cleanDstName;
534 return false;
535 }
536
537 bool result = true;
538 QDir dir = QDir(cleanSrcName);
539 QDir destinationDir = QDir(cleanDstName);
540 QFileInfoList allEntries = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
541 for (int i = 0; result && (i < allEntries.count()); ++i) {
542 QFileInfo entry = allEntries.at(i);
543 bool intermediate = true;
544 if (entry.isDir()) {
545 QString newIncSrcDir;
546 if (!includeSrcDir.isEmpty())
547 newIncSrcDir = QString("%1/%2").arg(cleanIncludeName).arg(entry.fileName());
548
549 intermediate = cpdir(QString("%1/%2").arg(cleanSrcName).arg(entry.fileName()),
550 QString("%1/%2").arg(cleanDstName).arg(entry.fileName()),
551 newIncSrcDir);
552 } else {
553 QString destFile = QString("%1/%2").arg(cleanDstName).arg(entry.fileName());
554#ifdef CONFIGURE_DEBUG_CP_DIR
555 qDebug() << "About to cp (file)" << entry.absoluteFilePath() << "->" << destFile;
556#endif
557 QFile::remove(destFile);
558 QString suffix = entry.suffix();
559 if (!includeSrcDir.isEmpty() && (suffix == "prf" || suffix == "conf" || suffix == "h")) {
560 QString relativeIncludeFilePath = QString("%1/%2").arg(cleanIncludeName).arg(entry.fileName());
561 relativeIncludeFilePath = destinationDir.relativeFilePath(relativeIncludeFilePath);
562#ifdef CONFIGURE_DEBUG_CP_DIR
563 qDebug() << "...instead generate relative include to" << relativeIncludeFilePath;
564#endif
565 QFile currentFile(destFile);
566 if (currentFile.open(QFile::WriteOnly | QFile::Text)) {
567 QTextStream fileStream;
568 fileStream.setDevice(&currentFile);
569
570 if (suffix == "prf" || suffix == "conf") {
571 if (entry.fileName() == "qmake.conf") {
572 // While QMAKESPEC_ORIGINAL being relative or absolute doesn't matter for the
573 // primary use of this variable by qmake to identify the original mkspec, the
574 // variable is also used for few special cases where the absolute path is required.
575 // Conversely, the include of the original qmake.conf must be done using relative path,
576 // as some Qt binary deployments are done in a manner that doesn't allow for patching
577 // the paths at the installation time.
578 fileStream << "QMAKESPEC_ORIGINAL=" << cleanSrcName << endl << endl;
579 }
580 fileStream << "include(" << relativeIncludeFilePath << ")" << endl << endl;
581 } else if (suffix == "h") {
582 fileStream << "#include \"" << relativeIncludeFilePath << "\"" << endl << endl;
583 }
584
585 fileStream.flush();
586 currentFile.close();
587 }
588 } else {
589 intermediate = QFile::copy(entry.absoluteFilePath(), destFile);
590 SetFileAttributes((wchar_t*)destFile.utf16(), FILE_ATTRIBUTE_NORMAL);
591 }
592 }
593 if(!intermediate) {
594 qDebug() << "cpdir: Failure for " << entry.fileName() << entry.isDir();
595 result = false;
596 }
597 }
598 return result;
599}
600
601bool Environment::rmdir(const QString &name)
602{
603 bool result = true;
604 QString cleanName = QDir::cleanPath(name);
605
606 QDir dir = QDir(cleanName);
607 QFileInfoList allEntries = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
608 for (int i = 0; result && (i < allEntries.count()); ++i) {
609 QFileInfo entry = allEntries.at(i);
610 if (entry.isDir()) {
611 result &= rmdir(entry.absoluteFilePath());
612 } else {
613 result &= QFile::remove(entry.absoluteFilePath());
614 }
615 }
616 result &= dir.rmdir(cleanName);
617 return result;
618}
619
620QString Environment::symbianEpocRoot()
621{
622 // Call function defined in tools/shared/symbian/epocroot_p.h
623 return ::qt_epocRoot();
624}
625
626QT_END_NAMESPACE
627

Warning: That file was not part of the compilation database. It may have many parsing errors.