From 0d0acf7d4dfaedce6d849d2db4613ca8a4e9952b Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Fri, 29 Jan 2021 16:06:44 +0300 Subject: baremetal: Improve detection of IAR compiler includes The IAR compiler has an undocumented command line option `--IDE3`, which allows you to print a list of compiler include paths as: `$$TOOL_BEGIN $$VERSION "3" $$INC_BEGIN $$FILEPATH "" $$TOOL_END` Besides, the same approach is used in the IAR extension for the VSCode IDE. So we can use this approach to implement it the Qbs module as well. In addition, this commit contains an autotest to check the `cpp.compilerIncludePaths` property. Change-Id: I434dd630913e5afd6cba5b4e31e1021ee0c5fe31 Reviewed-by: Ivan Komissarov --- share/qbs/modules/cpp/iar.js | 56 +++++++++++----------- .../compiler-include-paths.qbs | 9 ++++ .../compiler-include-paths/main.c | 4 ++ tests/auto/blackbox/tst_blackboxbaremetal.cpp | 28 +++++++++++ tests/auto/blackbox/tst_blackboxbaremetal.h | 1 + 5 files changed, 71 insertions(+), 27 deletions(-) create mode 100644 tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs create mode 100644 tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js index 9e40223df..183b2e0cd 100644 --- a/share/qbs/modules/cpp/iar.js +++ b/share/qbs/modules/cpp/iar.js @@ -510,45 +510,47 @@ function dumpMacros(compilerFilePath, tag) { return ModUtils.extractMacros(outFile.readAll()); } -function dumpDefaultPaths(compilerFilePath, tag) { +function dumpCompilerIncludePaths(compilerFilePath, tag) { + // We can dump the compiler include paths using the undocumented `--IDE3` flag, + // e.g. which also is used in the IAR extension for the VSCode. In this case the + // compiler procuces the console output in the following format: + // `$$TOOL_BEGIN $$VERSION "3" $$INC_BEGIN $$FILEPATH "" $$TOOL_END` + var tempDir = new TemporaryDir(); var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c"); var inFile = new TextFile(inFilePath, TextFile.WriteOnly); - var args = [ inFilePath, "--preinclude", "." ]; + var args = ["--IDE3", inFilePath]; if (tag === "cpp" && supportCppLanguage(compilerFilePath)) args.push(cppLanguageOption(compilerFilePath)); + var includePaths = []; var p = new Process(); - // This process should return an error, don't throw - // an error in this case. + // It is possible that the process can return an error code in case the + // compiler does not support the `--IDE3` flag. So, don't throw an error in this case. p.exec(compilerFilePath, args, false); - var output = p.readStdErr(); - - var includePaths = []; - var pass = 0; - for (var pos = 0; pos < output.length; ++pos) { - var searchIndex = output.indexOf("searched:", pos); - if (searchIndex === -1) - break; - var startQuoteIndex = output.indexOf('"', searchIndex + 1); - if (startQuoteIndex === -1) - break; - var endQuoteIndex = output.indexOf('"', startQuoteIndex + 1); - if (endQuoteIndex === -1) - break; - pos = endQuoteIndex + 1; - - // Ignore the first path as it is not a compiler include path. - ++pass; - if (pass === 1) - continue; + p.readStdOut().trim().split(/\r?\n/g).map(function(line) { + var m = line.match(/\$\$INC_BEGIN\s\$\$FILEPATH\s\"([^"]*)/); + if (m) { + var includePath = m[1].replace(/\\\\/g, '/'); + if (includePath) + includePaths.push(includePath); + } + }); - var path = output.substring(startQuoteIndex + 1, endQuoteIndex) - .replace(/[\s]{2,}/g, ' '); - includePaths.push(path); + if (includePaths.length === 0) { + // This can happen if the compiler does not support the `--IDE3` flag, + // e.g. IAR for S08 architecture. In this case we use fallback to the + // detection of the `inc` directory. + var includePath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "../inc/"); + includePaths.push(includePath); } + return includePaths; +} + +function dumpDefaultPaths(compilerFilePath, tag) { + var includePaths = dumpCompilerIncludePaths(compilerFilePath, tag); return { "includePaths": includePaths }; diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs new file mode 100644 index 000000000..5c73302ad --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbs @@ -0,0 +1,9 @@ +import "../BareMetalApplication.qbs" as BareMetalApplication + +BareMetalApplication { + files: ["main.c"] + property bool dummy: { + console.info("compilerIncludePaths: %%" + cpp.compilerIncludePaths + "%%"); + return true; + } +} diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c new file mode 100644 index 000000000..58fe69254 --- /dev/null +++ b/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/tests/auto/blackbox/tst_blackboxbaremetal.cpp b/tests/auto/blackbox/tst_blackboxbaremetal.cpp index 41f50a0ed..6d7590209 100644 --- a/tests/auto/blackbox/tst_blackboxbaremetal.cpp +++ b/tests/auto/blackbox/tst_blackboxbaremetal.cpp @@ -32,6 +32,7 @@ #include "../shared.h" +#include #include static bool extractToolset(const QByteArray &output, @@ -47,6 +48,17 @@ static bool extractToolset(const QByteArray &output, return true; } +static bool extractCompilerIncludePaths(const QByteArray &output, QStringList &compilerIncludePaths) +{ + const QRegularExpression re("%%([^%%]+)%%"); + QRegularExpressionMatchIterator it = re.globalMatch(output); + if (!it.hasNext()) + return false; + const QRegularExpressionMatch match = it.next(); + compilerIncludePaths = match.captured(1).split(","); + return true; +} + static QByteArray unsupportedToolsetMessage(const QByteArray &output) { QByteArray toolchain; @@ -142,6 +154,22 @@ void TestBlackboxBareMetal::distributionIncludePaths() QCOMPARE(runQbs(), 0); } +void TestBlackboxBareMetal::compilerIncludePaths() +{ + QDir::setCurrent(testDataDir + "/compiler-include-paths"); + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + if (!m_qbsStdout.contains("compilerIncludePaths:")) + QFAIL("No compiler include paths exists"); + + QStringList includePaths; + QVERIFY(extractCompilerIncludePaths(m_qbsStdout, includePaths)); + QVERIFY(includePaths.count() > 0); + for (const auto &includePath : includePaths) { + const QDir dir(includePath); + QVERIFY(dir.exists()); + } +} + void TestBlackboxBareMetal::preincludeHeaders() { QDir::setCurrent(testDataDir + "/preinclude-headers"); diff --git a/tests/auto/blackbox/tst_blackboxbaremetal.h b/tests/auto/blackbox/tst_blackboxbaremetal.h index 3695cb1c3..581d1d580 100644 --- a/tests/auto/blackbox/tst_blackboxbaremetal.h +++ b/tests/auto/blackbox/tst_blackboxbaremetal.h @@ -52,6 +52,7 @@ private slots: void userIncludePaths(); void systemIncludePaths(); void distributionIncludePaths(); + void compilerIncludePaths(); void preincludeHeaders(); -- cgit v1.2.3