ProjectExplorer: Get predefined clang-cl macros in g++ and cl driver modes

By default clang-cl accepts only MSVC-style compile flags.
However it's possible to run it with gcc-style flags when
--driver-mode=g++ is set.

With this change clang-cl is run in order to get proper
predefined macros for both cases.

Change-Id: I248d411561a503a60385b3a3106beecb38f3d063
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-10-30 10:21:04 +01:00
parent b97d4c2f80
commit f91862a212
6 changed files with 94 additions and 64 deletions

View File

@@ -98,54 +98,6 @@ QString AbstractMsvcToolChain::originalTargetTriple() const
: QLatin1String("i686-pc-windows-msvc"); : 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 &macros)
{
int mscVer = -1;
QByteArray msvcLang;
for (const ProjectExplorer::Macro &macro : 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) bool static hasFlagEffectOnMacros(const QString &flag)
{ {
if (flag.startsWith("-") || flag.startsWith("/")) { if (flag.startsWith("-") || flag.startsWith("/")) {
@@ -177,8 +129,7 @@ ToolChain::MacroInspectionRunner AbstractMsvcToolChain::createMacroInspectionRun
const Macros macros = msvcPredefinedMacros(filteredFlags, env); const Macros macros = msvcPredefinedMacros(filteredFlags, env);
const auto report = MacroInspectionReport{macros, const auto report = MacroInspectionReport{macros, languageVersion(macros)};
languageVersionForMsvc(lang, macros)};
macroCache->insert(filteredFlags, report); macroCache->insert(filteredFlags, report);
return report; return report;

View File

@@ -98,7 +98,7 @@ protected:
// Function must be thread-safe! // Function must be thread-safe!
virtual Macros msvcPredefinedMacros(const QStringList cxxflags, virtual Macros msvcPredefinedMacros(const QStringList cxxflags,
const Utils::Environment& env) const = 0; const Utils::Environment& env) const = 0;
virtual LanguageVersion languageVersion(const Macros &macros) const = 0;
Utils::FileName m_debuggerCommand; Utils::FileName m_debuggerCommand;

View File

@@ -29,7 +29,6 @@
#include "gccparser.h" #include "gccparser.h"
#include "linuxiccparser.h" #include "linuxiccparser.h"
#include "projectmacro.h" #include "projectmacro.h"
#include "projectexplorerconstants.h"
#include "toolchainmanager.h" #include "toolchainmanager.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -98,18 +97,6 @@ static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, cons
return response.allOutput().toUtf8(); 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, static ProjectExplorer::Macros gccPredefinedMacros(const FileName &gcc,
const QStringList &args, const QStringList &args,
const QStringList &env) const QStringList &env)

View File

@@ -27,6 +27,7 @@
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include "projectexplorerconstants.h"
#include "toolchain.h" #include "toolchain.h"
#include "toolchaincache.h" #include "toolchaincache.h"
#include "abi.h" #include "abi.h"
@@ -51,6 +52,18 @@ class LinuxIccToolChainFactory;
// GccToolChain // 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 class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain
{ {
public: public:

View File

@@ -25,6 +25,7 @@
#include "msvctoolchain.h" #include "msvctoolchain.h"
#include "gcctoolchain.h"
#include "msvcparser.h" #include "msvcparser.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
@@ -506,6 +507,55 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
return predefinedMacros; 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 &macros) const
{
const Core::Id lang = language();
int mscVer = -1;
QByteArray msvcLang;
for (const ProjectExplorer::Macro &macro : 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 // Windows: Expand the delayed evaluation references returned by the
// SDK setup scripts: "PATH=!Path!;foo". Some values might expand // SDK setup scripts: "PATH=!Path!;foo". Some values might expand
// to empty and should not be added // to empty and should not be added
@@ -1063,6 +1113,31 @@ bool ClangClToolChain::operator ==(const ToolChain &other) const
return m_clangPath == clangClTc->m_clangPath; 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 &macros) const
{
return ToolChain::languageVersion(language(), macros);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// MsvcToolChainFactory // MsvcToolChainFactory
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@@ -94,6 +94,7 @@ protected:
// Function must be thread-safe! // Function must be thread-safe!
Macros msvcPredefinedMacros(const QStringList cxxflags, Macros msvcPredefinedMacros(const QStringList cxxflags,
const Utils::Environment &env) const override; const Utils::Environment &env) const override;
LanguageVersion languageVersion(const Macros &macros) const override;
private: private:
struct GenerateEnvResult struct GenerateEnvResult
@@ -136,6 +137,9 @@ public:
void setClangPath(const QString &path) { m_clangPath = path; } void setClangPath(const QString &path) { m_clangPath = path; }
void resetMsvcToolChain(const MsvcToolChain *base = nullptr); void resetMsvcToolChain(const MsvcToolChain *base = nullptr);
Macros msvcPredefinedMacros(const QStringList cxxflags,
const Utils::Environment &env) const override;
LanguageVersion languageVersion(const Macros &macros) const override;
bool operator ==(const ToolChain &) const override; bool operator ==(const ToolChain &) const override;
private: private: