Commit 70bc5e84 authored by Nikolai Kosjar's avatar Nikolai Kosjar

CppTools: Add toolchain type to project part and use it

Making CompilerOptionsBuilder to use the toolchain from the project part
simplifies its public API, but following the code paths initiated by
ClangCodeModel and ClangStaticAnalyzer gets harder, so better enable the
separation of those by making CompilerOptionsBuilder a base class.

Change-Id: I0a6bb3f8323ba09b88135a7f9d1ef967331a8ff0
Reviewed-by: default avatarChristian Kandeler <christian.kandeler@theqtcompany.com>
parent f8544bbc
...@@ -58,20 +58,6 @@ namespace Utils { ...@@ -58,20 +58,6 @@ namespace Utils {
Q_LOGGING_CATEGORY(verboseRunLog, "qtc.clangcodemodel.verboserun") Q_LOGGING_CATEGORY(verboseRunLog, "qtc.clangcodemodel.verboserun")
namespace {
bool isBlacklisted(const QString &path)
{
static QStringList blacklistedPaths = QStringList()
<< QLatin1String("lib/gcc/i686-apple-darwin");
foreach (const QString &blacklisted, blacklistedPaths)
if (path.contains(blacklisted))
return true;
return false;
}
} // anonymous namespace
UnsavedFiles createUnsavedFiles(WorkingCopy workingCopy) UnsavedFiles createUnsavedFiles(WorkingCopy workingCopy)
{ {
// TODO: change the modelmanager to hold one working copy, and amend it every time we ask for one. // TODO: change the modelmanager to hold one working copy, and amend it every time we ask for one.
...@@ -132,60 +118,80 @@ static bool maybeIncludeBorlandExtensions() ...@@ -132,60 +118,80 @@ static bool maybeIncludeBorlandExtensions()
#endif #endif
} }
/** class LibClangOptionsBuilder : public CompilerOptionsBuilder
* @brief Creates list of command-line arguments required for correct parsing
* @param pPart Null if file isn't part of any project
* @param fileKind Determines language and source/header state
*/
QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind fileKind)
{ {
if (pPart.isNull()) public:
return QStringList(); static QStringList build(const ProjectPart::Ptr &pPart, ProjectFile::Kind fileKind)
{
CompilerOptionsBuilder optionsBuilder(pPart); if (pPart.isNull())
return QStringList();
LibClangOptionsBuilder optionsBuilder(pPart);
if (verboseRunLog().isDebugEnabled())
optionsBuilder.add(QLatin1String("-v"));
optionsBuilder.addLanguageOption(fileKind);
optionsBuilder.addOptionsForLanguage(maybeIncludeBorlandExtensions());
optionsBuilder.addToolchainAndProjectDefines();
static const QString resourceDir = getResourceDir();
if (!resourceDir.isEmpty()) {
optionsBuilder.add(QLatin1String("-nostdlibinc"));
optionsBuilder.add(QLatin1String("-I") + resourceDir);
optionsBuilder.add(QLatin1String("-undef"));
}
if (verboseRunLog().isDebugEnabled()) optionsBuilder.addHeaderPathOptions();
optionsBuilder.add(QLatin1String("-v"));
optionsBuilder.addLanguageOption(fileKind); // Inject header file
optionsBuilder.addOptionsForLanguage(maybeIncludeBorlandExtensions()); static const QString injectedHeader = ICore::instance()->resourcePath()
optionsBuilder.addToolchainAndProjectDefines(); + QLatin1String("/cplusplus/qt%1-qobjectdefs-injected.h");
static const QString resourceDir = getResourceDir(); // if (pPart->qtVersion == ProjectPart::Qt4) {
if (!resourceDir.isEmpty()) { // builder.addOption(QLatin1String("-include"));
optionsBuilder.add(QLatin1String("-nostdlibinc")); // builder.addOption(injectedHeader.arg(QLatin1Char('4')));
optionsBuilder.add(QLatin1String("-I") + resourceDir); // }
optionsBuilder.add(QLatin1String("-undef"));
}
optionsBuilder.addHeaderPathOptions(isBlacklisted); if (pPart->qtVersion == ProjectPart::Qt5) {
optionsBuilder.add(QLatin1String("-include"));
optionsBuilder.add(injectedHeader.arg(QLatin1Char('5')));
}
// Inject header file if (!pPart->projectConfigFile.isEmpty()) {
static const QString injectedHeader = ICore::instance()->resourcePath() optionsBuilder.add(QLatin1String("-include"));
+ QLatin1String("/cplusplus/qt%1-qobjectdefs-injected.h"); optionsBuilder.add(pPart->projectConfigFile);
}
// if (pPart->qtVersion == ProjectPart::Qt4) { optionsBuilder.add(QLatin1String("-fmessage-length=0"));
// builder.addOption(QLatin1String("-include")); optionsBuilder.add(QLatin1String("-fdiagnostics-show-note-include-stack"));
// builder.addOption(injectedHeader.arg(QLatin1Char('4'))); optionsBuilder.add(QLatin1String("-fmacro-backtrace-limit=0"));
// } optionsBuilder.add(QLatin1String("-fretain-comments-from-system-headers"));
// TODO: -Xclang -ferror-limit -Xclang 0 ?
if (pPart->qtVersion == ProjectPart::Qt5) { return optionsBuilder.options();
optionsBuilder.add(QLatin1String("-include"));
optionsBuilder.add(injectedHeader.arg(QLatin1Char('5')));
} }
if (!pPart->projectConfigFile.isEmpty()) { private:
optionsBuilder.add(QLatin1String("-include")); LibClangOptionsBuilder(const CppTools::ProjectPart::Ptr &projectPart)
optionsBuilder.add(pPart->projectConfigFile); : CompilerOptionsBuilder(projectPart)
{
} }
optionsBuilder.add(QLatin1String("-fmessage-length=0")); bool excludeHeaderPath(const QString &path) const override
optionsBuilder.add(QLatin1String("-fdiagnostics-show-note-include-stack")); {
optionsBuilder.add(QLatin1String("-fmacro-backtrace-limit=0")); return path.contains(QLatin1String("lib/gcc/i686-apple-darwin"));
optionsBuilder.add(QLatin1String("-fretain-comments-from-system-headers")); }
// TODO: -Xclang -ferror-limit -Xclang 0 ? };
return optionsBuilder.options(); /**
* @brief Creates list of command-line arguments required for correct parsing
* @param pPart Null if file isn't part of any project
* @param fileKind Determines language and source/header state
*/
QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind fileKind)
{
return LibClangOptionsBuilder::build(pPart, fileKind);
} }
/// @return Option to speed up parsing with precompiled header /// @return Option to speed up parsing with precompiled header
......
...@@ -113,6 +113,7 @@ void ProjectPart::evaluateToolchain(const ToolChain *tc, ...@@ -113,6 +113,7 @@ void ProjectPart::evaluateToolchain(const ToolChain *tc,
} }
toolchainDefines = tc->predefinedMacros(commandLineFlags); toolchainDefines = tc->predefinedMacros(commandLineFlags);
toolchainType = tc->type();
updateLanguageFeatures(); updateLanguageFeatures();
} }
...@@ -516,12 +517,27 @@ void CompilerOptionsBuilder::add(const QString &option) ...@@ -516,12 +517,27 @@ void CompilerOptionsBuilder::add(const QString &option)
m_options.append(option); m_options.append(option);
} }
void CompilerOptionsBuilder::addHeaderPathOptions(IsBlackListed isBlackListed, QString CompilerOptionsBuilder::defineLineToDefineOption(const QByteArray &defineLine)
const QString &toolchainType) {
QByteArray str = defineLine.mid(8);
int spaceIdx = str.indexOf(' ');
const QString option = defineOption();
const bool hasValue = spaceIdx != -1;
QString arg = option + QLatin1String(str.left(hasValue ? spaceIdx : str.size()) + '=');
if (hasValue)
arg += QLatin1String(str.mid(spaceIdx + 1));
return arg;
}
void CompilerOptionsBuilder::addDefine(const QByteArray &defineLine)
{
m_options.append(defineLineToDefineOption(defineLine));
}
void CompilerOptionsBuilder::addHeaderPathOptions()
{ {
typedef ProjectPart::HeaderPath HeaderPath; typedef ProjectPart::HeaderPath HeaderPath;
const QString defaultPrefix const QString defaultPrefix = includeOption();
= QLatin1String(toolchainType == QLatin1String("msvc") ? "/I" : "-I");
QStringList result; QStringList result;
...@@ -529,7 +545,7 @@ void CompilerOptionsBuilder::addHeaderPathOptions(IsBlackListed isBlackListed, ...@@ -529,7 +545,7 @@ void CompilerOptionsBuilder::addHeaderPathOptions(IsBlackListed isBlackListed,
if (headerPath.path.isEmpty()) if (headerPath.path.isEmpty())
continue; continue;
if (isBlackListed && isBlackListed(headerPath.path)) if (excludeHeaderPath(headerPath.path))
continue; continue;
QString prefix; QString prefix;
...@@ -550,45 +566,18 @@ void CompilerOptionsBuilder::addHeaderPathOptions(IsBlackListed isBlackListed, ...@@ -550,45 +566,18 @@ void CompilerOptionsBuilder::addHeaderPathOptions(IsBlackListed isBlackListed,
m_options.append(result); m_options.append(result);
} }
void CompilerOptionsBuilder::addToolchainAndProjectDefines(const QString &toolchainType) void CompilerOptionsBuilder::addToolchainAndProjectDefines()
{ {
QByteArray extendedDefines = m_projectPart->toolchainDefines + m_projectPart->projectDefines; QByteArray extendedDefines = m_projectPart->toolchainDefines + m_projectPart->projectDefines;
QStringList result; QStringList result;
// In gcc headers, lots of built-ins are referenced that clang does not understand.
// Therefore, prevent the inclusion of the header that references them. Of course, this
// will break if code actually requires stuff from there, but that should be the less common
// case.
if (toolchainType == QLatin1String("mingw") || toolchainType == QLatin1String("gcc"))
extendedDefines += "#define _X86INTRIN_H_INCLUDED\n";
foreach (QByteArray def, extendedDefines.split('\n')) { foreach (QByteArray def, extendedDefines.split('\n')) {
if (def.isEmpty()) if (def.isEmpty() || excludeDefineLine(def))
continue;
// This is a quick fix for QTCREATORBUG-11501.
// TODO: do a proper fix, see QTCREATORBUG-11709.
if (def.startsWith("#define __cplusplus"))
continue;
// gcc 4.9 has:
// #define __has_include(STR) __has_include__(STR)
// #define __has_include_next(STR) __has_include_next__(STR)
// The right-hand sides are gcc built-ins that clang does not understand, and they'd
// override clang's own (non-macro, it seems) definitions of the symbols on the left-hand
// side.
if (toolchainType == QLatin1String("gcc") && def.contains("has_include"))
continue; continue;
QByteArray str = def.mid(8); const QString defineOption = defineLineToDefineOption(def);
int spaceIdx = str.indexOf(' '); if (!result.contains(defineOption))
const QString option = QLatin1String(toolchainType == QLatin1String("msvc") ? "/D" : "-D"); result.append(defineOption);
const bool hasValue = spaceIdx != -1;
QString arg = option + QLatin1String(str.left(hasValue ? spaceIdx : str.size()) + '=');
if (hasValue)
arg += QLatin1String(str.mid(spaceIdx + 1));
if (!result.contains(arg))
result.append(arg);
} }
m_options.append(result); m_options.append(result);
...@@ -651,41 +640,16 @@ static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objc ...@@ -651,41 +640,16 @@ static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objc
return opts; return opts;
} }
static QStringList createLanguageOptionMsvc(ProjectFile::Kind fileKind) void CompilerOptionsBuilder::addLanguageOption(ProjectFile::Kind fileKind)
{
QStringList opts;
switch (fileKind) {
case ProjectFile::CHeader:
case ProjectFile::CSource:
opts << QLatin1String("/TC");
break;
case ProjectFile::CXXHeader:
case ProjectFile::CXXSource:
opts << QLatin1String("/TP");
break;
default:
break;
}
return opts;
}
void CompilerOptionsBuilder::addLanguageOption(ProjectFile::Kind fileKind,
const QString &toolchainType)
{ {
const bool objcExt = m_projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions; const bool objcExt = m_projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions;
const QStringList options = toolchainType == QLatin1String("msvc") const QStringList options = createLanguageOptionGcc(fileKind, objcExt);
? createLanguageOptionMsvc(fileKind)
: createLanguageOptionGcc(fileKind, objcExt);
m_options.append(options); m_options.append(options);
} }
void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtensions, void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtensions)
const QString &toolchainType)
{ {
QStringList opts; QStringList opts;
if (toolchainType == QLatin1String("msvc"))
return;
const ProjectPart::LanguageExtensions languageExtensions = m_projectPart->languageExtensions; const ProjectPart::LanguageExtensions languageExtensions = m_projectPart->languageExtensions;
const bool gnuExtensions = languageExtensions & ProjectPart::GnuExtensions; const bool gnuExtensions = languageExtensions & ProjectPart::GnuExtensions;
switch (m_projectPart->languageVersion) { switch (m_projectPart->languageVersion) {
...@@ -723,3 +687,29 @@ void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtension ...@@ -723,3 +687,29 @@ void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtension
m_options.append(opts); m_options.append(opts);
} }
QString CompilerOptionsBuilder::includeOption() const
{
return QLatin1String("-I");
}
QString CompilerOptionsBuilder::defineOption() const
{
return QLatin1String("-D");
}
bool CompilerOptionsBuilder::excludeDefineLine(const QByteArray &defineLine) const
{
// This is a quick fix for QTCREATORBUG-11501.
// TODO: do a proper fix, see QTCREATORBUG-11709.
if (defineLine.startsWith("#define __cplusplus"))
return true;
return false;
}
bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const
{
Q_UNUSED(headerPath);
return false;
}
...@@ -130,6 +130,7 @@ public: // fields ...@@ -130,6 +130,7 @@ public: // fields
QString projectConfigFile; // currently only used by the Generic Project Manager QString projectConfigFile; // currently only used by the Generic Project Manager
QByteArray projectDefines; QByteArray projectDefines;
QByteArray toolchainDefines; QByteArray toolchainDefines;
QString toolchainType;
QList<HeaderPath> headerPaths; QList<HeaderPath> headerPaths;
QStringList precompiledHeaders; QStringList precompiledHeaders;
LanguageVersion languageVersion; LanguageVersion languageVersion;
...@@ -215,22 +216,32 @@ class CPPTOOLS_EXPORT CompilerOptionsBuilder ...@@ -215,22 +216,32 @@ class CPPTOOLS_EXPORT CompilerOptionsBuilder
{ {
public: public:
CompilerOptionsBuilder(const ProjectPart::Ptr &projectPart); CompilerOptionsBuilder(const ProjectPart::Ptr &projectPart);
virtual ~CompilerOptionsBuilder() {}
QStringList options() const; QStringList options() const;
// Add custom options
void add(const QString &option); void add(const QString &option);
void addDefine(const QByteArray &defineLine);
typedef std::function<bool (const QString &)> IsBlackListed; // Add options based on project part
void addHeaderPathOptions(IsBlackListed isBlackListed = IsBlackListed(), void addHeaderPathOptions();
const QString &toolchainType = QLatin1String("clang")); void addToolchainAndProjectDefines();
void addToolchainAndProjectDefines(const QString &toolchainType = QLatin1String("clang")); virtual void addLanguageOption(ProjectFile::Kind fileKind);
void addLanguageOption(ProjectFile::Kind fileKind, virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
const QString &toolchainType = QLatin1String("clang"));
void addOptionsForLanguage(bool checkForBorlandExtensions = true, protected:
const QString &toolchainType = QLatin1String("clang")); virtual bool excludeDefineLine(const QByteArray &defineLine) const;
virtual bool excludeHeaderPath(const QString &headerPath) const;
virtual QString defineOption() const;
virtual QString includeOption() const;
const ProjectPart::Ptr m_projectPart;
private: private:
ProjectPart::Ptr m_projectPart; QString defineLineToDefineOption(const QByteArray &defineLine);
QStringList m_options; QStringList m_options;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment