forked from qt-creator/qt-creator
CMake: separate processing C and C++ flags in TeaLeafReader
C and C++ flags holds at the different variables/compiler settings in the generated Make and Ninja files. Currently only C++ Flags processed and assumes that same one uses for C lang. But now QtC core can handle C and C++ separatelly, so just add processing for that flags and use it for code model. Change-Id: If1f71a2c58284a46324f04e962fc120cc316b0fb Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
@@ -65,7 +65,10 @@ BuildDirReader::Parameters::Parameters(const CMakeBuildConfiguration *bc)
|
|||||||
|
|
||||||
auto tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::ToolChain::Language::Cxx);
|
auto tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::ToolChain::Language::Cxx);
|
||||||
if (tc)
|
if (tc)
|
||||||
toolChainId = tc->id();
|
cxxToolChainId = tc->id();
|
||||||
|
tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::ToolChain::Language::C);
|
||||||
|
if (tc)
|
||||||
|
cToolChainId = tc->id();
|
||||||
sysRoot = ProjectExplorer::SysRootKitInformation::sysRoot(k);
|
sysRoot = ProjectExplorer::SysRootKitInformation::sysRoot(k);
|
||||||
|
|
||||||
expander = k->macroExpander();
|
expander = k->macroExpander();
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ public:
|
|||||||
bool cmakeHasServerMode;
|
bool cmakeHasServerMode;
|
||||||
CMakeTool::PathMapper pathMapper;
|
CMakeTool::PathMapper pathMapper;
|
||||||
|
|
||||||
QByteArray toolChainId;
|
QByteArray cxxToolChainId;
|
||||||
|
QByteArray cToolChainId;
|
||||||
|
|
||||||
Utils::FileName sysRoot;
|
Utils::FileName sysRoot;
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,15 @@ TeaLeafReader::TeaLeafReader()
|
|||||||
if (m_cmakeFiles.contains(document->filePath()) || !m_parameters.isAutorun)
|
if (m_cmakeFiles.contains(document->filePath()) || !m_parameters.isAutorun)
|
||||||
emit dirty();
|
emit dirty();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove \' (quote) for function-style macrosses:
|
||||||
|
// -D'MACRO()'=xxx
|
||||||
|
// -D'MACRO()=xxx'
|
||||||
|
// -D'MACRO()'
|
||||||
|
// otherwise, compiler will fails
|
||||||
|
m_macroFixupRe1.setPattern("^-D(\\s*)'([0-9a-ZA-Z_\\(\\)]+)'=");
|
||||||
|
m_macroFixupRe2.setPattern("^-D(\\s*)'([0-9a-ZA-Z_\\(\\)]+)=(.+)'$");
|
||||||
|
m_macroFixupRe3.setPattern("^-D(\\s*)'([0-9a-ZA-Z_\\(\\)]+)'$");
|
||||||
}
|
}
|
||||||
|
|
||||||
TeaLeafReader::~TeaLeafReader()
|
TeaLeafReader::~TeaLeafReader()
|
||||||
@@ -312,13 +321,30 @@ void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<FileNo
|
|||||||
m_files.clear(); // Some of the FileNodes in files() were deleted!
|
m_files.clear(); // Some of the FileNodes in files() were deleted!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void processCMakeIncludes(const CMakeBuildTarget &cbt, const ToolChain *tc,
|
||||||
|
const QStringList& flags, const FileName &sysroot,
|
||||||
|
QSet<FileName> &tcIncludes, QStringList &includePaths)
|
||||||
|
{
|
||||||
|
if (!tc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (const HeaderPath &hp, tc->systemHeaderPaths(flags, sysroot))
|
||||||
|
tcIncludes.insert(FileName::fromString(hp.path()));
|
||||||
|
foreach (const FileName &i, cbt.includeFiles) {
|
||||||
|
if (!tcIncludes.contains(i))
|
||||||
|
includePaths.append(i.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QSet<Id> TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
QSet<Id> TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
||||||
{
|
{
|
||||||
QSet<Id> languages;
|
QSet<Id> languages;
|
||||||
const ToolChain *tc = ToolChainManager::findToolChain(m_parameters.toolChainId);
|
const ToolChain *tcCxx = ToolChainManager::findToolChain(m_parameters.cxxToolChainId);
|
||||||
|
const ToolChain *tcC = ToolChainManager::findToolChain(m_parameters.cToolChainId);
|
||||||
const FileName sysroot = m_parameters.sysRoot;
|
const FileName sysroot = m_parameters.sysRoot;
|
||||||
|
|
||||||
QHash<QString, QStringList> targetDataCache;
|
QHash<QString, QStringList> targetDataCacheCxx;
|
||||||
|
QHash<QString, QStringList> targetDataCacheC;
|
||||||
foreach (const CMakeBuildTarget &cbt, m_buildTargets) {
|
foreach (const CMakeBuildTarget &cbt, m_buildTargets) {
|
||||||
if (cbt.targetType == UtilityType)
|
if (cbt.targetType == UtilityType)
|
||||||
continue;
|
continue;
|
||||||
@@ -326,22 +352,19 @@ QSet<Id> TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
|||||||
// CMake shuffles the include paths that it reports via the CodeBlocks generator
|
// CMake shuffles the include paths that it reports via the CodeBlocks generator
|
||||||
// So remove the toolchain include paths, so that at least those end up in the correct
|
// So remove the toolchain include paths, so that at least those end up in the correct
|
||||||
// place.
|
// place.
|
||||||
const QStringList cxxflags = getCXXFlagsFor(cbt, targetDataCache);
|
auto cxxflags = getFlagsFor(cbt, targetDataCacheCxx, ToolChain::Language::Cxx);
|
||||||
|
auto cflags = getFlagsFor(cbt, targetDataCacheC, ToolChain::Language::C);
|
||||||
QSet<FileName> tcIncludes;
|
QSet<FileName> tcIncludes;
|
||||||
QStringList includePaths;
|
QStringList includePaths;
|
||||||
if (tc) {
|
if (tcCxx || tcC) {
|
||||||
foreach (const HeaderPath &hp, tc->systemHeaderPaths(cxxflags, sysroot))
|
processCMakeIncludes(cbt, tcCxx, cxxflags, sysroot, tcIncludes, includePaths);
|
||||||
tcIncludes.insert(FileName::fromString(hp.path()));
|
processCMakeIncludes(cbt, tcC, cflags, sysroot, tcIncludes, includePaths);
|
||||||
foreach (const FileName &i, cbt.includeFiles) {
|
|
||||||
if (!tcIncludes.contains(i))
|
|
||||||
includePaths.append(i.toString());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
includePaths = transform(cbt.includeFiles, &FileName::toString);
|
includePaths = transform(cbt.includeFiles, &FileName::toString);
|
||||||
}
|
}
|
||||||
includePaths += m_parameters.buildDirectory.toString();
|
includePaths += m_parameters.buildDirectory.toString();
|
||||||
ppBuilder.setIncludePaths(includePaths);
|
ppBuilder.setIncludePaths(includePaths);
|
||||||
ppBuilder.setCFlags(cxxflags);
|
ppBuilder.setCFlags(cflags);
|
||||||
ppBuilder.setCxxFlags(cxxflags);
|
ppBuilder.setCxxFlags(cxxflags);
|
||||||
ppBuilder.setDefines(cbt.defines);
|
ppBuilder.setDefines(cbt.defines);
|
||||||
ppBuilder.setDisplayName(cbt.title);
|
ppBuilder.setDisplayName(cbt.title);
|
||||||
@@ -530,25 +553,42 @@ void TeaLeafReader::processCMakeError()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList TeaLeafReader::getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
|
QStringList TeaLeafReader::getFlagsFor(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache,
|
||||||
|
ToolChain::Language lang)
|
||||||
{
|
{
|
||||||
// check cache:
|
// check cache:
|
||||||
auto it = cache.constFind(buildTarget.title);
|
auto it = cache.constFind(buildTarget.title);
|
||||||
if (it != cache.constEnd())
|
if (it != cache.constEnd())
|
||||||
return *it;
|
return *it;
|
||||||
|
|
||||||
if (extractCXXFlagsFromMake(buildTarget, cache))
|
if (extractFlagsFromMake(buildTarget, cache, lang))
|
||||||
return cache.value(buildTarget.title);
|
return cache.value(buildTarget.title);
|
||||||
|
|
||||||
if (extractCXXFlagsFromNinja(buildTarget, cache))
|
if (extractFlagsFromNinja(buildTarget, cache, lang))
|
||||||
return cache.value(buildTarget.title);
|
return cache.value(buildTarget.title);
|
||||||
|
|
||||||
cache.insert(buildTarget.title, QStringList());
|
cache.insert(buildTarget.title, QStringList());
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TeaLeafReader::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
|
bool TeaLeafReader::extractFlagsFromMake(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache,
|
||||||
|
ToolChain::Language lang)
|
||||||
{
|
{
|
||||||
|
QString flagsPrefix;
|
||||||
|
switch (lang)
|
||||||
|
{
|
||||||
|
case ToolChain::Language::Cxx:
|
||||||
|
flagsPrefix = QLatin1String("CXX_FLAGS =");
|
||||||
|
break;
|
||||||
|
case ToolChain::Language::C:
|
||||||
|
flagsPrefix = QLatin1String("C_FLAGS =");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString makeCommand = buildTarget.makeCommand.toString();
|
QString makeCommand = buildTarget.makeCommand.toString();
|
||||||
int startIndex = makeCommand.indexOf('\"');
|
int startIndex = makeCommand.indexOf('\"');
|
||||||
int endIndex = makeCommand.indexOf('\"', startIndex + 1);
|
int endIndex = makeCommand.indexOf('\"', startIndex + 1);
|
||||||
@@ -558,16 +598,30 @@ bool TeaLeafReader::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget,
|
|||||||
int slashIndex = makefile.lastIndexOf('/');
|
int slashIndex = makefile.lastIndexOf('/');
|
||||||
makefile.truncate(slashIndex);
|
makefile.truncate(slashIndex);
|
||||||
makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
|
makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
|
||||||
|
// Remove un-needed shell escaping:
|
||||||
|
makefile = makefile.remove("\\");
|
||||||
QFile file(makefile);
|
QFile file(makefile);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
QTextStream stream(&file);
|
QTextStream stream(&file);
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
QString line = stream.readLine().trimmed();
|
QString line = stream.readLine().trimmed();
|
||||||
if (line.startsWith("CXX_FLAGS =")) {
|
if (line.startsWith(flagsPrefix)) {
|
||||||
// Skip past =
|
// Skip past =
|
||||||
cache.insert(buildTarget.title,
|
auto flags =
|
||||||
line.mid(11).trimmed().split(' ', QString::SkipEmptyParts));
|
Utils::transform(line.mid(flagsPrefix.length()).trimmed().split(' ', QString::SkipEmptyParts), [this](QString flag) -> QString {
|
||||||
|
// TODO: maybe Gcc-specific
|
||||||
|
// Remove \' (quote) for function-style macrosses:
|
||||||
|
// -D'MACRO()'=xxx
|
||||||
|
// -D'MACRO()=xxx'
|
||||||
|
// -D'MACRO()'
|
||||||
|
// otherwise, compiler will fails
|
||||||
|
return flag
|
||||||
|
.replace(m_macroFixupRe1, "-D\\1\\2=")
|
||||||
|
.replace(m_macroFixupRe2, "-D\\1\\2=\\3")
|
||||||
|
.replace(m_macroFixupRe3, "-D\\1\\2");
|
||||||
|
});
|
||||||
|
cache.insert(buildTarget.title, flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -576,13 +630,28 @@ bool TeaLeafReader::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TeaLeafReader::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
|
bool TeaLeafReader::extractFlagsFromNinja(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache,
|
||||||
|
ProjectExplorer::ToolChain::Language lang)
|
||||||
{
|
{
|
||||||
Q_UNUSED(buildTarget)
|
Q_UNUSED(buildTarget)
|
||||||
if (!cache.isEmpty()) // We fill the cache in one go!
|
if (!cache.isEmpty()) // We fill the cache in one go!
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS) from there if no suitable flags.make were
|
QString compilerPrefix;
|
||||||
|
switch (lang)
|
||||||
|
{
|
||||||
|
case ToolChain::Language::Cxx:
|
||||||
|
compilerPrefix = QLatin1String("CXX_COMPILER");
|
||||||
|
break;
|
||||||
|
case ToolChain::Language::C:
|
||||||
|
compilerPrefix = QLatin1String("C_COMPILER");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS/C_FLAGS) from there if no suitable flags.make were
|
||||||
// found
|
// found
|
||||||
// Get "all" target's working directory
|
// Get "all" target's working directory
|
||||||
QByteArray ninjaFile;
|
QByteArray ninjaFile;
|
||||||
@@ -599,7 +668,7 @@ bool TeaLeafReader::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
QTextStream stream(ninjaFile);
|
QTextStream stream(ninjaFile);
|
||||||
bool cxxFound = false;
|
bool compilerFound = false;
|
||||||
const QString targetSignature = "# Object build statements for ";
|
const QString targetSignature = "# Object build statements for ";
|
||||||
QString currentTarget;
|
QString currentTarget;
|
||||||
|
|
||||||
@@ -614,8 +683,8 @@ bool TeaLeafReader::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget
|
|||||||
currentTarget = line.mid(pos + 1);
|
currentTarget = line.mid(pos + 1);
|
||||||
}
|
}
|
||||||
} else if (!currentTarget.isEmpty() && line.startsWith("build")) {
|
} else if (!currentTarget.isEmpty() && line.startsWith("build")) {
|
||||||
cxxFound = line.indexOf("CXX_COMPILER") != -1;
|
compilerFound = line.indexOf(compilerPrefix) != -1;
|
||||||
} else if (cxxFound && line.startsWith("FLAGS =")) {
|
} else if (compilerFound && line.startsWith("FLAGS =")) {
|
||||||
// Skip past =
|
// Skip past =
|
||||||
cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
|
cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
|
||||||
#include "builddirreader.h"
|
#include "builddirreader.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace Utils { class QtcProcess; }
|
namespace Utils { class QtcProcess; }
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
@@ -66,9 +70,9 @@ private:
|
|||||||
void processCMakeOutput();
|
void processCMakeOutput();
|
||||||
void processCMakeError();
|
void processCMakeError();
|
||||||
|
|
||||||
QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
QStringList getFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, ProjectExplorer::ToolChain::Language lang);
|
||||||
bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
bool extractFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, ProjectExplorer::ToolChain::Language lang);
|
||||||
bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
bool extractFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, ProjectExplorer::ToolChain::Language lang);
|
||||||
|
|
||||||
Utils::QtcProcess *m_cmakeProcess = nullptr;
|
Utils::QtcProcess *m_cmakeProcess = nullptr;
|
||||||
|
|
||||||
@@ -85,6 +89,11 @@ private:
|
|||||||
QList<ProjectExplorer::FileNode *> m_files;
|
QList<ProjectExplorer::FileNode *> m_files;
|
||||||
QSet<Internal::CMakeFile *> m_watchedFiles;
|
QSet<Internal::CMakeFile *> m_watchedFiles;
|
||||||
|
|
||||||
|
// RegExps for function-like macrosses names fixups
|
||||||
|
QRegularExpression m_macroFixupRe1;
|
||||||
|
QRegularExpression m_macroFixupRe2;
|
||||||
|
QRegularExpression m_macroFixupRe3;
|
||||||
|
|
||||||
friend class CMakeFile;
|
friend class CMakeFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user