1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "baremetalconstants.h"
27
28 #include "iarewparser.h"
29 #include "iarewtoolchain.h"
30
31 #include <projectexplorer/abiwidget.h>
32 #include <projectexplorer/projectexplorerconstants.h>
33 #include <projectexplorer/projectmacro.h>
34 #include <projectexplorer/toolchainmanager.h>
35
36 #include <utils/algorithm.h>
37 #include <utils/environment.h>
38 #include <utils/pathchooser.h>
39 #include <utils/qtcassert.h>
40 #include <utils/qtcprocess.h>
41
42 #include <QDebug>
43 #include <QDir>
44 #include <QFile>
45 #include <QFileInfo>
46 #include <QFormLayout>
47 #include <QLineEdit>
48 #include <QPlainTextEdit>
49 #include <QSettings>
50 #include <QTemporaryFile>
51
52 using namespace ProjectExplorer;
53 using namespace Utils;
54
55 namespace BareMetal {
56 namespace Internal {
57
58 // Helpers:
59
60 static const char compilerPlatformCodeGenFlagsKeyC[] = "PlatformCodeGenFlags";
61
compilerExists(const FilePath & compilerPath)62 static bool compilerExists(const FilePath &compilerPath)
63 {
64 const QFileInfo fi = compilerPath.toFileInfo();
65 return fi.exists() && fi.isExecutable() && fi.isFile();
66 }
67
cppLanguageOption(const FilePath & compiler)68 static QString cppLanguageOption(const FilePath &compiler)
69 {
70 const QString baseName = compiler.baseName();
71 if (baseName == "iccarm" || baseName == "iccrl78"
72 || baseName == "iccrh850" || baseName == "iccrx"
73 || baseName == "iccriscv") {
74 return QString("--c++");
75 }
76 if (baseName == "icc8051" || baseName == "iccavr"
77 || baseName == "iccstm8" || baseName == "icc430"
78 || baseName == "iccv850" || baseName == "icc78k"
79 || baseName == "iccavr32" || baseName == "iccsh"
80 || baseName == "icccf" || baseName == "iccm32c"
81 || baseName == "iccm16c" || baseName == "iccr32c"
82 || baseName == "icccr16c") {
83 return QString("--ec++");
84 }
85 return {};
86 }
87
dumpPredefinedMacros(const FilePath & compiler,const QStringList & extraArgs,const Id languageId,const Environment & env)88 static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs,
89 const Id languageId, const Environment &env)
90 {
91 if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
92 return {};
93
94 // IAR compiler requires an input and output files.
95
96 QTemporaryFile fakeIn;
97 if (!fakeIn.open())
98 return {};
99 fakeIn.close();
100
101 const QString outpath = fakeIn.fileName() + ".tmp";
102
103 QtcProcess cpp;
104 cpp.setEnvironment(env);
105 cpp.setTimeoutS(10);
106
107 CommandLine cmd(compiler, {fakeIn.fileName()});
108 if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
109 cmd.addArg(cppLanguageOption(compiler));
110 cmd.addArgs(extraArgs);
111 cmd.addArg("--predef_macros");
112 cmd.addArg(outpath);
113
114 cpp.setCommand(cmd);
115 cpp.runBlocking();
116 if (cpp.result() != QtcProcess::FinishedWithSuccess) {
117 qWarning() << cpp.exitMessage();
118 return {};
119 }
120
121 QByteArray output;
122 QFile fakeOut(outpath);
123 if (fakeOut.open(QIODevice::ReadOnly))
124 output = fakeOut.readAll();
125 fakeOut.remove();
126
127 return Macro::toMacros(output);
128 }
129
dumpHeaderPaths(const FilePath & compiler,const Id languageId,const Environment & env)130 static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Id languageId,
131 const Environment &env)
132 {
133 if (!compiler.exists())
134 return {};
135
136 // Seems, that IAR compiler has not options to show a list of system
137 // include directories. But, we can use the following trick to enumerate
138 // this directories. We need to specify the '--preinclude' option with
139 // the wrong value (e.g. a dot). In this case the compiler fails and its
140 // error output will contains a mention about the using search directories
141 // in a form of tokens, like: ' searched: "<path/to/include>" '. Where are
142 // the resulting paths are escaped with a quotes.
143
144 QTemporaryFile fakeIn;
145 if (!fakeIn.open())
146 return {};
147 fakeIn.close();
148
149 CommandLine cmd(compiler, {fakeIn.fileName()});
150 if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
151 cmd.addArg(cppLanguageOption(compiler));
152 cmd.addArg("--preinclude");
153 cmd.addArg(".");
154
155 QtcProcess cpp;
156 cpp.setEnvironment(env);
157 cpp.setTimeoutS(10);
158 cpp.setCommand(cmd);
159 cpp.runBlocking();
160
161 HeaderPaths headerPaths;
162
163 const QByteArray output = cpp.allOutput().toUtf8();
164 for (auto pos = 0; pos < output.size(); ++pos) {
165 const int searchIndex = output.indexOf("searched:", pos);
166 if (searchIndex == -1)
167 break;
168 const int startQuoteIndex = output.indexOf('"', searchIndex + 1);
169 if (startQuoteIndex == -1)
170 break;
171 const int endQuoteIndex = output.indexOf('"', startQuoteIndex + 1);
172 if (endQuoteIndex == -1)
173 break;
174
175 const QByteArray candidate = output.mid(startQuoteIndex + 1,
176 endQuoteIndex - startQuoteIndex - 1)
177 .simplified();
178
179 const QString headerPath = QFileInfo(QFile::decodeName(candidate))
180 .canonicalFilePath();
181
182 // Ignore the QtC binary directory path.
183 if (headerPath != QCoreApplication::applicationDirPath())
184 headerPaths.append({headerPath, HeaderPathType::BuiltIn});
185
186 pos = endQuoteIndex + 1;
187 }
188
189 return headerPaths;
190 }
191
guessArchitecture(const Macros & macros)192 static Abi::Architecture guessArchitecture(const Macros ¯os)
193 {
194 for (const Macro ¯o : macros) {
195 if (macro.key == "__ICCARM__")
196 return Abi::Architecture::ArmArchitecture;
197 if (macro.key == "__ICC8051__")
198 return Abi::Architecture::Mcs51Architecture;
199 if (macro.key == "__ICCAVR__")
200 return Abi::Architecture::AvrArchitecture;
201 if (macro.key == "__ICCAVR32__")
202 return Abi::Architecture::Avr32Architecture;
203 if (macro.key == "__ICCSTM8__")
204 return Abi::Architecture::Stm8Architecture;
205 if (macro.key == "__ICC430__")
206 return Abi::Architecture::Msp430Architecture;
207 if (macro.key == "__ICCRL78__")
208 return Abi::Architecture::Rl78Architecture;
209 if (macro.key == "__ICCV850__")
210 return Abi::Architecture::V850Architecture;
211 if (macro.key == "__ICCRH850__")
212 return Abi::Architecture::Rh850Architecture;
213 if (macro.key == "__ICCRX__")
214 return Abi::Architecture::RxArchitecture;
215 if (macro.key == "__ICC78K__")
216 return Abi::Architecture::K78Architecture;
217 if (macro.key == "__ICCSH__")
218 return Abi::Architecture::ShArchitecture;
219 if (macro.key == "__ICCRISCV__")
220 return Abi::Architecture::RiscVArchitecture;
221 if (macro.key == "__ICCCF__")
222 return Abi::Architecture::M68KArchitecture;
223 if (macro.key == "__ICCM32C__")
224 return Abi::Architecture::M32CArchitecture;
225 if (macro.key == "__ICCM16C__")
226 return Abi::Architecture::M16CArchitecture;
227 if (macro.key == "__ICCR32C__")
228 return Abi::Architecture::R32CArchitecture;
229 if (macro.key == "__ICCCR16C__")
230 return Abi::Architecture::CR16Architecture;
231 }
232 return Abi::Architecture::UnknownArchitecture;
233 }
234
guessWordWidth(const Macros & macros)235 static unsigned char guessWordWidth(const Macros ¯os)
236 {
237 const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) {
238 return m.key == "__INT_SIZE__";
239 });
240 if (sizeMacro.isValid() && sizeMacro.type == MacroType::Define)
241 return sizeMacro.value.toInt() * 8;
242 return 0;
243 }
244
guessFormat(Abi::Architecture arch)245 static Abi::BinaryFormat guessFormat(Abi::Architecture arch)
246 {
247 if (arch == Abi::Architecture::ArmArchitecture
248 || arch == Abi::Architecture::Stm8Architecture
249 || arch == Abi::Architecture::Rl78Architecture
250 || arch == Abi::Architecture::Rh850Architecture
251 || arch == Abi::Architecture::RxArchitecture
252 || arch == Abi::Architecture::ShArchitecture
253 || arch == Abi::Architecture::RiscVArchitecture) {
254 return Abi::BinaryFormat::ElfFormat;
255 }
256 if (arch == Abi::Architecture::Mcs51Architecture
257 || arch == Abi::Architecture::AvrArchitecture
258 || arch == Abi::Architecture::Avr32Architecture
259 || arch == Abi::Architecture::Msp430Architecture
260 || arch == Abi::Architecture::V850Architecture
261 || arch == Abi::Architecture::K78Architecture
262 || arch == Abi::Architecture::M68KArchitecture
263 || arch == Abi::Architecture::M32CArchitecture
264 || arch == Abi::Architecture::M16CArchitecture
265 || arch == Abi::Architecture::R32CArchitecture
266 || arch == Abi::Architecture::CR16Architecture) {
267 return Abi::BinaryFormat::UbrofFormat;
268 }
269 return Abi::BinaryFormat::UnknownFormat;
270 }
271
guessAbi(const Macros & macros)272 static Abi guessAbi(const Macros ¯os)
273 {
274 const auto arch = guessArchitecture(macros);
275 return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor,
276 guessFormat(arch), guessWordWidth(macros)};
277 }
278
buildDisplayName(Abi::Architecture arch,Utils::Id language,const QString & version)279 static QString buildDisplayName(Abi::Architecture arch, Utils::Id language,
280 const QString &version)
281 {
282 const auto archName = Abi::toString(arch);
283 const auto langName = ToolChainManager::displayNameOfLanguageId(language);
284 return IarToolChain::tr("IAREW %1 (%2, %3)").arg(version, langName, archName);
285 }
286
287 // IarToolChain
288
IarToolChain()289 IarToolChain::IarToolChain() :
290 ToolChain(Constants::IAREW_TOOLCHAIN_TYPEID)
291 {
292 setTypeDisplayName(Internal::IarToolChain::tr("IAREW"));
293 setTargetAbiKey("TargetAbi");
294 setCompilerCommandKey("CompilerPath");
295 }
296
createMacroInspectionRunner() const297 ToolChain::MacroInspectionRunner IarToolChain::createMacroInspectionRunner() const
298 {
299 Environment env = Environment::systemEnvironment();
300 addToEnvironment(env);
301
302 const FilePath compiler = compilerCommand();
303 const Id languageId = language();
304 const QStringList extraArgs = m_extraCodeModelFlags;
305 MacrosCache macrosCache = predefinedMacrosCache();
306
307 return [env, compiler, extraArgs, macrosCache, languageId]
308 (const QStringList &flags) {
309 Q_UNUSED(flags)
310
311 Macros macros = dumpPredefinedMacros(compiler, extraArgs, languageId, env);
312 macros.append({"__intrinsic", "", MacroType::Define});
313 macros.append({"__nounwind", "", MacroType::Define});
314 macros.append({"__noreturn", "", MacroType::Define});
315 macros.append({"__packed", "", MacroType::Define});
316 macros.append({"__spec_string", "", MacroType::Define});
317 macros.append({"__constrange(__a,__b)", "", MacroType::Define});
318
319 const auto languageVersion = ToolChain::languageVersion(languageId, macros);
320 const auto report = MacroInspectionReport{macros, languageVersion};
321 macrosCache->insert({}, report);
322
323 return report;
324 };
325 }
326
languageExtensions(const QStringList &) const327 Utils::LanguageExtensions IarToolChain::languageExtensions(const QStringList &) const
328 {
329 return LanguageExtension::None;
330 }
331
warningFlags(const QStringList & cxxflags) const332 WarningFlags IarToolChain::warningFlags(const QStringList &cxxflags) const
333 {
334 Q_UNUSED(cxxflags)
335 return WarningFlags::Default;
336 }
337
createBuiltInHeaderPathsRunner(const Environment &) const338 ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner(
339 const Environment &) const
340 {
341 Environment env = Environment::systemEnvironment();
342 addToEnvironment(env);
343
344 const FilePath compiler = compilerCommand();
345 const Id languageId = language();
346
347 HeaderPathsCache headerPaths = headerPathsCache();
348
349 return [env, compiler, headerPaths, languageId](const QStringList &flags,
350 const QString &fileName,
351 const QString &) {
352 Q_UNUSED(flags)
353 Q_UNUSED(fileName)
354
355 const HeaderPaths paths = dumpHeaderPaths(compiler, languageId, env);
356 headerPaths->insert({}, paths);
357
358 return paths;
359 };
360 }
361
addToEnvironment(Environment & env) const362 void IarToolChain::addToEnvironment(Environment &env) const
363 {
364 if (!compilerCommand().isEmpty()) {
365 const FilePath path = compilerCommand().parentDir();
366 env.prependOrSetPath(path.toString());
367 }
368 }
369
createOutputParsers() const370 QList<Utils::OutputLineParser *> IarToolChain::createOutputParsers() const
371 {
372 return {new IarParser()};
373 }
374
toMap() const375 QVariantMap IarToolChain::toMap() const
376 {
377 QVariantMap data = ToolChain::toMap();
378 data.insert(compilerPlatformCodeGenFlagsKeyC, m_extraCodeModelFlags);
379 return data;
380 }
381
fromMap(const QVariantMap & data)382 bool IarToolChain::fromMap(const QVariantMap &data)
383 {
384 if (!ToolChain::fromMap(data))
385 return false;
386 m_extraCodeModelFlags = data.value(compilerPlatformCodeGenFlagsKeyC).toStringList();
387 return true;
388 }
389
createConfigurationWidget()390 std::unique_ptr<ToolChainConfigWidget> IarToolChain::createConfigurationWidget()
391 {
392 return std::make_unique<IarToolChainConfigWidget>(this);
393 }
394
operator ==(const ToolChain & other) const395 bool IarToolChain::operator==(const ToolChain &other) const
396 {
397 if (!ToolChain::operator==(other))
398 return false;
399
400 const auto customTc = static_cast<const IarToolChain *>(&other);
401 return compilerCommand() == customTc->compilerCommand()
402 && m_extraCodeModelFlags == customTc->m_extraCodeModelFlags;
403 }
404
setExtraCodeModelFlags(const QStringList & flags)405 void IarToolChain::setExtraCodeModelFlags(const QStringList &flags)
406 {
407 if (flags == m_extraCodeModelFlags)
408 return;
409 m_extraCodeModelFlags = flags;
410 toolChainUpdated();
411 }
412
extraCodeModelFlags() const413 QStringList IarToolChain::extraCodeModelFlags() const
414 {
415 return m_extraCodeModelFlags;
416 }
417
makeCommand(const Environment & env) const418 FilePath IarToolChain::makeCommand(const Environment &env) const
419 {
420 Q_UNUSED(env)
421 return {};
422 }
423
424 // IarToolChainFactory
425
IarToolChainFactory()426 IarToolChainFactory::IarToolChainFactory()
427 {
428 setDisplayName(IarToolChain::tr("IAREW"));
429 setSupportedToolChainType(Constants::IAREW_TOOLCHAIN_TYPEID);
430 setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
431 ProjectExplorer::Constants::CXX_LANGUAGE_ID});
432 setToolchainConstructor([] { return new IarToolChain; });
433 setUserCreatable(true);
434 }
435
autoDetect(const QList<ToolChain * > & alreadyKnown,const IDevice::Ptr & device)436 QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
437 const IDevice::Ptr &device)
438 {
439 Q_UNUSED(device);
440 Candidates candidates;
441
442 #ifdef Q_OS_WIN
443
444 #ifdef Q_OS_WIN64
445 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\IAR Systems\\Embedded Workbench";
446 #else
447 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\IAR Systems\\Embedded Workbench";
448 #endif
449
450 // Dictionary for know toolchains.
451 static const struct Entry {
452 QString registryKey;
453 QString subExePath;
454 } knowToolchains[] = {
455 {{"EWARM"}, {"/arm/bin/iccarm.exe"}},
456 {{"EWAVR"}, {"/avr/bin/iccavr.exe"}},
457 {{"EWAVR32"}, {"/avr32/bin/iccavr32.exe"}},
458 {{"EW8051"}, {"/8051/bin/icc8051.exe"}},
459 {{"EWSTM8"}, {"/stm8/bin/iccstm8.exe"}},
460 {{"EW430"}, {"/430/bin/icc430.exe"}},
461 {{"EWRL78"}, {"/rl78/bin/iccrl78.exe"}},
462 {{"EWV850"}, {"/v850/bin/iccv850.exe"}},
463 {{"EWRH850"}, {"/rh850/bin/iccrh850.exe"}},
464 {{"EWRX"}, {"/rx/bin/iccrx.exe"}},
465 {{"EW78K"}, {"/78k/bin/icc78k.exe"}},
466 {{"EWSH"}, {"/sh/bin/iccsh.exe"}},
467 {{"EWRISCV"}, {"/riscv/bin/iccriscv.exe"}},
468 {{"EWCF"}, {"/cf/bin/icccf.exe"}},
469 {{"EWM32C"}, {"/m32c/bin/iccm32c.exe"}},
470 {{"EWM16C"}, {"/m16c/bin/iccm16c.exe"}},
471 {{"EWR32C"}, {"/r32c/bin/iccr32c.exe"}},
472 {{"EWCR16C"}, {"/cr16c/bin/icccr16c.exe"}},
473 };
474
475 QSettings registry(kRegistryNode, QSettings::NativeFormat);
476 const auto oneLevelGroups = registry.childGroups();
477 for (const QString &oneLevelKey : oneLevelGroups) {
478 registry.beginGroup(oneLevelKey);
479 const auto twoLevelGroups = registry.childGroups();
480 for (const Entry &entry : knowToolchains) {
481 if (twoLevelGroups.contains(entry.registryKey)) {
482 registry.beginGroup(entry.registryKey);
483 const auto threeLevelGroups = registry.childGroups();
484 for (const QString &threeLevelKey : threeLevelGroups) {
485 registry.beginGroup(threeLevelKey);
486 QString compilerPath = registry.value("InstallPath").toString();
487 if (!compilerPath.isEmpty()) {
488 // Build full compiler path.
489 compilerPath += entry.subExePath;
490 const FilePath fn = FilePath::fromString(compilerPath);
491 if (compilerExists(fn)) {
492 // Note: threeLevelKey is a guessed toolchain version.
493 candidates.push_back({fn, threeLevelKey});
494 }
495 }
496 registry.endGroup();
497 }
498 registry.endGroup();
499 }
500 }
501 registry.endGroup();
502 }
503
504 #endif // Q_OS_WIN
505
506 return autoDetectToolchains(candidates, alreadyKnown);
507 }
508
autoDetectToolchains(const Candidates & candidates,const QList<ToolChain * > & alreadyKnown) const509 QList<ToolChain *> IarToolChainFactory::autoDetectToolchains(
510 const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const
511 {
512 QList<ToolChain *> result;
513
514 for (const Candidate &candidate : qAsConst(candidates)) {
515 const QList<ToolChain *> filtered = Utils::filtered(
516 alreadyKnown, [candidate](ToolChain *tc) {
517 return tc->typeId() == Constants::IAREW_TOOLCHAIN_TYPEID
518 && tc->compilerCommand() == candidate.compilerPath
519 && (tc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID
520 || tc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID);
521 });
522
523 if (!filtered.isEmpty()) {
524 result << filtered;
525 continue;
526 }
527
528 // Create toolchains for both C and C++ languages.
529 result << autoDetectToolchain(candidate, ProjectExplorer::Constants::C_LANGUAGE_ID);
530 result << autoDetectToolchain(candidate, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
531 }
532
533 return result;
534 }
535
autoDetectToolchain(const Candidate & candidate,Utils::Id languageId) const536 QList<ToolChain *> IarToolChainFactory::autoDetectToolchain(
537 const Candidate &candidate, Utils::Id languageId) const
538 {
539 const auto env = Environment::systemEnvironment();
540 const Macros macros = dumpPredefinedMacros(candidate.compilerPath, {}, languageId, env);
541 if (macros.isEmpty())
542 return {};
543 const Abi abi = guessAbi(macros);
544
545 const auto tc = new IarToolChain;
546 tc->setDetection(ToolChain::AutoDetection);
547 tc->setLanguage(languageId);
548 tc->setCompilerCommand(candidate.compilerPath);
549 tc->setTargetAbi(abi);
550 tc->setDisplayName(buildDisplayName(abi.architecture(), languageId,
551 candidate.compilerVersion));
552
553 const auto languageVersion = ToolChain::languageVersion(languageId, macros);
554 tc->predefinedMacrosCache()->insert({}, {macros, languageVersion});
555 return {tc};
556 }
557
558 // IarToolChainConfigWidget
559
IarToolChainConfigWidget(IarToolChain * tc)560 IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) :
561 ToolChainConfigWidget(tc),
562 m_compilerCommand(new PathChooser),
563 m_abiWidget(new AbiWidget)
564 {
565 m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
566 m_compilerCommand->setHistoryCompleter("PE.IAREW.Command.History");
567 m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
568 m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
569 m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
570 m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
571 m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
572
573 m_abiWidget->setEnabled(false);
574
575 addErrorLabel();
576 setFromToolchain();
577
578 connect(m_compilerCommand, &PathChooser::rawPathChanged,
579 this, &IarToolChainConfigWidget::handleCompilerCommandChange);
580 connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished,
581 this, &IarToolChainConfigWidget::handlePlatformCodeGenFlagsChange);
582 connect(m_abiWidget, &AbiWidget::abiChanged,
583 this, &ToolChainConfigWidget::dirty);
584 }
585
applyImpl()586 void IarToolChainConfigWidget::applyImpl()
587 {
588 if (toolChain()->isAutoDetected())
589 return;
590
591 const auto tc = static_cast<IarToolChain *>(toolChain());
592 const QString displayName = tc->displayName();
593 tc->setCompilerCommand(m_compilerCommand->filePath());
594 tc->setExtraCodeModelFlags(splitString(m_platformCodeGenFlagsLineEdit->text()));
595 tc->setTargetAbi(m_abiWidget->currentAbi());
596 tc->setDisplayName(displayName);
597
598 if (m_macros.isEmpty())
599 return;
600
601 const auto languageVersion = ToolChain::languageVersion(tc->language(), m_macros);
602 tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion});
603
604 setFromToolchain();
605 }
606
isDirtyImpl() const607 bool IarToolChainConfigWidget::isDirtyImpl() const
608 {
609 const auto tc = static_cast<IarToolChain *>(toolChain());
610 return m_compilerCommand->filePath() != tc->compilerCommand()
611 || m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(tc->extraCodeModelFlags())
612 || m_abiWidget->currentAbi() != tc->targetAbi()
613 ;
614 }
615
makeReadOnlyImpl()616 void IarToolChainConfigWidget::makeReadOnlyImpl()
617 {
618 m_compilerCommand->setReadOnly(true);
619 m_platformCodeGenFlagsLineEdit->setEnabled(false);
620 m_abiWidget->setEnabled(false);
621 }
622
setFromToolchain()623 void IarToolChainConfigWidget::setFromToolchain()
624 {
625 const QSignalBlocker blocker(this);
626 const auto tc = static_cast<IarToolChain *>(toolChain());
627 m_compilerCommand->setFilePath(tc->compilerCommand());
628 m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
629 m_abiWidget->setAbis({}, tc->targetAbi());
630 const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
631 m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
632 }
633
handleCompilerCommandChange()634 void IarToolChainConfigWidget::handleCompilerCommandChange()
635 {
636 const FilePath compilerPath = m_compilerCommand->filePath();
637 const bool haveCompiler = compilerExists(compilerPath);
638 if (haveCompiler) {
639 const auto env = Environment::systemEnvironment();
640 const QStringList extraArgs = splitString(m_platformCodeGenFlagsLineEdit->text());
641 const Id languageId = toolChain()->language();
642 m_macros = dumpPredefinedMacros(compilerPath, extraArgs, languageId, env);
643 const Abi guessed = guessAbi(m_macros);
644 m_abiWidget->setAbis({}, guessed);
645 }
646
647 m_abiWidget->setEnabled(haveCompiler);
648 emit dirty();
649 }
650
handlePlatformCodeGenFlagsChange()651 void IarToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
652 {
653 const QString str1 = m_platformCodeGenFlagsLineEdit->text();
654 const QString str2 = ProcessArgs::joinArgs(splitString(str1));
655 if (str1 != str2)
656 m_platformCodeGenFlagsLineEdit->setText(str2);
657 else
658 handleCompilerCommandChange();
659 }
660
661 } // namespace Internal
662 } // namespace BareMetal
663