forked from qt-creator/qt-creator
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:
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include "gccparser.h"
|
||||
#include "linuxiccparser.h"
|
||||
#include "projectmacro.h"
|
||||
#include "projectexplorerconstants.h"
|
||||
#include "toolchainmanager.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
// --------------------------------------------------------------------------
|
||||
|
@@ -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:
|
||||
|
Reference in New Issue
Block a user