diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp index 74816753ba3..fb3ad79b7af 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp @@ -98,54 +98,6 @@ QString AbstractMsvcToolChain::originalTargetTriple() const : QLatin1String("i686-pc-windows-msvc"); } -// -// We want to detect the language version based on the predefined macros. -// Unfortunately MSVC does not conform to standard when it comes to the predefined -// __cplusplus macro - it reports "199711L", even for newer language versions. -// -// However: -// * For >= Visual Studio 2015 Update 3 predefines _MSVC_LANG which has the proper value -// of __cplusplus. -// See https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017 -// * For >= Visual Studio 2017 Version 15.7 __cplusplus is correct once /Zc:__cplusplus -// is provided on the command line. Then __cplusplus == _MSVC_LANG. -// See https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus -// -// We rely on _MSVC_LANG if possible, otherwise on some hard coded language versions -// depending on _MSC_VER. -// -// For _MSV_VER values, see https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017. -// -LanguageVersion static languageVersionForMsvc(const Core::Id &language, const Macros ¯os) -{ - int mscVer = -1; - QByteArray msvcLang; - for (const ProjectExplorer::Macro ¯o : macros) { - if (macro.key == "_MSVC_LANG") - msvcLang = macro.value; - if (macro.key == "_MSC_VER") - mscVer = macro.value.toInt(nullptr); - } - QTC_CHECK(mscVer > 0); - - if (language == Constants::CXX_LANGUAGE_ID) { - if (!msvcLang.isEmpty()) // >= Visual Studio 2015 Update 3 - return ToolChain::cxxLanguageVersion(msvcLang); - if (mscVer >= 1800) // >= Visual Studio 2013 (12.0) - return LanguageVersion::CXX14; - if (mscVer >= 1600) // >= Visual Studio 2010 (10.0) - return LanguageVersion::CXX11; - return LanguageVersion::CXX98; - } else if (language == Constants::C_LANGUAGE_ID) { - if (mscVer >= 1910) // >= Visual Studio 2017 RTW (15.0) - return LanguageVersion::C11; - return LanguageVersion::C99; - } else { - QTC_CHECK(false && "Unexpected toolchain language, assuming latest C++ we support."); - return LanguageVersion::LatestCxx; - } -} - bool static hasFlagEffectOnMacros(const QString &flag) { if (flag.startsWith("-") || flag.startsWith("/")) { @@ -177,8 +129,7 @@ ToolChain::MacroInspectionRunner AbstractMsvcToolChain::createMacroInspectionRun const Macros macros = msvcPredefinedMacros(filteredFlags, env); - const auto report = MacroInspectionReport{macros, - languageVersionForMsvc(lang, macros)}; + const auto report = MacroInspectionReport{macros, languageVersion(macros)}; macroCache->insert(filteredFlags, report); return report; diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.h b/src/plugins/projectexplorer/abstractmsvctoolchain.h index a0836e4dc6c..ccafa4f2995 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.h +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.h @@ -98,7 +98,7 @@ protected: // Function must be thread-safe! virtual Macros msvcPredefinedMacros(const QStringList cxxflags, const Utils::Environment& env) const = 0; - + virtual LanguageVersion languageVersion(const Macros ¯os) const = 0; Utils::FileName m_debuggerCommand; diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 0f2060b840d..be82713d4cd 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -29,7 +29,6 @@ #include "gccparser.h" #include "linuxiccparser.h" #include "projectmacro.h" -#include "projectexplorerconstants.h" #include "toolchainmanager.h" #include @@ -98,18 +97,6 @@ static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, cons return response.allOutput().toUtf8(); } -static const QStringList languageOption(Core::Id languageId) -{ - if (languageId == Constants::C_LANGUAGE_ID) - return {"-x", "c"}; - return {"-x", "c++"}; -} - -static const QStringList gccPredefinedMacrosOptions(Core::Id languageId) -{ - return languageOption(languageId) + QStringList({"-E", "-dM"}); -} - static ProjectExplorer::Macros gccPredefinedMacros(const FileName &gcc, const QStringList &args, const QStringList &env) diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 13685101fdc..c6e42fe73df 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -27,6 +27,7 @@ #include "projectexplorer_export.h" +#include "projectexplorerconstants.h" #include "toolchain.h" #include "toolchaincache.h" #include "abi.h" @@ -51,6 +52,18 @@ class LinuxIccToolChainFactory; // GccToolChain // -------------------------------------------------------------------------- +inline const QStringList languageOption(Core::Id languageId) +{ + if (languageId == Constants::C_LANGUAGE_ID) + return {"-x", "c"}; + return {"-x", "c++"}; +} + +inline const QStringList gccPredefinedMacrosOptions(Core::Id languageId) +{ + return languageOption(languageId) + QStringList({"-E", "-dM"}); +} + class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain { public: diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 45fa8a5ecef..4707375ab29 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -25,6 +25,7 @@ #include "msvctoolchain.h" +#include "gcctoolchain.h" #include "msvcparser.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" @@ -506,6 +507,55 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags, return predefinedMacros; } +// +// We want to detect the language version based on the predefined macros. +// Unfortunately MSVC does not conform to standard when it comes to the predefined +// __cplusplus macro - it reports "199711L", even for newer language versions. +// +// However: +// * For >= Visual Studio 2015 Update 3 predefines _MSVC_LANG which has the proper value +// of __cplusplus. +// See https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017 +// * For >= Visual Studio 2017 Version 15.7 __cplusplus is correct once /Zc:__cplusplus +// is provided on the command line. Then __cplusplus == _MSVC_LANG. +// See https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus +// +// We rely on _MSVC_LANG if possible, otherwise on some hard coded language versions +// depending on _MSC_VER. +// +// For _MSV_VER values, see https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017. +// +LanguageVersion MsvcToolChain::languageVersion(const Macros ¯os) const +{ + const Core::Id lang = language(); + int mscVer = -1; + QByteArray msvcLang; + for (const ProjectExplorer::Macro ¯o : macros) { + if (macro.key == "_MSVC_LANG") + msvcLang = macro.value; + if (macro.key == "_MSC_VER") + mscVer = macro.value.toInt(nullptr); + } + QTC_CHECK(mscVer > 0); + + if (lang == Constants::CXX_LANGUAGE_ID) { + if (!msvcLang.isEmpty()) // >= Visual Studio 2015 Update 3 + return ToolChain::cxxLanguageVersion(msvcLang); + if (mscVer >= 1800) // >= Visual Studio 2013 (12.0) + return LanguageVersion::CXX14; + if (mscVer >= 1600) // >= Visual Studio 2010 (10.0) + return LanguageVersion::CXX11; + return LanguageVersion::CXX98; + } else if (lang == Constants::C_LANGUAGE_ID) { + if (mscVer >= 1910) // >= Visual Studio 2017 RTW (15.0) + return LanguageVersion::C11; + return LanguageVersion::C99; + } else { + QTC_CHECK(false && "Unexpected toolchain language, assuming latest C++ we support."); + return LanguageVersion::LatestCxx; + } +} + // Windows: Expand the delayed evaluation references returned by the // SDK setup scripts: "PATH=!Path!;foo". Some values might expand // to empty and should not be added @@ -1063,6 +1113,31 @@ bool ClangClToolChain::operator ==(const ToolChain &other) const return m_clangPath == clangClTc->m_clangPath; } +Macros ClangClToolChain::msvcPredefinedMacros(const QStringList cxxflags, + const Utils::Environment &env) const +{ + Utils::SynchronousProcess cpp; + cpp.setEnvironment(env.toStringList()); + cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath()); + + QStringList arguments = cxxflags; + arguments.append(gccPredefinedMacrosOptions(language())); + arguments.append("-"); + Utils::SynchronousProcessResponse response = cpp.runBlocking(compilerCommand().toString(), + arguments); + if (response.result != Utils::SynchronousProcessResponse::Finished || + response.exitCode != 0) { + return {}; + } + + return Macro::toMacros(response.allRawOutput()); +} + +LanguageVersion ClangClToolChain::languageVersion(const Macros ¯os) const +{ + return ToolChain::languageVersion(language(), macros); +} + // -------------------------------------------------------------------------- // MsvcToolChainFactory // -------------------------------------------------------------------------- diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index d26b8c52bf4..46b7489d23c 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -94,6 +94,7 @@ protected: // Function must be thread-safe! Macros msvcPredefinedMacros(const QStringList cxxflags, const Utils::Environment &env) const override; + LanguageVersion languageVersion(const Macros ¯os) const override; private: struct GenerateEnvResult @@ -136,6 +137,9 @@ public: void setClangPath(const QString &path) { m_clangPath = path; } void resetMsvcToolChain(const MsvcToolChain *base = nullptr); + Macros msvcPredefinedMacros(const QStringList cxxflags, + const Utils::Environment &env) const override; + LanguageVersion languageVersion(const Macros ¯os) const override; bool operator ==(const ToolChain &) const override; private: