/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ #include "toolchain.h" #include "project.h" #include "cesdkhandler.h" #include "projectexplorersettings.h" #include "gccparser.h" #include "msvcparser.h" #include #include #include #include #include #include #include #include using namespace ProjectExplorer; using namespace ProjectExplorer::Internal; #ifdef Q_OS_WIN64 static const char * MSVC_RegKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"; #else static const char * MSVC_RegKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"; #endif bool ToolChain::equals(ToolChain *a, ToolChain *b) { if (a == b) return true; if (a == 0 || b == 0) return false; if (a->type() == b->type()) return a->equals(b); return false; } ToolChain::ToolChain() { } ToolChain::~ToolChain() { } ToolChain *ToolChain::createGccToolChain(const QString &gcc) { return new GccToolChain(gcc); } ToolChain *ToolChain::createMinGWToolChain(const QString &gcc, const QString &mingwPath) { return new MinGWToolChain(gcc, mingwPath); } ToolChain *ToolChain::createMSVCToolChain(const QString &name, bool amd64 = false) { return new MSVCToolChain(name, amd64); } ToolChain *ToolChain::createWinCEToolChain(const QString &name, const QString &platform) { return new WinCEToolChain(name, platform); } QStringList ToolChain::availableMSVCVersions() { QSettings registry(MSVC_RegKey, QSettings::NativeFormat); QStringList versions = registry.allKeys(); return versions; } QList ToolChain::supportedToolChains() { QList toolChains; for (int i = 0; i < LAST_VALID; ++i) { toolChains.append(ToolChainType(i)); } return toolChains; } QString ToolChain::toolChainName(ToolChainType tc) { switch (tc) { case GCC: return QCoreApplication::translate("ToolChain", "GCC"); // case LinuxICC: // return QCoreApplication::translate("ToolChain", "Intel C++ Compiler (Linux)"); case MinGW: return QString::fromLatin1("MinGW"); case MSVC: return QCoreApplication::translate("ToolChain", "Microsoft Visual C++"); case WINCE: return QCoreApplication::translate("ToolChain", "Windows CE"); case WINSCW: return QCoreApplication::translate("ToolChain", "WINSCW"); case GCCE: return QCoreApplication::translate("ToolChain", "GCCE"); case GCCE_GNUPOC: return QCoreApplication::translate("ToolChain", "GCCE/GnuPoc"); case RVCT_ARMV6_GNUPOC: return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)/GnuPoc"); case RVCT_ARMV5: return QCoreApplication::translate("ToolChain", "RVCT (ARMV5)"); case RVCT_ARMV6: return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)"); case GCC_MAEMO: return QCoreApplication::translate("ToolChain", "GCC for Maemo"); case OTHER: return QCoreApplication::translate("ToolChain", "Other"); case INVALID: return QCoreApplication::translate("ToolChain", ""); case UNKNOWN: break; default: Q_ASSERT("Missing name for Toolchaintype"); }; return QCoreApplication::translate("ToolChain", ""); } GccToolChain::GccToolChain(const QString &gcc) : m_gcc(gcc) { } ToolChain::ToolChainType GccToolChain::type() const { return ToolChain::GCC; } QByteArray GccToolChain::predefinedMacros() { if (m_predefinedMacros.isEmpty()) { QStringList arguments; arguments << QLatin1String("-xc++") << QLatin1String("-E") << QLatin1String("-dM") << QLatin1String("-"); QProcess cpp; ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); cpp.setEnvironment(env.toStringList()); cpp.start(m_gcc, arguments); cpp.closeWriteChannel(); cpp.waitForFinished(); m_predefinedMacros = cpp.readAllStandardOutput(); #ifdef Q_OS_MAC // Turn off flag indicating Apple's blocks support int idx = m_predefinedMacros.indexOf("#define __BLOCKS__ 1"); if (idx != -1) { idx = m_predefinedMacros.indexOf('1', idx); m_predefinedMacros[idx] = '0'; } // Define __strong and __weak (used for Apple's GC extension of C) to be empty m_predefinedMacros.append("#define __strong\n"); m_predefinedMacros.append("#define __weak\n"); #endif // Q_OS_MAC } return m_predefinedMacros; } QList GccToolChain::systemHeaderPaths() { if (m_systemHeaderPaths.isEmpty()) { QStringList arguments; arguments << QLatin1String("-xc++") << QLatin1String("-E") << QLatin1String("-v") << QLatin1String("-"); QProcess cpp; ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); env.set(QLatin1String("LC_ALL"), QLatin1String("C")); //override current locale settings cpp.setEnvironment(env.toStringList()); cpp.setReadChannelMode(QProcess::MergedChannels); cpp.start(m_gcc, arguments); cpp.closeWriteChannel(); cpp.waitForFinished(); QByteArray line; while (cpp.canReadLine()) { line = cpp.readLine(); if (line.startsWith("#include")) break; } if (! line.isEmpty() && line.startsWith("#include")) { HeaderPath::Kind kind = HeaderPath::UserHeaderPath; while (cpp.canReadLine()) { line = cpp.readLine(); if (line.startsWith("#include")) { kind = HeaderPath::GlobalHeaderPath; } else if (! line.isEmpty() && QChar(line.at(0)).isSpace()) { HeaderPath::Kind thisHeaderKind = kind; line = line.trimmed(); if (line.endsWith('\n')) line.chop(1); int index = line.indexOf(" (framework directory)"); if (index != -1) { line = line.left(index); thisHeaderKind = HeaderPath::FrameworkHeaderPath; } m_systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind)); } else if (line.startsWith("End of search list.")) { break; } else { qWarning() << "ignore line:" << line; } } } } return m_systemHeaderPaths; } void GccToolChain::addToEnvironment(ProjectExplorer::Environment &env) { Q_UNUSED(env) } QString GccToolChain::makeCommand() const { return QLatin1String("make"); } IOutputParser *GccToolChain::outputParser() const { return new GccParser; } bool GccToolChain::equals(ToolChain *other) const { return (m_gcc == static_cast(other)->m_gcc); } MinGWToolChain::MinGWToolChain(const QString &gcc, const QString &mingwPath) : GccToolChain(gcc), m_mingwPath(mingwPath) { } ToolChain::ToolChainType MinGWToolChain::type() const { return ToolChain::MinGW; } bool MinGWToolChain::equals(ToolChain *other) const { MinGWToolChain *o = static_cast(other); return (m_mingwPath == o->m_mingwPath && this->GccToolChain::equals(other)); } void MinGWToolChain::addToEnvironment(ProjectExplorer::Environment &env) { if (m_mingwPath.isEmpty()) return; QString binDir = m_mingwPath + "/bin"; if (QFileInfo(binDir).exists()) env.prependOrSetPath(binDir); } QString MinGWToolChain::makeCommand() const { return QLatin1String("mingw32-make.exe"); } IOutputParser *MinGWToolChain::outputParser() const { return new GccParser; } MSVCToolChain::MSVCToolChain(const QString &name, bool amd64) : m_name(name), m_valuesSet(false), m_amd64(amd64) { if (m_name.isEmpty()) { // Could be because system qt doesn't set this QSettings registry(MSVC_RegKey, QSettings::NativeFormat); QStringList keys = registry.allKeys(); if (keys.count()) m_name = keys.first(); } } ToolChain::ToolChainType MSVCToolChain::type() const { return ToolChain::MSVC; } bool MSVCToolChain::equals(ToolChain *other) const { MSVCToolChain *o = static_cast(other); return (m_name == o->m_name); } QByteArray msvcCompilationFile() { static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER", "__cplusplus_cli", "__COUNTER__", "__cplusplus", "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND", "_DEBUG", "_DLL", "__FUNCDNAME__", "__FUNCSIG__","__FUNCTION__","_INTEGRAL_MAX_BITS", "_M_ALPHA","_M_CEE","_M_CEE_PURE", "_M_CEE_SAFE","_M_IX86","_M_IA64", "_M_IX86_FP","_M_MPPC","_M_MRX000", "_M_PPC","_M_X64","_MANAGED", "_MFC_VER","_MSC_BUILD", /* "_MSC_EXTENSIONS", */ "_MSC_FULL_VER","_MSC_VER","__MSVC_RUNTIME_CHECKS", "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP", "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32", "_WIN32_WCE", "_WIN64", "_Wp64", "__DATE__", "__DATE__", "__TIME__", "__TIMESTAMP__", 0}; QByteArray file = "#define __PPOUT__(x) V##x=x\n\n"; int i =0; while (macros[i] != 0) { const QByteArray macro(macros[i]); file += "#if defined(" + macro + ")\n__PPOUT__(" + macro + ")\n#endif\n"; ++i; } file += "\nvoid main(){}\n\n"; return file; } QByteArray MSVCToolChain::predefinedMacros() { if (m_predefinedMacros.isEmpty()) { m_predefinedMacros += "#define __MSVCRT__\n" "#define __w64\n" "#define __int64 long long\n" "#define __int32 long\n" "#define __int16 short\n" "#define __int8 char\n" "#define __ptr32\n" "#define __ptr64\n"; QString tmpFilePath; { // QTemporaryFile is buggy and will not unlock the file for cl.exe QTemporaryFile tmpFile(QDir::tempPath()+"/envtestXXXXXX.cpp"); tmpFile.setAutoRemove(false); if (!tmpFile.open()) return m_predefinedMacros; tmpFilePath = QFileInfo(tmpFile).canonicalFilePath(); tmpFile.write(msvcCompilationFile()); tmpFile.close(); } ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); QProcess cpp; cpp.setEnvironment(env.toStringList()); cpp.setWorkingDirectory(QDir::tempPath()); QStringList arguments; arguments << "/EP" << QDir::toNativeSeparators(tmpFilePath); cpp.start(QLatin1String("cl.exe"), arguments); cpp.closeWriteChannel(); cpp.waitForFinished(); QList output = cpp.readAllStandardOutput().split('\n'); foreach (const QByteArray& line, output) { if (line.startsWith('V')) { QList split = line.split('='); QByteArray key = split.at(0).mid(1); QByteArray value = split.at(1); if (!value.isEmpty()) { value.chop(1); //remove '\n' } QByteArray newDefine = "#define " + key + ' ' + value + '\n'; m_predefinedMacros.append(newDefine); } } QFile::remove(tmpFilePath); } return m_predefinedMacros; } QList MSVCToolChain::systemHeaderPaths() { //TODO fix this code ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); QList headerPaths; foreach(const QString &path, env.value("INCLUDE").split(QLatin1Char(';'))) { headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath)); } return headerPaths; } void MSVCToolChain::addToEnvironment(ProjectExplorer::Environment &env) { if (!m_valuesSet || env != m_lastEnvironment) { m_lastEnvironment = env; QSettings registry(MSVC_RegKey, QSettings::NativeFormat); if (m_name.isEmpty()) return; QString path = registry.value(m_name).toString(); QString desc; QString varsbat; if (m_amd64) varsbat = path + "bin\\amd64\\vcvarsamd64.bat"; else varsbat = path + "bin\\vcvars32.bat"; if (QFileInfo(varsbat).exists()) { QTemporaryFile tf(QDir::tempPath() + "\\XXXXXX.bat"); if (!tf.open()) return; QString filename = tf.fileName(); tf.write("call \"" + varsbat.toLocal8Bit()+"\"\r\n"); QString redirect = "set > \"" + QDir::tempPath() + "\\qtcreator-msvc-environment.txt\"\r\n"; tf.write(redirect.toLocal8Bit()); tf.flush(); tf.waitForBytesWritten(30000); QProcess run; run.setEnvironment(env.toStringList()); QString cmdPath = env.searchInPath("cmd"); run.start(cmdPath, QStringList()<<"/c"<(variable, value)); } } vars.close(); vars.remove(); } } m_valuesSet = true; } QList< QPair >::const_iterator it, end; end = m_values.constEnd(); for (it = m_values.constBegin(); it != end; ++it) { env.set((*it).first, (*it).second); } } QString MSVCToolChain::makeCommand() const { if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) { // We want jom! Try to find it. QString jom = QCoreApplication::applicationDirPath() + QLatin1String("/jom.exe"); if (QFileInfo(jom).exists()) return jom; else return QLatin1String("jom.exe"); } return QLatin1String("nmake.exe"); } IOutputParser *MSVCToolChain::outputParser() const { return new MsvcParser; } WinCEToolChain::WinCEToolChain(const QString &name, const QString &platform) : MSVCToolChain(name), m_platform(platform) { } ToolChain::ToolChainType WinCEToolChain::type() const { return ToolChain::WINCE; } bool WinCEToolChain::equals(ToolChain *other) const { WinCEToolChain *o = static_cast(other); return (m_platform == o->m_platform && this->MSVCToolChain::equals(other)); } QByteArray WinCEToolChain::predefinedMacros() { //TODO return MSVCToolChain::predefinedMacros(); } QList WinCEToolChain::systemHeaderPaths() { //TODO fix this code ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); QList headerPaths; const QStringList includes = env.value("INCLUDE").split(QLatin1Char(';')); foreach (const QString &path, includes) { const HeaderPath headerPath(path, HeaderPath::GlobalHeaderPath); headerPaths.append(headerPath); } return headerPaths; } void WinCEToolChain::addToEnvironment(ProjectExplorer::Environment &env) { MSVCToolChain::addToEnvironment(env); QSettings registry(MSVC_RegKey, QSettings::NativeFormat); QString path = registry.value(m_name).toString(); // Find MSVC path path += QLatin1Char('/'); // Find Platform name CeSdkHandler cesdkhandler; cesdkhandler.parse(path); cesdkhandler.find(m_platform).addToEnvironment(env); }