diff options
Diffstat (limited to 'src/plugins/baremetal/keiltoolchain.cpp')
-rw-r--r-- | src/plugins/baremetal/keiltoolchain.cpp | 432 |
1 files changed, 337 insertions, 95 deletions
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index 80ae51240e..96cef9a583 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -37,6 +37,7 @@ #include <utils/environment.h> #include <utils/pathchooser.h> #include <utils/qtcassert.h> +#include <utils/qtcprocess.h> #include <utils/synchronousprocess.h> #include <QDebug> @@ -60,6 +61,7 @@ namespace Internal { // Helpers: static const char compilerCommandKeyC[] = "BareMetal.KeilToolchain.CompilerPath"; +static const char compilerPlatformCodeGenFlagsKeyC[] = "BareMetal.KeilToolchain.PlatformCodeGenFlags"; static const char targetAbiKeyC[] = "BareMetal.KeilToolchain.TargetAbi"; static bool compilerExists(const FilePath &compilerPath) @@ -74,28 +76,66 @@ static Abi::Architecture guessArchitecture(const FilePath &compilerPath) const QString bn = fi.baseName().toLower(); if (bn == "c51" || bn == "cx51") return Abi::Architecture::Mcs51Architecture; + if (bn == "c251") + return Abi::Architecture::Mcs251Architecture; + if (bn == "c166") + return Abi::Architecture::C166Architecture; if (bn == "armcc") return Abi::Architecture::ArmArchitecture; return Abi::Architecture::UnknownArchitecture; } -// Note: The KEIL 8051 compiler does not support the predefined -// macros dumping. So, we do it with following trick where we try -// to compile a temporary file and to parse the console output. -static Macros dumpC51PredefinedMacros(const FilePath &compiler, const QStringList &env) +static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const QStringList &env) { + // Note: The KEIL C51 or C251 compiler does not support the predefined + // macros dumping. So, we do it with the following trick, where we try + // to create and compile a special temporary file and to parse the console + // output with the own magic pattern: (""|"key"|"value"|""). + QTemporaryFile fakeIn; if (!fakeIn.open()) return {}; + fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); - fakeIn.write("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)\n"); - fakeIn.write("#ifdef __C51__\n"); - fakeIn.write("#pragma message(VAR_NAME_VALUE(__C51__))\n"); + + // Prepare for C51 compiler. + fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n"); + fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n"); + fakeIn.write("# if defined (__C51__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__CX51__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MODEL__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__MODEL__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__STDC__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__STDC__))\n"); + fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); - fakeIn.write("#ifdef __CX51__\n"); - fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n"); + + // Prepare for C251 compiler. + fakeIn.write("#if defined(__C251__)\n"); + fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n"); + fakeIn.write("# if defined(__C251__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MODEL__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__MODEL__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__STDC__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__STDC__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__FLOAT64__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__FLOAT64__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MODSRC__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__MODSRC__))\n"); + fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); + fakeIn.close(); SynchronousProcess cpp; @@ -103,34 +143,151 @@ static Macros dumpC51PredefinedMacros(const FilePath &compiler, const QStringLis cpp.setTimeoutS(10); const CommandLine cmd(compiler, {fakeIn.fileName()}); - const SynchronousProcessResponse response = cpp.runBlocking(cmd); - if (response.result != SynchronousProcessResponse::Finished - || response.exitCode != 0) { - qWarning() << response.exitMessage(cmd.toUserOutput(), 10); - return {}; - } - QString output = response.allOutput(); Macros macros; QTextStream stream(&output); QString line; while (stream.readLineInto(&line)) { + enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 }; const QStringList parts = line.split("\"|\""); - if (parts.count() != 3) + if (parts.count() != ALL_PARTS) continue; - macros.push_back({parts.at(1).toUtf8(), parts.at(2).toUtf8()}); + macros.push_back({parts.at(KEY_INDEX).toUtf8(), parts.at(VALUE_INDEX).toUtf8()}); } return macros; } -static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &env) +static Macros dumpC166PredefinedMacros(const FilePath &compiler, const QStringList &env) +{ + // Note: The KEIL C166 compiler does not support the predefined + // macros dumping. Also, it does not support the '#pragma' and + // '#message|warning|error' directives properly (it is impossible + // to print to console the value of macro). + // So, we do it with the following trick, where we try + // to create and compile a special temporary file and to parse the console + // output with the own magic pattern, e.g: + // + // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ + // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored + // + // where the '__C166__' is a key, and the '757' is a value. + + QTemporaryFile fakeIn; + if (!fakeIn.open()) + return {}; + + // Prepare for C166 compiler. + fakeIn.write("#if defined(__C166__)\n"); + fakeIn.write("# if defined(__C166__)\n"); + fakeIn.write("# warning __C166__\n"); + fakeIn.write("# pragma __C166__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__DUS__)\n"); + fakeIn.write("# warning __DUS__\n"); + fakeIn.write("# pragma __DUS__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MAC__)\n"); + fakeIn.write("# warning __MAC__\n"); + fakeIn.write("# pragma __MAC__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MOD167__)\n"); + fakeIn.write("# warning __MOD167__\n"); + fakeIn.write("# pragma __MOD167__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MODEL__)\n"); + fakeIn.write("# warning __MODEL__\n"); + fakeIn.write("# pragma __MODEL__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__MODV2__)\n"); + fakeIn.write("# warning __MODV2__\n"); + fakeIn.write("# pragma __MODV2__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__SAVEMAC__)\n"); + fakeIn.write("# warning __SAVEMAC__\n"); + fakeIn.write("# pragma __SAVEMAC__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__STDC__)\n"); + fakeIn.write("# warning __STDC__\n"); + fakeIn.write("# pragma __STDC__\n"); + fakeIn.write("# endif\n"); + fakeIn.write("#endif\n"); + + fakeIn.close(); + + SynchronousProcess cpp; + cpp.setEnvironment(env); + cpp.setTimeoutS(10); + + Macros macros; + auto extractMacros = [¯os](const QString &output) { + const QStringList lines = output.split('\n'); + for (auto it = lines.cbegin(); it != lines.cend();) { + if (!it->startsWith("***")) { + ++it; + continue; + } + + // Search for the key at a first line. + QByteArray key; + if (it->endsWith("__C166__")) + key = "__C166__"; + else if (it->endsWith("__DUS__")) + key = "__DUS__"; + else if (it->endsWith("__MAC__")) + key = "__MAC__"; + else if (it->endsWith("__MOD167__")) + key = "__MOD167__"; + else if (it->endsWith("__MODEL__")) + key = "__MODEL__"; + else if (it->endsWith("__MODV2__")) + key = "__MODV2__"; + else if (it->endsWith("__SAVEMAC__")) + key = "__SAVEMAC__"; + else if (it->endsWith("__STDC__")) + key = "__STDC__"; + + if (key.isEmpty()) { + ++it; + continue; + } + + ++it; + if (it == lines.cend() || !it->startsWith("***")) + break; + + // Search for the value at a second line. + const int startIndex = it->indexOf('\''); + if (startIndex == -1) + break; + const int stopIndex = it->indexOf('\'', startIndex + 1); + if (stopIndex == -1) + break; + const QByteArray value = it->mid(startIndex + 1, stopIndex - startIndex - 1).toLatin1(); + + macros.append(Macro{key, value}); + + ++it; + } + }; + + const CommandLine cmd(compiler, {fakeIn.fileName()}); + const SynchronousProcessResponse response = cpp.runBlocking(cmd); + const QString output = response.allOutput(); + extractMacros(output); + return macros; +} + +static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const QStringList &env) { SynchronousProcess cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); - const CommandLine cmd(compiler, {"-E", "--list-macros"}); + QStringList args = extraArgs; + args.push_back("-E"); + args.push_back("--list-macros"); + const CommandLine cmd(compiler, args); const SynchronousProcessResponse response = cpp.runBlocking(cmd); if (response.result != SynchronousProcessResponse::Finished @@ -143,20 +300,35 @@ static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringLis return Macro::toMacros(output); } -static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env) +static bool isMcsArchitecture(Abi::Architecture arch) +{ + return arch == Abi::Architecture::Mcs51Architecture + || arch == Abi::Architecture::Mcs251Architecture; +} + +static bool isC166Architecture(Abi::Architecture arch) +{ + return arch == Abi::Architecture::C166Architecture; +} + +static bool isArmArchitecture(Abi::Architecture arch) +{ + return arch == Abi::Architecture::ArmArchitecture; +} + +static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &args, const QStringList &env) { if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable()) return {}; const Abi::Architecture arch = guessArchitecture(compiler); - switch (arch) { - case Abi::Architecture::Mcs51Architecture: - return dumpC51PredefinedMacros(compiler, env); - case Abi::Architecture::ArmArchitecture: - return dumpArmPredefinedMacros(compiler, env); - default: - return {}; - } + if (isMcsArchitecture(arch)) + return dumpMcsPredefinedMacros(compiler, env); + if (isC166Architecture(arch)) + return dumpC166PredefinedMacros(compiler, env); + if (isArmArchitecture(arch)) + return dumpArmPredefinedMacros(compiler, args, env); + return {}; } static HeaderPaths dumpHeaderPaths(const FilePath &compiler) @@ -171,11 +343,11 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler) HeaderPaths headerPaths; const Abi::Architecture arch = guessArchitecture(compiler); - if (arch == Abi::Architecture::Mcs51Architecture) { + if (isMcsArchitecture(arch) || isC166Architecture(arch)) { QDir includeDir(toolkitDir); if (includeDir.cd("inc")) headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn}); - } else if (arch == Abi::Architecture::ArmArchitecture) { + } else if (isArmArchitecture(arch)) { QDir includeDir(toolkitDir); if (includeDir.cd("include")) headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn}); @@ -191,15 +363,22 @@ static Abi::Architecture guessArchitecture(const Macros ¯os) return Abi::Architecture::ArmArchitecture; if (macro.key == "__C51__" || macro.key == "__CX51__") return Abi::Architecture::Mcs51Architecture; + if (macro.key == "__C251__") + return Abi::Architecture::Mcs251Architecture; + if (macro.key == "__C166__") + return Abi::Architecture::C166Architecture; } return Abi::Architecture::UnknownArchitecture; } static unsigned char guessWordWidth(const Macros ¯os, Abi::Architecture arch) { - // Check for C51 compiler first. - if (arch == Abi::Architecture::Mcs51Architecture) - return 16; // C51 always have 16-bit word width. + // Check for C51 or C251 compiler first, which are always have 16-bit word width: + // * http://www.keil.com/support/man/docs/c51/c51_le_datatypes.htm + // * http://www.keil.com/support/man/docs/c251/c251_le_datatypes.htm + // * http://www.keil.com/support/man/docs/c166/c166_le_datatypes.htm + if (isMcsArchitecture(arch) || isC166Architecture(arch)) + return 16; const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) { return m.key == "__sizeof_int"; @@ -211,9 +390,9 @@ static unsigned char guessWordWidth(const Macros ¯os, Abi::Architecture arch static Abi::BinaryFormat guessFormat(Abi::Architecture arch) { - if (arch == Abi::Architecture::ArmArchitecture) + if (isArmArchitecture(arch)) return Abi::BinaryFormat::ElfFormat; - if (arch == Abi::Architecture::Mcs51Architecture) + if (isMcsArchitecture(arch) || isC166Architecture(arch)) return Abi::BinaryFormat::OmfFormat; return Abi::BinaryFormat::UnknownFormat; } @@ -225,24 +404,38 @@ static Abi guessAbi(const Macros ¯os) guessFormat(arch), guessWordWidth(macros, arch)}; } -static QString buildDisplayName(Abi::Architecture arch, Core::Id language, +static QString buildDisplayName(Abi::Architecture arch, Utils::Id language, const QString &version) { const auto archName = Abi::toString(arch); const auto langName = ToolChainManager::displayNameOfLanguageId(language); - return KeilToolchain::tr("KEIL %1 (%2, %3)") + return KeilToolChain::tr("KEIL %1 (%2, %3)") .arg(version, langName, archName); } +static void addDefaultCpuArgs(const FilePath &compiler, QStringList &extraArgs) +{ + const Abi::Architecture arch = guessArchitecture(compiler); + if (!isArmArchitecture(arch)) + return; + + const auto extraArgsIt = std::find_if(std::begin(extraArgs), std::end(extraArgs), + [](const QString &extraArg) { + return extraArg.contains("-cpu") || extraArg.contains("--cpu"); + }); + if (extraArgsIt == std::end(extraArgs)) + extraArgs.push_back("--cpu=cortex-m0"); +} + // KeilToolchain -KeilToolchain::KeilToolchain() : +KeilToolChain::KeilToolChain() : ToolChain(Constants::KEIL_TOOLCHAIN_TYPEID) { - setTypeDisplayName(Internal::KeilToolchainFactory::tr("KEIL")); + setTypeDisplayName(tr("KEIL")); } -void KeilToolchain::setTargetAbi(const Abi &abi) +void KeilToolChain::setTargetAbi(const Abi &abi) { if (abi == m_targetAbi) return; @@ -250,31 +443,32 @@ void KeilToolchain::setTargetAbi(const Abi &abi) toolChainUpdated(); } -Abi KeilToolchain::targetAbi() const +Abi KeilToolChain::targetAbi() const { return m_targetAbi; } -bool KeilToolchain::isValid() const +bool KeilToolChain::isValid() const { return true; } -ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() const +ToolChain::MacroInspectionRunner KeilToolChain::createMacroInspectionRunner() const { Environment env = Environment::systemEnvironment(); addToEnvironment(env); const Utils::FilePath compilerCommand = m_compilerCommand; - const Core::Id lang = language(); + const Utils::Id lang = language(); MacrosCache macroCache = predefinedMacrosCache(); + const QStringList extraArgs = m_extraCodeModelFlags; - return [env, compilerCommand, macroCache, lang] + return [env, compilerCommand, extraArgs, macroCache, lang] (const QStringList &flags) { Q_UNUSED(flags) - const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList()); + const Macros macros = dumpPredefinedMacros(compilerCommand, extraArgs, env.toStringList()); const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)}; macroCache->insert({}, report); @@ -282,23 +476,23 @@ ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() co }; } -Macros KeilToolchain::predefinedMacros(const QStringList &cxxflags) const +Macros KeilToolChain::predefinedMacros(const QStringList &cxxflags) const { return createMacroInspectionRunner()(cxxflags).macros; } -Utils::LanguageExtensions KeilToolchain::languageExtensions(const QStringList &) const +Utils::LanguageExtensions KeilToolChain::languageExtensions(const QStringList &) const { return LanguageExtension::None; } -WarningFlags KeilToolchain::warningFlags(const QStringList &cxxflags) const +WarningFlags KeilToolChain::warningFlags(const QStringList &cxxflags) const { Q_UNUSED(cxxflags) return WarningFlags::Default; } -ToolChain::BuiltInHeaderPathsRunner KeilToolchain::createBuiltInHeaderPathsRunner( +ToolChain::BuiltInHeaderPathsRunner KeilToolChain::createBuiltInHeaderPathsRunner( const Environment &) const { const Utils::FilePath compilerCommand = m_compilerCommand; @@ -317,14 +511,14 @@ ToolChain::BuiltInHeaderPathsRunner KeilToolchain::createBuiltInHeaderPathsRunne }; } -HeaderPaths KeilToolchain::builtInHeaderPaths(const QStringList &cxxFlags, +HeaderPaths KeilToolChain::builtInHeaderPaths(const QStringList &cxxFlags, const FilePath &fileName, const Environment &env) const { return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), ""); } -void KeilToolchain::addToEnvironment(Environment &env) const +void KeilToolChain::addToEnvironment(Environment &env) const { if (!m_compilerCommand.isEmpty()) { const FilePath path = m_compilerCommand.parentDir(); @@ -332,45 +526,48 @@ void KeilToolchain::addToEnvironment(Environment &env) const } } -IOutputParser *KeilToolchain::outputParser() const +QList<OutputLineParser *> KeilToolChain::createOutputParsers() const { - return new KeilParser; + return {new KeilParser}; } -QVariantMap KeilToolchain::toMap() const +QVariantMap KeilToolChain::toMap() const { QVariantMap data = ToolChain::toMap(); data.insert(compilerCommandKeyC, m_compilerCommand.toString()); + data.insert(compilerPlatformCodeGenFlagsKeyC, m_extraCodeModelFlags); data.insert(targetAbiKeyC, m_targetAbi.toString()); return data; } -bool KeilToolchain::fromMap(const QVariantMap &data) +bool KeilToolChain::fromMap(const QVariantMap &data) { if (!ToolChain::fromMap(data)) return false; m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString()); + m_extraCodeModelFlags = data.value(compilerPlatformCodeGenFlagsKeyC).toStringList(); m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString()); return true; } -std::unique_ptr<ToolChainConfigWidget> KeilToolchain::createConfigurationWidget() +std::unique_ptr<ToolChainConfigWidget> KeilToolChain::createConfigurationWidget() { - return std::make_unique<KeilToolchainConfigWidget>(this); + return std::make_unique<KeilToolChainConfigWidget>(this); } -bool KeilToolchain::operator ==(const ToolChain &other) const +bool KeilToolChain::operator ==(const ToolChain &other) const { if (!ToolChain::operator ==(other)) return false; - const auto customTc = static_cast<const KeilToolchain *>(&other); + const auto customTc = static_cast<const KeilToolChain *>(&other); return m_compilerCommand == customTc->m_compilerCommand && m_targetAbi == customTc->m_targetAbi + && m_extraCodeModelFlags == customTc->m_extraCodeModelFlags ; } -void KeilToolchain::setCompilerCommand(const FilePath &file) +void KeilToolChain::setCompilerCommand(const FilePath &file) { if (file == m_compilerCommand) return; @@ -378,12 +575,25 @@ void KeilToolchain::setCompilerCommand(const FilePath &file) toolChainUpdated(); } -FilePath KeilToolchain::compilerCommand() const +FilePath KeilToolChain::compilerCommand() const { return m_compilerCommand; } -FilePath KeilToolchain::makeCommand(const Environment &env) const +void KeilToolChain::setExtraCodeModelFlags(const QStringList &flags) +{ + if (flags == m_extraCodeModelFlags) + return; + m_extraCodeModelFlags = flags; + toolChainUpdated(); +} + +QStringList KeilToolChain::extraCodeModelFlags() const +{ + return m_extraCodeModelFlags; +} + +FilePath KeilToolChain::makeCommand(const Environment &env) const { Q_UNUSED(env) return {}; @@ -391,13 +601,13 @@ FilePath KeilToolchain::makeCommand(const Environment &env) const // KeilToolchainFactory -KeilToolchainFactory::KeilToolchainFactory() +KeilToolChainFactory::KeilToolChainFactory() { - setDisplayName(tr("KEIL")); + setDisplayName(KeilToolChain::tr("KEIL")); setSupportedToolChainType(Constants::KEIL_TOOLCHAIN_TYPEID); setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID, ProjectExplorer::Constants::CXX_LANGUAGE_ID}); - setToolchainConstructor([] { return new KeilToolchain; }); + setToolchainConstructor([] { return new KeilToolChain; }); setUserCreatable(true); } @@ -445,7 +655,7 @@ static QString extractVersion(const QString &toolsFile, const QString §ion) return {}; } -QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) +QList<ToolChain *> KeilToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) { #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\" \ @@ -468,9 +678,13 @@ QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &al // Fetch the toolchain executable path. FilePath compilerPath; if (productPath.endsWith("ARM")) - compilerPath = productPath.pathAppended("\\ARMCC\\bin\\armcc.exe"); + compilerPath = productPath.pathAppended("ARMCC/bin/armcc.exe"); else if (productPath.endsWith("C51")) - compilerPath = productPath.pathAppended("\\BIN\\c51.exe"); + compilerPath = productPath.pathAppended("BIN/c51.exe"); + else if (productPath.endsWith("C251")) + compilerPath = productPath.pathAppended("BIN/c251.exe"); + else if (productPath.endsWith("C166")) + compilerPath = productPath.pathAppended("BIN/c166.exe"); if (compilerPath.exists()) { // Fetch the toolchain version. @@ -492,7 +706,7 @@ QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &al return autoDetectToolchains(candidates, alreadyKnown); } -QList<ToolChain *> KeilToolchainFactory::autoDetectToolchains( +QList<ToolChain *> KeilToolChainFactory::autoDetectToolchains( const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const { QList<ToolChain *> result; @@ -519,26 +733,30 @@ QList<ToolChain *> KeilToolchainFactory::autoDetectToolchains( return result; } -QList<ToolChain *> KeilToolchainFactory::autoDetectToolchain( - const Candidate &candidate, Core::Id language) const +QList<ToolChain *> KeilToolChainFactory::autoDetectToolchain( + const Candidate &candidate, Utils::Id language) const { const auto env = Environment::systemEnvironment(); - const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env.toStringList()); + + QStringList extraArgs; + addDefaultCpuArgs(candidate.compilerPath, extraArgs); + const Macros macros = dumpPredefinedMacros(candidate.compilerPath, extraArgs, env.toStringList()); if (macros.isEmpty()) return {}; const Abi abi = guessAbi(macros); const Abi::Architecture arch = abi.architecture(); - if (arch == Abi::Architecture::Mcs51Architecture + if ((isMcsArchitecture(arch) || isC166Architecture(arch)) && language == ProjectExplorer::Constants::CXX_LANGUAGE_ID) { - // KEIL C51 compiler does not support C++ language. + // KEIL C51/C251/C166 compilers does not support C++ language. return {}; } - const auto tc = new KeilToolchain; + const auto tc = new KeilToolChain; tc->setDetection(ToolChain::AutoDetection); tc->setLanguage(language); tc->setCompilerCommand(candidate.compilerPath); + tc->setExtraCodeModelFlags(extraArgs); tc->setTargetAbi(abi); tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.compilerVersion)); @@ -549,7 +767,7 @@ QList<ToolChain *> KeilToolchainFactory::autoDetectToolchain( // KeilToolchainConfigWidget -KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) : +KeilToolChainConfigWidget::KeilToolChainConfigWidget(KeilToolChain *tc) : ToolChainConfigWidget(tc), m_compilerCommand(new PathChooser), m_abiWidget(new AbiWidget) @@ -557,27 +775,33 @@ KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) : m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.History"); m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand); + m_platformCodeGenFlagsLineEdit = new QLineEdit(this); + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags())); + m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit); m_mainLayout->addRow(tr("&ABI:"), m_abiWidget); m_abiWidget->setEnabled(false); addErrorLabel(); - setFromToolchain(); + setFromToolChain(); connect(m_compilerCommand, &PathChooser::rawPathChanged, - this, &KeilToolchainConfigWidget::handleCompilerCommandChange); + this, &KeilToolChainConfigWidget::handleCompilerCommandChange); + connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished, + this, &KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty); } -void KeilToolchainConfigWidget::applyImpl() +void KeilToolChainConfigWidget::applyImpl() { if (toolChain()->isAutoDetected()) return; - const auto tc = static_cast<KeilToolchain *>(toolChain()); + const auto tc = static_cast<KeilToolChain *>(toolChain()); const QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->fileName()); + tc->setCompilerCommand(m_compilerCommand->filePath()); + tc->setExtraCodeModelFlags(splitString(m_platformCodeGenFlagsLineEdit->text())); tc->setTargetAbi(m_abiWidget->currentAbi()); tc->setDisplayName(displayName); @@ -587,40 +811,48 @@ void KeilToolchainConfigWidget::applyImpl() const auto languageVersion = ToolChain::languageVersion(tc->language(), m_macros); tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion}); - setFromToolchain(); + setFromToolChain(); } -bool KeilToolchainConfigWidget::isDirtyImpl() const +bool KeilToolChainConfigWidget::isDirtyImpl() const { - const auto tc = static_cast<KeilToolchain *>(toolChain()); - return m_compilerCommand->fileName() != tc->compilerCommand() + const auto tc = static_cast<KeilToolChain *>(toolChain()); + return m_compilerCommand->filePath() != tc->compilerCommand() + || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags()) || m_abiWidget->currentAbi() != tc->targetAbi() ; } -void KeilToolchainConfigWidget::makeReadOnlyImpl() +void KeilToolChainConfigWidget::makeReadOnlyImpl() { m_compilerCommand->setReadOnly(true); + m_platformCodeGenFlagsLineEdit->setEnabled(false); m_abiWidget->setEnabled(false); } -void KeilToolchainConfigWidget::setFromToolchain() +void KeilToolChainConfigWidget::setFromToolChain() { const QSignalBlocker blocker(this); - const auto tc = static_cast<KeilToolchain *>(toolChain()); - m_compilerCommand->setFileName(tc->compilerCommand()); + const auto tc = static_cast<KeilToolChain *>(toolChain()); + m_compilerCommand->setFilePath(tc->compilerCommand()); + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags())); m_abiWidget->setAbis({}, tc->targetAbi()); - const bool haveCompiler = compilerExists(m_compilerCommand->fileName()); + const bool haveCompiler = compilerExists(m_compilerCommand->filePath()); m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected()); } -void KeilToolchainConfigWidget::handleCompilerCommandChange() +void KeilToolChainConfigWidget::handleCompilerCommandChange() { - const FilePath compilerPath = m_compilerCommand->fileName(); + const FilePath compilerPath = m_compilerCommand->filePath(); const bool haveCompiler = compilerExists(compilerPath); if (haveCompiler) { const auto env = Environment::systemEnvironment(); - m_macros = dumpPredefinedMacros(compilerPath, env.toStringList()); + const QStringList prevExtraArgs = splitString(m_platformCodeGenFlagsLineEdit->text()); + QStringList newExtraArgs = prevExtraArgs; + addDefaultCpuArgs(compilerPath, newExtraArgs); + if (prevExtraArgs != newExtraArgs) + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(newExtraArgs)); + m_macros = dumpPredefinedMacros(compilerPath, newExtraArgs, env.toStringList()); const Abi guessed = guessAbi(m_macros); m_abiWidget->setAbis({}, guessed); } @@ -629,5 +861,15 @@ void KeilToolchainConfigWidget::handleCompilerCommandChange() emit dirty(); } +void KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange() +{ + const QString str1 = m_platformCodeGenFlagsLineEdit->text(); + const QString str2 = QtcProcess::joinArgs(splitString(str1)); + if (str1 != str2) + m_platformCodeGenFlagsLineEdit->setText(str2); + else + handleCompilerCommandChange(); +} + } // namespace Internal } // namespace BareMetal |