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 | |
58 | using 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 | |
67 | QT_BEGIN_NAMESPACE |
68 | |
69 | struct 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 |
92 | Compiler Environment::detectedCompiler = CC_UNKNOWN; |
93 | |
94 | /*! |
95 | Returns the pointer to the CompilerInfo for a \a compiler. |
96 | */ |
97 | CompilerInfo *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 | */ |
108 | QString 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 | */ |
156 | Compiler 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 | */ |
233 | bool 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 | |
259 | int 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 | |
277 | QString 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 | */ |
330 | static 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( |
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 += |
359 | } |
360 | } |
361 | return args; |
362 | } |
363 | |
364 | /*! |
365 | Creates a QByteArray of the \a environment. |
366 | */ |
367 | static 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 | */ |
413 | int 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 | */ |
521 | bool 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(¤tFile); |
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 | |
601 | bool 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 | |
620 | QString Environment::symbianEpocRoot() |
621 | { |
622 | // Call function defined in tools/shared/symbian/epocroot_p.h |
623 | return ::qt_epocRoot(); |
624 | } |
625 | |
626 | QT_END_NAMESPACE |
627 |
Warning: That file was not part of the compilation database. It may have many parsing errors.