aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.cpp18
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.h14
-rw-r--r--src/app/qbs-setup-toolchains/commandlineparser.h3
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.cpp515
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.h62
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.cpp107
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.cpp124
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp5
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.h14
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp347
-rw-r--r--src/app/qbs-setup-toolchains/probe.h32
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs2
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.cpp166
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.h6
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.h6
-rw-r--r--src/app/qbs/commandlinefrontend.cpp6
-rw-r--r--src/app/qbs/parser/commandlineparser.cpp1
-rw-r--r--src/app/qbs/parser/commandpool.cpp3
-rw-r--r--src/app/qbs/parser/commandtype.h2
-rw-r--r--src/app/qbs/parser/parsercommand.cpp23
-rw-r--r--src/app/qbs/parser/parsercommand.h14
-rw-r--r--src/app/qbs/qbs.pro8
-rw-r--r--src/app/qbs/qbs.qbs8
-rw-r--r--src/app/qbs/session.cpp766
-rw-r--r--src/app/qbs/session.h51
-rw-r--r--src/app/qbs/sessionpacket.cpp113
-rw-r--r--src/app/qbs/sessionpacket.h70
-rw-r--r--src/app/qbs/sessionpacketreader.cpp85
-rw-r--r--src/app/qbs/sessionpacketreader.h70
-rw-r--r--src/app/qbs/stdinreader.cpp146
-rw-r--r--src/app/qbs/stdinreader.h66
-rw-r--r--src/lib/corelib/api/project.cpp22
-rw-r--r--src/lib/corelib/api/project.h3
-rw-r--r--src/lib/corelib/api/projectdata.cpp156
-rw-r--r--src/lib/corelib/api/projectdata.h5
-rw-r--r--src/lib/corelib/buildgraph/abstractcommandexecutor.cpp21
-rw-r--r--src/lib/corelib/buildgraph/abstractcommandexecutor.h9
-rw-r--r--src/lib/corelib/buildgraph/jscommandexecutor.cpp16
-rw-r--r--src/lib/corelib/buildgraph/jscommandexecutor.h5
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.cpp26
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.h6
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.cpp14
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.h6
-rw-r--r--src/lib/corelib/corelib.qbs18
-rw-r--r--src/lib/corelib/generators/generators.pri22
-rw-r--r--src/lib/corelib/generators/generatorutils.cpp262
-rw-r--r--src/lib/corelib/generators/generatorutils.h96
-rw-r--r--src/lib/corelib/generators/generatorversioninfo.cpp83
-rw-r--r--src/lib/corelib/generators/generatorversioninfo.h78
-rw-r--r--src/lib/corelib/generators/ixmlnodevisitor.h69
-rw-r--r--src/lib/corelib/generators/xmlproject.cpp50
-rw-r--r--src/lib/corelib/generators/xmlproject.h54
-rw-r--r--src/lib/corelib/generators/xmlprojectwriter.cpp92
-rw-r--r--src/lib/corelib/generators/xmlprojectwriter.h70
-rw-r--r--src/lib/corelib/generators/xmlproperty.cpp56
-rw-r--r--src/lib/corelib/generators/xmlproperty.h88
-rw-r--r--src/lib/corelib/generators/xmlpropertygroup.cpp67
-rw-r--r--src/lib/corelib/generators/xmlpropertygroup.h78
-rw-r--r--src/lib/corelib/generators/xmlworkspace.cpp66
-rw-r--r--src/lib/corelib/generators/xmlworkspace.h69
-rw-r--r--src/lib/corelib/generators/xmlworkspacewriter.cpp92
-rw-r--r--src/lib/corelib/generators/xmlworkspacewriter.h70
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.cpp13
-rw-r--r--src/lib/corelib/language/moduleloader.cpp6
-rw-r--r--src/lib/corelib/tools/buildoptions.cpp55
-rw-r--r--src/lib/corelib/tools/buildoptions.h3
-rw-r--r--src/lib/corelib/tools/cleanoptions.cpp12
-rw-r--r--src/lib/corelib/tools/cleanoptions.h6
-rw-r--r--src/lib/corelib/tools/codelocation.cpp15
-rw-r--r--src/lib/corelib/tools/codelocation.h2
-rw-r--r--src/lib/corelib/tools/error.cpp24
-rw-r--r--src/lib/corelib/tools/error.h5
-rw-r--r--src/lib/corelib/tools/installoptions.cpp21
-rw-r--r--src/lib/corelib/tools/installoptions.h3
-rw-r--r--src/lib/corelib/tools/jsonhelper.h89
-rw-r--r--src/lib/corelib/tools/processresult.cpp30
-rw-r--r--src/lib/corelib/tools/processresult.h3
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.cpp47
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.h2
-rw-r--r--src/lib/corelib/tools/stringconstants.h11
-rw-r--r--src/lib/corelib/tools/tools.pri1
-rw-r--r--src/lib/corelib/tools/version.cpp12
-rw-r--r--src/lib/corelib/tools/version.h4
-rw-r--r--src/plugins/generator/generator.pro6
-rw-r--r--src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.cpp95
-rw-r--r--src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.h58
-rw-r--r--src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.cpp230
-rw-r--r--src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.h63
-rw-r--r--src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.cpp98
-rw-r--r--src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.h71
-rw-r--r--src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.cpp478
-rw-r--r--src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.h63
-rw-r--r--src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp551
-rw-r--r--src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h63
-rw-r--r--src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.cpp489
-rw-r--r--src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.h71
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.cpp94
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.h58
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.cpp226
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.h61
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.cpp98
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.h72
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.cpp492
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.h64
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.cpp774
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.h63
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.cpp388
-rw-r--r--src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.h66
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.cpp95
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.h59
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.cpp228
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.h62
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.cpp98
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.h71
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.cpp476
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.h65
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.cpp1014
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.h66
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.cpp336
-rw-r--r--src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.h68
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.cpp94
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.h59
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.cpp229
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.h62
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.cpp98
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.h72
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.cpp486
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.h65
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.cpp483
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.h64
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.cpp290
-rw-r--r--src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.h65
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.cpp94
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.h59
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.cpp229
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.h62
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.cpp98
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.h72
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.cpp442
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.h64
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.cpp366
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.h64
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp411
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.h73
-rw-r--r--src/plugins/generator/iarew/iarew.pro133
-rw-r--r--src/plugins/generator/iarew/iarew.qbs132
-rw-r--r--src/plugins/generator/iarew/iarewfileversionproperty.cpp57
-rw-r--r--src/plugins/generator/iarew/iarewfileversionproperty.h49
-rw-r--r--src/plugins/generator/iarew/iarewgenerator.cpp158
-rw-r--r--src/plugins/generator/iarew/iarewgenerator.h70
-rw-r--r--src/plugins/generator/iarew/iarewgeneratorplugin.cpp67
-rw-r--r--src/plugins/generator/iarew/iarewoptionpropertygroup.cpp57
-rw-r--r--src/plugins/generator/iarew/iarewoptionpropertygroup.h51
-rw-r--r--src/plugins/generator/iarew/iarewproject.cpp130
-rw-r--r--src/plugins/generator/iarew/iarewproject.h56
-rw-r--r--src/plugins/generator/iarew/iarewprojectwriter.cpp52
-rw-r--r--src/plugins/generator/iarew/iarewprojectwriter.h51
-rw-r--r--src/plugins/generator/iarew/iarewsettingspropertygroup.cpp106
-rw-r--r--src/plugins/generator/iarew/iarewsettingspropertygroup.h68
-rw-r--r--src/plugins/generator/iarew/iarewsourcefilepropertygroup.cpp54
-rw-r--r--src/plugins/generator/iarew/iarewsourcefilepropertygroup.h52
-rw-r--r--src/plugins/generator/iarew/iarewsourcefilespropertygroup.cpp56
-rw-r--r--src/plugins/generator/iarew/iarewsourcefilespropertygroup.h50
-rw-r--r--src/plugins/generator/iarew/iarewtoolchainpropertygroup.cpp43
-rw-r--r--src/plugins/generator/iarew/iarewtoolchainpropertygroup.h48
-rw-r--r--src/plugins/generator/iarew/iarewutils.cpp156
-rw-r--r--src/plugins/generator/iarew/iarewutils.h75
-rw-r--r--src/plugins/generator/iarew/iarewversioninfo.cpp77
-rw-r--r--src/plugins/generator/iarew/iarewversioninfo.h61
-rw-r--r--src/plugins/generator/iarew/iarewworkspace.cpp63
-rw-r--r--src/plugins/generator/iarew/iarewworkspace.h58
-rw-r--r--src/plugins/generator/iarew/iarewworkspacewriter.cpp52
-rw-r--r--src/plugins/generator/iarew/iarewworkspacewriter.h51
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.cpp108
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.h70
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.cpp154
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.cpp208
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.cpp218
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.cpp56
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.cpp164
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.cpp75
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.cpp109
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.h70
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.cpp143
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.cpp140
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.cpp281
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.cpp56
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.cpp240
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.cpp104
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.cpp50
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.h54
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51utils.cpp83
-rw-r--r--src/plugins/generator/keiluv/archs/mcs51/mcs51utils.h56
-rw-r--r--src/plugins/generator/keiluv/keiluv.pro92
-rw-r--r--src/plugins/generator/keiluv/keiluv.qbs90
-rw-r--r--src/plugins/generator/keiluv/keiluvconstants.h44
-rw-r--r--src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.cpp197
-rw-r--r--src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.h52
-rw-r--r--src/plugins/generator/keiluv/keiluvgenerator.cpp149
-rw-r--r--src/plugins/generator/keiluv/keiluvgenerator.h71
-rw-r--r--src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp67
-rw-r--r--src/plugins/generator/keiluv/keiluvproject.cpp114
-rw-r--r--src/plugins/generator/keiluv/keiluvproject.h58
-rw-r--r--src/plugins/generator/keiluv/keiluvprojectwriter.cpp58
-rw-r--r--src/plugins/generator/keiluv/keiluvprojectwriter.h51
-rw-r--r--src/plugins/generator/keiluv/keiluvutils.cpp123
-rw-r--r--src/plugins/generator/keiluv/keiluvutils.h64
-rw-r--r--src/plugins/generator/keiluv/keiluvversioninfo.cpp76
-rw-r--r--src/plugins/generator/keiluv/keiluvversioninfo.h61
-rw-r--r--src/plugins/generator/keiluv/keiluvworkspace.cpp68
-rw-r--r--src/plugins/generator/keiluv/keiluvworkspace.h56
-rw-r--r--src/plugins/generator/keiluv/keiluvworkspacewriter.cpp58
-rw-r--r--src/plugins/generator/keiluv/keiluvworkspacewriter.h51
-rw-r--r--src/plugins/plugins.qbs2
243 files changed, 23713 insertions, 380 deletions
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp
index 5c2a87731..816d28546 100644
--- a/src/app/qbs-setup-toolchains/clangclprobe.cpp
+++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp
@@ -60,9 +60,9 @@ using qbs::Internal::Tr;
namespace {
-QString getToolchainInstallPath(const QString &compilerFilePath)
+QString getToolchainInstallPath(const QFileInfo &compiler)
{
- return QFileInfo(compilerFilePath).path(); // 1 level up
+ return compiler.path(); // 1 level up
}
Profile createProfileHelper(
@@ -159,19 +159,19 @@ QString findClangCl()
} // namespace
-void createClangClProfile(
- const QString &profileName, const QString &compilerFilePath, Settings *settings)
+void createClangClProfile(const QFileInfo &compiler, Settings *settings,
+ const QString &profileName)
{
const auto compilerName = QStringLiteral("clang-cl");
const auto vcvarsallPath = findCompatibleVcsarsallBat();
if (vcvarsallPath.isEmpty()) {
qbsWarning()
<< Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
- .arg(compilerName);
+ .arg(compilerName);
return;
}
- const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath);
+ const auto toolchainInstallPath = getToolchainInstallPath(compiler);
const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture());
createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch);
}
@@ -184,12 +184,12 @@ void clangClProbe(Settings *settings, QList<Profile> &profiles)
{
const auto compilerName = QStringLiteral("clang-cl");
qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName);
- const auto compilerFilePath = findClangCl();
+ const QString compilerFilePath = findClangCl();
if (compilerFilePath.isEmpty()) {
qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName);
return;
}
-
+ const QFileInfo compiler(compilerFilePath);
const auto vcvarsallPath = findCompatibleVcsarsallBat();
if (vcvarsallPath.isEmpty()) {
qbsWarning()
@@ -202,7 +202,7 @@ void clangClProbe(Settings *settings, QList<Profile> &profiles)
QStringLiteral("x86_64"),
QStringLiteral("x86")
};
- const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath);
+ const auto toolchainInstallPath = getToolchainInstallPath(compiler);
for (const auto &arch: architectures) {
const auto profileName = QStringLiteral("clang-cl-%1").arg(arch);
auto profile = createProfileHelper(
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.h b/src/app/qbs-setup-toolchains/clangclprobe.h
index 1e7724fbf..1afbbb1b8 100644
--- a/src/app/qbs-setup-toolchains/clangclprobe.h
+++ b/src/app/qbs-setup-toolchains/clangclprobe.h
@@ -37,19 +37,23 @@
**
****************************************************************************/
-#ifndef CLANGCLPROBE_H
-#define CLANGCLPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H
+#define QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H
#include <QtCore/qlist.h>
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+QT_END_NAMESPACE
+
namespace qbs {
class Profile;
class Settings;
}
-void createClangClProfile(
- const QString &profileName, const QString &compilerFilePath, qbs::Settings *settings);
+void createClangClProfile(const QFileInfo &compiler, qbs::Settings *settings,
+ const QString &profileName);
void clangClProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // CLANGCLPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/commandlineparser.h b/src/app/qbs-setup-toolchains/commandlineparser.h
index 9d5b0c246..0616f068e 100644
--- a/src/app/qbs-setup-toolchains/commandlineparser.h
+++ b/src/app/qbs-setup-toolchains/commandlineparser.h
@@ -36,6 +36,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
#ifndef QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H
#define QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H
@@ -75,4 +76,4 @@ private:
QString m_command;
};
-#endif // Include guard
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/gccprobe.cpp b/src/app/qbs-setup-toolchains/gccprobe.cpp
new file mode 100644
index 000000000..a8482f8d0
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/gccprobe.cpp
@@ -0,0 +1,515 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "probe.h"
+#include "gccprobe.h"
+
+#include "../shared/logging/consolelogger.h"
+
+#include <logging/translator.h>
+
+#include <tools/hostosinfo.h>
+#include <tools/profile.h>
+#include <tools/settings.h>
+#include <tools/toolchains.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qprocess.h>
+
+#include <algorithm>
+
+using namespace qbs;
+using Internal::HostOsInfo;
+using Internal::Tr;
+
+static QString qsystem(const QString &exe, const QStringList &args = QStringList())
+{
+ QProcess p;
+ p.setProcessChannelMode(QProcess::MergedChannels);
+ p.start(exe, args);
+ if (!p.waitForStarted()) {
+ throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
+ .arg(exe, p.errorString()));
+ }
+ if (!p.waitForFinished(-1) || p.exitCode() != 0)
+ throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2")
+ .arg(exe, p.errorString()));
+ return QString::fromLocal8Bit(p.readAll());
+}
+
+static QStringList validMinGWMachines()
+{
+ // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
+ return {QStringLiteral("mingw32"),
+ QStringLiteral("mingw64"),
+ QStringLiteral("i686-w64-mingw32"),
+ QStringLiteral("x86_64-w64-mingw32"),
+ QStringLiteral("i686-w64-mingw32.shared"),
+ QStringLiteral("x86_64-w64-mingw32.shared"),
+ QStringLiteral("i686-w64-mingw32.static"),
+ QStringLiteral("x86_64-w64-mingw32.static"),
+ QStringLiteral("i586-mingw32msvc"),
+ QStringLiteral("amd64-mingw32msvc")};
+}
+
+static QString gccMachineName(const QFileInfo &compiler)
+{
+ return qsystem(compiler.absoluteFilePath(), {QStringLiteral("-dumpmachine")})
+ .trimmed();
+}
+
+static QStringList standardCompilerFileNames()
+{
+ return {HostOsInfo::appendExecutableSuffix(QStringLiteral("gcc")),
+ HostOsInfo::appendExecutableSuffix(QStringLiteral("g++")),
+ HostOsInfo::appendExecutableSuffix(QStringLiteral("clang")),
+ HostOsInfo::appendExecutableSuffix(QStringLiteral("clang++"))};
+}
+
+class ToolchainDetails
+{
+public:
+ explicit ToolchainDetails(const QFileInfo &compiler)
+ {
+ auto baseName = compiler.completeBaseName();
+ if (baseName.contains(QRegExp(QLatin1String("\\d$")))) {
+ const auto dashIndex = baseName.lastIndexOf(QLatin1Char('-'));
+ version = baseName.mid(dashIndex + 1);
+ baseName = baseName.left(dashIndex);
+ }
+
+ const auto dashIndex = baseName.lastIndexOf(QLatin1Char('-'));
+ suffix = baseName.mid(dashIndex + 1);
+ prefix = baseName.left(dashIndex + 1);
+ }
+
+ QString prefix;
+ QString suffix;
+ QString version;
+};
+
+static void setCommonProperties(Profile &profile, const QFileInfo &compiler,
+ const QStringList &toolchainTypes, const ToolchainDetails &details)
+{
+ if (toolchainTypes.contains(QStringLiteral("mingw")))
+ profile.setValue(QStringLiteral("qbs.targetPlatform"),
+ QStringLiteral("windows"));
+
+ if (!details.prefix.isEmpty())
+ profile.setValue(QStringLiteral("cpp.toolchainPrefix"), details.prefix);
+
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"),
+ compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchain"), toolchainTypes);
+
+ if (!standardCompilerFileNames().contains(
+ HostOsInfo::appendExecutableSuffix(details.suffix))) {
+ qWarning("%s", qPrintable(
+ QStringLiteral("'%1' is not a standard compiler file name; "
+ "you must set the cpp.cCompilerName and "
+ "cpp.cxxCompilerName properties of this profile "
+ "manually").arg(compiler.fileName())));
+ }
+}
+
+class ToolPathSetup
+{
+public:
+ explicit ToolPathSetup(Profile *profile, QString path, ToolchainDetails details)
+ : m_profile(profile),
+ m_compilerDirPath(std::move(path)),
+ m_details(std::move(details))
+ {
+ }
+
+ void apply(const QString &toolName, const QString &propertyName) const
+ {
+ // Check for full tool name at first (includes suffix and version).
+ QString filePath = toolFilePath(toolName, UseFullToolName);
+ if (filePath.isEmpty()) {
+ // Check for base tool name at second (without of suffix and version).
+ filePath = toolFilePath(toolName, UseBaseToolName);
+ if (filePath.isEmpty()) {
+ // Check for short tool name at third (only a tool name).
+ filePath = toolFilePath(toolName, UseOnlyShortToolName);
+ }
+ }
+
+ if (filePath.isEmpty()) {
+ qWarning("%s", qPrintable(
+ QStringLiteral("'%1' not found in '%2'. "
+ "Qbs will try to find it in PATH at build time.")
+ .arg(toolName, m_compilerDirPath)));
+ } else {
+ m_profile->setValue(propertyName, filePath);
+ }
+ }
+
+private:
+ enum ToolNameParts : quint8 {
+ UseOnlyShortToolName = 0x0,
+ UseToolPrefix = 0x01,
+ UseToolSuffix = 0x02,
+ UseToolVersion = 0x04,
+ UseFullToolName = UseToolPrefix | UseToolSuffix | UseToolVersion,
+ UseBaseToolName = UseToolPrefix,
+ };
+
+ QString toolFilePath(const QString &toolName, int parts) const
+ {
+ QString fileName;
+ if ((parts & UseToolPrefix) && !m_details.prefix.isEmpty())
+ fileName += m_details.prefix;
+ if ((parts & UseToolSuffix) && !m_details.suffix.isEmpty())
+ fileName += m_details.suffix + QLatin1Char('-');
+ fileName += toolName;
+ if ((parts & UseToolVersion) && !m_details.version.isEmpty())
+ fileName += QLatin1Char('-') + m_details.version;
+
+ fileName = HostOsInfo::appendExecutableSuffix(fileName);
+ QString filePath = QDir(m_compilerDirPath).absoluteFilePath(fileName);
+ if (QFile::exists(filePath))
+ return filePath;
+ return {};
+ }
+
+ Profile * const m_profile;
+ QString m_compilerDirPath;
+ ToolchainDetails m_details;
+};
+
+static bool doesProfileTargetOS(const Profile &profile, const QString &os)
+{
+ const auto target = profile.value(QStringLiteral("qbs.targetPlatform"));
+ if (target.isValid()) {
+ return Internal::contains(HostOsInfo::canonicalOSIdentifiers(
+ target.toString().toStdString()),
+ os.toStdString());
+ }
+ return Internal::contains(HostOsInfo::hostOSIdentifiers(), os.toStdString());
+}
+
+static QString buildProfileName(const QFileInfo &cfi)
+{
+ // We need to replace a dot-separated compiler version string
+ // with a underscore-separated string, because the profile
+ // name does not allow a dots.
+ auto result = cfi.completeBaseName();
+ result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return result;
+}
+
+static QStringList buildCompilerNameFilters(const QString &compilerName)
+{
+ QStringList filters = {
+ // "clang", "gcc"
+ compilerName,
+ // "clang-8", "gcc-5"
+ compilerName + QLatin1String("-[1-9]*"),
+ // "avr-gcc"
+ QLatin1String("*-") + compilerName,
+ // "avr-gcc-5.4.0"
+ QLatin1String("*-") + compilerName + QLatin1String("-[1-9]*"),
+ // "arm-none-eabi-gcc"
+ QLatin1String("*-*-*-") + compilerName,
+ // "arm-none-eabi-gcc-9.1.0"
+ QLatin1String("*-*-*-") + compilerName + QLatin1String("-[1-9]*"),
+ // "x86_64-pc-linux-gnu-gcc"
+ QLatin1String("*-*-*-*-") + compilerName,
+ // "x86_64-pc-linux-gnu-gcc-7.4.1"
+ QLatin1String("*-*-*-*-") + compilerName + QLatin1String("-[1-9]*")
+ };
+
+ std::transform(filters.begin(), filters.end(), filters.begin(),
+ [](const auto &filter) {
+ return HostOsInfo::appendExecutableSuffix(filter);
+ });
+
+ return filters;
+}
+
+static QStringList gnuRegistrySearchPaths()
+{
+ if (!HostOsInfo::isWindowsHost())
+ return {};
+
+ // Registry token for the "GNU Tools for ARM Embedded Processors".
+ static const char kRegistryToken[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \
+ "Windows\\CurrentVersion\\Uninstall\\";
+
+ QStringList searchPaths;
+
+ QSettings registry(QLatin1String(kRegistryToken), QSettings::NativeFormat);
+ const auto productGroups = registry.childGroups();
+ for (const QString &productKey : productGroups) {
+ if (!productKey.startsWith(
+ QLatin1String("GNU Tools for ARM Embedded Processors"))) {
+ continue;
+ }
+ registry.beginGroup(productKey);
+ QString uninstallFilePath = registry.value(
+ QLatin1String("UninstallString")).toString();
+ if (uninstallFilePath.startsWith(QLatin1Char('"')))
+ uninstallFilePath.remove(0, 1);
+ if (uninstallFilePath.endsWith(QLatin1Char('"')))
+ uninstallFilePath.remove(uninstallFilePath.size() - 1, 1);
+ registry.endGroup();
+
+ const QString toolkitRootPath = QFileInfo(uninstallFilePath).path();
+ const QString toolchainPath = toolkitRootPath + QLatin1String("/bin");
+ searchPaths.push_back(toolchainPath);
+ }
+
+ return searchPaths;
+}
+
+static QStringList atmelRegistrySearchPaths()
+{
+ if (!HostOsInfo::isWindowsHost())
+ return {};
+
+ // Registry token for the "Atmel" toolchains, e.g. provided by installed
+ // "Atmel Studio" IDE.
+ static const char kRegistryToken[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Atmel\\";
+
+ QStringList searchPaths;
+ QSettings registry(QLatin1String(kRegistryToken), QSettings::NativeFormat);
+
+ // This code enumerate the installed toolchains provided
+ // by the Atmel Studio v6.x.
+ const auto toolchainGroups = registry.childGroups();
+ for (const QString &toolchainKey : toolchainGroups) {
+ if (!toolchainKey.endsWith(QLatin1String("GCC")))
+ continue;
+ registry.beginGroup(toolchainKey);
+ const auto entries = registry.childGroups();
+ for (const auto &entryKey : entries) {
+ registry.beginGroup(entryKey);
+ const QString installDir = registry.value(
+ QStringLiteral("Native/InstallDir")).toString();
+ const QString version = registry.value(
+ QStringLiteral("Native/Version")).toString();
+ registry.endGroup();
+
+ QString toolchainPath = installDir
+ + QLatin1String("/Atmel Toolchain/")
+ + toolchainKey + QLatin1String("/Native/")
+ + version;
+ if (toolchainKey.startsWith(QLatin1String("ARM")))
+ toolchainPath += QLatin1String("/arm-gnu-toolchain");
+ else if (toolchainKey.startsWith(QLatin1String("AVR32")))
+ toolchainPath += QLatin1String("/avr32-gnu-toolchain");
+ else if (toolchainKey.startsWith(QLatin1String("AVR8)")))
+ toolchainPath += QLatin1String("/avr8-gnu-toolchain");
+ else
+ break;
+
+ toolchainPath += QLatin1String("/bin");
+
+ if (QFileInfo::exists(toolchainPath)) {
+ searchPaths.push_back(toolchainPath);
+ break;
+ }
+ }
+ registry.endGroup();
+ }
+
+ // This code enumerate the installed toolchains provided
+ // by the Atmel Studio v7.
+ registry.beginGroup(QStringLiteral("AtmelStudio"));
+ const auto productVersions = registry.childGroups();
+ for (const auto &productVersionKey : productVersions) {
+ registry.beginGroup(productVersionKey);
+ const QString installDir = registry.value(
+ QStringLiteral("InstallDir")).toString();
+ registry.endGroup();
+
+ const QStringList knownToolchainSubdirs = {
+ QStringLiteral("/toolchain/arm/arm-gnu-toolchain/bin/"),
+ QStringLiteral("/toolchain/avr8/avr8-gnu-toolchain/bin/"),
+ QStringLiteral("/toolchain/avr32/avr32-gnu-toolchain/bin/"),
+ };
+
+ for (const auto &subdir : knownToolchainSubdirs) {
+ const QString toolchainPath = installDir + subdir;
+ if (!QFileInfo::exists(toolchainPath))
+ continue;
+ searchPaths.push_back(toolchainPath);
+ }
+ }
+ registry.endGroup();
+
+ return searchPaths;
+}
+
+Profile createGccProfile(const QFileInfo &compiler, Settings *settings,
+ const QStringList &toolchainTypes,
+ const QString &profileName)
+{
+ const QString machineName = gccMachineName(compiler);
+
+ if (toolchainTypes.contains(QLatin1String("mingw"))) {
+ if (!validMinGWMachines().contains(machineName)) {
+ throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
+ .arg(machineName));
+ }
+ }
+
+ Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
+ profile.removeProfile();
+
+ const ToolchainDetails details(compiler);
+
+ setCommonProperties(profile, compiler, toolchainTypes, details);
+
+ if (HostOsInfo::isWindowsHost() && toolchainTypes.contains(QLatin1String("clang"))) {
+ const QStringList profileNames = settings->profiles();
+ bool foundMingw = false;
+ for (const QString &profileName : profileNames) {
+ const Profile otherProfile(profileName, settings);
+ if (otherProfile.value(QLatin1String("qbs.toolchainType")).toString()
+ == QLatin1String("mingw")
+ || otherProfile.value(QLatin1String("qbs.toolchain"))
+ .toStringList().contains(QLatin1String("mingw"))) {
+ const QFileInfo tcDir(otherProfile.value(QLatin1String("cpp.toolchainInstallPath"))
+ .toString());
+ if (!tcDir.fileName().isEmpty() && tcDir.exists()) {
+ profile.setValue(QLatin1String("qbs.sysroot"), tcDir.path());
+ foundMingw = true;
+ break;
+ }
+ }
+ }
+ if (!foundMingw) {
+ qbsWarning() << Tr::tr("Using clang on Windows requires a mingw installation. "
+ "Please set qbs.sysroot accordingly for profile '%1'.")
+ .arg(profile.name());
+ }
+ }
+
+ if (!toolchainTypes.contains(QLatin1String("clang"))) {
+ // Check whether auxiliary tools reside within the toolchain's install path.
+ // This might not be the case when using icecc or another compiler wrapper.
+ const QString compilerDirPath = compiler.absolutePath();
+ const ToolPathSetup toolPathSetup(&profile, compilerDirPath, details);
+ toolPathSetup.apply(QStringLiteral("ar"), QStringLiteral("cpp.archiverPath"));
+ toolPathSetup.apply(QStringLiteral("as"), QStringLiteral("cpp.assemblerPath"));
+ toolPathSetup.apply(QStringLiteral("nm"), QStringLiteral("cpp.nmPath"));
+ if (doesProfileTargetOS(profile, QStringLiteral("darwin")))
+ toolPathSetup.apply(QStringLiteral("dsymutil"),
+ QStringLiteral("cpp.dsymutilPath"));
+ else
+ toolPathSetup.apply(QStringLiteral("objcopy"),
+ QStringLiteral("cpp.objcopyPath"));
+ toolPathSetup.apply(QStringLiteral("strip"),
+ QStringLiteral("cpp.stripPath"));
+ }
+
+ qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
+ .arg(profile.name(), compiler.absoluteFilePath());
+ return profile;
+}
+
+void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
+{
+ qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName);
+
+ QStringList searchPaths;
+ searchPaths << systemSearchPaths() << gnuRegistrySearchPaths()
+ << atmelRegistrySearchPaths();
+
+ std::vector<QFileInfo> candidates;
+ const auto filters = buildCompilerNameFilters(compilerName);
+ for (const auto &searchPath : searchPaths) {
+ const QDir dir(searchPath);
+ const QStringList fileNames = dir.entryList(
+ filters, QDir::Files | QDir::Executable);
+ for (const QString &fileName : fileNames) {
+ // Ignore unexpected compiler names.
+ if (fileName.startsWith(QLatin1String("c89-gcc"))
+ || fileName.startsWith(QLatin1String("c99-gcc"))) {
+ continue;
+ }
+ const QFileInfo candidate = dir.filePath(fileName);
+ // Filter duplicates.
+ const auto existingEnd = candidates.end();
+ const auto existingIt = std::find_if(
+ candidates.begin(), existingEnd,
+ [candidate](const QFileInfo &existing) {
+ return isSameExecutable(candidate.absoluteFilePath(),
+ existing.absoluteFilePath());
+ });
+ if (existingIt == existingEnd) {
+ // No duplicates are found, just add a new candidate.
+ candidates.push_back(candidate);
+ } else {
+ // Replace the existing entry if a candidate name more than
+ // an existing name.
+ const auto candidateName = candidate.completeBaseName();
+ const auto existingName = existingIt->completeBaseName();
+ if (candidateName > existingName)
+ *existingIt = candidate;
+ }
+ }
+ }
+
+ if (candidates.empty()) {
+ qbsInfo() << Tr::tr("No %1 toolchains found.").arg(compilerName);
+ return;
+ }
+
+ // Sort candidates so that mingw comes first. Information from mingw profiles is potentially
+ // used for setting up clang profiles.
+ if (HostOsInfo::isWindowsHost()) {
+ std::sort(candidates.begin(), candidates.end(),
+ [](const QFileInfo &fi1, const QFileInfo &fi2) {
+ return fi1.absoluteFilePath().contains(QLatin1String("mingw"))
+ && !fi2.absoluteFilePath().contains(QLatin1String("mingw"));
+ });
+ }
+
+ for (const auto &candidate : qAsConst(candidates)) {
+ const QStringList toolchainTypes = toolchainTypeFromCompilerName(
+ candidate.baseName());
+ const QString profileName = buildProfileName(candidate);
+ auto profile = createGccProfile(candidate, settings,
+ toolchainTypes, profileName);
+ profiles.push_back(std::move(profile));
+ }
+}
diff --git a/src/app/qbs-setup-toolchains/gccprobe.h b/src/app/qbs-setup-toolchains/gccprobe.h
new file mode 100644
index 000000000..4344c5836
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/gccprobe.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_SETUPTOOLCHAINS_GCCPROBE_H
+#define QBS_SETUPTOOLCHAINS_GCCPROBE_H
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+QT_END_NAMESPACE
+
+namespace qbs {
+class Profile;
+class Settings;
+}
+
+qbs::Profile createGccProfile(const QFileInfo &compiler,
+ qbs::Settings *settings,
+ const QStringList &toolchainTypes,
+ const QString &profileName = QString());
+
+void gccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles,
+ const QString &compilerName);
+
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/iarewprobe.cpp b/src/app/qbs-setup-toolchains/iarewprobe.cpp
index 5d3785759..47592b9c0 100644
--- a/src/app/qbs-setup-toolchains/iarewprobe.cpp
+++ b/src/app/qbs-setup-toolchains/iarewprobe.cpp
@@ -47,9 +47,9 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
+#include <QtCore/qstandardpaths.h>
using namespace qbs;
using Internal::Tr;
@@ -57,7 +57,9 @@ using Internal::HostOsInfo;
static QStringList knownIarCompilerNames()
{
- return {QStringLiteral("icc8051"), QStringLiteral("iccarm"), QStringLiteral("iccavr")};
+ return {QStringLiteral("icc8051"), QStringLiteral("iccarm"),
+ QStringLiteral("iccavr"), QStringLiteral("iccstm8"),
+ QStringLiteral("icc430")};
}
static QString guessIarArchitecture(const QFileInfo &compiler)
@@ -69,17 +71,31 @@ static QString guessIarArchitecture(const QFileInfo &compiler)
return QStringLiteral("arm");
if (baseName == QLatin1String("iccavr"))
return QStringLiteral("avr");
+ if (baseName == QLatin1String("iccstm8"))
+ return QStringLiteral("stm8");
+ if (baseName == QLatin1String("icc430"))
+ return QStringLiteral("msp430");
return {};
}
-static Profile createIarProfileHelper(const QFileInfo &compiler, Settings *settings,
+static Profile createIarProfileHelper(const ToolchainInstallInfo &info,
+ Settings *settings,
QString profileName = QString())
{
+ const QFileInfo compiler = info.compilerPath;
const QString architecture = guessIarArchitecture(compiler);
// In case the profile is auto-detected.
- if (profileName.isEmpty())
- profileName = QLatin1String("iar-") + architecture;
+ if (profileName.isEmpty()) {
+ if (!info.compilerVersion.isValid()) {
+ profileName = QStringLiteral("iar-unknown-%1").arg(architecture);
+ } else {
+ const QString version = info.compilerVersion.toString(QLatin1Char('_'),
+ QLatin1Char('_'));
+ profileName = QStringLiteral("iar-%1-%2").arg(
+ version, architecture);
+ }
+ }
Profile profile(profileName, settings);
profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath());
@@ -92,9 +108,53 @@ static Profile createIarProfileHelper(const QFileInfo &compiler, Settings *setti
return profile;
}
-static std::vector<IarInstallInfo> installedIarsFromPath()
+static Version dumpIarCompilerVersion(const QFileInfo &compiler)
+{
+ const QString outFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation)
+ + QLatin1String("/macros.dump");
+ const QStringList args = {QStringLiteral("."),
+ QStringLiteral("--predef_macros"),
+ outFilePath};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+ const auto es = p.exitStatus();
+ if (es != QProcess::NormalExit) {
+ const QByteArray out = p.readAll();
+ qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
+ .arg(QString::fromUtf8(out));
+ return Version{};
+ }
+
+ QByteArray dump;
+ QFile out(outFilePath);
+ if (out.open(QIODevice::ReadOnly))
+ dump = out.readAll();
+ out.remove();
+
+ const int verCode = extractVersion(dump, "__VER__ ");
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No '__VER__' token was found in a compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+
+ const QString arch = guessIarArchitecture(compiler);
+ if (arch == QLatin1String("arm")) {
+ return Version{verCode / 1000000, (verCode / 1000) % 1000, verCode % 1000};
+ } else if (arch == QLatin1String("avr")
+ || arch == QLatin1String("mcs51")
+ || arch == QLatin1String("stm8")
+ || arch == QLatin1String("msp430")) {
+ return Version{verCode / 100, verCode % 100};
+ }
+
+ return Version{};
+}
+
+static std::vector<ToolchainInstallInfo> installedIarsFromPath()
{
- std::vector<IarInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
const auto compilerNames = knownIarCompilerNames();
for (const QString &compilerName : compilerNames) {
const QFileInfo iarPath(
@@ -102,14 +162,16 @@ static std::vector<IarInstallInfo> installedIarsFromPath()
HostOsInfo::appendExecutableSuffix(compilerName)));
if (!iarPath.exists())
continue;
- infos.push_back({iarPath.absoluteFilePath(), {}});
+ const Version version = dumpIarCompilerVersion(iarPath);
+ infos.push_back({iarPath, version});
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
-static std::vector<IarInstallInfo> installedIarsFromRegistry()
+static std::vector<ToolchainInstallInfo> installedIarsFromRegistry()
{
- std::vector<IarInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
if (HostOsInfo::isWindowsHost()) {
@@ -127,6 +189,8 @@ static std::vector<IarInstallInfo> installedIarsFromRegistry()
{QStringLiteral("EWARM"), QStringLiteral("\\arm\\bin\\iccarm.exe")},
{QStringLiteral("EWAVR"), QStringLiteral("\\avr\\bin\\iccavr.exe")},
{QStringLiteral("EW8051"), QStringLiteral("\\8051\\bin\\icc8051.exe")},
+ {QStringLiteral("EWSTM8"), QStringLiteral("\\stm8\\bin\\iccstm8.exe")},
+ {QStringLiteral("EW430"), QStringLiteral("\\430\\bin\\icc430.exe")},
};
QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat);
@@ -148,7 +212,7 @@ static std::vector<IarInstallInfo> installedIarsFromRegistry()
if (iarPath.exists()) {
// Note: threeLevelKey is a guessed toolchain version.
const QString version = threeLevelKey;
- infos.push_back({iarPath.absoluteFilePath(), version});
+ infos.push_back({iarPath, Version::fromString(version)});
}
}
registry.endGroup();
@@ -161,6 +225,7 @@ static std::vector<IarInstallInfo> installedIarsFromRegistry()
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
@@ -175,19 +240,25 @@ bool isIarCompiler(const QString &compilerName)
void createIarProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
- createIarProfileHelper(compiler, settings, profileName);
+ const ToolchainInstallInfo info = {compiler, Version{}};
+ createIarProfileHelper(info, settings, profileName);
}
void iarProbe(Settings *settings, QList<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect IAR toolchains...");
- std::vector<IarInstallInfo> allInfos = installedIarsFromRegistry();
- const std::vector<IarInstallInfo> pathInfos = installedIarsFromPath();
- allInfos.insert(std::end(allInfos), std::begin(pathInfos), std::end(pathInfos));
+ // Make sure that a returned infos are sorted before using the std::set_union!
+ const std::vector<ToolchainInstallInfo> regInfos = installedIarsFromRegistry();
+ const std::vector<ToolchainInstallInfo> pathInfos = installedIarsFromPath();
+ std::vector<ToolchainInstallInfo> allInfos;
+ allInfos.reserve(regInfos.size() + pathInfos.size());
+ std::set_union(regInfos.cbegin(), regInfos.cend(),
+ pathInfos.cbegin(), pathInfos.cend(),
+ std::back_inserter(allInfos));
- for (const IarInstallInfo &info : allInfos) {
- const auto profile = createIarProfileHelper(info.compilerPath, settings);
+ for (const ToolchainInstallInfo &info : allInfos) {
+ const auto profile = createIarProfileHelper(info, settings);
profiles.push_back(profile);
}
diff --git a/src/app/qbs-setup-toolchains/iarewprobe.h b/src/app/qbs-setup-toolchains/iarewprobe.h
index f5caf61ed..b604d6c6b 100644
--- a/src/app/qbs-setup-toolchains/iarewprobe.h
+++ b/src/app/qbs-setup-toolchains/iarewprobe.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef IAREWPROBE_H
-#define IAREWPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_IAREWPROBE_H
+#define QBS_SETUPTOOLCHAINS_IAREWPROBE_H
#include <QtCore/qlist.h>
@@ -51,12 +51,6 @@ class Profile;
class Settings;
}
-struct IarInstallInfo
-{
- QString compilerPath;
- QString version;
-};
-
bool isIarCompiler(const QString &compilerName);
void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings,
@@ -64,4 +58,4 @@ void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings,
void iarProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // IAREWPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/keilprobe.cpp b/src/app/qbs-setup-toolchains/keilprobe.cpp
index dc327d2ee..08f0f2167 100644
--- a/src/app/qbs-setup-toolchains/keilprobe.cpp
+++ b/src/app/qbs-setup-toolchains/keilprobe.cpp
@@ -47,9 +47,9 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
+#include <QtCore/qtemporaryfile.h>
using namespace qbs;
using Internal::Tr;
@@ -70,14 +70,24 @@ static QString guessKeilArchitecture(const QFileInfo &compiler)
return {};
}
-static Profile createKeilProfileHelper(const QFileInfo &compiler, Settings *settings,
+static Profile createKeilProfileHelper(const ToolchainInstallInfo &info,
+ Settings *settings,
QString profileName = QString())
{
+ const QFileInfo compiler = info.compilerPath;
const QString architecture = guessKeilArchitecture(compiler);
// In case the profile is auto-detected.
- if (profileName.isEmpty())
- profileName = QLatin1String("keil-") + architecture;
+ if (profileName.isEmpty()) {
+ if (!info.compilerVersion.isValid()) {
+ profileName = QStringLiteral("keil-unknown-%1").arg(architecture);
+ } else {
+ const QString version = info.compilerVersion.toString(QLatin1Char('_'),
+ QLatin1Char('_'));
+ profileName = QStringLiteral("keil-%1-%2").arg(
+ version, architecture);
+ }
+ }
Profile profile(profileName, settings);
profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
@@ -90,9 +100,80 @@ static Profile createKeilProfileHelper(const QFileInfo &compiler, Settings *sett
return profile;
}
-static std::vector<KeilInstallInfo> installedKeilsFromPath()
+static Version dumpKeilCompilerVersion(const QFileInfo &compiler)
+{
+ const QString arch = guessKeilArchitecture(compiler);
+ if (arch == QLatin1String("mcs51")) {
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open()) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return Version{};
+ }
+ 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");
+ fakeIn.write("#endif\n");
+ fakeIn.write("#ifdef __CX51__\n");
+ fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n");
+ fakeIn.write("#endif\n");
+ fakeIn.close();
+
+ const QStringList args = {fakeIn.fileName()};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+ const auto es = p.exitStatus();
+ if (es != QProcess::NormalExit) {
+ const QByteArray out = p.readAll();
+ qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
+ .arg(QString::fromUtf8(out));
+ return Version{};
+ }
+
+ const QByteArray dump = p.readAllStandardOutput();
+ const int verCode = extractVersion(dump, "\"__C51__\"|\"");
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No '__C51__' token was found"
+ " in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+ return Version{verCode / 100, verCode % 100};
+ } else if (arch == QLatin1String("arm")) {
+ const QStringList args = {QStringLiteral("-E"),
+ QStringLiteral("--list-macros"),
+ QStringLiteral("nul")};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+ const auto es = p.exitStatus();
+ if (es != QProcess::NormalExit) {
+ const QByteArray out = p.readAll();
+ qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
+ .arg(QString::fromUtf8(out));
+ return Version{};
+ }
+
+ const QByteArray dump = p.readAll();
+ const int verCode = extractVersion(dump, "__ARMCC_VERSION ");
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found "
+ "in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+ return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000};
+ }
+
+ return Version{};
+}
+
+static std::vector<ToolchainInstallInfo> installedKeilsFromPath()
{
- std::vector<KeilInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
const auto compilerNames = knownKeilCompilerNames();
for (const QString &compilerName : compilerNames) {
const QFileInfo keilPath(
@@ -100,14 +181,16 @@ static std::vector<KeilInstallInfo> installedKeilsFromPath()
HostOsInfo::appendExecutableSuffix(compilerName)));
if (!keilPath.exists())
continue;
- infos.push_back({keilPath.absoluteFilePath(), {}});
+ const Version version = dumpKeilCompilerVersion(keilPath);
+ infos.push_back({keilPath, version});
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
-static std::vector<KeilInstallInfo> installedKeilsFromRegistry()
+static std::vector<ToolchainInstallInfo> installedKeilsFromRegistry()
{
- std::vector<KeilInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
if (HostOsInfo::isWindowsHost()) {
@@ -148,7 +231,7 @@ static std::vector<KeilInstallInfo> installedKeilsFromRegistry()
.toString();
if (version.startsWith(QLatin1Char('V')))
version.remove(0, 1);
- infos.push_back({keilPath.absoluteFilePath(), version});
+ infos.push_back({keilPath, Version::fromString(version)});
}
}
registry.endGroup();
@@ -156,6 +239,7 @@ static std::vector<KeilInstallInfo> installedKeilsFromRegistry()
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
@@ -170,19 +254,25 @@ bool isKeilCompiler(const QString &compilerName)
void createKeilProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
- createKeilProfileHelper(compiler, settings, profileName);
+ const ToolchainInstallInfo info = {compiler, Version{}};
+ createKeilProfileHelper(info, settings, profileName);
}
void keilProbe(Settings *settings, QList<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect KEIL toolchains...");
- std::vector<KeilInstallInfo> allInfos = installedKeilsFromRegistry();
- const std::vector<KeilInstallInfo> pathInfos = installedKeilsFromPath();
- allInfos.insert(std::end(allInfos), std::begin(pathInfos), std::end(pathInfos));
+ // Make sure that a returned infos are sorted before using the std::set_union!
+ const std::vector<ToolchainInstallInfo> regInfos = installedKeilsFromRegistry();
+ const std::vector<ToolchainInstallInfo> pathInfos = installedKeilsFromPath();
+ std::vector<ToolchainInstallInfo> allInfos;
+ allInfos.reserve(regInfos.size() + pathInfos.size());
+ std::set_union(regInfos.cbegin(), regInfos.cend(),
+ pathInfos.cbegin(), pathInfos.cend(),
+ std::back_inserter(allInfos));
- for (const KeilInstallInfo &info : allInfos) {
- const auto profile = createKeilProfileHelper(info.compilerPath, settings);
+ for (const ToolchainInstallInfo &info : allInfos) {
+ const auto profile = createKeilProfileHelper(info, settings);
profiles.push_back(profile);
}
diff --git a/src/app/qbs-setup-toolchains/keilprobe.h b/src/app/qbs-setup-toolchains/keilprobe.h
index 6a897b84b..c7e66ee24 100644
--- a/src/app/qbs-setup-toolchains/keilprobe.h
+++ b/src/app/qbs-setup-toolchains/keilprobe.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef KEILPROBE_H
-#define KEILPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_KEILPROBE_H
+#define QBS_SETUPTOOLCHAINS_KEILPROBE_H
#include <QtCore/qlist.h>
@@ -51,12 +51,6 @@ class Profile;
class Settings;
}
-struct KeilInstallInfo
-{
- QString compilerPath;
- QString version;
-};
-
bool isKeilCompiler(const QString &compilerName);
void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings,
@@ -64,4 +58,4 @@ void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings,
void keilProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // KEILPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index d0b60a7fe..c8108bfd2 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -464,9 +464,10 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
}
}
-void createMsvcProfile(const QString &profileName, const QString &compilerFilePath,
- Settings *settings)
+void createMsvcProfile(const QFileInfo &compiler, Settings *settings,
+ const QString &profileName)
{
+ const auto compilerFilePath = compiler.absoluteFilePath();
MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath));
msvc.init();
QList<Profile> dummy;
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.h b/src/app/qbs-setup-toolchains/msvcprobe.h
index 4fa2cde48..f63dd5dc8 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.h
+++ b/src/app/qbs-setup-toolchains/msvcprobe.h
@@ -37,13 +37,17 @@
**
****************************************************************************/
-#ifndef MSVCPROBE_H
-#define MSVCPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_MSVCPROBE_H
+#define QBS_SETUPTOOLCHAINS_MSVCPROBE_H
#include <QtCore/qlist.h>
#include <vector>
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+QT_END_NAMESPACE
+
namespace qbs {
class Profile;
class Settings;
@@ -59,9 +63,9 @@ struct MSVCInstallInfo
std::vector<MSVCInstallInfo> installedMSVCs();
-void createMsvcProfile(const QString &profileName, const QString &compilerFilePath,
- qbs::Settings *settings);
+void createMsvcProfile(const QFileInfo &compiler, qbs::Settings *settings,
+ const QString &profileName);
void msvcProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // MSVCPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 3fae20a6e..205306acd 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -39,6 +39,7 @@
#include "probe.h"
#include "clangclprobe.h"
+#include "gccprobe.h"
#include "iarewprobe.h"
#include "keilprobe.h"
#include "msvcprobe.h"
@@ -46,22 +47,26 @@
#include "xcodeprobe.h"
#include <logging/translator.h>
-#include <tools/architectures.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <tools/qttools.h>
#include <tools/settings.h>
#include <tools/toolchains.h>
-#include <tools/stlutils.h>
#include <QtCore/qdir.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qprocess.h>
-#include <QtCore/qstringlist.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qtextstream.h>
-#include <cstdio>
+#ifdef Q_OS_WIN
+// We need defines for Windows 8.
+#undef _WIN32_WINNT
+#define _WIN32_WINNT _WIN32_WINNT_WIN8
+
+#include <qt_windows.h>
+#include <shlobj.h>
+#else
+#include <qplatformdefs.h>
+#endif // Q_OS_WIN
using namespace qbs;
using Internal::HostOsInfo;
@@ -70,6 +75,11 @@ using Internal::Tr;
static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);
+QStringList systemSearchPaths()
+{
+ return QString::fromLocal8Bit(qgetenv("PATH")).split(HostOsInfo::pathListSeparator());
+}
+
QString findExecutable(const QString &fileName)
{
QString fullFileName = fileName;
@@ -77,8 +87,7 @@ QString findExecutable(const QString &fileName)
&& !fileName.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) {
fullFileName += QLatin1String(".exe");
}
- const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
- const auto ppaths = path.split(HostOsInfo::pathListSeparator());
+ const auto ppaths = systemSearchPaths();
for (const QString &ppath : ppaths) {
const QString fullPath = ppath + QLatin1Char('/') + fullFileName;
if (QFileInfo::exists(fullPath))
@@ -87,31 +96,7 @@ QString findExecutable(const QString &fileName)
return {};
}
-static QString qsystem(const QString &exe, const QStringList &args = QStringList())
-{
- QProcess p;
- p.setProcessChannelMode(QProcess::MergedChannels);
- p.start(exe, args);
- if (!p.waitForStarted()) {
- throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
- .arg(exe, p.errorString()));
- }
- if (!p.waitForFinished(-1) || p.exitCode() != 0)
- throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
- return QString::fromLocal8Bit(p.readAll());
-}
-
-static QStringList validMinGWMachines()
-{
- // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
- return {QStringLiteral("mingw32"), QStringLiteral("mingw64"),
- QStringLiteral("i686-w64-mingw32"), QStringLiteral("x86_64-w64-mingw32"),
- QStringLiteral("i686-w64-mingw32.shared"), QStringLiteral("x86_64-w64-mingw32.shared"),
- QStringLiteral("i686-w64-mingw32.static"), QStringLiteral("x86_64-w64-mingw32.static"),
- QStringLiteral("i586-mingw32msvc"), QStringLiteral("amd64-mingw32msvc")};
-}
-
-static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
+QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
if (compilerName == QLatin1String("cl.exe"))
return canonicalToolchain(QStringLiteral("msvc"));
@@ -134,174 +119,19 @@ static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
return {};
}
-static QString gccMachineName(const QString &compilerFilePath)
-{
- return qsystem(compilerFilePath, QStringList() << QStringLiteral("-dumpmachine")).trimmed();
-}
-
-static QStringList standardCompilerFileNames()
-{
- return {HostOsInfo::appendExecutableSuffix(QStringLiteral("gcc")),
- HostOsInfo::appendExecutableSuffix(QStringLiteral("g++")),
- HostOsInfo::appendExecutableSuffix(QStringLiteral("clang")),
- HostOsInfo::appendExecutableSuffix(QStringLiteral("clang++"))};
-}
-
-static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
- const QStringList &toolchainTypes)
-{
- const QFileInfo cfi(compilerFilePath);
- const QString compilerName = cfi.fileName();
-
- if (toolchainTypes.contains(QStringLiteral("mingw")))
- profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows"));
-
- const QString prefix = compilerName.left(compilerName.lastIndexOf(QLatin1Char('-')) + 1);
- if (!prefix.isEmpty())
- profile.setValue(QStringLiteral("cpp.toolchainPrefix"), prefix);
-
- profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), cfi.absolutePath());
- profile.setValue(QStringLiteral("qbs.toolchain"), toolchainTypes);
-
- const QString suffix = compilerName.right(compilerName.size() - prefix.size());
- if (!standardCompilerFileNames().contains(suffix))
- qWarning("%s", qPrintable(
- QStringLiteral("'%1' is not a standard compiler file name; "
- "you must set the cpp.cCompilerName and "
- "cpp.cxxCompilerName properties of this profile "
- "manually").arg(compilerName)));
-}
-
-class ToolPathSetup
-{
-public:
- ToolPathSetup(Profile *profile, QString path, QString toolchainPrefix)
- : m_profile(profile),
- m_compilerDirPath(std::move(path)),
- m_toolchainPrefix(std::move(toolchainPrefix))
- {
- }
-
- void apply(const QString &toolName, const QString &propertyName) const
- {
- QString toolFileName = m_toolchainPrefix + HostOsInfo::appendExecutableSuffix(toolName);
- if (QFile::exists(m_compilerDirPath + QLatin1Char('/') + toolFileName))
- return;
- const QString toolFilePath = findExecutable(toolFileName);
- if (toolFilePath.isEmpty()) {
- qWarning("%s", qPrintable(QStringLiteral("'%1' exists neither in '%2' nor in PATH.")
- .arg(toolFileName, m_compilerDirPath)));
- }
- m_profile->setValue(propertyName, toolFilePath);
- }
-
-private:
- Profile * const m_profile;
- QString m_compilerDirPath;
- QString m_toolchainPrefix;
-};
-
-static bool doesProfileTargetOS(const Profile &profile, const QString &os)
-{
- const auto target = profile.value(QStringLiteral("qbs.targetPlatform"));
- if (target.isValid()) {
- return Internal::contains(HostOsInfo::canonicalOSIdentifiers(
- target.toString().toStdString()), os.toStdString());
- }
- return Internal::contains(HostOsInfo::hostOSIdentifiers(), os.toStdString());
-}
-
-static Profile createGccProfile(const QString &compilerFilePath, Settings *settings,
- const QStringList &toolchainTypes,
- const QString &profileName = QString())
-{
- const QString machineName = gccMachineName(compilerFilePath);
-
- if (toolchainTypes.contains(QLatin1String("mingw"))) {
- if (!validMinGWMachines().contains(machineName)) {
- throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
- .arg(machineName));
- }
- }
-
- Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
- profile.removeProfile();
- setCommonProperties(profile, compilerFilePath, toolchainTypes);
-
- // Check whether auxiliary tools reside within the toolchain's install path.
- // This might not be the case when using icecc or another compiler wrapper.
- const QString compilerDirPath = QFileInfo(compilerFilePath).absolutePath();
- const ToolPathSetup toolPathSetup(&profile, compilerDirPath,
- profile.value(QStringLiteral("cpp.toolchainPrefix"))
- .toString());
- toolPathSetup.apply(QStringLiteral("ar"), QStringLiteral("cpp.archiverPath"));
- toolPathSetup.apply(QStringLiteral("as"), QStringLiteral("cpp.assemblerPath"));
- toolPathSetup.apply(QStringLiteral("nm"), QStringLiteral("cpp.nmPath"));
- if (doesProfileTargetOS(profile, QStringLiteral("darwin")))
- toolPathSetup.apply(QStringLiteral("dsymutil"), QStringLiteral("cpp.dsymutilPath"));
- else
- toolPathSetup.apply(QStringLiteral("objcopy"), QStringLiteral("cpp.objcopyPath"));
- toolPathSetup.apply(QStringLiteral("strip"), QStringLiteral("cpp.stripPath"));
-
- qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
- << endl;
- return profile;
-}
-
-static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
-{
- qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;
-
- const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
- const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
- QFileInfo cfi(compilerFilePath);
- if (!cfi.exists()) {
- qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
- return;
- }
- const QString profileName = cfi.completeBaseName();
- const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
- profiles.push_back(createGccProfile(compilerFilePath, settings, toolchainTypes, profileName));
-}
-
-static void mingwProbe(Settings *settings, QList<Profile> &profiles)
-{
- // List of possible compiler binary names for this platform
- QStringList compilerNames;
- if (HostOsInfo::isWindowsHost()) {
- compilerNames << QStringLiteral("gcc");
- } else {
- const auto machineNames = validMinGWMachines();
- for (const QString &machineName : machineNames) {
- compilerNames << machineName + QLatin1String("-gcc");
- }
- }
-
- for (const QString &compilerName : qAsConst(compilerNames)) {
- const QString gccPath
- = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
- if (!gccPath.isEmpty())
- profiles.push_back(createGccProfile(gccPath, settings,
- canonicalToolchain(QStringLiteral("mingw"))));
- }
-}
-
void probe(Settings *settings)
{
QList<Profile> profiles;
if (HostOsInfo::isWindowsHost()) {
msvcProbe(settings, profiles);
clangClProbe(settings, profiles);
- } else {
- gccProbe(settings, profiles, QStringLiteral("gcc"));
- gccProbe(settings, profiles, QStringLiteral("clang"));
-
- if (HostOsInfo::isMacosHost()) {
- xcodeProbe(settings, profiles);
- }
+ } else if (HostOsInfo::isMacosHost()) {
+ xcodeProbe(settings, profiles);
}
- mingwProbe(settings, profiles);
+ gccProbe(settings, profiles, QStringLiteral("gcc"));
+ gccProbe(settings, profiles, QStringLiteral("clang"));
+
iarProbe(settings, profiles);
keilProbe(settings, profiles);
sdccProbe(settings, profiles);
@@ -334,11 +164,11 @@ void createProfile(const QString &profileName, const QString &toolchainType,
toolchainTypes = canonicalToolchain(toolchainType);
if (toolchainTypes.contains(QLatin1String("msvc")))
- createMsvcProfile(profileName, compiler.absoluteFilePath(), settings);
+ createMsvcProfile(compiler, settings, profileName);
else if (toolchainTypes.contains(QLatin1String("clang-cl")))
- createClangClProfile(profileName, compiler.absoluteFilePath(), settings);
+ createClangClProfile(compiler, settings, profileName);
else if (toolchainTypes.contains(QLatin1String("gcc")))
- createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
+ createGccProfile(compiler, settings, toolchainTypes, profileName);
else if (toolchainTypes.contains(QLatin1String("iar")))
createIarProfile(compiler, settings, profileName);
else if (toolchainTypes.contains(QLatin1String("keil")))
@@ -348,3 +178,126 @@ void createProfile(const QString &profileName, const QString &toolchainType,
else
throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
+
+int extractVersion(const QByteArray &macroDump, const QByteArray &keyToken)
+{
+ const int startIndex = macroDump.indexOf(keyToken);
+ if (startIndex == -1)
+ return -1;
+ const int endIndex = macroDump.indexOf('\n', startIndex);
+ if (endIndex == -1)
+ return -1;
+ const auto keyLength = keyToken.length();
+ const int version = macroDump.mid(startIndex + keyLength,
+ endIndex - startIndex - keyLength)
+ .toInt();
+ return version;
+}
+
+static QString resolveSymlinks(const QString &filePath)
+{
+ QFileInfo fi(filePath);
+ int links = 16;
+ while (links-- && fi.isSymLink())
+ fi.setFile(fi.dir(), fi.symLinkTarget());
+ if (links <= 0)
+ return {};
+ return fi.filePath();
+}
+
+// Copied from qfilesystemengine_win.cpp.
+#ifdef Q_OS_WIN
+
+// File ID for Windows up to version 7.
+static inline QByteArray fileIdWin7(HANDLE handle)
+{
+ BY_HANDLE_FILE_INFORMATION info;
+ if (GetFileInformationByHandle(handle, &info)) {
+ char buffer[sizeof "01234567:0123456701234567\0"];
+ qsnprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx",
+ info.dwVolumeSerialNumber,
+ info.nFileIndexHigh,
+ info.nFileIndexLow);
+ return QByteArray(buffer);
+ }
+ return {};
+}
+
+// File ID for Windows starting from version 8.
+static QByteArray fileIdWin8(HANDLE handle)
+{
+ QByteArray result;
+ FILE_ID_INFO infoEx = {};
+ if (::GetFileInformationByHandleEx(
+ handle,
+ static_cast<FILE_INFO_BY_HANDLE_CLASS>(18), // FileIdInfo in Windows 8
+ &infoEx, sizeof(FILE_ID_INFO))) {
+ result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
+ result += ':';
+ // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one.
+ result += QByteArray(reinterpret_cast<const char *>(&infoEx.FileId),
+ int(sizeof(infoEx.FileId))).toHex();
+ }
+ return result;
+}
+
+static QByteArray fileIdWin(HANDLE fHandle)
+{
+ return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8
+ ? fileIdWin8(HANDLE(fHandle))
+ : fileIdWin7(HANDLE(fHandle));
+}
+
+static QByteArray fileId(const QString &filePath)
+{
+ QByteArray result;
+ const HANDLE handle = ::CreateFile(
+ reinterpret_cast<const wchar_t*>(filePath.utf16()), 0,
+ FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ if (handle != INVALID_HANDLE_VALUE) {
+ result = fileIdWin(handle);
+ ::CloseHandle(handle);
+ }
+ return result;
+}
+
+static qint64 fileSize(const QString &filePath)
+{
+ return QFileInfo(filePath).size();
+}
+
+#else
+
+static QByteArray fileId(const QString &filePath)
+{
+ QByteArray result;
+ if (Q_UNLIKELY(filePath.isEmpty()))
+ return {};
+ QT_STATBUF statResult = {};
+ if (QT_STAT(filePath.toLocal8Bit().constData(), &statResult))
+ return {};
+ result = QByteArray::number(quint64(statResult.st_dev), 16);
+ result += ':';
+ result += QByteArray::number(quint64(statResult.st_ino));
+ return result;
+}
+
+#endif // Q_OS_WIN
+
+bool isSameExecutable(const QString &filePath1, const QString &filePath2)
+{
+ if (filePath1 == filePath2)
+ return true;
+ if (resolveSymlinks(filePath1) == resolveSymlinks(filePath2))
+ return true;
+ if (fileId(filePath1) == fileId(filePath2))
+ return true;
+
+#ifdef Q_OS_WIN
+ if (fileSize(filePath1) == fileSize(filePath2))
+ return true;
+#endif
+
+ return false;
+}
diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h
index 510747ef7..235d7a899 100644
--- a/src/app/qbs-setup-toolchains/probe.h
+++ b/src/app/qbs-setup-toolchains/probe.h
@@ -36,10 +36,15 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QBS_PROBE_H
-#define QBS_PROBE_H
-#include <QtCore/qglobal.h>
+#ifndef QBS_SETUPTOOLCHAINS_PROBE_H
+#define QBS_SETUPTOOLCHAINS_PROBE_H
+
+#include <tools/version.h>
+
+#include <QtCore/qfileinfo.h>
+
+#include <tuple> // for std::tie
QT_BEGIN_NAMESPACE
class QString;
@@ -48,11 +53,32 @@ QT_END_NAMESPACE
namespace qbs { class Settings; }
+QStringList systemSearchPaths();
+
QString findExecutable(const QString &fileName);
+QStringList toolchainTypeFromCompilerName(const QString &compilerName);
+
void createProfile(const QString &profileName, const QString &toolchainType,
const QString &compilerFilePath, qbs::Settings *settings);
void probe(qbs::Settings *settings);
+struct ToolchainInstallInfo
+{
+ QFileInfo compilerPath;
+ qbs::Version compilerVersion;
+};
+
+inline bool operator<(const ToolchainInstallInfo &lhs, const ToolchainInstallInfo &rhs)
+{
+ const auto lp = lhs.compilerPath.absoluteFilePath();
+ const auto rp = rhs.compilerPath.absoluteFilePath();
+ return std::tie(lp, lhs.compilerVersion) < std::tie(rp, rhs.compilerVersion);
+}
+
+int extractVersion(const QByteArray &macroDump, const QByteArray &keyToken);
+
+bool isSameExecutable(const QString &exe1, const QString &exe2);
+
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
index e83a9c716..6581bec63 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
@@ -5,6 +5,7 @@ TARGET = qbs-setup-toolchains
HEADERS += \
clangclprobe.h \
commandlineparser.h \
+ gccprobe.h \
iarewprobe.h \
keilprobe.h \
msvcprobe.h \
@@ -15,6 +16,7 @@ HEADERS += \
SOURCES += \
clangclprobe.cpp \
commandlineparser.cpp \
+ gccprobe.cpp \
iarewprobe.cpp \
keilprobe.cpp \
main.cpp \
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
index fd3043a28..554891fc4 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
@@ -8,6 +8,8 @@ QbsApp {
"clangclprobe.h",
"commandlineparser.cpp",
"commandlineparser.h",
+ "gccprobe.cpp",
+ "gccprobe.h",
"iarewprobe.cpp",
"iarewprobe.h",
"keilprobe.cpp",
diff --git a/src/app/qbs-setup-toolchains/sdccprobe.cpp b/src/app/qbs-setup-toolchains/sdccprobe.cpp
index 87c616ff0..eccd3ccae 100644
--- a/src/app/qbs-setup-toolchains/sdccprobe.cpp
+++ b/src/app/qbs-setup-toolchains/sdccprobe.cpp
@@ -47,9 +47,9 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
+#include <QtCore/qtemporaryfile.h>
using namespace qbs;
using Internal::Tr;
@@ -60,37 +60,119 @@ static QStringList knownSdccCompilerNames()
return {QStringLiteral("sdcc")};
}
-static QString guessSdccArchitecture(const QFileInfo &compiler)
+static QByteArray dumpSdccMacros(const QFileInfo &compiler,
+ const QString &targetFlag = QString())
{
- const auto baseName = compiler.baseName();
- if (baseName == QLatin1String("sdcc"))
- return QStringLiteral("mcs51");
- return {};
+ QTemporaryFile fakeIn(QStringLiteral("XXXXXX.c"));
+ if (!fakeIn.open()) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return {};
+ }
+ fakeIn.close();
+
+ const QStringList args = {QStringLiteral("-dM"),
+ QStringLiteral("-E"),
+ targetFlag,
+ fakeIn.fileName()};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+ const auto es = p.exitStatus();
+ if (es != QProcess::NormalExit) {
+ const QByteArray out = p.readAll();
+ qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
+ .arg(QString::fromUtf8(out));
+ return {};
+ }
+
+ return p.readAllStandardOutput();
+}
+
+static QString dumpSdccArchitecture(const QFileInfo &compiler,
+ const QString &arch)
+{
+ const auto targetFlag = QStringLiteral("-m%1").arg(arch);
+ const auto token = QStringLiteral("__SDCC_%1").arg(arch);
+ const auto macros = dumpSdccMacros(compiler, targetFlag);
+ return macros.contains(token.toLatin1()) ? arch : QString();
}
-static Profile createSdccProfileHelper(const QFileInfo &compiler, Settings *settings,
- QString profileName = QString())
+static std::vector<Profile> createSdccProfileHelper(
+ const ToolchainInstallInfo &info,
+ Settings *settings,
+ const QString &profileName = QString())
{
- const QString architecture = guessSdccArchitecture(compiler);
+ const QFileInfo compiler = info.compilerPath;
- // In case the profile is auto-detected.
- if (profileName.isEmpty())
- profileName = QLatin1String("sdcc-") + architecture;
+ std::vector<Profile> profiles;
- Profile profile(profileName, settings);
- profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
- profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("sdcc"));
- if (!architecture.isEmpty())
- profile.setValue(QStringLiteral("qbs.architecture"), architecture);
+ const char *knownArchs[] = {"mcs51", "stm8"};
+ for (const auto &knownArch : knownArchs) {
+ const auto actualArch = dumpSdccArchitecture(
+ compiler, QString::fromLatin1(knownArch));
+ // Don't create a profile in case the compiler does
+ // not support the proposed architecture.
+ if (actualArch != QString::fromLatin1(knownArch))
+ continue;
+
+ QString fullProfileName = profileName;
+ if (fullProfileName.isEmpty()) {
+ // Create a full profile name in case we is
+ // in auto-detecting mode.
+ if (!info.compilerVersion.isValid()) {
+ fullProfileName = QStringLiteral("sdcc-unknown-%1")
+ .arg(actualArch);
+ } else {
+ const QString version = info.compilerVersion.toString(
+ QLatin1Char('_'), QLatin1Char('_'));
+ fullProfileName = QStringLiteral("sdcc-%1-%2").arg(
+ version, actualArch);
+ }
+ } else {
+ // Append the detected actual architecture name
+ // to the proposed profile name.
+ fullProfileName = QStringLiteral("%1-%2").arg(
+ fullProfileName, actualArch);
+ }
+
+ Profile profile(fullProfileName, settings);
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"),
+ compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchainType"),
+ QStringLiteral("sdcc"));
+ if (!actualArch.isEmpty())
+ profile.setValue(QStringLiteral("qbs.architecture"), actualArch);
+
+ qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(
+ profile.name(), compiler.absoluteFilePath());
+ }
+
+ return profiles;
+}
+
+static Version dumpSdccCompilerVersion(const QFileInfo &compiler)
+{
+ const QByteArray dump = dumpSdccMacros(compiler);
+ if (dump.isEmpty())
+ return Version{};
+
+ const int major = extractVersion(dump, "__SDCC_VERSION_MAJOR ");
+ const int minor = extractVersion(dump, "__SDCC_VERSION_MINOR ");
+ const int patch = extractVersion(dump, "__SDCC_VERSION_PATCH ");
+ if (major < 0 || minor < 0 || patch < 0) {
+ qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' token was found "
+ "in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
- qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(
- profile.name(), compiler.absoluteFilePath());
- return profile;
+ return Version{major, minor, patch};
}
-static std::vector<SdccInstallInfo> installedSdccsFromPath()
+static std::vector<ToolchainInstallInfo> installedSdccsFromPath()
{
- std::vector<SdccInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
const auto compilerNames = knownSdccCompilerNames();
for (const QString &compilerName : compilerNames) {
const QFileInfo sdccPath(
@@ -98,14 +180,16 @@ static std::vector<SdccInstallInfo> installedSdccsFromPath()
HostOsInfo::appendExecutableSuffix(compilerName)));
if (!sdccPath.exists())
continue;
- infos.push_back({sdccPath.absoluteFilePath(), {}});
+ const Version version = dumpSdccCompilerVersion(sdccPath);
+ infos.push_back({sdccPath, version});
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
-static std::vector<SdccInstallInfo> installedSdccsFromRegistry()
+static std::vector<ToolchainInstallInfo> installedSdccsFromRegistry()
{
- std::vector<SdccInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
if (HostOsInfo::isWindowsHost()) {
// Tries to detect the candidate from the 32-bit
@@ -146,14 +230,16 @@ static std::vector<SdccInstallInfo> installedSdccsFromRegistry()
continue;
const auto infosEnd = infos.cend();
const auto infosIt = std::find_if(infos.cbegin(), infosEnd,
- [candidate](const SdccInstallInfo &info) {
- return candidate == info;
+ [candidate](const ToolchainInstallInfo &info) {
+ return candidate == SdccInstallInfo{
+ info.compilerPath.filePath(), info.compilerVersion.toString()};
});
if (infosIt == infosEnd)
- infos.push_back(candidate);
+ infos.push_back({candidate.compilerPath, Version::fromString(candidate.version)});
}
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
@@ -168,20 +254,28 @@ bool isSdccCompiler(const QString &compilerName)
void createSdccProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
- createSdccProfileHelper(compiler, settings, profileName);
+ const ToolchainInstallInfo info = {compiler, Version{}};
+ createSdccProfileHelper(info, settings, profileName);
}
void sdccProbe(Settings *settings, QList<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect SDCC toolchains...");
- std::vector<SdccInstallInfo> allInfos = installedSdccsFromRegistry();
- const std::vector<SdccInstallInfo> pathInfos = installedSdccsFromPath();
- allInfos.insert(std::end(allInfos), std::begin(pathInfos), std::end(pathInfos));
+ // Make sure that a returned infos are sorted before using the std::set_union!
+ const std::vector<ToolchainInstallInfo> regInfos = installedSdccsFromRegistry();
+ const std::vector<ToolchainInstallInfo> pathInfos = installedSdccsFromPath();
+ std::vector<ToolchainInstallInfo> allInfos;
+ allInfos.reserve(regInfos.size() + pathInfos.size());
+ std::set_union(regInfos.cbegin(), regInfos.cend(),
+ pathInfos.cbegin(), pathInfos.cend(),
+ std::back_inserter(allInfos));
- for (const SdccInstallInfo &info : allInfos) {
- const auto profile = createSdccProfileHelper(info.compilerPath, settings);
- profiles.push_back(profile);
+ for (const ToolchainInstallInfo &info : allInfos) {
+ const auto newProfiles = createSdccProfileHelper(info, settings);
+ profiles.reserve(profiles.size() + int(newProfiles.size()));
+ std::copy(newProfiles.cbegin(), newProfiles.cend(),
+ std::back_inserter(profiles));
}
if (allInfos.empty())
diff --git a/src/app/qbs-setup-toolchains/sdccprobe.h b/src/app/qbs-setup-toolchains/sdccprobe.h
index 55062ff19..aa2c613f3 100644
--- a/src/app/qbs-setup-toolchains/sdccprobe.h
+++ b/src/app/qbs-setup-toolchains/sdccprobe.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef SDCCPROBE_H
-#define SDCCPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_SDCCPROBE_H
+#define QBS_SETUPTOOLCHAINS_SDCCPROBE_H
#include <QtCore/qlist.h>
@@ -72,4 +72,4 @@ void createSdccProfile(const QFileInfo &compiler, qbs::Settings *settings,
void sdccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // SDCCPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.h b/src/app/qbs-setup-toolchains/xcodeprobe.h
index 11fc2bffa..ab501036b 100644
--- a/src/app/qbs-setup-toolchains/xcodeprobe.h
+++ b/src/app/qbs-setup-toolchains/xcodeprobe.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef XCODEPROBE_H
-#define XCODEPROBE_H
+#ifndef QBS_SETUPTOOLCHAINS_XCODEPROBE_H
+#define QBS_SETUPTOOLCHAINS_XCODEPROBE_H
#include <QtCore/qlist.h>
@@ -49,4 +49,4 @@ class Settings;
void xcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
-#endif // XCODEPROBE_H
+#endif // Header guard
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 95c3c10bc..8be06f3af 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -40,6 +40,7 @@
#include "application.h"
#include "consoleprogressobserver.h"
+#include "session.h"
#include "status.h"
#include "parser/commandlineoption.h"
#include "../shared/logging/consolelogger.h"
@@ -129,6 +130,10 @@ void CommandLineFrontend::start()
throw ErrorInfo(error);
}
break;
+ case SessionCommandType: {
+ startSession();
+ return;
+ }
default:
break;
}
@@ -418,6 +423,7 @@ void CommandLineFrontend::handleProjectsResolved()
break;
case HelpCommandType:
case VersionCommandType:
+ case SessionCommandType:
Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible.");
}
}
diff --git a/src/app/qbs/parser/commandlineparser.cpp b/src/app/qbs/parser/commandlineparser.cpp
index 3c25c51e2..052f6b92f 100644
--- a/src/app/qbs/parser/commandlineparser.cpp
+++ b/src/app/qbs/parser/commandlineparser.cpp
@@ -386,6 +386,7 @@ QList<Command *> CommandLineParser::CommandLineParserPrivate::allCommands() cons
commandPool.getCommand(DumpNodesTreeCommandType),
commandPool.getCommand(ListProductsCommandType),
commandPool.getCommand(VersionCommandType),
+ commandPool.getCommand(SessionCommandType),
commandPool.getCommand(HelpCommandType)};
}
diff --git a/src/app/qbs/parser/commandpool.cpp b/src/app/qbs/parser/commandpool.cpp
index a49608c56..1362a563c 100644
--- a/src/app/qbs/parser/commandpool.cpp
+++ b/src/app/qbs/parser/commandpool.cpp
@@ -95,6 +95,9 @@ qbs::Command *CommandPool::getCommand(CommandType type) const
case VersionCommandType:
command = new VersionCommand(m_optionPool);
break;
+ case SessionCommandType:
+ command = new SessionCommand(m_optionPool);
+ break;
}
}
return command;
diff --git a/src/app/qbs/parser/commandtype.h b/src/app/qbs/parser/commandtype.h
index a8c618933..7d70356e7 100644
--- a/src/app/qbs/parser/commandtype.h
+++ b/src/app/qbs/parser/commandtype.h
@@ -45,7 +45,7 @@ enum CommandType {
ResolveCommandType, BuildCommandType, CleanCommandType, RunCommandType, ShellCommandType,
StatusCommandType, UpdateTimestampsCommandType, DumpNodesTreeCommandType,
InstallCommandType, HelpCommandType, GenerateCommandType, ListProductsCommandType,
- VersionCommandType,
+ VersionCommandType, SessionCommandType,
};
} // namespace qbs
diff --git a/src/app/qbs/parser/parsercommand.cpp b/src/app/qbs/parser/parsercommand.cpp
index 9485b0878..c7185a725 100644
--- a/src/app/qbs/parser/parsercommand.cpp
+++ b/src/app/qbs/parser/parsercommand.cpp
@@ -593,4 +593,27 @@ void VersionCommand::parseNext(QStringList &input)
throwError(Tr::tr("This command takes no arguments."));
}
+QString SessionCommand::shortDescription() const
+{
+ return Tr::tr("Starts a session for an IDE.");
+}
+
+QString SessionCommand::longDescription() const
+{
+ QString description = Tr::tr("qbs %1\n").arg(representation());
+ return description += Tr::tr("Communicates on stdin and stdout via a JSON-based API.\n"
+ "Intended for use with other tools, such as IDEs.\n");
+}
+
+QString SessionCommand::representation() const
+{
+ return QLatin1String("session");
+}
+
+void SessionCommand::parseNext(QStringList &input)
+{
+ QBS_CHECK(!input.empty());
+ throwError(Tr::tr("This command takes no arguments."));
+}
+
} // namespace qbs
diff --git a/src/app/qbs/parser/parsercommand.h b/src/app/qbs/parser/parsercommand.h
index 649563ba1..8998d38e6 100644
--- a/src/app/qbs/parser/parsercommand.h
+++ b/src/app/qbs/parser/parsercommand.h
@@ -261,6 +261,20 @@ private:
void parseNext(QStringList &input) override;
};
+class SessionCommand : public Command
+{
+public:
+ SessionCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {}
+
+private:
+ CommandType type() const override { return SessionCommandType; }
+ QString shortDescription() const override;
+ QString longDescription() const override;
+ QString representation() const override;
+ QList<CommandLineOption::Type> supportedOptions() const override { return {}; }
+ void parseNext(QStringList &input) override;
+};
+
} // namespace qbs
#endif // QBS_PARSER_COMMAND_H
diff --git a/src/app/qbs/qbs.pro b/src/app/qbs/qbs.pro
index ac9d6f0ca..e9f0061c6 100644
--- a/src/app/qbs/qbs.pro
+++ b/src/app/qbs/qbs.pro
@@ -6,6 +6,10 @@ TARGET = qbs
SOURCES += main.cpp \
ctrlchandler.cpp \
application.cpp \
+ session.cpp \
+ sessionpacket.cpp \
+ sessionpacketreader.cpp \
+ stdinreader.cpp \
status.cpp \
consoleprogressobserver.cpp \
commandlinefrontend.cpp \
@@ -14,6 +18,10 @@ SOURCES += main.cpp \
HEADERS += \
ctrlchandler.h \
application.h \
+ session.h \
+ sessionpacket.h \
+ sessionpacketreader.h \
+ stdinreader.h \
status.h \
consoleprogressobserver.h \
commandlinefrontend.h \
diff --git a/src/app/qbs/qbs.qbs b/src/app/qbs/qbs.qbs
index f22fe5de5..91357445e 100644
--- a/src/app/qbs/qbs.qbs
+++ b/src/app/qbs/qbs.qbs
@@ -23,8 +23,16 @@ QbsApp {
"main.cpp",
"qbstool.cpp",
"qbstool.h",
+ "session.cpp",
+ "session.h",
+ "sessionpacket.cpp",
+ "sessionpacket.h",
+ "sessionpacketreader.cpp",
+ "sessionpacketreader.h",
"status.cpp",
"status.h",
+ "stdinreader.cpp",
+ "stdinreader.h",
]
Group {
name: "parser"
diff --git a/src/app/qbs/session.cpp b/src/app/qbs/session.cpp
new file mode 100644
index 000000000..30e71dfd5
--- /dev/null
+++ b/src/app/qbs/session.cpp
@@ -0,0 +1,766 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "session.h"
+
+#include "sessionpacket.h"
+#include "sessionpacketreader.h"
+
+#include <api/jobs.h>
+#include <api/project.h>
+#include <api/projectdata.h>
+#include <api/runenvironment.h>
+#include <logging/ilogsink.h>
+#include <tools/buildoptions.h>
+#include <tools/cleanoptions.h>
+#include <tools/error.h>
+#include <tools/installoptions.h>
+#include <tools/jsonhelper.h>
+#include <tools/preferences.h>
+#include <tools/processresult.h>
+#include <tools/qbsassert.h>
+#include <tools/settings.h>
+#include <tools/setupprojectparameters.h>
+#include <tools/stringconstants.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qprocess.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+#ifdef Q_OS_WIN32
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+namespace qbs {
+namespace Internal {
+
+class SessionLogSink : public QObject, public ILogSink
+{
+ Q_OBJECT
+signals:
+ void newMessage(const QJsonObject &msg);
+
+private:
+ void doPrintMessage(LoggerLevel, const QString &message, const QString &) override
+ {
+ QJsonObject msg;
+ msg.insert(StringConstants::type(), QLatin1String("log-data"));
+ msg.insert(StringConstants::messageKey(), message);
+ emit newMessage(msg);
+ }
+
+ void doPrintWarning(const ErrorInfo &warning) override
+ {
+ QJsonObject msg;
+ static const QString warningString(QLatin1String("warning"));
+ msg.insert(StringConstants::type(), warningString);
+ msg.insert(warningString, warning.toJson());
+ emit newMessage(msg);
+ }
+};
+
+class Session : public QObject
+{
+ Q_OBJECT
+public:
+ Session();
+
+private:
+ enum class ProjectDataMode { Never, Always, OnlyIfChanged };
+ ProjectDataMode dataModeFromRequest(const QJsonObject &request);
+ QStringList modulePropertiesFromRequest(const QJsonObject &request);
+ void insertProjectDataIfNecessary(
+ QJsonObject &reply,
+ ProjectDataMode dataMode,
+ const ProjectData &oldProjectData,
+ bool includeTopLevelData
+ );
+ void setLogLevelFromRequest(const QJsonObject &request);
+ bool checkNormalRequestPrerequisites(const char *replyType);
+
+ void sendPacket(const QJsonObject &message);
+ void setupProject(const QJsonObject &request);
+ void buildProject(const QJsonObject &request);
+ void cleanProject(const QJsonObject &request);
+ void installProject(const QJsonObject &request);
+ void addFiles(const QJsonObject &request);
+ void removeFiles(const QJsonObject &request);
+ void getRunEnvironment(const QJsonObject &request);
+ void getGeneratedFilesForSources(const QJsonObject &request);
+ void releaseProject();
+ void cancelCurrentJob();
+ void quitSession();
+
+ void sendErrorReply(const char *replyType, const QString &message);
+ void sendErrorReply(const char *replyType, const ErrorInfo &error);
+ void insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error);
+ void connectProgressSignals(AbstractJob *job);
+ QList<ProductData> getProductsByName(const QStringList &productNames) const;
+ ProductData getProductByName(const QString &productName) const;
+
+ struct ProductSelection {
+ ProductSelection(Project::ProductSelection s) : selection(s) {}
+ ProductSelection(const QList<ProductData> &p) : products(p) {}
+
+ Project::ProductSelection selection = Project::ProductSelectionDefaultOnly;
+ QList<ProductData> products;
+ };
+ ProductSelection getProductSelection(const QJsonObject &request);
+
+ struct FileUpdateData {
+ QJsonObject createErrorReply(const char *type, const QString &mainMessage) const;
+
+ ProductData product;
+ GroupData group;
+ QStringList filePaths;
+ ErrorInfo error;
+ };
+ FileUpdateData prepareFileUpdate(const QJsonObject &request);
+
+ SessionPacketReader m_packetReader;
+ Project m_project;
+ ProjectData m_projectData;
+ SessionLogSink m_logSink;
+ std::unique_ptr<Settings> m_settings;
+ QJsonObject m_resolveRequest;
+ QStringList m_moduleProperties;
+ AbstractJob *m_currentJob = nullptr;
+};
+
+void startSession()
+{
+ const auto session = new Session;
+ QObject::connect(qApp, &QCoreApplication::aboutToQuit, session, [session] { delete session; });
+}
+
+Session::Session()
+{
+#ifdef Q_OS_WIN32
+ // Make sure the line feed character appears as itself.
+ if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
+ std::cerr << "Failed to set stdout to binary mode: " << std::strerror(errno) << std::endl;
+ qApp->exit(EXIT_FAILURE);
+ }
+#endif
+ sendPacket(SessionPacket::helloMessage());
+ connect(&m_logSink, &SessionLogSink::newMessage, this, &Session::sendPacket);
+ connect(&m_packetReader, &SessionPacketReader::errorOccurred,
+ this, [](const QString &msg) {
+ std::cerr << qPrintable(tr("Error: %1").arg(msg));
+ qApp->exit(EXIT_FAILURE);
+ });
+ connect(&m_packetReader, &SessionPacketReader::packetReceived, this, [this](const QJsonObject &packet) {
+ // qDebug() << "got packet:" << packet; // Uncomment for debugging.
+ const QString type = packet.value(StringConstants::type()).toString();
+ if (type == QLatin1String("resolve-project"))
+ setupProject(packet);
+ else if (type == QLatin1String("build-project"))
+ buildProject(packet);
+ else if (type == QLatin1String("clean-project"))
+ cleanProject(packet);
+ else if (type == QLatin1String("install-project"))
+ installProject(packet);
+ else if (type == QLatin1String("add-files"))
+ addFiles(packet);
+ else if (type == QLatin1String("remove-files"))
+ removeFiles(packet);
+ else if (type == QLatin1String("get-run-environment"))
+ getRunEnvironment(packet);
+ else if (type == QLatin1String("get-generated-files-for-sources"))
+ getGeneratedFilesForSources(packet);
+ else if (type == QLatin1String("release-project"))
+ releaseProject();
+ else if (type == QLatin1String("quit"))
+ quitSession();
+ else if (type == QLatin1String("cancel-job"))
+ cancelCurrentJob();
+ else
+ sendErrorReply("protocol-error", tr("Unknown request type '%1'.").arg(type));
+ });
+ m_packetReader.start();
+}
+
+Session::ProjectDataMode Session::dataModeFromRequest(const QJsonObject &request)
+{
+ const QString modeString = request.value(QLatin1String("data-mode")).toString();
+ if (modeString == QLatin1String("only-if-changed"))
+ return ProjectDataMode::OnlyIfChanged;
+ if (modeString == QLatin1String("always"))
+ return ProjectDataMode::Always;
+ return ProjectDataMode::Never;
+}
+
+void Session::sendPacket(const QJsonObject &message)
+{
+ std::cout << SessionPacket::createPacket(message).constData() << std::flush;
+}
+
+void Session::setupProject(const QJsonObject &request)
+{
+ if (m_currentJob) {
+ if (qobject_cast<SetupProjectJob *>(m_currentJob)
+ && m_currentJob->state() == AbstractJob::StateCanceling) {
+ m_resolveRequest = std::move(request);
+ return;
+ }
+ sendErrorReply("project-resolved",
+ tr("Cannot start resolving while another job is still running."));
+ return;
+ }
+ m_moduleProperties = modulePropertiesFromRequest(request);
+ auto params = SetupProjectParameters::fromJson(request);
+ const ProjectDataMode dataMode = dataModeFromRequest(request);
+ m_settings.reset(new Settings(params.settingsDirectory()));
+ const Preferences prefs(m_settings.get());
+ const QString appDir = QDir::cleanPath(QCoreApplication::applicationDirPath());
+ params.setSearchPaths(prefs.searchPaths(appDir + QLatin1String(
+ "/" QBS_RELATIVE_SEARCH_PATH)));
+ params.setPluginPaths(prefs.pluginPaths(appDir + QLatin1String(
+ "/" QBS_RELATIVE_PLUGINS_PATH)));
+ params.setLibexecPath(appDir + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH));
+ params.setOverrideBuildGraphData(true);
+ setLogLevelFromRequest(request);
+ SetupProjectJob * const setupJob = m_project.setupProject(params, &m_logSink, this);
+ m_currentJob = setupJob;
+ connectProgressSignals(setupJob);
+ connect(setupJob, &AbstractJob::finished, this,
+ [this, setupJob, dataMode](bool success) {
+ if (!m_resolveRequest.isEmpty()) { // Canceled job was superseded.
+ const QJsonObject newRequest = std::move(m_resolveRequest);
+ m_resolveRequest = QJsonObject();
+ m_currentJob->deleteLater();
+ m_currentJob = nullptr;
+ setupProject(newRequest);
+ return;
+ }
+ const ProjectData oldProjectData = m_projectData;
+ m_project = setupJob->project();
+ m_projectData = m_project.projectData();
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("project-resolved"));
+ if (success)
+ insertProjectDataIfNecessary(reply, dataMode, oldProjectData, true);
+ else
+ insertErrorInfoIfNecessary(reply, setupJob->error());
+ sendPacket(reply);
+ m_currentJob->deleteLater();
+ m_currentJob = nullptr;
+ });
+}
+
+void Session::buildProject(const QJsonObject &request)
+{
+ if (!checkNormalRequestPrerequisites("build-done"))
+ return;
+ const ProductSelection productSelection = getProductSelection(request);
+ setLogLevelFromRequest(request);
+ auto options = BuildOptions::fromJson(request);
+ options.setSettingsDirectory(m_settings->baseDirectory());
+ BuildJob * const buildJob = productSelection.products.empty()
+ ? m_project.buildAllProducts(options, productSelection.selection, this)
+ : m_project.buildSomeProducts(productSelection.products, options, this);
+ m_currentJob = buildJob;
+ m_moduleProperties = modulePropertiesFromRequest(request);
+ const ProjectDataMode dataMode = dataModeFromRequest(request);
+ connectProgressSignals(buildJob);
+ connect(buildJob, &BuildJob::reportCommandDescription, this,
+ [this](const QString &highlight, const QString &message) {
+ QJsonObject descData;
+ descData.insert(StringConstants::type(), QLatin1String("command-description"));
+ descData.insert(QLatin1String("highlight"), highlight);
+ descData.insert(StringConstants::messageKey(), message);
+ sendPacket(descData);
+ });
+ connect(buildJob, &BuildJob::reportProcessResult, this, [this](const ProcessResult &result) {
+ if (result.success() && result.stdOut().isEmpty() && result.stdErr().isEmpty())
+ return;
+ QJsonObject resultData = result.toJson();
+ resultData.insert(StringConstants::type(), QLatin1String("process-result"));
+ sendPacket(resultData);
+ });
+ connect(buildJob, &BuildJob::finished, this,
+ [this, dataMode](bool success) {
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("project-built"));
+ const ProjectData oldProjectData = m_projectData;
+ m_projectData = m_project.projectData();
+ if (success)
+ insertProjectDataIfNecessary(reply, dataMode, oldProjectData, false);
+ else
+ insertErrorInfoIfNecessary(reply, m_currentJob->error());
+ sendPacket(reply);
+ m_currentJob->deleteLater();
+ m_currentJob = nullptr;
+ });
+}
+
+void Session::cleanProject(const QJsonObject &request)
+{
+ if (!checkNormalRequestPrerequisites("project-cleaned"))
+ return;
+ setLogLevelFromRequest(request);
+ const ProductSelection productSelection = getProductSelection(request);
+ const auto options = CleanOptions::fromJson(request);
+ m_currentJob = productSelection.products.empty()
+ ? m_project.cleanAllProducts(options, this)
+ : m_project.cleanSomeProducts(productSelection.products, options, this);
+ connectProgressSignals(m_currentJob);
+ connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) {
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("project-cleaned"));
+ if (!success)
+ insertErrorInfoIfNecessary(reply, m_currentJob->error());
+ sendPacket(reply);
+ m_currentJob->deleteLater();
+ m_currentJob = nullptr;
+ });
+}
+
+void Session::installProject(const QJsonObject &request)
+{
+ if (!checkNormalRequestPrerequisites("install-done"))
+ return;
+ setLogLevelFromRequest(request);
+ const ProductSelection productSelection = getProductSelection(request);
+ const auto options = InstallOptions::fromJson(request);
+ m_currentJob = productSelection.products.empty()
+ ? m_project.installAllProducts(options, productSelection.selection, this)
+ : m_project.installSomeProducts(productSelection.products, options, this);
+ connectProgressSignals(m_currentJob);
+ connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) {
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("install-done"));
+ if (!success)
+ insertErrorInfoIfNecessary(reply, m_currentJob->error());
+ sendPacket(reply);
+ m_currentJob->deleteLater();
+ m_currentJob = nullptr;
+ });
+}
+
+void Session::addFiles(const QJsonObject &request)
+{
+ const FileUpdateData data = prepareFileUpdate(request);
+ if (data.error.hasError()) {
+ sendPacket(data.createErrorReply("files-added", tr("Failed to add files to project: %1")
+ .arg(data.error.toString())));
+ return;
+ }
+ ErrorInfo error;
+ QStringList failedFiles;
+#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
+ for (const QString &filePath : data.filePaths) {
+ const ErrorInfo e = m_project.addFiles(data.product, data.group, {filePath});
+ if (e.hasError()) {
+ for (const ErrorItem &ei : e.items())
+ error.append(ei);
+ failedFiles.push_back(filePath);
+ }
+ }
+#endif
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("files-added"));
+ insertErrorInfoIfNecessary(reply, error);
+
+ if (failedFiles.size() != data.filePaths.size()) {
+ // Note that Project::addFiles() directly changes the existing project data object, so
+ // there's no need to retrieve it from m_project.
+ insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false);
+ }
+
+ if (!failedFiles.isEmpty())
+ reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles));
+ sendPacket(reply);
+}
+
+void Session::removeFiles(const QJsonObject &request)
+{
+ const FileUpdateData data = prepareFileUpdate(request);
+ if (data.error.hasError()) {
+ sendPacket(data.createErrorReply("files-removed",
+ tr("Failed to remove files from project: %1")
+ .arg(data.error.toString())));
+ return;
+ }
+ ErrorInfo error;
+ QStringList failedFiles;
+#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
+ for (const QString &filePath : data.filePaths) {
+ const ErrorInfo e = m_project.removeFiles(data.product, data.group, {filePath});
+ if (e.hasError()) {
+ for (const ErrorItem &ei : e.items())
+ error.append(ei);
+ failedFiles.push_back(filePath);
+ }
+ }
+#endif
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String("files-removed"));
+ insertErrorInfoIfNecessary(reply, error);
+ if (failedFiles.size() != data.filePaths.size())
+ insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false);
+ if (!failedFiles.isEmpty())
+ reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles));
+ sendPacket(reply);
+}
+
+void Session::connectProgressSignals(AbstractJob *job)
+{
+ static QString maxProgressString(QLatin1String("max-progress"));
+ connect(job, &AbstractJob::taskStarted, this,
+ [this](const QString &description, int maxProgress) {
+ QJsonObject msg;
+ msg.insert(StringConstants::type(), QLatin1String("task-started"));
+ msg.insert(StringConstants::descriptionProperty(), description);
+ msg.insert(maxProgressString, maxProgress);
+ sendPacket(msg);
+ });
+ connect(job, &AbstractJob::totalEffortChanged, this, [this](int maxProgress) {
+ QJsonObject msg;
+ msg.insert(StringConstants::type(), QLatin1String("new-max-progress"));
+ msg.insert(maxProgressString, maxProgress);
+ sendPacket(msg);
+ });
+ connect(job, &AbstractJob::taskProgress, this, [this](int progress) {
+ QJsonObject msg;
+ msg.insert(StringConstants::type(), QLatin1String("task-progress"));
+ msg.insert(QLatin1String("progress"), progress);
+ sendPacket(msg);
+ });
+}
+
+static QList<ProductData> getProductsByNameForProject(const ProjectData &project,
+ QStringList &productNames)
+{
+ QList<ProductData> products;
+ if (productNames.empty())
+ return products;
+ for (const ProductData &p : project.products()) {
+ for (auto it = productNames.begin(); it != productNames.end(); ++it) {
+ if (*it == p.fullDisplayName()) {
+ products << p;
+ productNames.erase(it);
+ if (productNames.empty())
+ return products;
+ break;
+ }
+ }
+ }
+ for (const ProjectData &p : project.subProjects()) {
+ products << getProductsByNameForProject(p, productNames);
+ if (productNames.empty())
+ break;
+ }
+ return products;
+}
+
+QList<ProductData> Session::getProductsByName(const QStringList &productNames) const
+{
+ QStringList remainingNames = productNames;
+ return getProductsByNameForProject(m_projectData, remainingNames);
+}
+
+ProductData Session::getProductByName(const QString &productName) const
+{
+ const QList<ProductData> products = getProductsByName({productName});
+ return products.empty() ? ProductData() : products.first();
+}
+
+void Session::getRunEnvironment(const QJsonObject &request)
+{
+ const char * const replyType = "run-environment";
+ if (!checkNormalRequestPrerequisites(replyType))
+ return;
+ const QString productName = request.value(QLatin1String("product")).toString();
+ const ProductData product = getProductByName(productName);
+ if (!product.isValid()) {
+ sendErrorReply(replyType, tr("No such product '%1'.").arg(productName));
+ return;
+ }
+ const auto inEnv = fromJson<QProcessEnvironment>(
+ request.value(QLatin1String("base-environment")));
+ const QStringList config = fromJson<QStringList>(request.value(QLatin1String("config")));
+ const RunEnvironment runEnv = m_project.getRunEnvironment(product, InstallOptions(), inEnv,
+ config, m_settings.get());
+ ErrorInfo error;
+ const QProcessEnvironment outEnv = runEnv.runEnvironment(&error);
+ if (error.hasError()) {
+ sendErrorReply(replyType, error);
+ return;
+ }
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String(replyType));
+ QJsonObject outEnvObj;
+ const QStringList keys = outEnv.keys();
+ for (const QString &key : keys)
+ outEnvObj.insert(key, outEnv.value(key));
+ reply.insert(QLatin1String("full-environment"), outEnvObj);
+ sendPacket(reply);
+}
+
+void Session::getGeneratedFilesForSources(const QJsonObject &request)
+{
+ const char * const replyType = "generated-files-for-sources";
+ if (!checkNormalRequestPrerequisites(replyType))
+ return;
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String(replyType));
+ const QJsonArray specs = request.value(StringConstants::productsKey()).toArray();
+ QJsonArray resultProducts;
+ for (const QJsonValue &p : specs) {
+ const QJsonObject productObject = p.toObject();
+ const ProductData product = getProductByName(
+ productObject.value(StringConstants::fullDisplayNameKey()).toString());
+ if (!product.isValid())
+ continue;
+ QJsonObject resultProduct;
+ resultProduct.insert(StringConstants::fullDisplayNameKey(), product.fullDisplayName());
+ QJsonArray results;
+ const QJsonArray requests = productObject.value(QLatin1String("requests")).toArray();
+ for (const QJsonValue &r : requests) {
+ const QJsonObject request = r.toObject();
+ const QString filePath = request.value(QLatin1String("source-file")).toString();
+ const QStringList tags = fromJson<QStringList>(request.value(QLatin1String("tags")));
+ const bool recursive = request.value(QLatin1String("recursive")).toBool();
+ const QStringList generatedFiles = m_project.generatedFiles(product, filePath,
+ recursive, tags);
+ if (!generatedFiles.isEmpty()) {
+ QJsonObject result;
+ result.insert(QLatin1String("source-file"), filePath);
+ result.insert(QLatin1String("generated-files"),
+ QJsonArray::fromStringList(generatedFiles));
+ results << result;
+ }
+ }
+ if (!results.isEmpty()) {
+ resultProduct.insert(QLatin1String("results"), results);
+ resultProducts << resultProduct;
+ }
+ }
+ reply.insert(StringConstants::productsKey(), resultProducts);
+ sendPacket(reply);
+}
+
+void Session::releaseProject()
+{
+ const char * const replyType = "project-released";
+ if (!m_project.isValid()) {
+ sendErrorReply(replyType, tr("No open project."));
+ return;
+ }
+ if (m_currentJob) {
+ m_currentJob->disconnect(this);
+ m_currentJob->cancel();
+ m_currentJob = nullptr;
+ }
+ m_project = Project();
+ m_projectData = ProjectData();
+ m_resolveRequest = QJsonObject();
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String(replyType));
+ sendPacket(reply);
+}
+
+void Session::cancelCurrentJob()
+{
+ if (m_currentJob) {
+ if (!m_resolveRequest.isEmpty())
+ m_resolveRequest = QJsonObject();
+ m_currentJob->cancel();
+ }
+}
+
+Session::ProductSelection Session::getProductSelection(const QJsonObject &request)
+{
+ const QJsonValue productSelection = request.value(StringConstants::productsKey());
+ if (productSelection.isArray())
+ return ProductSelection(getProductsByName(fromJson<QStringList>(productSelection)));
+ return ProductSelection(productSelection.toString() == QLatin1String("all")
+ ? Project::ProductSelectionWithNonDefault
+ : Project::ProductSelectionDefaultOnly);
+}
+
+Session::FileUpdateData Session::prepareFileUpdate(const QJsonObject &request)
+{
+ FileUpdateData data;
+ const QString productName = request.value(QLatin1String("product")).toString();
+ data.product = getProductByName(productName);
+ if (data.product.isValid()) {
+ const QString groupName = request.value(QLatin1String("group")).toString();
+ for (const GroupData &g : data.product.groups()) {
+ if (g.name() == groupName) {
+ data.group = g;
+ break;
+ }
+ }
+ if (!data.group.isValid())
+ data.error = tr("Group '%1' not found in product '%2'.").arg(groupName, productName);
+ } else {
+ data.error = tr("Product '%1' not found in project.").arg(productName);
+ }
+ const QJsonArray filesArray = request.value(QLatin1String("files")).toArray();
+ for (const QJsonValue &v : filesArray)
+ data.filePaths << v.toString();
+ if (m_currentJob)
+ data.error = tr("Cannot update the list of source files while a job is running.");
+ if (!m_project.isValid())
+ data.error = tr("No valid project. You need to resolve first.");
+#ifndef QBS_ENABLE_PROJECT_FILE_UPDATES
+ data.error = ErrorInfo(tr("Project file updates are not enabled in this build of qbs."));
+#endif
+ return data;
+}
+
+void Session::insertProjectDataIfNecessary(QJsonObject &reply, ProjectDataMode dataMode,
+ const ProjectData &oldProjectData, bool includeTopLevelData)
+{
+ const bool sendProjectData = dataMode == ProjectDataMode::Always
+ || (dataMode == ProjectDataMode::OnlyIfChanged && m_projectData != oldProjectData);
+ if (!sendProjectData)
+ return;
+ QJsonObject projectData = m_projectData.toJson(m_moduleProperties);
+ if (includeTopLevelData) {
+ QJsonArray buildSystemFiles;
+ for (const QString &f : m_project.buildSystemFiles())
+ buildSystemFiles.push_back(f);
+ projectData.insert(StringConstants::buildDirectoryKey(), m_projectData.buildDirectory());
+ projectData.insert(QLatin1String("build-system-files"), buildSystemFiles);
+ const Project::BuildGraphInfo bgInfo = m_project.getBuildGraphInfo();
+ projectData.insert(QLatin1String("build-graph-file-path"), bgInfo.bgFilePath);
+ projectData.insert(QLatin1String("profile-data"),
+ QJsonObject::fromVariantMap(bgInfo.profileData));
+ projectData.insert(QLatin1String("overridden-properties"),
+ QJsonObject::fromVariantMap(bgInfo.overriddenProperties));
+ }
+ reply.insert(QLatin1String("project-data"), projectData);
+}
+
+void Session::setLogLevelFromRequest(const QJsonObject &request)
+{
+ const QString logLevelString = request.value(QLatin1String("log-level")).toString();
+ if (logLevelString.isEmpty())
+ return;
+ for (const LoggerLevel l : {LoggerError, LoggerWarning, LoggerInfo, LoggerDebug, LoggerTrace}) {
+ if (logLevelString == logLevelName(l)) {
+ m_logSink.setLogLevel(l);
+ return;
+ }
+ }
+}
+
+bool Session::checkNormalRequestPrerequisites(const char *replyType)
+{
+ if (m_currentJob) {
+ sendErrorReply(replyType, tr("Another job is still running."));
+ return false;
+ }
+ if (!m_project.isValid()) {
+ sendErrorReply(replyType, tr("No valid project. You need to resolve first."));
+ return false;
+ }
+ return true;
+}
+
+QStringList Session::modulePropertiesFromRequest(const QJsonObject &request)
+{
+ return fromJson<QStringList>(request.value(StringConstants::modulePropertiesKey()));
+}
+
+void Session::sendErrorReply(const char *replyType, const ErrorInfo &error)
+{
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String(replyType));
+ insertErrorInfoIfNecessary(reply, error);
+ sendPacket(reply);
+}
+
+void Session::sendErrorReply(const char *replyType, const QString &message)
+{
+ sendErrorReply(replyType, ErrorInfo(message));
+}
+
+void Session::insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error)
+{
+ if (error.hasError())
+ reply.insert(QLatin1String("error"), error.toJson());
+}
+
+void Session::quitSession()
+{
+ m_logSink.disconnect(this);
+ m_packetReader.disconnect(this);
+ if (m_currentJob) {
+ m_currentJob->disconnect(this);
+ connect(m_currentJob, &AbstractJob::finished, qApp, QCoreApplication::quit);
+ m_currentJob->cancel();
+ } else {
+ qApp->quit();
+ }
+}
+
+QJsonObject Session::FileUpdateData::createErrorReply(const char *type,
+ const QString &mainMessage) const
+{
+ QBS_ASSERT(error.hasError(), return QJsonObject());
+ ErrorInfo error(mainMessage);
+ for (const ErrorItem &ei : error.items())
+ error.append(ei);
+ QJsonObject reply;
+ reply.insert(StringConstants::type(), QLatin1String(type));
+ reply.insert(QLatin1String("error"), error.toJson());
+ reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(filePaths));
+ return reply;
+}
+
+} // namespace Internal
+} // namespace qbs
+
+#include <session.moc>
diff --git a/src/app/qbs/session.h b/src/app/qbs/session.h
new file mode 100644
index 000000000..ebbc93b1f
--- /dev/null
+++ b/src/app/qbs/session.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_SESSION_H
+#define QBS_SESSION_H
+
+namespace qbs {
+namespace Internal {
+
+void startSession();
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/app/qbs/sessionpacket.cpp b/src/app/qbs/sessionpacket.cpp
new file mode 100644
index 000000000..ce9fdaf76
--- /dev/null
+++ b/src/app/qbs/sessionpacket.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "sessionpacket.h"
+
+#include <tools/qbsassert.h>
+#include <tools/stringconstants.h>
+#include <tools/version.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qstring.h>
+
+namespace qbs {
+namespace Internal {
+
+const QByteArray packetStart = "qbsmsg:";
+
+SessionPacket::Status SessionPacket::parseInput(QByteArray &input)
+{
+ //qDebug() << m_expectedPayloadLength << m_payload << input;
+ if (m_expectedPayloadLength == -1) {
+ const int packetStartOffset = input.indexOf(packetStart);
+ if (packetStartOffset == -1)
+ return Status::Incomplete;
+ const int numberOffset = packetStartOffset + packetStart.length();
+ const int newLineOffset = input.indexOf('\n', numberOffset);
+ if (newLineOffset == -1)
+ return Status::Incomplete;
+ const QByteArray sizeString = input.mid(numberOffset, newLineOffset - numberOffset);
+ bool isNumber;
+ const int payloadLen = sizeString.toInt(&isNumber);
+ if (!isNumber || payloadLen < 0)
+ return Status::Invalid;
+ m_expectedPayloadLength = payloadLen;
+ input.remove(0, newLineOffset + 1);
+ }
+ const int bytesToAdd = m_expectedPayloadLength - m_payload.length();
+ QBS_ASSERT(bytesToAdd >= 0, return Status::Invalid);
+ m_payload += input.left(bytesToAdd);
+ input.remove(0, bytesToAdd);
+ return isComplete() ? Status::Complete : Status::Incomplete;
+}
+
+QJsonObject SessionPacket::retrievePacket()
+{
+ QBS_ASSERT(isComplete(), return QJsonObject());
+ const auto packet = QJsonDocument::fromJson(QByteArray::fromBase64(m_payload)).object();
+ m_payload.clear();
+ m_expectedPayloadLength = -1;
+ return packet;
+}
+
+QByteArray SessionPacket::createPacket(const QJsonObject &packet)
+{
+ const QByteArray jsonData = QJsonDocument(packet).toJson(QJsonDocument::Compact).toBase64();
+ return QByteArray(packetStart).append(QByteArray::number(jsonData.length())).append('\n')
+ .append(jsonData);
+}
+
+QJsonObject SessionPacket::helloMessage()
+{
+ return QJsonObject{
+ {StringConstants::type(), QLatin1String("hello")},
+ {QLatin1String("api-level"), 1},
+ {QLatin1String("api-compat-level"), 1}
+ };
+}
+
+bool SessionPacket::isComplete() const
+{
+ return m_payload.length() == m_expectedPayloadLength;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/app/qbs/sessionpacket.h b/src/app/qbs/sessionpacket.h
new file mode 100644
index 000000000..d919ff340
--- /dev/null
+++ b/src/app/qbs/sessionpacket.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_SESSIONPACKET_H
+#define QBS_SESSIONPACKET_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qjsonobject.h>
+
+namespace qbs {
+namespace Internal {
+
+class SessionPacket
+{
+public:
+ enum class Status { Incomplete, Complete, Invalid };
+ Status parseInput(QByteArray &input);
+
+ QJsonObject retrievePacket();
+
+ static QByteArray createPacket(const QJsonObject &packet);
+ static QJsonObject helloMessage();
+
+private:
+ bool isComplete() const;
+
+ QByteArray m_payload;
+ int m_expectedPayloadLength = -1;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/app/qbs/sessionpacketreader.cpp b/src/app/qbs/sessionpacketreader.cpp
new file mode 100644
index 000000000..fe4b73f69
--- /dev/null
+++ b/src/app/qbs/sessionpacketreader.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "sessionpacketreader.h"
+
+#include "sessionpacket.h"
+#include "stdinreader.h"
+
+namespace qbs {
+namespace Internal {
+
+class SessionPacketReader::Private
+{
+public:
+ QByteArray incomingData;
+ SessionPacket currentPacket;
+};
+
+SessionPacketReader::SessionPacketReader(QObject *parent) : QObject(parent), d(new Private) { }
+
+SessionPacketReader::~SessionPacketReader()
+{
+ delete d;
+}
+
+void SessionPacketReader::start()
+{
+ StdinReader * const stdinReader = StdinReader::create(this);
+ connect(stdinReader, &StdinReader::errorOccurred, this, &SessionPacketReader::errorOccurred);
+ connect(stdinReader, &StdinReader::dataAvailable, this, [this](const QByteArray &data) {
+ d->incomingData += data;
+ while (!d->incomingData.isEmpty()) {
+ switch (d->currentPacket.parseInput(d->incomingData)) {
+ case SessionPacket::Status::Invalid:
+ emit errorOccurred(tr("Received invalid input."));
+ return;
+ case SessionPacket::Status::Complete:
+ emit packetReceived(d->currentPacket.retrievePacket());
+ break;
+ case SessionPacket::Status::Incomplete:
+ return;
+ }
+ }
+ });
+ stdinReader->start();
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/app/qbs/sessionpacketreader.h b/src/app/qbs/sessionpacketreader.h
new file mode 100644
index 000000000..87d70cf39
--- /dev/null
+++ b/src/app/qbs/sessionpacketreader.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_SESSIONPACKETREADER_H
+#define QBS_SESSIONPACKETREADER_H
+
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qobject.h>
+
+namespace qbs {
+namespace Internal {
+
+class SessionPacketReader : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SessionPacketReader(QObject *parent = nullptr);
+ ~SessionPacketReader();
+
+ void start();
+
+signals:
+ void packetReceived(const QJsonObject &packet);
+ void errorOccurred(const QString &msg);
+
+private:
+ class Private;
+ Private * const d;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/app/qbs/stdinreader.cpp b/src/app/qbs/stdinreader.cpp
new file mode 100644
index 000000000..4f784505d
--- /dev/null
+++ b/src/app/qbs/stdinreader.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdinreader.h"
+
+#include <tools/hostosinfo.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qsocketnotifier.h>
+
+#include <cerrno>
+#include <cstring>
+
+#ifdef Q_OS_WIN32
+#include <qt_windows.h>
+#include <QtCore/qtimer.h>
+#else
+#include <fcntl.h>
+#endif
+
+namespace qbs {
+namespace Internal {
+
+class UnixStdinReader : public StdinReader
+{
+public:
+ UnixStdinReader(QObject *parent) : StdinReader(parent), m_notifier(0, QSocketNotifier::Read) {}
+
+private:
+ void start() override
+ {
+ if (!m_stdIn.open(stdin, QIODevice::ReadOnly)) {
+ emit errorOccurred(tr("Cannot read from standard input."));
+ return;
+ }
+ const auto emitError = [this] {
+ emit errorOccurred(tr("Failed to make standard input non-blocking: %1")
+ .arg(QLatin1String(std::strerror(errno))));
+ };
+#ifdef Q_OS_UNIX
+ const int flags = fcntl(0, F_GETFL, 0);
+ if (flags == -1) {
+ emitError();
+ return;
+ }
+ if (fcntl(0, F_SETFL, flags | O_NONBLOCK)) {
+ emitError();
+ return;
+ }
+#endif
+ connect(&m_notifier, &QSocketNotifier::activated, this, [this] {
+ emit dataAvailable(m_stdIn.readAll());
+ });
+ }
+
+ QFile m_stdIn;
+ QSocketNotifier m_notifier;
+};
+
+class WindowsStdinReader : public StdinReader
+{
+public:
+ WindowsStdinReader(QObject *parent) : StdinReader(parent) {}
+
+private:
+ void start() override
+ {
+#ifdef Q_OS_WIN32
+ m_stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
+ if (!m_stdinHandle) {
+ emit errorOccurred(tr("Failed to create handle for standard input."));
+ return;
+ }
+
+ // A timer seems slightly less awful than to block in a thread
+ // (how would we abort that one?), but ideally we'd like
+ // to have a signal-based approach like in the Unix variant.
+ const auto timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, this, [this] {
+ char buf[1024];
+ DWORD bytesAvail;
+ PeekNamedPipe(m_stdinHandle, nullptr, 0, nullptr, &bytesAvail, nullptr);
+ while (bytesAvail > 0) {
+ DWORD bytesRead;
+ ReadFile(m_stdinHandle, buf, std::min<DWORD>(bytesAvail, sizeof buf), &bytesRead,
+ nullptr);
+ emit dataAvailable(QByteArray(buf, bytesRead));
+ bytesAvail -= bytesRead;
+ }
+ });
+ timer->start(10);
+#endif
+ }
+
+#ifdef Q_OS_WIN32
+ HANDLE m_stdinHandle;
+#endif
+};
+
+StdinReader *StdinReader::create(QObject *parent)
+{
+ if (HostOsInfo::isWindowsHost())
+ return new WindowsStdinReader(parent);
+ return new UnixStdinReader(parent);
+}
+
+StdinReader::StdinReader(QObject *parent) : QObject(parent) { }
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/app/qbs/stdinreader.h b/src/app/qbs/stdinreader.h
new file mode 100644
index 000000000..b3737e5ae
--- /dev/null
+++ b/src/app/qbs/stdinreader.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_STDINREADER_H
+#define QBS_STDINREADER_H
+
+#include <QtCore/qobject.h>
+
+namespace qbs {
+namespace Internal {
+
+class StdinReader : public QObject
+{
+ Q_OBJECT
+public:
+ static StdinReader *create(QObject *parent);
+ virtual void start() = 0;
+
+signals:
+ void errorOccurred(const QString &error);
+ void dataAvailable(const QByteArray &data);
+
+protected:
+ explicit StdinReader(QObject *parent);
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index 3ffd6b2e9..d0fe7296e 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -726,7 +726,7 @@ void ProjectPrivate::updateExternalCodeLocations(const ProjectData &project,
void ProjectPrivate::prepareChangeToProject()
{
if (internalProject->locked)
- throw ErrorInfo(Tr::tr("A job is currently in process."));
+ throw ErrorInfo(Tr::tr("A job is currently in progress."));
if (!m_projectData.isValid())
retrieveProjectData(m_projectData, internalProject);
}
@@ -766,7 +766,7 @@ RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product,
const QString &inputFilePath, const QString &outputFileTag)
{
if (internalProject->locked)
- throw ErrorInfo(Tr::tr("A job is currently in process."));
+ throw ErrorInfo(Tr::tr("A job is currently in progress."));
const ResolvedProductConstPtr resolvedProduct = internalProduct(product);
if (!resolvedProduct)
throw ErrorInfo(Tr::tr("No such product '%1'.").arg(product.name()));
@@ -896,7 +896,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
}
for (const ResolvedProductPtr &resolvedDependentProduct
: qAsConst(resolvedProduct->dependencies)) {
- product.d->dependencies << resolvedDependentProduct->name;
+ product.d->dependencies << resolvedDependentProduct->name; // FIXME: Shouldn't this be a unique name?
}
std::sort(product.d->type.begin(), product.d->type.end());
std::sort(product.d->groups.begin(), product.d->groups.end());
@@ -1252,6 +1252,22 @@ Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath,
return info;
}
+Project::BuildGraphInfo Project::getBuildGraphInfo() const
+{
+ QBS_ASSERT(isValid(), return {});
+ BuildGraphInfo info;
+ try {
+ if (d->internalProject->locked)
+ throw ErrorInfo(Tr::tr("A job is currently in progress."));
+ info.bgFilePath = d->internalProject->buildGraphFilePath();
+ info.overriddenProperties = d->internalProject->overriddenValues;
+ info.profileData = d->internalProject->profileConfigs;
+ } catch (const ErrorInfo &e) {
+ info.error = e;
+ }
+ return info;
+}
+
#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
/*!
* \brief Adds a new empty group to the given product.
diff --git a/src/lib/corelib/api/project.h b/src/lib/corelib/api/project.h
index 05f08deee..9000d6548 100644
--- a/src/lib/corelib/api/project.h
+++ b/src/lib/corelib/api/project.h
@@ -155,6 +155,9 @@ public:
static BuildGraphInfo getBuildGraphInfo(const QString &bgFilePath,
const QStringList &requestedProperties);
+ // Use with loaded project. Does not set requestedProperties.
+ BuildGraphInfo getBuildGraphInfo() const;
+
#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
ErrorInfo addGroup(const ProductData &product, const QString &groupName);
diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp
index 56700b8be..7c64bf6ff 100644
--- a/src/lib/corelib/api/projectdata.cpp
+++ b/src/lib/corelib/api/projectdata.cpp
@@ -45,21 +45,57 @@
#include <tools/fileinfo.h>
#include <tools/jsliterals.h>
#include <tools/qbsassert.h>
+#include <tools/stringconstants.h>
#include <tools/qttools.h>
#include <tools/stringconstants.h>
#include <QtCore/qdir.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
#include <algorithm>
namespace qbs {
+using namespace Internal;
+
+template<typename T> static QJsonArray toJsonArray(const QList<T> &list,
+ const QStringList &moduleProperties)
+{
+ QJsonArray jsonArray;
+ std::transform(list.begin(), list.end(), std::back_inserter(jsonArray),
+ [&moduleProperties](const T &v) { return v.toJson(moduleProperties);});
+ return jsonArray;
+}
+
+static QVariant getModuleProperty(const PropertyMap &properties, const QString &fullPropertyName)
+{
+ const int lastDotIndex = fullPropertyName.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex == -1)
+ return QVariant();
+ return properties.getModuleProperty(fullPropertyName.left(lastDotIndex),
+ fullPropertyName.mid(lastDotIndex + 1));
+}
+
+static void addModuleProperties(QJsonObject &obj, const PropertyMap &properties,
+ const QStringList &propertyNames)
+{
+ QJsonObject propertyValues;
+ for (const QString &prop : propertyNames) {
+ const QVariant v = getModuleProperty(properties, prop);
+ if (v.isValid())
+ propertyValues.insert(prop, QJsonValue::fromVariant(v));
+ }
+ if (!propertyValues.isEmpty())
+ obj.insert(StringConstants::modulePropertiesKey(), propertyValues);
+}
+
/*!
* \class GroupData
* \brief The \c GroupData class corresponds to the Group item in a qbs source file.
*/
-GroupData::GroupData() : d(new Internal::GroupDataPrivate)
+GroupData::GroupData() : d(new GroupDataPrivate)
{
}
@@ -81,6 +117,22 @@ bool GroupData::isValid() const
return d->isValid;
}
+QJsonObject GroupData::toJson(const QStringList &moduleProperties) const
+{
+ QJsonObject obj;
+ if (isValid()) {
+ obj.insert(StringConstants::locationKey(), location().toJson());
+ obj.insert(StringConstants::nameProperty(), name());
+ obj.insert(StringConstants::prefixProperty(), prefix());
+ obj.insert(StringConstants::isEnabledKey(), isEnabled());
+ obj.insert(QStringLiteral("source-artifacts"), toJsonArray(sourceArtifacts(), {}));
+ obj.insert(QStringLiteral("source-artifacts-from-wildcards"),
+ toJsonArray(sourceArtifactsFromWildcards(), {}));
+ addModuleProperties(obj, properties(), moduleProperties);
+ }
+ return obj;
+}
+
/*!
* \brief The location at which the group is defined in the respective source file.
*/
@@ -204,7 +256,7 @@ bool operator<(const GroupData &lhs, const GroupData &rhs)
* or it gets generated during the build process.
*/
-ArtifactData::ArtifactData() : d(new Internal::ArtifactDataPrivate)
+ArtifactData::ArtifactData() : d(new ArtifactDataPrivate)
{
}
@@ -226,6 +278,21 @@ bool ArtifactData::isValid() const
return d->isValid;
}
+QJsonObject ArtifactData::toJson(const QStringList &moduleProperties) const
+{
+ QJsonObject obj;
+ if (isValid()) {
+ obj.insert(StringConstants::filePathKey(), filePath());
+ obj.insert(QStringLiteral("file-tags"), QJsonArray::fromStringList(fileTags()));
+ obj.insert(QStringLiteral("is-generated"), isGenerated());
+ obj.insert(QStringLiteral("is-executable"), isExecutable());
+ obj.insert(QStringLiteral("is-target"), isTargetArtifact());
+ obj.insert(QStringLiteral("install-data"), installData().toJson());
+ addModuleProperties(obj, properties(), moduleProperties);
+ }
+ return obj;
+}
+
/*!
* \brief The full path of this file.
*/
@@ -256,8 +323,8 @@ bool ArtifactData::isExecutable() const
{
const bool isBundle = d->properties.getModuleProperty(
QStringLiteral("bundle"), QStringLiteral("isBundle")).toBool();
- return Internal::isRunnableArtifact(
- Internal::FileTags::fromStringList(d->fileTags), isBundle);
+ return isRunnableArtifact(
+ FileTags::fromStringList(d->fileTags), isBundle);
}
/*!
@@ -309,7 +376,7 @@ bool operator<(const ArtifactData &ta1, const ArtifactData &ta2)
* \brief The \c InstallData class provides the installation-related data of an artifact.
*/
-InstallData::InstallData() : d(new Internal::InstallDataPrivate)
+InstallData::InstallData() : d(new InstallDataPrivate)
{
}
@@ -331,6 +398,19 @@ bool InstallData::isValid() const
return d->isValid;
}
+QJsonObject InstallData::toJson() const
+{
+ QJsonObject obj;
+ if (isValid()) {
+ obj.insert(QStringLiteral("is-installable"), isInstallable());
+ if (isInstallable()) {
+ obj.insert(QStringLiteral("install-file-path"), installFilePath());
+ obj.insert(QStringLiteral("install-root"), installRoot());
+ }
+ }
+ return obj;
+}
+
/*!
\brief Returns true if and only if \c{qbs.install} is \c true for the artifact.
*/
@@ -348,7 +428,7 @@ bool InstallData::isInstallable() const
QString InstallData::installDir() const
{
QBS_ASSERT(isValid(), return {});
- return Internal::FileInfo::path(installFilePath());
+ return FileInfo::path(installFilePath());
}
/*!
@@ -392,7 +472,7 @@ QString InstallData::localInstallFilePath() const
* \brief The \c ProductData class corresponds to the Product item in a qbs source file.
*/
-ProductData::ProductData() : d(new Internal::ProductDataPrivate)
+ProductData::ProductData() : d(new ProductDataPrivate)
{
}
@@ -414,6 +494,39 @@ bool ProductData::isValid() const
return d->isValid;
}
+QJsonObject ProductData::toJson(const QStringList &propertyNames) const
+{
+ QJsonObject obj;
+ if (!isValid())
+ return obj;
+ obj.insert(StringConstants::typeProperty(), QJsonArray::fromStringList(type()));
+ obj.insert(StringConstants::dependenciesProperty(),
+ QJsonArray::fromStringList(dependencies()));
+ obj.insert(StringConstants::nameProperty(), name());
+ obj.insert(StringConstants::fullDisplayNameKey(), fullDisplayName());
+ obj.insert(QStringLiteral("target-name"), targetName());
+ obj.insert(StringConstants::versionProperty(), version());
+ obj.insert(QStringLiteral("multiplex-configuration-id"), multiplexConfigurationId());
+ obj.insert(StringConstants::locationKey(), location().toJson());
+ obj.insert(StringConstants::buildDirectoryKey(), buildDirectory());
+ obj.insert(QStringLiteral("generated-artifacts"), toJsonArray(generatedArtifacts(),
+ propertyNames));
+ obj.insert(QStringLiteral("target-executable"), targetExecutable());
+ QJsonArray groupArray;
+ for (const GroupData &g : groups()) {
+ const QStringList groupPropNames = g.properties() == moduleProperties()
+ ? QStringList() : propertyNames;
+ groupArray << g.toJson(groupPropNames);
+ }
+ obj.insert(QStringLiteral("groups"), groupArray);
+ obj.insert(QStringLiteral("properties"), QJsonObject::fromVariantMap(properties()));
+ obj.insert(StringConstants::isEnabledKey(), isEnabled());
+ obj.insert(QStringLiteral("is-runnable"), isRunnable());
+ obj.insert(QStringLiteral("is-multiplexed"), isMultiplexed());
+ addModuleProperties(obj, moduleProperties(), propertyNames);
+ return obj;
+}
+
/*!
* \brief The product type, which is the list of file tags matching the product's target artifacts.
*/
@@ -445,7 +558,7 @@ QString ProductData::name() const
*/
QString ProductData::fullDisplayName() const
{
- return Internal::ResolvedProduct::fullDisplayName(name(), multiplexConfigurationId());
+ return ResolvedProduct::fullDisplayName(name(), multiplexConfigurationId());
}
/*!
@@ -470,8 +583,8 @@ QString ProductData::version() const
QString ProductData::profile() const
{
return d->moduleProperties.getModuleProperty(
- Internal::StringConstants::qbsModule(),
- Internal::StringConstants::profileProperty()).toString();
+ StringConstants::qbsModule(),
+ StringConstants::profileProperty()).toString();
}
QString ProductData::multiplexConfigurationId() const
@@ -661,7 +774,7 @@ bool operator<(const ProductData &lhs, const ProductData &rhs)
* \brief The products in this project.
*/
-ProjectData::ProjectData() : d(new Internal::ProjectDataPrivate)
+ProjectData::ProjectData() : d(new ProjectDataPrivate)
{
}
@@ -683,6 +796,19 @@ bool ProjectData::isValid() const
return d->isValid;
}
+QJsonObject ProjectData::toJson(const QStringList &moduleProperties) const
+{
+ QJsonObject obj;
+ if (!isValid())
+ return obj;
+ obj.insert(StringConstants::nameProperty(), name());
+ obj.insert(StringConstants::locationKey(), location().toJson());
+ obj.insert(StringConstants::isEnabledKey(), isEnabled());
+ obj.insert(StringConstants::productsKey(), toJsonArray(products(), moduleProperties));
+ obj.insert(QStringLiteral("sub-projects"), toJsonArray(subProjects(), moduleProperties));
+ return obj;
+}
+
/*!
* \brief The name of this project.
*/
@@ -788,14 +914,14 @@ bool operator<(const ProjectData &lhs, const ProjectData &rhs)
*/
PropertyMap::PropertyMap()
- : d(std::make_unique<Internal::PropertyMapPrivate>())
+ : d(std::make_unique<PropertyMapPrivate>())
{
- static Internal::PropertyMapPtr defaultInternalMap = Internal::PropertyMapInternal::create();
+ static PropertyMapPtr defaultInternalMap = PropertyMapInternal::create();
d->m_map = defaultInternalMap;
}
PropertyMap::PropertyMap(const PropertyMap &other)
- : d(std::make_unique<Internal::PropertyMapPrivate>(*other.d))
+ : d(std::make_unique<PropertyMapPrivate>(*other.d))
{
}
@@ -806,7 +932,7 @@ PropertyMap::~PropertyMap() = default;
PropertyMap &PropertyMap::operator =(const PropertyMap &other)
{
if (this != &other)
- d = std::make_unique<Internal::PropertyMapPrivate>(*other.d);
+ d = std::make_unique<PropertyMapPrivate>(*other.d);
return *this;
}
diff --git a/src/lib/corelib/api/projectdata.h b/src/lib/corelib/api/projectdata.h
index 3bd1c4540..a285f8570 100644
--- a/src/lib/corelib/api/projectdata.h
+++ b/src/lib/corelib/api/projectdata.h
@@ -110,6 +110,7 @@ public:
~ArtifactData();
bool isValid() const;
+ QJsonObject toJson(const QStringList &moduleProperties = {}) const;
QString filePath() const;
QStringList fileTags() const;
@@ -135,6 +136,7 @@ public:
~InstallData();
bool isValid() const;
+ QJsonObject toJson() const;
bool isInstallable() const;
QString installDir() const;
@@ -162,6 +164,7 @@ public:
~GroupData();
bool isValid() const;
+ QJsonObject toJson(const QStringList &moduleProperties = {}) const;
CodeLocation location() const;
QString name() const;
@@ -193,6 +196,7 @@ public:
~ProductData();
bool isValid() const;
+ QJsonObject toJson(const QStringList &propertyNames = {}) const;
QStringList type() const;
QStringList dependencies() const;
@@ -235,6 +239,7 @@ public:
~ProjectData();
bool isValid() const;
+ QJsonObject toJson(const QStringList &moduleProperties = {}) const;
QString name() const;
CodeLocation location() const;
diff --git a/src/lib/corelib/buildgraph/abstractcommandexecutor.cpp b/src/lib/corelib/buildgraph/abstractcommandexecutor.cpp
index 1a1d51f11..16c3621b6 100644
--- a/src/lib/corelib/buildgraph/abstractcommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/abstractcommandexecutor.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -58,6 +59,14 @@ AbstractCommandExecutor::AbstractCommandExecutor(Logger logger, QObject *parent)
, m_dryRun(false)
, m_logger(std::move(logger))
{
+ m_watchdog.setSingleShot(true);
+ connect(&m_watchdog, &QTimer::timeout,
+ this, [this]() {
+ cancel(ErrorInfo{Tr::tr("Command cancelled because it exceeded the timeout.")});
+ });
+ connect(this, &AbstractCommandExecutor::finished,
+ &m_watchdog, &QTimer::stop);
+
}
void AbstractCommandExecutor::start(Transformer *transformer, AbstractCommand *cmd)
@@ -66,7 +75,8 @@ void AbstractCommandExecutor::start(Transformer *transformer, AbstractCommand *c
m_command = cmd;
doSetup();
doReportCommandDescription(transformer->product()->fullDisplayName());
- doStart();
+ if (doStart())
+ startTimeout();
}
void AbstractCommandExecutor::doReportCommandDescription(const QString &productName)
@@ -84,5 +94,14 @@ void AbstractCommandExecutor::doReportCommandDescription(const QString &productN
}
}
+void AbstractCommandExecutor::startTimeout()
+{
+ if (!m_dryRun || m_command->ignoreDryRun()) {
+ const auto timeout = m_command->timeout();
+ if (timeout > 0)
+ m_watchdog.start(timeout * 1000);
+ }
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/abstractcommandexecutor.h b/src/lib/corelib/buildgraph/abstractcommandexecutor.h
index 60b2b40b2..c0f149622 100644
--- a/src/lib/corelib/buildgraph/abstractcommandexecutor.h
+++ b/src/lib/corelib/buildgraph/abstractcommandexecutor.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -45,6 +46,7 @@
#include <tools/error.h>
#include <QtCore/qobject.h>
+#include <QtCore/qtimer.h>
namespace qbs {
class ErrorInfo;
@@ -64,7 +66,7 @@ public:
void setDryRunEnabled(bool enabled) { m_dryRun = enabled; }
void setEchoMode(CommandEchoMode echoMode) { m_echoMode = echoMode; }
- virtual void cancel() = 0;
+ virtual void cancel(const qbs::ErrorInfo &reason = {}) = 0;
void start(Transformer *transformer, AbstractCommand *cmd);
@@ -83,7 +85,9 @@ protected:
private:
virtual void doSetup() { };
- virtual void doStart() = 0;
+ virtual bool doStart() = 0;
+
+ void startTimeout();
private:
AbstractCommand *m_command;
@@ -91,6 +95,7 @@ private:
ScriptEngine *m_mainThreadScriptEngine;
bool m_dryRun;
Internal::Logger m_logger;
+ QTimer m_watchdog;
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.cpp b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
index 30970779c..5c83b2056 100644
--- a/src/lib/corelib/buildgraph/jscommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -82,9 +83,11 @@ public:
return m_result;
}
- void cancel()
+ void cancel(const qbs::ErrorInfo &reason)
{
QBS_ASSERT(m_scriptEngine, return);
+ m_result.success = !reason.hasError();
+ m_result.errorMessage = reason.toString();
m_scriptEngine->abortEvaluation();
}
@@ -226,24 +229,25 @@ void JsCommandExecutor::waitForFinished()
loop.exec();
}
-void JsCommandExecutor::doStart()
+bool JsCommandExecutor::doStart()
{
- QBS_ASSERT(!m_running, return);
+ QBS_ASSERT(!m_running, return false);
m_thread->start();
if (dryRun() && !command()->ignoreDryRun()) {
QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller.
- return;
+ return false;
}
m_running = true;
emit startRequested(jsCommand(), transformer());
+ return true;
}
-void JsCommandExecutor::cancel()
+void JsCommandExecutor::cancel(const qbs::ErrorInfo &reason)
{
if (m_running && !dryRun())
- QTimer::singleShot(0, m_objectInThread, [this] { m_objectInThread->cancel(); });
+ QTimer::singleShot(0, m_objectInThread, [objectInThread = m_objectInThread, reason] { objectInThread->cancel(reason); });
}
void JsCommandExecutor::onJavaScriptCommandFinished()
diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.h b/src/lib/corelib/buildgraph/jscommandexecutor.h
index 0170c5231..0725f0d24 100644
--- a/src/lib/corelib/buildgraph/jscommandexecutor.h
+++ b/src/lib/corelib/buildgraph/jscommandexecutor.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -65,8 +66,8 @@ private:
void onJavaScriptCommandFinished();
void doReportCommandDescription(const QString &productName) override;
- void doStart() override;
- void cancel() override;
+ bool doStart() override;
+ void cancel(const qbs::ErrorInfo &reason) override;
void waitForFinished();
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
index c4e4a2be6..79edda320 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -119,9 +120,9 @@ void ProcessCommandExecutor::doSetup()
m_shellInvocation = shellQuote(QDir::toNativeSeparators(m_program), m_arguments);
}
-void ProcessCommandExecutor::doStart()
+bool ProcessCommandExecutor::doStart()
{
- QBS_ASSERT(m_process.state() == QProcess::NotRunning, return);
+ QBS_ASSERT(m_process.state() == QProcess::NotRunning, return false);
const ProcessCommand * const cmd = processCommand();
@@ -131,7 +132,7 @@ void ProcessCommandExecutor::doStart()
if (dryRun() && !cmd->ignoreDryRun()) {
QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller.
- return;
+ return false;
}
const QString workingDir = QDir::fromNativeSeparators(cmd->workingDir());
@@ -142,7 +143,7 @@ void ProcessCommandExecutor::doStart()
"is invalid.").arg(QDir::toNativeSeparators(workingDir),
QDir::toNativeSeparators(m_program)),
cmd->codeLocation()));
- return;
+ return false;
}
}
@@ -163,7 +164,7 @@ void ProcessCommandExecutor::doStart()
if (!responseFile.open()) {
emit finished(ErrorInfo(Tr::tr("Cannot create response file '%1'.")
.arg(responseFile.fileName())));
- return;
+ return false;
}
for (int i = cmd->responseFileArgumentIndex(); i < cmd->arguments().size(); ++i) {
const QString arg = cmd->arguments().at(i);
@@ -172,7 +173,7 @@ void ProcessCommandExecutor::doStart()
if (!f.open(QIODevice::ReadOnly)) {
emit finished(ErrorInfo(Tr::tr("Cannot open command file '%1'.")
.arg(QDir::toNativeSeparators(f.fileName()))));
- return;
+ return false;
}
responseFile.write(f.readAll());
} else {
@@ -194,13 +195,15 @@ void ProcessCommandExecutor::doStart()
qCDebug(lcExec) << "Additional environment:" << additionalVariables.toStringList();
m_process.setWorkingDirectory(workingDir);
m_process.start(m_program, arguments);
+ return true;
}
-void ProcessCommandExecutor::cancel()
+void ProcessCommandExecutor::cancel(const qbs::ErrorInfo &reason)
{
// We don't want this command to be reported as failing, since we explicitly terminated it.
disconnect(this, &ProcessCommandExecutor::reportProcessResult, nullptr, nullptr);
+ m_cancelReason = reason;
m_process.cancel();
}
@@ -304,10 +307,13 @@ void ProcessCommandExecutor::sendProcessOutput()
const bool processError = result.error() != QProcess::UnknownError;
const bool failureExit = quint32(m_process.exitCode())
> quint32(processCommand()->maxExitCode());
- result.d->success = !processError && !failureExit;
+ const bool cancelledWithError = m_cancelReason.hasError();
+ result.d->success = !processError && !failureExit && !cancelledWithError;
emit reportProcessResult(result);
- if (Q_UNLIKELY(processError)) {
+ if (Q_UNLIKELY(cancelledWithError)) {
+ emit finished(m_cancelReason);
+ } else if (Q_UNLIKELY(processError)) {
emit finished(ErrorInfo(errorString));
} else if (Q_UNLIKELY(failureExit)) {
emit finished(ErrorInfo(Tr::tr("Process failed with exit code %1.")
@@ -325,6 +331,8 @@ void ProcessCommandExecutor::onProcessError()
QTimer::singleShot(0, this, &ProcessCommandExecutor::onProcessError);
return;
}
+ if (m_cancelReason.hasError())
+ return; // Ignore. Cancel reasons will be handled by on ProcessFinished().
switch (m_process.error()) {
case QProcess::FailedToStart: {
removeResponseFile();
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.h b/src/lib/corelib/buildgraph/processcommandexecutor.h
index 67eb9f746..b0f955882 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.h
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -71,8 +72,8 @@ private:
void doSetup() override;
void doReportCommandDescription(const QString &productName) override;
- void doStart() override;
- void cancel() override;
+ bool doStart() override;
+ void cancel(const qbs::ErrorInfo &reason) override;
void startProcessCommand();
QString filterProcessOutput(const QByteArray &output, const QString &filterFunctionSource);
@@ -91,6 +92,7 @@ private:
QProcessEnvironment m_buildEnvironment;
QProcessEnvironment m_commandEnvironment;
QString m_responseFileName;
+ qbs::ErrorInfo m_cancelReason;
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp
index ecbc54292..31ff6be4b 100644
--- a/src/lib/corelib/buildgraph/rulecommands.cpp
+++ b/src/lib/corelib/buildgraph/rulecommands.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -74,6 +75,7 @@ static QString stderrFilePathProperty() { return QStringLiteral("stderrFilePath"
static QString stderrFilterFunctionProperty() { return QStringLiteral("stderrFilterFunction"); }
static QString stdoutFilePathProperty() { return QStringLiteral("stdoutFilePath"); }
static QString stdoutFilterFunctionProperty() { return QStringLiteral("stdoutFilterFunction"); }
+static QString timeoutProperty() { return QStringLiteral("timeout"); }
static QString workingDirProperty() { return QStringLiteral("workingDirectory"); }
static QString invokedSourceCode(const QScriptValue codeOrFunction)
@@ -87,7 +89,8 @@ AbstractCommand::AbstractCommand()
m_extendedDescription(defaultExtendedDescription()),
m_highlight(defaultHighLight()),
m_ignoreDryRun(defaultIgnoreDryRun()),
- m_silent(defaultIsSilent())
+ m_silent(defaultIsSilent()),
+ m_timeout(defaultTimeout())
{
}
@@ -104,6 +107,7 @@ bool AbstractCommand::equals(const AbstractCommand *other) const
&& m_ignoreDryRun == other->m_ignoreDryRun
&& m_silent == other->m_silent
&& m_jobPool == other->m_jobPool
+ && m_timeout == other->m_timeout
&& m_properties == other->m_properties;
}
@@ -115,6 +119,9 @@ void AbstractCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
m_ignoreDryRun = scriptValue->property(ignoreDryRunProperty()).toBool();
m_silent = scriptValue->property(silentProperty()).toBool();
m_jobPool = scriptValue->property(StringConstants::jobPoolProperty()).toString();
+ const auto timeoutScriptValue = scriptValue->property(timeoutProperty());
+ if (!timeoutScriptValue.isUndefined() && !timeoutScriptValue.isNull())
+ m_timeout = timeoutScriptValue.toInt32();
m_codeLocation = codeLocation;
m_predefinedProperties
@@ -123,7 +130,8 @@ void AbstractCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
<< highlightProperty()
<< ignoreDryRunProperty()
<< StringConstants::jobPoolProperty()
- << silentProperty();
+ << silentProperty()
+ << timeoutProperty();
}
QString AbstractCommand::fullDescription(const QString &productName) const
@@ -173,6 +181,8 @@ static QScriptValue js_CommandBase(QScriptContext *context, QScriptEngine *engin
engine->toScriptValue(AbstractCommand::defaultIgnoreDryRun()));
cmd.setProperty(silentProperty(),
engine->toScriptValue(AbstractCommand::defaultIsSilent()));
+ cmd.setProperty(timeoutProperty(),
+ engine->toScriptValue(AbstractCommand::defaultTimeout()));
return cmd;
}
diff --git a/src/lib/corelib/buildgraph/rulecommands.h b/src/lib/corelib/buildgraph/rulecommands.h
index d9d561454..d4d70d591 100644
--- a/src/lib/corelib/buildgraph/rulecommands.h
+++ b/src/lib/corelib/buildgraph/rulecommands.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
@@ -70,6 +71,7 @@ public:
static QString defaultHighLight() { return {}; }
static bool defaultIgnoreDryRun() { return false; }
static bool defaultIsSilent() { return false; }
+ static int defaultTimeout() { return -1; }
virtual CommandType type() const = 0;
virtual bool equals(const AbstractCommand *other) const;
@@ -83,6 +85,7 @@ public:
bool isSilent() const { return m_silent; }
QString jobPool() const { return m_jobPool; }
CodeLocation codeLocation() const { return m_codeLocation; }
+ int timeout() const { return m_timeout; }
const QVariantMap &properties() const { return m_properties; }
@@ -100,7 +103,7 @@ private:
{
pool.serializationOp<opType>(m_description, m_extendedDescription, m_highlight,
m_ignoreDryRun, m_silent, m_codeLocation, m_jobPool,
- m_properties);
+ m_timeout, m_properties);
}
QString m_description;
@@ -110,6 +113,7 @@ private:
bool m_silent;
CodeLocation m_codeLocation;
QString m_jobPool;
+ int m_timeout;
QVariantMap m_properties;
};
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index a9ca5131a..2f0ced926 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -198,7 +198,24 @@ QbsLibrary {
"generatableprojectiterator.h",
"generator.cpp",
"generatordata.cpp",
+ "generatorutils.cpp",
+ "generatorutils.h",
+ "generatorversioninfo.cpp",
+ "generatorversioninfo.h",
"igeneratableprojectvisitor.h",
+ "ixmlnodevisitor.h",
+ "xmlproject.cpp",
+ "xmlproject.h",
+ "xmlprojectwriter.cpp",
+ "xmlprojectwriter.h",
+ "xmlproperty.cpp",
+ "xmlproperty.h",
+ "xmlpropertygroup.cpp",
+ "xmlpropertygroup.h",
+ "xmlworkspace.cpp",
+ "xmlworkspace.h",
+ "xmlworkspacewriter.cpp",
+ "xmlworkspacewriter.h",
]
}
Group {
@@ -401,6 +418,7 @@ QbsLibrary {
"joblimits.cpp",
"jsliterals.cpp",
"jsliterals.h",
+ "jsonhelper.h",
"installoptions.cpp",
"launcherinterface.cpp",
"launcherinterface.h",
diff --git a/src/lib/corelib/generators/generators.pri b/src/lib/corelib/generators/generators.pri
index 093e45f40..e9730d895 100644
--- a/src/lib/corelib/generators/generators.pri
+++ b/src/lib/corelib/generators/generators.pri
@@ -3,13 +3,31 @@ include(../../../install_prefix.pri)
SOURCES += \
$$PWD/generatableprojectiterator.cpp \
$$PWD/generator.cpp \
- $$PWD/generatordata.cpp
+ $$PWD/generatordata.cpp \
+ $$PWD/generatorutils.cpp \
+ $$PWD/generatorversioninfo.cpp \
+ $$PWD/xmlproject.cpp \
+ $$PWD/xmlprojectwriter.cpp\
+ $$PWD/xmlproperty.cpp \
+ $$PWD/xmlpropertygroup.cpp \
+ $$PWD/xmlworkspace.cpp \
+ $$PWD/xmlworkspacewriter.cpp
HEADERS += \
$$PWD/generatableprojectiterator.h \
$$PWD/generator.h \
$$PWD/generatordata.h \
- $$PWD/igeneratableprojectvisitor.h
+ $$PWD/generatorutils.h \
+ $$PWD/generatorversioninfo.h \
+ $$PWD/igeneratableprojectvisitor.h \
+ $$PWD/ixmlnodevisitor.h \
+ $$PWD/ixmlnodevisitor.h \
+ $$PWD/xmlproject.h \
+ $$PWD/xmlprojectwriter.h \
+ $$PWD/xmlproperty.h \
+ $$PWD/xmlpropertygroup.h \
+ $$PWD/xmlworkspace.h \
+ $$PWD/xmlworkspacewriter.h
!qbs_no_dev_install {
generators_headers.files = \
diff --git a/src/lib/corelib/generators/generatorutils.cpp b/src/lib/corelib/generators/generatorutils.cpp
new file mode 100644
index 000000000..9c00eef05
--- /dev/null
+++ b/src/lib/corelib/generators/generatorutils.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "generatorutils.h"
+
+namespace qbs {
+namespace gen {
+namespace utils {
+
+QString architectureName(Architecture arch)
+{
+ switch (arch) {
+ case Architecture::Arm:
+ return QStringLiteral("arm");
+ case Architecture::Avr:
+ return QStringLiteral("avr");
+ case Architecture::Mcs51:
+ return QStringLiteral("mcs51");
+ default:
+ return QStringLiteral("unknown");
+ }
+}
+
+Architecture architecture(const Project &qbsProject)
+{
+ const auto qbsArch = qbsProject.projectConfiguration()
+ .value(Internal::StringConstants::qbsModule()).toMap()
+ .value(QStringLiteral("architecture")).toString();
+
+ if (qbsArch == QLatin1String("arm"))
+ return Architecture::Arm;
+ if (qbsArch == QLatin1String("avr"))
+ return Architecture::Avr;
+ if (qbsArch == QLatin1String("mcs51"))
+ return Architecture::Mcs51;
+ if (qbsArch == QLatin1String("stm8"))
+ return Architecture::Stm8;
+ if (qbsArch == QLatin1String("msp430"))
+ return Architecture::Msp430;
+ return Architecture::Unknown;
+}
+
+QString buildConfigurationName(const Project &qbsProject)
+{
+ return qbsProject.projectConfiguration()
+ .value(Internal::StringConstants::qbsModule()).toMap()
+ .value(QStringLiteral("configurationName")).toString();
+}
+
+int debugInformation(const ProductData &qbsProduct)
+{
+ return qbsProduct.moduleProperties().getModuleProperty(
+ Internal::StringConstants::qbsModule(),
+ QStringLiteral("debugInformation"))
+ .toInt();
+}
+
+QString buildRootPath(const Project &qbsProject)
+{
+ QDir dir(qbsProject.projectData().buildDirectory());
+ dir.cdUp();
+ return dir.absolutePath();
+}
+
+QString relativeFilePath(const QString &baseDirectory,
+ const QString &fullFilePath)
+{
+ return QDir(baseDirectory).relativeFilePath(fullFilePath);
+}
+
+QString binaryOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ return QDir(baseDirectory).relativeFilePath(
+ qbsProduct.buildDirectory())
+ + QLatin1String("/bin");
+}
+
+QString objectsOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ return QDir(baseDirectory).relativeFilePath(
+ qbsProduct.buildDirectory())
+ + QLatin1String("/obj");
+}
+
+QString listingOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ return QDir(baseDirectory).relativeFilePath(
+ qbsProduct.buildDirectory())
+ + QLatin1String("/lst");
+}
+
+std::vector<ProductData> dependenciesOf(const ProductData &qbsProduct,
+ const GeneratableProject &genProject,
+ const QString &configurationName)
+{
+ std::vector<ProductData> result;
+ const auto depsNames = qbsProduct.dependencies();
+ for (const auto &product : qAsConst(genProject.products)) {
+ const auto pt = product.type();
+ if (!pt.contains(QLatin1String("staticlibrary")))
+ continue;
+ const auto pn = product.name();
+ if (!depsNames.contains(pn))
+ continue;
+ result.push_back(product.data.value(configurationName));
+ }
+ return result;
+}
+
+QString targetBinary(const ProductData &qbsProduct)
+{
+ const auto type = qbsProduct.type();
+ if (type.contains(QLatin1String("application"))) {
+ return QFileInfo(qbsProduct.targetExecutable()).fileName();
+ } else if (type.contains(QLatin1String("staticlibrary"))) {
+ const auto artifacts = qbsProduct.targetArtifacts();
+ for (const auto &artifact : artifacts) {
+ if (artifact.fileTags().contains(QLatin1String("staticlibrary")))
+ return QFileInfo(artifact.filePath()).fileName();
+ }
+ }
+
+ return {};
+}
+
+QString targetBinaryPath(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ return binaryOutputDirectory(baseDirectory, qbsProduct)
+ + QLatin1Char('/') + targetBinary(qbsProduct);
+}
+
+QString cppStringModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName)
+{
+ return qbsProps.getModuleProperty(
+ Internal::StringConstants::cppModule(),
+ propertyName).toString().trimmed();
+}
+
+bool cppBooleanModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName)
+{
+ return qbsProps.getModuleProperty(
+ Internal::StringConstants::cppModule(),
+ propertyName).toBool();
+}
+
+int cppIntegerModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName)
+{
+ return qbsProps.getModuleProperty(
+ Internal::StringConstants::cppModule(),
+ propertyName).toInt();
+}
+
+QStringList cppStringModuleProperties(const PropertyMap &qbsProps,
+ const QStringList &propertyNames)
+{
+ QStringList properties;
+ for (const auto &propertyName : propertyNames) {
+ const auto entries = qbsProps.getModuleProperty(
+ Internal::StringConstants::cppModule(),
+ propertyName).toStringList();
+ for (const auto &entry : entries)
+ properties.push_back(entry.trimmed());
+ }
+ return properties;
+}
+
+QVariantList cppVariantModuleProperties(const PropertyMap &qbsProps,
+ const QStringList &propertyNames)
+{
+ QVariantList properties;
+ for (const auto &propertyName : propertyNames) {
+ properties << qbsProps.getModuleProperty(
+ Internal::StringConstants::cppModule(),
+ propertyName).toList();
+ }
+ return properties;
+}
+
+static QString parseFlagValue(const QString &flagKey,
+ QStringList::const_iterator &flagIt,
+ const QStringList::const_iterator &flagEnd)
+{
+ if (flagIt->contains(QLatin1Char('='))) {
+ // In this case an option is in form of 'flagKey=<flagValue>'.
+ const auto parts = flagIt->split(QLatin1Char('='));
+ if (parts.count() == 2)
+ return parts.at(1).trimmed();
+ } else if (flagKey < *flagIt) {
+ // In this case an option is in form of 'flagKey<flagValue>'.
+ return flagIt->mid(flagKey.count()).trimmed();
+ } else {
+ // In this case an option is in form of 'flagKey <flagValue>'.
+ ++flagIt;
+ if (flagIt < flagEnd && !flagIt->startsWith(QLatin1Char('-')))
+ return (*flagIt).trimmed();
+ }
+ return {};
+}
+
+QString firstFlagValue(const QStringList &flags, const QString &flagKey)
+{
+ const auto flagBegin = flags.cbegin();
+ const auto flagEnd = flags.cend();
+ auto flagIt = std::find_if(flagBegin, flagEnd, [flagKey](const QString &flag) {
+ return flag == flagKey || flag.startsWith(flagKey);
+ });
+ if (flagIt == flagEnd)
+ return {};
+ return parseFlagValue(flagKey, flagIt, flagEnd);
+}
+
+QStringList allFlagValues(const QStringList &flags, const QString &flagKey)
+{
+ QStringList values;
+ const auto flagEnd = flags.cend();
+ for (auto flagIt = flags.cbegin(); flagIt < flagEnd; ++flagIt) {
+ if (*flagIt == flagKey || flagIt->startsWith(flagKey)) {
+ const QString value = parseFlagValue(flagKey, flagIt, flagEnd);
+ if (!value.isEmpty())
+ values.push_back(value);
+ }
+ }
+ return values;
+}
+
+} // namespace utils
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/generatorutils.h b/src/lib/corelib/generators/generatorutils.h
new file mode 100644
index 000000000..9348ab18c
--- /dev/null
+++ b/src/lib/corelib/generators/generatorutils.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_UTILS_H
+#define GENERATORS_UTILS_H
+
+#include <qbs.h>
+
+#include <tools/qbs_export.h>
+#include <tools/stringconstants.h>
+
+namespace qbs {
+namespace gen {
+namespace utils {
+
+enum class Architecture {
+ Arm,
+ Avr,
+ Mcs51,
+ Stm8,
+ Msp430,
+ Unknown
+};
+
+QBS_EXPORT QString architectureName(Architecture arch);
+QBS_EXPORT Architecture architecture(const Project &qbsProject);
+QBS_EXPORT QString buildConfigurationName(const Project &qbsProject);
+QBS_EXPORT int debugInformation(const ProductData &qbsProduct);
+QBS_EXPORT QString buildRootPath(const Project &qbsProject);
+QBS_EXPORT QString relativeFilePath(const QString &baseDirectory,
+ const QString &fullFilePath);
+QBS_EXPORT QString binaryOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+QBS_EXPORT QString objectsOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+QBS_EXPORT QString listingOutputDirectory(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+QBS_EXPORT std::vector<ProductData> dependenciesOf(const ProductData &qbsProduct,
+ const GeneratableProject &genProject,
+ const QString &configurationName);
+QBS_EXPORT QString targetBinary(const ProductData &qbsProduct);
+QBS_EXPORT QString targetBinaryPath(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+QBS_EXPORT QString cppStringModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName);
+QBS_EXPORT bool cppBooleanModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName);
+QBS_EXPORT int cppIntegerModuleProperty(const PropertyMap &qbsProps,
+ const QString &propertyName);
+QBS_EXPORT QStringList cppStringModuleProperties(const PropertyMap &qbsProps,
+ const QStringList &propertyNames);
+QBS_EXPORT QVariantList cppVariantModuleProperties(const PropertyMap &qbsProps,
+ const QStringList &propertyNames);
+QBS_EXPORT QString firstFlagValue(const QStringList &flags,
+ const QString &flagKey);
+QBS_EXPORT QStringList allFlagValues(const QStringList &flags,
+ const QString &flagKey);
+
+template <typename T>
+bool inBounds(const T &value, const T &low, const T &high)
+{
+ return !(value < low) && !(high < value);
+}
+
+} // namespace utils
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_UTILS_H
diff --git a/src/lib/corelib/generators/generatorversioninfo.cpp b/src/lib/corelib/generators/generatorversioninfo.cpp
new file mode 100644
index 000000000..3e2106b57
--- /dev/null
+++ b/src/lib/corelib/generators/generatorversioninfo.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "generatorversioninfo.h"
+
+namespace qbs {
+namespace gen {
+
+VersionInfo::VersionInfo(const Version &version,
+ const std::set<utils::Architecture> &archs)
+ : m_version(version), m_archs(archs)
+{
+}
+
+bool VersionInfo::operator<(const VersionInfo &other) const
+{
+ return m_version < other.m_version;
+}
+
+bool VersionInfo::operator==(const VersionInfo &other) const
+{
+ return m_version == other.m_version
+ && m_archs == other.m_archs;
+}
+
+Version VersionInfo::version() const
+{
+ return m_version;
+}
+
+bool VersionInfo::containsArchitecture(utils::Architecture arch) const
+{
+ return m_archs.find(arch) != m_archs.cend();
+}
+
+int VersionInfo::marketingVersion() const
+{
+ return m_version.majorVersion();
+}
+
+quint32 qHash(const VersionInfo &info)
+{
+ return qHash(info.version().toString());
+}
+
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/generatorversioninfo.h b/src/lib/corelib/generators/generatorversioninfo.h
new file mode 100644
index 000000000..65bfcf685
--- /dev/null
+++ b/src/lib/corelib/generators/generatorversioninfo.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GENERATORS_VERSION_INFO_H
+#define GENERATORS_VERSION_INFO_H
+
+#include "generatorutils.h"
+
+#include <tools/qbs_export.h>
+#include <tools/version.h>
+
+#include <set>
+
+namespace qbs {
+namespace gen {
+
+class QBS_EXPORT VersionInfo
+{
+public:
+ VersionInfo(const Version &version,
+ const std::set<utils::Architecture> &archs);
+ virtual ~VersionInfo() = default;
+
+ bool operator<(const VersionInfo &other) const;
+ bool operator==(const VersionInfo &other) const;
+
+ Version version() const;
+ bool containsArchitecture(utils::Architecture arch) const;
+
+ virtual int marketingVersion() const;
+
+private:
+ Version m_version;
+ std::set<utils::Architecture> m_archs;
+};
+
+quint32 qHash(const VersionInfo &info);
+
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_VERSION_INFO_H
diff --git a/src/lib/corelib/generators/ixmlnodevisitor.h b/src/lib/corelib/generators/ixmlnodevisitor.h
new file mode 100644
index 000000000..d3d118975
--- /dev/null
+++ b/src/lib/corelib/generators/ixmlnodevisitor.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_INODE_VISITOR_H
+#define GENERATORS_XML_INODE_VISITOR_H
+
+#include <tools/qbs_export.h>
+
+#include <QtCore/qxmlstream.h>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class Project;
+class Property;
+class PropertyGroup;
+class Workspace;
+
+class QBS_EXPORT INodeVisitor
+{
+public:
+ virtual ~INodeVisitor() {}
+
+ virtual void visitWorkspaceStart(const Workspace *workspace) { Q_UNUSED(workspace) }
+ virtual void visitWorkspaceEnd(const Workspace *workspace) { Q_UNUSED(workspace) }
+
+ virtual void visitProjectStart(const Project *project) { Q_UNUSED(project) }
+ virtual void visitProjectEnd(const Project *project) { Q_UNUSED(project) }
+
+ virtual void visitPropertyStart(const Property *property) = 0;
+ virtual void visitPropertyEnd(const Property *property) = 0;
+
+ virtual void visitPropertyGroupStart(const PropertyGroup *propertyGroup) = 0;
+ virtual void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) = 0;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_INODE_VISITOR_H
diff --git a/src/lib/corelib/generators/xmlproject.cpp b/src/lib/corelib/generators/xmlproject.cpp
new file mode 100644
index 000000000..e2ac951aa
--- /dev/null
+++ b/src/lib/corelib/generators/xmlproject.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "xmlproject.h"
+#include "ixmlnodevisitor.h"
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+void Project::accept(INodeVisitor *visitor) const
+{
+ visitor->visitProjectStart(this);
+
+ for (const auto &child : children())
+ child->accept(visitor);
+
+ visitor->visitProjectEnd(this);
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlproject.h b/src/lib/corelib/generators/xmlproject.h
new file mode 100644
index 000000000..a7f5b2b65
--- /dev/null
+++ b/src/lib/corelib/generators/xmlproject.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_PROJECT_H
+#define GENERATORS_XML_PROJECT_H
+
+#include "xmlproperty.h"
+
+#include <tools/qbs_export.h>
+
+#include <memory>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class QBS_EXPORT Project : public Property
+{
+public:
+ void accept(INodeVisitor *visitor) const final;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_PROJECT_H
diff --git a/src/lib/corelib/generators/xmlprojectwriter.cpp b/src/lib/corelib/generators/xmlprojectwriter.cpp
new file mode 100644
index 000000000..5554e5935
--- /dev/null
+++ b/src/lib/corelib/generators/xmlprojectwriter.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "xmlproject.h"
+#include "xmlprojectwriter.h"
+#include "xmlproperty.h"
+#include "xmlpropertygroup.h"
+
+#include <ostream>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+ProjectWriter::ProjectWriter(std::ostream *device)
+ : m_device(device)
+{
+ m_writer.reset(new QXmlStreamWriter(&m_buffer));
+ m_writer->setAutoFormatting(true);
+}
+
+bool ProjectWriter::write(const Project *project)
+{
+ m_buffer.clear();
+ m_writer->writeStartDocument();
+ project->accept(this);
+ m_writer->writeEndDocument();
+ if (m_writer->hasError())
+ return false;
+ m_device->write(&*std::begin(m_buffer), m_buffer.size());
+ return m_device->good();
+}
+
+void ProjectWriter::visitPropertyStart(const Property *property)
+{
+ const auto value = property->value().toString();
+ const auto name = QString::fromUtf8(property->name());
+ m_writer->writeTextElement(name, value);
+}
+
+void ProjectWriter::visitPropertyEnd(const Property *property)
+{
+ Q_UNUSED(property)
+}
+
+void ProjectWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup)
+{
+ const auto name = QString::fromUtf8(propertyGroup->name());
+ m_writer->writeStartElement(name);
+}
+
+void ProjectWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup)
+{
+ Q_UNUSED(propertyGroup)
+ m_writer->writeEndElement();
+}
+
+QXmlStreamWriter *ProjectWriter::writer() const
+{
+ return m_writer.get();
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlprojectwriter.h b/src/lib/corelib/generators/xmlprojectwriter.h
new file mode 100644
index 000000000..8198de61c
--- /dev/null
+++ b/src/lib/corelib/generators/xmlprojectwriter.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_PROJECT_WRITER_H
+#define GENERATORS_XML_PROJECT_WRITER_H
+
+#include "ixmlnodevisitor.h"
+
+#include <tools/qbs_export.h>
+
+#include <memory>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class QBS_EXPORT ProjectWriter : public INodeVisitor
+{
+ Q_DISABLE_COPY(ProjectWriter)
+public:
+ explicit ProjectWriter(std::ostream *device);
+ bool write(const Project *project);
+
+protected:
+ QXmlStreamWriter *writer() const;
+
+private:
+ void visitPropertyStart(const Property *property) final;
+ void visitPropertyEnd(const Property *property) final;
+
+ void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final;
+ void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final;
+
+ std::ostream *m_device = nullptr;
+ QByteArray m_buffer;
+ std::unique_ptr<QXmlStreamWriter> m_writer;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_PROJECT_WRITER_H
diff --git a/src/lib/corelib/generators/xmlproperty.cpp b/src/lib/corelib/generators/xmlproperty.cpp
new file mode 100644
index 000000000..2fe5a0147
--- /dev/null
+++ b/src/lib/corelib/generators/xmlproperty.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "ixmlnodevisitor.h"
+#include "xmlproperty.h"
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+Property::Property(QByteArray name, QVariant value)
+{
+ setName(std::move(name));
+ setValue(std::move(value));
+}
+
+void Property::accept(INodeVisitor *visitor) const
+{
+ visitor->visitPropertyStart(this);
+
+ for (const auto &child : children())
+ child->accept(visitor);
+
+ visitor->visitPropertyEnd(this);
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlproperty.h b/src/lib/corelib/generators/xmlproperty.h
new file mode 100644
index 000000000..795735881
--- /dev/null
+++ b/src/lib/corelib/generators/xmlproperty.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_PROPERTY_H
+#define GENERATORS_XML_PROPERTY_H
+
+#include <tools/qbs_export.h>
+
+#include <QtCore/qvariant.h>
+
+#include <memory>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class INodeVisitor;
+
+class QBS_EXPORT Property
+{
+ Q_DISABLE_COPY(Property)
+public:
+ Property() = default;
+ explicit Property(QByteArray name, QVariant value);
+ virtual ~Property() = default;
+
+ QByteArray name() const { return m_name; }
+ void setName(QByteArray name) { m_name = std::move(name); }
+
+ QVariant value() const { return m_value; }
+ void setValue(QVariant value) { m_value = std::move(value); }
+
+ template<class T>
+ T *appendChild(std::unique_ptr<T> child) {
+ const auto p = child.get();
+ m_children.push_back(std::move(child));
+ return p;
+ }
+
+ template<class T, class... Args>
+ T *appendChild(Args&&... args) {
+ return appendChild(std::make_unique<T>(std::forward<Args>(args)...));
+ }
+
+ virtual void accept(INodeVisitor *visitor) const;
+
+protected:
+ const std::vector<std::unique_ptr<Property>> &children() const
+ { return m_children; }
+
+private:
+ QByteArray m_name;
+ QVariant m_value;
+ std::vector<std::unique_ptr<Property>> m_children;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_PROPERTY_H
diff --git a/src/lib/corelib/generators/xmlpropertygroup.cpp b/src/lib/corelib/generators/xmlpropertygroup.cpp
new file mode 100644
index 000000000..398d68e77
--- /dev/null
+++ b/src/lib/corelib/generators/xmlpropertygroup.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "ixmlnodevisitor.h"
+#include "xmlpropertygroup.h"
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+PropertyGroup::PropertyGroup(QByteArray name)
+{
+ setName(std::move(name));
+}
+
+void PropertyGroup::appendProperty(QByteArray name, QVariant value)
+{
+ appendChild<Property>(std::move(name), std::move(value));
+}
+
+void PropertyGroup::appendMultiLineProperty(
+ QByteArray key, QStringList values, QChar sep)
+{
+ const auto line = values.join(std::move(sep));
+ appendProperty(std::move(key), QVariant::fromValue(line));
+}
+
+void PropertyGroup::accept(INodeVisitor *visitor) const
+{
+ visitor->visitPropertyGroupStart(this);
+
+ for (const auto &child : children())
+ child->accept(visitor);
+
+ visitor->visitPropertyGroupEnd(this);
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlpropertygroup.h b/src/lib/corelib/generators/xmlpropertygroup.h
new file mode 100644
index 000000000..e63b515fc
--- /dev/null
+++ b/src/lib/corelib/generators/xmlpropertygroup.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_PROPERTY_GROUP_H
+#define GENERATORS_XML_PROPERTY_GROUP_H
+
+#include "generatorversioninfo.h"
+#include "xmlproperty.h"
+
+#include <tools/qbs_export.h>
+
+#include <memory>
+
+namespace qbs {
+
+class ProductData;
+class Project;
+
+namespace gen {
+namespace xml {
+
+class QBS_EXPORT PropertyGroup : public Property
+{
+public:
+ explicit PropertyGroup(QByteArray name);
+
+ void appendProperty(QByteArray name, QVariant value);
+ void appendMultiLineProperty(QByteArray key, QStringList values,
+ QChar sep = QLatin1Char(','));
+
+ void accept(INodeVisitor *visitor) const final;
+};
+
+class PropertyGroupFactory
+{
+public:
+ virtual ~PropertyGroupFactory() = default;
+ virtual bool canCreate(utils::Architecture arch,
+ const Version &version) const = 0;
+
+ virtual std::unique_ptr<PropertyGroup> create(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const = 0;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_PROPERTY_GROUP_H
diff --git a/src/lib/corelib/generators/xmlworkspace.cpp b/src/lib/corelib/generators/xmlworkspace.cpp
new file mode 100644
index 000000000..7ce3f5164
--- /dev/null
+++ b/src/lib/corelib/generators/xmlworkspace.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ixmlnodevisitor.h"
+#include "xmlproperty.h"
+#include "xmlpropertygroup.h"
+#include "xmlworkspace.h"
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+Workspace::Workspace(const QString &workspacePath)
+ : m_baseDirectory(QFileInfo(workspacePath).absoluteDir())
+{
+}
+
+void Workspace::accept(INodeVisitor *visitor) const
+{
+ visitor->visitWorkspaceStart(this);
+
+ for (const auto &child : children())
+ child->accept(visitor);
+
+ visitor->visitWorkspaceEnd(this);
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlworkspace.h b/src/lib/corelib/generators/xmlworkspace.h
new file mode 100644
index 000000000..beab22c4a
--- /dev/null
+++ b/src/lib/corelib/generators/xmlworkspace.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_WWORKSPACE_H
+#define GENERATORS_XML_WWORKSPACE_H
+
+#include "xmlproperty.h"
+
+#include <tools/qbs_export.h>
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class QBS_EXPORT Workspace : public Property
+{
+public:
+ explicit Workspace(const QString &workspacePath);
+ void accept(INodeVisitor *visitor) const final;
+
+ virtual void addProject(const QString &projectPath) = 0;
+
+protected:
+ const QDir m_baseDirectory;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_WWORKSPACE_H
diff --git a/src/lib/corelib/generators/xmlworkspacewriter.cpp b/src/lib/corelib/generators/xmlworkspacewriter.cpp
new file mode 100644
index 000000000..c88cb06d0
--- /dev/null
+++ b/src/lib/corelib/generators/xmlworkspacewriter.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "xmlproperty.h"
+#include "xmlpropertygroup.h"
+#include "xmlworkspace.h"
+#include "xmlworkspacewriter.h"
+
+#include <ostream>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+WorkspaceWriter::WorkspaceWriter(std::ostream *device)
+ : m_device(device)
+{
+ m_writer.reset(new QXmlStreamWriter(&m_buffer));
+ m_writer->setAutoFormatting(true);
+}
+
+bool WorkspaceWriter::write(const Workspace *workspace)
+{
+ m_buffer.clear();
+ m_writer->writeStartDocument();
+ workspace->accept(this);
+ m_writer->writeEndDocument();
+ if (m_writer->hasError())
+ return false;
+ m_device->write(&*std::begin(m_buffer), m_buffer.size());
+ return m_device->good();
+}
+
+void WorkspaceWriter::visitPropertyStart(const Property *property)
+{
+ const auto value = property->value().toString();
+ const auto name = QString::fromUtf8(property->name());
+ m_writer->writeTextElement(name, value);
+}
+
+void WorkspaceWriter::visitPropertyEnd(const Property *property)
+{
+ Q_UNUSED(property)
+}
+
+void WorkspaceWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup)
+{
+ const auto name = QString::fromUtf8(propertyGroup->name());
+ m_writer->writeStartElement(name);
+}
+
+void WorkspaceWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup)
+{
+ Q_UNUSED(propertyGroup)
+ m_writer->writeEndElement();
+}
+
+QXmlStreamWriter *WorkspaceWriter::writer() const
+{
+ return m_writer.get();
+}
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
diff --git a/src/lib/corelib/generators/xmlworkspacewriter.h b/src/lib/corelib/generators/xmlworkspacewriter.h
new file mode 100644
index 000000000..343face5d
--- /dev/null
+++ b/src/lib/corelib/generators/xmlworkspacewriter.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef GENERATORS_XML_WORKSPACE_WRITER_H
+#define GENERATORS_XML_WORKSPACE_WRITER_H
+
+#include "ixmlnodevisitor.h"
+
+#include <tools/qbs_export.h>
+
+#include <memory>
+
+namespace qbs {
+namespace gen {
+namespace xml {
+
+class QBS_EXPORT WorkspaceWriter : public INodeVisitor
+{
+ Q_DISABLE_COPY(WorkspaceWriter)
+public:
+ explicit WorkspaceWriter(std::ostream *device);
+ bool write(const Workspace *workspace);
+
+protected:
+ QXmlStreamWriter *writer() const;
+
+private:
+ void visitPropertyStart(const Property *property) final;
+ void visitPropertyEnd(const Property *property) final;
+
+ void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final;
+ void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final;
+
+ std::ostream *m_device = nullptr;
+ QByteArray m_buffer;
+ std::unique_ptr<QXmlStreamWriter> m_writer;
+};
+
+} // namespace xml
+} // namespace gen
+} // namespace qbs
+
+#endif // GENERATORS_XML_WORKSPACE_WRITER_H
diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp
index 55a9e1aac..375954133 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.cpp
+++ b/src/lib/corelib/language/evaluatorscriptclass.cpp
@@ -205,7 +205,18 @@ private:
result.second = false;
return result;
}
- SVConverter converter(scriptClass, object, item->property(*propertyName), item,
+ const ValuePtr v = item->property(*propertyName);
+
+ // This can happen when resolving shadow products. The error will be ignored
+ // in that case.
+ if (!v) {
+ const QString errorMessage = Tr::tr("Error setting up 'original'.");
+ extraScope = engine->currentContext()->throwError(errorMessage);
+ result.second = false;
+ return result;
+ }
+
+ SVConverter converter(scriptClass, object, v, item,
propertyName, data, &originalValue);
converter.start();
} else {
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 67d60e05d..9c8f9da1d 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -688,6 +688,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
m_qbsVersion.toString()));
}
+ resolveProbes(&dummyProductContext, projectItem);
+ projectContext.topLevelProject->probes << dummyProductContext.info.probes;
+
handleProfileItems(projectItem, &projectContext);
QList<Item *> multiplexedProducts;
@@ -699,9 +702,6 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
for (Item * const additionalProductItem : qAsConst(multiplexedProducts))
Item::addChild(projectItem, additionalProductItem);
- resolveProbes(&dummyProductContext, projectItem);
- projectContext.topLevelProject->probes << dummyProductContext.info.probes;
-
const QList<Item *> originalChildren = projectItem->children();
for (Item * const child : originalChildren) {
switch (child->type()) {
diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp
index 5507e0842..75417ab0b 100644
--- a/src/lib/corelib/tools/buildoptions.cpp
+++ b/src/lib/corelib/tools/buildoptions.cpp
@@ -38,6 +38,9 @@
****************************************************************************/
#include "buildoptions.h"
+#include "jsonhelper.h"
+
+#include <QtCore/qjsonobject.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qthread.h>
@@ -413,4 +416,56 @@ bool operator==(const BuildOptions &bo1, const BuildOptions &bo2)
&& bo1.removeExistingInstallation() == bo2.removeExistingInstallation();
}
+namespace Internal {
+template<> JobLimits fromJson(const QJsonValue &limitsData)
+{
+ JobLimits limits;
+ const QJsonArray &limitsArray = limitsData.toArray();
+ for (const QJsonValue &v : limitsArray) {
+ const QJsonObject limitData = v.toObject();
+ QString pool;
+ int limit = 0;
+ setValueFromJson(pool, limitData, "pool");
+ setValueFromJson(limit, limitData, "limit");
+ if (!pool.isEmpty() && limit > 0)
+ limits.setJobLimit(pool, limit);
+ }
+ return limits;
+}
+
+template<> CommandEchoMode fromJson(const QJsonValue &modeData)
+{
+ const QString modeString = modeData.toString();
+ if (modeString == QLatin1String("silent"))
+ return CommandEchoModeSilent;
+ if (modeString == QLatin1String("command-line"))
+ return CommandEchoModeCommandLine;
+ if (modeString == QLatin1String("command-line-with-environment"))
+ return CommandEchoModeCommandLineWithEnvironment;
+ return CommandEchoModeSummary;
+}
+} // namespace Internal
+
+qbs::BuildOptions qbs::BuildOptions::fromJson(const QJsonObject &data)
+{
+ using namespace Internal;
+ BuildOptions opt;
+ setValueFromJson(opt.d->changedFiles, data, "changed-files");
+ setValueFromJson(opt.d->filesToConsider, data, "files-to-consider");
+ setValueFromJson(opt.d->activeFileTags, data, "active-file-tags");
+ setValueFromJson(opt.d->jobLimits, data, "job-limits");
+ setValueFromJson(opt.d->maxJobCount, data, "max-job-count");
+ setValueFromJson(opt.d->dryRun, data, "dry-run");
+ setValueFromJson(opt.d->keepGoing, data, "keep-going");
+ setValueFromJson(opt.d->forceTimestampCheck, data, "check-timestamps");
+ setValueFromJson(opt.d->forceOutputCheck, data, "check-outputs");
+ setValueFromJson(opt.d->logElapsedTime, data, "log-time");
+ setValueFromJson(opt.d->echoMode, data, "command-echo-mode");
+ setValueFromJson(opt.d->install, data, "install");
+ setValueFromJson(opt.d->removeExistingInstallation, data, "clean-install-root");
+ setValueFromJson(opt.d->onlyExecuteRules, data, "only-execute-rules");
+ setValueFromJson(opt.d->jobLimitsFromProjectTakePrecedence, data, "enforce-project-job-limits");
+ return opt;
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/buildoptions.h b/src/lib/corelib/tools/buildoptions.h
index cea89d0ea..bd0fb22cb 100644
--- a/src/lib/corelib/tools/buildoptions.h
+++ b/src/lib/corelib/tools/buildoptions.h
@@ -47,6 +47,7 @@
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
+class QJsonObject;
class QStringList;
QT_END_NAMESPACE
@@ -61,6 +62,8 @@ public:
BuildOptions &operator=(const BuildOptions &other);
~BuildOptions();
+ static BuildOptions fromJson(const QJsonObject &data);
+
QStringList filesToConsider() const;
void setFilesToConsider(const QStringList &files);
diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp
index 4fbe77b5d..b888fb1e8 100644
--- a/src/lib/corelib/tools/cleanoptions.cpp
+++ b/src/lib/corelib/tools/cleanoptions.cpp
@@ -38,6 +38,8 @@
****************************************************************************/
#include "cleanoptions.h"
+#include "jsonhelper.h"
+
#include <QtCore/qshareddata.h>
namespace qbs {
@@ -151,4 +153,14 @@ void CleanOptions::setLogElapsedTime(bool log)
d->logElapsedTime = log;
}
+qbs::CleanOptions qbs::CleanOptions::fromJson(const QJsonObject &data)
+{
+ CleanOptions opt;
+ using namespace Internal;
+ setValueFromJson(opt.d->dryRun, data, "dry-run");
+ setValueFromJson(opt.d->keepGoing, data, "keep-going");
+ setValueFromJson(opt.d->logElapsedTime, data, "log-time");
+ return opt;
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/cleanoptions.h b/src/lib/corelib/tools/cleanoptions.h
index 3f67cf5a5..7827697bb 100644
--- a/src/lib/corelib/tools/cleanoptions.h
+++ b/src/lib/corelib/tools/cleanoptions.h
@@ -43,6 +43,10 @@
#include <QtCore/qshareddata.h>
+QT_BEGIN_NAMESPACE
+class QJsonObject;
+QT_END_NAMESPACE
+
namespace qbs {
namespace Internal { class CleanOptionsPrivate; }
@@ -56,6 +60,8 @@ public:
CleanOptions &operator=(CleanOptions &&other) Q_DECL_NOEXCEPT;
~CleanOptions();
+ static CleanOptions fromJson(const QJsonObject &data);
+
bool dryRun() const;
void setDryRun(bool dryRun);
diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp
index 2c6ade3b0..5eff378e1 100644
--- a/src/lib/corelib/tools/codelocation.cpp
+++ b/src/lib/corelib/tools/codelocation.cpp
@@ -41,9 +41,12 @@
#include <tools/fileinfo.h>
#include <tools/persistence.h>
#include <tools/qbsassert.h>
+#include <tools/stringconstants.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qdir.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
#include <QtCore/qregexp.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
@@ -134,6 +137,18 @@ QString CodeLocation::toString() const
return str;
}
+QJsonObject CodeLocation::toJson() const
+{
+ QJsonObject obj;
+ if (!filePath().isEmpty())
+ obj.insert(Internal::StringConstants::filePathKey(), filePath());
+ if (line() != -1)
+ obj.insert(QStringLiteral("line"), line());
+ if (column() != -1)
+ obj.insert(QStringLiteral("column"), column());
+ return obj;
+}
+
void CodeLocation::load(Internal::PersistentPool &pool)
{
const bool isValid = pool.load<bool>();
diff --git a/src/lib/corelib/tools/codelocation.h b/src/lib/corelib/tools/codelocation.h
index 3dc8f26b1..3e84ce2d1 100644
--- a/src/lib/corelib/tools/codelocation.h
+++ b/src/lib/corelib/tools/codelocation.h
@@ -47,6 +47,7 @@
QT_BEGIN_NAMESPACE
class QDataStream;
+class QJsonObject;
class QString;
QT_END_NAMESPACE
@@ -70,6 +71,7 @@ public:
bool isValid() const;
QString toString() const;
+ QJsonObject toJson() const;
void load(Internal::PersistentPool &pool);
void store(Internal::PersistentPool &pool) const;
diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp
index 185dc0531..fc0b9377e 100644
--- a/src/lib/corelib/tools/error.cpp
+++ b/src/lib/corelib/tools/error.cpp
@@ -41,7 +41,10 @@
#include "persistence.h"
#include "qttools.h"
+#include "stringconstants.h"
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstringlist.h>
@@ -156,6 +159,14 @@ QString ErrorItem::toString() const
return str += description();
}
+QJsonObject ErrorItem::toJson() const
+{
+ QJsonObject data;
+ data.insert(Internal::StringConstants::descriptionProperty(), description());
+ data.insert(Internal::StringConstants::locationKey(), codeLocation().toJson());
+ return data;
+}
+
class ErrorInfo::ErrorInfoPrivate : public QSharedData
{
@@ -248,7 +259,7 @@ void ErrorInfo::prepend(const QString &description, const CodeLocation &location
* Most often, there will be one element in this list, but there can be more e.g. to illustrate
* how an error condition propagates through several source files.
*/
-QList<ErrorItem> ErrorInfo::items() const
+const QList<ErrorItem> ErrorInfo::items() const
{
return d->items;
}
@@ -282,6 +293,17 @@ QString ErrorInfo::toString() const
return lines.join(QLatin1Char('\n'));
}
+QJsonObject ErrorInfo::toJson() const
+{
+ QJsonObject data;
+ data.insert(QLatin1String("is-internal"), isInternalError());
+ QJsonArray itemsArray;
+ for (const ErrorItem &item : items())
+ itemsArray.append(item.toJson());
+ data.insert(QLatin1String("items"), itemsArray);
+ return data;
+}
+
/*!
* \brief Returns true if this error represents a bug in qbs, false otherwise.
*/
diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h
index 4832499af..abad85bad 100644
--- a/src/lib/corelib/tools/error.h
+++ b/src/lib/corelib/tools/error.h
@@ -47,6 +47,7 @@
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
+class QJsonObject;
template <class T> class QList;
class QString;
class QStringList;
@@ -68,6 +69,7 @@ public:
QString description() const;
CodeLocation codeLocation() const;
QString toString() const;
+ QJsonObject toJson() const;
bool isBacktraceItem() const;
@@ -97,10 +99,11 @@ public:
void append(const ErrorItem &item);
void append(const QString &description, const CodeLocation &location = CodeLocation());
void prepend(const QString &description, const CodeLocation &location = CodeLocation());
- QList<ErrorItem> items() const;
+ const QList<ErrorItem> items() const;
bool hasError() const { return !items().empty(); }
void clear();
QString toString() const;
+ QJsonObject toJson() const;
bool isInternalError() const;
bool hasLocation() const;
diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp
index 5cddae4ad..93fd54efe 100644
--- a/src/lib/corelib/tools/installoptions.cpp
+++ b/src/lib/corelib/tools/installoptions.cpp
@@ -36,9 +36,13 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
#include "installoptions.h"
-#include "language/language.h"
-#include <tools/stringconstants.h>
+
+#include "jsonhelper.h"
+#include "stringconstants.h"
+
+#include <language/language.h>
#include <QtCore/qdir.h>
#include <QtCore/qshareddata.h>
@@ -230,4 +234,17 @@ void InstallOptions::setLogElapsedTime(bool logElapsedTime)
d->logElapsedTime = logElapsedTime;
}
+qbs::InstallOptions qbs::InstallOptions::fromJson(const QJsonObject &data)
+{
+ using namespace Internal;
+ InstallOptions opt;
+ setValueFromJson(opt.d->installRoot, data, "install-root");
+ setValueFromJson(opt.d->useSysroot, data, "use-sysroot");
+ setValueFromJson(opt.d->removeExisting, data, "clean-install-root");
+ setValueFromJson(opt.d->dryRun, data, "dry-run");
+ setValueFromJson(opt.d->keepGoing, data, "keep-going");
+ setValueFromJson(opt.d->logElapsedTime, data, "log-time");
+ return opt;
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/installoptions.h b/src/lib/corelib/tools/installoptions.h
index 69e00aae5..16511aa3d 100644
--- a/src/lib/corelib/tools/installoptions.h
+++ b/src/lib/corelib/tools/installoptions.h
@@ -44,6 +44,7 @@
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
+class QJsonObject;
class QString;
QT_END_NAMESPACE
@@ -65,6 +66,8 @@ public:
InstallOptions &operator=(InstallOptions &&other) Q_DECL_NOEXCEPT;
~InstallOptions();
+ static InstallOptions fromJson(const QJsonObject &data);
+
static QString defaultInstallRoot();
QString installRoot() const;
void setInstallRoot(const QString &installRoot);
diff --git a/src/lib/corelib/tools/jsonhelper.h b/src/lib/corelib/tools/jsonhelper.h
new file mode 100644
index 000000000..d87802c0a
--- /dev/null
+++ b/src/lib/corelib/tools/jsonhelper.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_JSON_HELPER_H
+#define QBS_JSON_HELPER_H
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+
+#include <algorithm>
+#include <iterator>
+
+namespace qbs {
+namespace Internal {
+
+template<typename T> inline T fromJson(const QJsonValue &v);
+template<> inline bool fromJson(const QJsonValue &v) { return v.toBool(); }
+template<> inline int fromJson(const QJsonValue &v) { return v.toInt(); }
+template<> inline QString fromJson(const QJsonValue &v) { return v.toString(); }
+template<> inline QStringList fromJson(const QJsonValue &v)
+{
+ const QJsonArray &jsonList = v.toArray();
+ QStringList stringList;
+ std::transform(jsonList.begin(), jsonList.end(), std::back_inserter(stringList),
+ [](const QVariant &v) { return v.toString(); });
+ return stringList;
+}
+template<> inline QVariantMap fromJson(const QJsonValue &v) { return v.toObject().toVariantMap(); }
+template<> inline QProcessEnvironment fromJson(const QJsonValue &v)
+{
+ const QJsonObject obj = v.toObject();
+ QProcessEnvironment env;
+ for (auto it = obj.begin(); it != obj.end(); ++it)
+ env.insert(it.key(), it.value().toString());
+ return env;
+}
+
+template<typename T> inline void setValueFromJson(T &targetValue, const QJsonObject &data,
+ const char *jsonProperty)
+{
+ const QJsonValue v = data.value(QLatin1String(jsonProperty));
+ if (!v.isNull())
+ targetValue = fromJson<T>(v);
+}
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp
index 12e45b251..3fb2f8dbc 100644
--- a/src/lib/corelib/tools/processresult.cpp
+++ b/src/lib/corelib/tools/processresult.cpp
@@ -39,6 +39,9 @@
#include "processresult.h"
#include "processresult_p.h"
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+
/*!
* \class SetupProjectParameters
* \brief The \c ProcessResult class describes a finished qbs process command.
@@ -129,4 +132,31 @@ QStringList ProcessResult::stdErr() const
return d->stdErr;
}
+static QJsonValue processErrorToJson(QProcess::ProcessError error)
+{
+ switch (error) {
+ case QProcess::FailedToStart: return QLatin1String("failed-to-start");
+ case QProcess::Crashed: return QLatin1String("crashed");
+ case QProcess::Timedout: return QLatin1String("timed-out");
+ case QProcess::WriteError: return QLatin1String("write-error");
+ case QProcess::ReadError: return QLatin1String("read-error");
+ case QProcess::UnknownError: return QStringLiteral("unknown-error");
+ }
+ return {}; // For dumb compilers.
+}
+
+QJsonObject qbs::ProcessResult::toJson() const
+{
+ return QJsonObject{
+ {QStringLiteral("success"), success()},
+ {QStringLiteral("executable-file-path"), executableFilePath()},
+ {QStringLiteral("arguments"), QJsonArray::fromStringList(arguments())},
+ {QStringLiteral("working-directory"), workingDirectory()},
+ {QStringLiteral("error"), processErrorToJson(error())},
+ {QStringLiteral("exit-code"), exitCode()},
+ {QStringLiteral("stdout"), QJsonArray::fromStringList(stdOut())},
+ {QStringLiteral("stderr"), QJsonArray::fromStringList(stdErr())}
+ };
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/processresult.h b/src/lib/corelib/tools/processresult.h
index 2d2ebbfb4..92408aa31 100644
--- a/src/lib/corelib/tools/processresult.h
+++ b/src/lib/corelib/tools/processresult.h
@@ -46,6 +46,7 @@
#include <QtCore/qprocess.h>
QT_BEGIN_NAMESPACE
+class QJsonObject;
class QString;
class QStringList;
QT_END_NAMESPACE
@@ -65,6 +66,8 @@ public:
ProcessResult &operator=(const ProcessResult &other);
~ProcessResult();
+ QJsonObject toJson() const;
+
bool success() const;
QString executableFilePath() const;
QStringList arguments() const;
diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp
index 6d817c8f3..41af7b926 100644
--- a/src/lib/corelib/tools/setupprojectparameters.cpp
+++ b/src/lib/corelib/tools/setupprojectparameters.cpp
@@ -42,6 +42,7 @@
#include <logging/translator.h>
#include <tools/buildgraphlocker.h>
#include <tools/installoptions.h>
+#include <tools/jsonhelper.h>
#include <tools/profile.h>
#include <tools/qbsassert.h>
#include <tools/scripttools.h>
@@ -50,6 +51,7 @@
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qprocess.h>
+#include <QtCore/qjsonobject.h>
namespace qbs {
namespace Internal {
@@ -69,14 +71,14 @@ public:
, forceProbeExecution(false)
, waitLockBuildGraph(false)
, restoreBehavior(SetupProjectParameters::RestoreAndTrackChanges)
- , propertyCheckingMode(ErrorHandlingMode::Relaxed)
+ , propertyCheckingMode(ErrorHandlingMode::Strict)
, productErrorMode(ErrorHandlingMode::Strict)
{
}
QString projectFilePath;
QString topLevelProfile;
- QString configurationName;
+ QString configurationName = QLatin1String("default");
QString buildRoot;
QStringList searchPaths;
QStringList pluginPaths;
@@ -121,6 +123,47 @@ SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectPara
return *this;
}
+namespace Internal {
+template<> ErrorHandlingMode fromJson(const QJsonValue &v)
+{
+ if (v.toString() == QLatin1String("relaxed"))
+ return ErrorHandlingMode::Relaxed;
+ return ErrorHandlingMode::Strict;
+}
+
+template<> SetupProjectParameters::RestoreBehavior fromJson(const QJsonValue &v)
+{
+ const QString value = v.toString();
+ if (value == QLatin1String("restore-only"))
+ return SetupProjectParameters::RestoreOnly;
+ if (value == QLatin1String("resolve-only"))
+ return SetupProjectParameters::ResolveOnly;
+ return SetupProjectParameters::RestoreAndTrackChanges;
+}
+} // namespace Internal
+
+SetupProjectParameters SetupProjectParameters::fromJson(const QJsonObject &data)
+{
+ using namespace Internal;
+ SetupProjectParameters params;
+ setValueFromJson(params.d->topLevelProfile, data, "top-level-profile");
+ setValueFromJson(params.d->configurationName, data, "configuration-name");
+ setValueFromJson(params.d->projectFilePath, data, "project-file-path");
+ setValueFromJson(params.d->buildRoot, data, "build-root");
+ setValueFromJson(params.d->settingsBaseDir, data, "settings-directory");
+ setValueFromJson(params.d->overriddenValues, data, "overridden-properties");
+ setValueFromJson(params.d->dryRun, data, "dry-run");
+ setValueFromJson(params.d->logElapsedTime, data, "log-time");
+ setValueFromJson(params.d->forceProbeExecution, data, "force-probe-execution");
+ setValueFromJson(params.d->waitLockBuildGraph, data, "wait-lock-build-graph");
+ setValueFromJson(params.d->fallbackProviderEnabled, data, "fallback-provider-enabled");
+ setValueFromJson(params.d->environment, data, "environment");
+ setValueFromJson(params.d->restoreBehavior, data, "restore-behavior");
+ setValueFromJson(params.d->propertyCheckingMode, data, "error-handling-mode");
+ params.d->productErrorMode = params.d->propertyCheckingMode;
+ return params;
+}
+
SetupProjectParameters &SetupProjectParameters::operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default;
/*!
diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h
index cf3b200cb..a4d090ec5 100644
--- a/src/lib/corelib/tools/setupprojectparameters.h
+++ b/src/lib/corelib/tools/setupprojectparameters.h
@@ -71,6 +71,8 @@ public:
SetupProjectParameters &operator=(const SetupProjectParameters &other);
SetupProjectParameters &operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT;
+ static SetupProjectParameters fromJson(const QJsonObject &data);
+
QString topLevelProfile() const;
void setTopLevelProfile(const QString &profile);
diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h
index cd41f3768..79cbcd125 100644
--- a/src/lib/corelib/tools/stringconstants.h
+++ b/src/lib/corelib/tools/stringconstants.h
@@ -69,6 +69,7 @@ public:
QBS_STRING_CONSTANT(baseNameProperty, "baseName")
QBS_STRING_CONSTANT(baseProfileProperty, "baseProfile")
QBS_STRING_CONSTANT(buildDirectoryProperty, "buildDirectory")
+ QBS_STRING_CONSTANT(buildDirectoryKey, "build-directory")
QBS_STRING_CONSTANT(builtByDefaultProperty, "builtByDefault")
QBS_STRING_CONSTANT(classNameProperty, "className")
QBS_STRING_CONSTANT(completeBaseNameProperty, "completeBaseName")
@@ -90,11 +91,13 @@ public:
static const QString &fileNameProperty() { return fileName(); }
static const QString &filePathProperty() { return filePath(); }
static const QString &filePathVar() { return filePath(); }
+ QBS_STRING_CONSTANT(filePathKey, "file-path")
QBS_STRING_CONSTANT(fileTagsFilterProperty, "fileTagsFilter")
QBS_STRING_CONSTANT(fileTagsProperty, "fileTags")
QBS_STRING_CONSTANT(filesProperty, "files")
QBS_STRING_CONSTANT(filesAreTargetsProperty, "filesAreTargets")
QBS_STRING_CONSTANT(foundProperty, "found")
+ QBS_STRING_CONSTANT(fullDisplayNameKey, "full-display-name")
QBS_STRING_CONSTANT(imports, "imports")
static const QString &importsDir() { return imports(); }
static const QString &importsProperty() { return imports(); }
@@ -106,12 +109,16 @@ public:
QBS_STRING_CONSTANT(installPrefixProperty, "installPrefix")
QBS_STRING_CONSTANT(installDirProperty, "installDir")
QBS_STRING_CONSTANT(installSourceBaseProperty, "installSourceBase")
+ QBS_STRING_CONSTANT(isEnabledKey, "is-enabled")
QBS_STRING_CONSTANT(jobCountProperty, "jobCount")
QBS_STRING_CONSTANT(jobPoolProperty, "jobPool")
QBS_STRING_CONSTANT(lengthProperty, "length")
QBS_STRING_CONSTANT(limitToSubProjectProperty, "limitToSubProject")
+ QBS_STRING_CONSTANT(locationKey, "location")
+ QBS_STRING_CONSTANT(messageKey, "message")
QBS_STRING_CONSTANT(minimumQbsVersionProperty, "minimumQbsVersion")
QBS_STRING_CONSTANT(moduleNameProperty, "moduleName")
+ QBS_STRING_CONSTANT(modulePropertiesKey, "module-properties")
QBS_STRING_CONSTANT(moduleProviders, "moduleProviders")
QBS_STRING_CONSTANT(multiplexByQbsPropertiesProperty, "multiplexByQbsProperties")
QBS_STRING_CONSTANT(multiplexConfigurationIdProperty, "multiplexConfigurationId")
@@ -135,6 +142,7 @@ public:
QBS_STRING_CONSTANT(profileProperty, "profile")
static const QString &profilesProperty() { return profiles(); }
QBS_STRING_CONSTANT(productTypesProperty, "productTypes")
+ QBS_STRING_CONSTANT(productsKey, "products")
QBS_STRING_CONSTANT(qbsSearchPathsProperty, "qbsSearchPaths")
QBS_STRING_CONSTANT(referencesProperty, "references")
QBS_STRING_CONSTANT(recursiveProperty, "recursive")
@@ -149,7 +157,8 @@ public:
QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory")
QBS_STRING_CONSTANT(submodulesProperty, "submodules")
QBS_STRING_CONSTANT(targetNameProperty, "targetName")
- QBS_STRING_CONSTANT(typeProperty, "type")
+ static const QString &typeProperty() { return type(); }
+ QBS_STRING_CONSTANT(type, "type")
QBS_STRING_CONSTANT(validateProperty, "validate")
QBS_STRING_CONSTANT(versionProperty, "version")
QBS_STRING_CONSTANT(versionAtLeastProperty, "versionAtLeast")
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index f9c6be9a5..89d752671 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -23,6 +23,7 @@ HEADERS += \
$$PWD/iosutils.h \
$$PWD/joblimits.h \
$$PWD/jsliterals.h \
+ $$PWD/jsonhelper.h \
$$PWD/launcherinterface.h \
$$PWD/launcherpackets.h \
$$PWD/launchersocket.h \
diff --git a/src/lib/corelib/tools/version.cpp b/src/lib/corelib/tools/version.cpp
index d2b337d3a..dfb7f49b7 100644
--- a/src/lib/corelib/tools/version.cpp
+++ b/src/lib/corelib/tools/version.cpp
@@ -105,13 +105,17 @@ Version Version::fromString(const QString &versionString, bool buildNumberAllowe
return Version{majorNr, minorNr, patchNr, buildNr};
}
-QString Version::toString() const
+QString Version::toString(const QChar &separator, const QChar &buildSeparator) const
{
if (m_build) {
- return QString(QStringLiteral("%1.%2.%3-%4"))
- .arg(m_major).arg(m_minor).arg(m_patch).arg(m_build);
+ return QStringLiteral("%1%5%2%5%3%6%4")
+ .arg(QString::number(m_major), QString::number(m_minor),
+ QString::number(m_patch), QString::number(m_build),
+ separator, buildSeparator);
}
- return QString(QStringLiteral("%1.%2.%3")).arg(m_major).arg(m_minor).arg(m_patch);
+ return QStringLiteral("%1%4%2%4%3")
+ .arg(QString::number(m_major), QString::number(m_minor),
+ QString::number(m_patch), separator);
}
int compare(const Version &lhs, const Version &rhs)
diff --git a/src/lib/corelib/tools/version.h b/src/lib/corelib/tools/version.h
index 4f5e46500..a0239a6e4 100644
--- a/src/lib/corelib/tools/version.h
+++ b/src/lib/corelib/tools/version.h
@@ -42,6 +42,7 @@
#include "qbs_export.h"
+#include <QtCore/qchar.h>
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -71,7 +72,8 @@ public:
void setBuildNumber(int nr);
static Version fromString(const QString &versionString, bool buildNumberAllowed = false);
- QString toString() const;
+ QString toString(const QChar &separator = QLatin1Char('.'),
+ const QChar &buildSeparator = QLatin1Char('-')) const;
private:
int m_major;
diff --git a/src/plugins/generator/generator.pro b/src/plugins/generator/generator.pro
index 1607aa14d..4a3861321 100644
--- a/src/plugins/generator/generator.pro
+++ b/src/plugins/generator/generator.pro
@@ -1,2 +1,6 @@
TEMPLATE = subdirs
-SUBDIRS = clangcompilationdb makefilegenerator visualstudio
+SUBDIRS += clangcompilationdb
+SUBDIRS += makefilegenerator
+SUBDIRS += visualstudio
+SUBDIRS += iarew
+SUBDIRS += keiluv
diff --git a/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.cpp
new file mode 100644
index 000000000..cc0750627
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armarchiversettingsgroup_v8.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+constexpr int kArchiverArchiveVersion = 0;
+constexpr int kArchiverDataVersion = 0;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ outputFile = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory, qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+} // namespace
+
+// ArmArchiverSettingsGroup
+
+ArmArchiverSettingsGroup::ArmArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("IARCHIVE"));
+ setArchiveVersion(kArchiverArchiveVersion);
+ setDataVersion(kArchiverDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void ArmArchiverSettingsGroup::buildOutputPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'IarchiveOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("IarchiveOverride"),
+ {1});
+ // Add 'IarchiveOutput' item (Output filename).
+ addOptionsGroup(QByteArrayLiteral("IarchiveOutput"),
+ {opts.outputFile});
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.h
new file mode 100644
index 000000000..c99c2eeba
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armarchiversettingsgroup_v8.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMAARCHIVERSETTINGSGROUP_V8_H
+#define QBS_IAREWARMAARCHIVERSETTINGSGROUP_V8_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmArchiverSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit ArmArchiverSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMAARCHIVERSETTINGSGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.cpp
new file mode 100644
index 000000000..66c4c9ee6
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armassemblersettingsgroup_v8.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+constexpr int kAssemblerArchiveVersion = 2;
+constexpr int kAssemblerDataVersion = 10;
+
+namespace {
+
+// Language page options.
+
+struct LanguagePageOptions final
+{
+ enum MacroQuoteCharacter {
+ AngleBracketsQuote,
+ RoundBracketsQuote,
+ SquareBracketsQuote,
+ FigureBracketsQuote
+ };
+
+ explicit LanguagePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleAssemblerFlags(qbsProps);
+ enableSymbolsCaseSensitive = flags.contains(QLatin1String("-s+"));
+ allowAlternativeRegister = flags.contains(QLatin1String("-j"));
+ disableCodeMemoryDataReads = flags.contains(
+ QLatin1String("--no_literal_pool"));
+ if (flags.contains(QLatin1String("-M<>")))
+ macroQuoteCharacter = LanguagePageOptions::AngleBracketsQuote;
+ else if (flags.contains(QLatin1String("-M()")))
+ macroQuoteCharacter = LanguagePageOptions::RoundBracketsQuote;
+ else if (flags.contains(QLatin1String("-M[]")))
+ macroQuoteCharacter = LanguagePageOptions::SquareBracketsQuote;
+ else if (flags.contains(QLatin1String("-M{}")))
+ macroQuoteCharacter = LanguagePageOptions::FigureBracketsQuote;
+ }
+
+ MacroQuoteCharacter macroQuoteCharacter = AngleBracketsQuote;
+ int enableSymbolsCaseSensitive = 0;
+ int allowAlternativeRegister = 0;
+ int disableCodeMemoryDataReads = 0;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ for (const QString &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString warningLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ if (warningLevel == QLatin1String("all")) {
+ enableWarnings = 0;
+ enableAllWarnings = 0;
+ } else if (warningLevel == QLatin1String("none")) {
+ enableWarnings = 1;
+ enableAllWarnings = 0;
+ } else {
+ enableWarnings = 0;
+ enableAllWarnings = 1;
+ }
+ }
+
+ int enableWarnings = 0;
+ int enableAllWarnings = 0;
+};
+
+} // namespace
+
+// ArmAssemblerSettingsGroup
+
+ArmAssemblerSettingsGroup::ArmAssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("AARM"));
+ setArchiveVersion(kAssemblerArchiveVersion);
+ setDataVersion(kAssemblerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildLanguagePage(qbsProduct);
+ buildOutputPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+}
+
+void ArmAssemblerSettingsGroup::buildLanguagePage(
+ const ProductData &qbsProduct)
+{
+ const LanguagePageOptions opts(qbsProduct);
+ // Add 'ACaseSensitivity' item (User symbols are case sensitive).
+ addOptionsGroup(QByteArrayLiteral("ACaseSensitivity"),
+ {opts.enableSymbolsCaseSensitive});
+ // Add 'AltRegisterNames' item (Allow alternative register names,
+ // mnemonics and operands).
+ addOptionsGroup(QByteArrayLiteral("AltRegisterNames"),
+ {opts.allowAlternativeRegister});
+ // Add 'AsmNoLiteralPool' item (No data reads in code memory).
+ addOptionsGroup(QByteArrayLiteral("AsmNoLiteralPool"),
+ {opts.disableCodeMemoryDataReads});
+ // Add 'MacroChars' item (Macro quote characters: ()/[]/{}/<>).
+ addOptionsGroup(QByteArrayLiteral("MacroChars"),
+ {opts.macroQuoteCharacter}, 0);
+}
+void ArmAssemblerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'ADebug' item (Generate debug information).
+ addOptionsGroup(QByteArrayLiteral("ADebug"),
+ {opts.debugInfo});
+}
+
+void ArmAssemblerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'ADefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("ADefines"),
+ opts.defineSymbols);
+ // Add 'AUserIncludes' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("AUserIncludes"),
+ opts.includePaths);
+}
+
+void ArmAssemblerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'AWarnEnable' item (Enable/disable warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnEnable"),
+ {opts.enableWarnings});
+ // Add 'AWarnWhat' item (Enable/disable all warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnWhat"),
+ {opts.enableAllWarnings});
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.h
new file mode 100644
index 000000000..620dcf1f5
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armassemblersettingsgroup_v8.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMASSEMBLERSETTINGSGROUP_V8_H
+#define QBS_IAREWARMASSEMBLERSETTINGSGROUP_V8_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmAssemblerSettingsGroup final
+ : public IarewSettingsPropertyGroup
+{
+public:
+ explicit ArmAssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildLanguagePage(const ProductData &qbsProduct);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMASSEMBLERSETTINGSGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.cpp
new file mode 100644
index 000000000..a16e57a42
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armarchiversettingsgroup_v8.h"
+#include "armassemblersettingsgroup_v8.h"
+#include "armbuildconfigurationgroup_v8.h"
+#include "armcompilersettingsgroup_v8.h"
+#include "armgeneralsettingsgroup_v8.h"
+#include "armlinkersettingsgroup_v8.h"
+
+#include "../../iarewtoolchainpropertygroup.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+ArmBuildConfigurationGroup::ArmBuildConfigurationGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup("configuration")
+{
+ // Append configuration name item.
+ const QString cfgName = gen::utils::buildConfigurationName(qbsProject);
+ appendProperty("name", cfgName);
+
+ // Apend toolchain name group item.
+ appendChild<IarewToolchainPropertyGroup>("ARM");
+
+ // Append debug info item.
+ const int debugBuild = gen::utils::debugInformation(qbsProduct);
+ appendProperty("debug", debugBuild);
+
+ // Append settings group items.
+ appendChild<ArmArchiverSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<ArmAssemblerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<ArmCompilerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<ArmGeneralSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<ArmLinkerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+}
+
+bool ArmBuildConfigurationGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Arm
+ && version.majorVersion() == 8;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+ArmBuildConfigurationGroupFactory::create(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const
+{
+ const auto group = new ArmBuildConfigurationGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<ArmBuildConfigurationGroup>(group);
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.h
new file mode 100644
index 000000000..26370c9b8
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armbuildconfigurationgroup_v8.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMBUILDCONFIGURATIONGROUP_V8_H
+#define QBS_IAREWARMBUILDCONFIGURATIONGROUP_V8_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmBuildConfigurationGroup final
+ : public gen::xml::PropertyGroup
+{
+private:
+ explicit ArmBuildConfigurationGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+ friend class ArmBuildConfigurationGroupFactory;
+};
+
+class ArmBuildConfigurationGroupFactory final
+ : public gen::xml::PropertyGroupFactory
+{
+public:
+ bool canCreate(gen::utils::Architecture arch,
+ const Version &version) const final;
+
+ std::unique_ptr<gen::xml::PropertyGroup> create(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const final;
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMBUILDCONFIGURATIONGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.cpp
new file mode 100644
index 000000000..0981fade4
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.cpp
@@ -0,0 +1,478 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armcompilersettingsgroup_v8.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+constexpr int kCompilerArchiveVersion = 2;
+constexpr int kCompilerDataVersion = 34;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// Language 1 page options.
+
+struct LanguageOnePageOptions final
+{
+ enum LanguageExtension {
+ CLanguageExtension,
+ CxxLanguageExtension,
+ AutoLanguageExtension
+ };
+
+ enum CLanguageDialect {
+ C89LanguageDialect,
+ C11LanguageDialect
+ };
+
+ enum LanguageConformance {
+ AllowIarExtension,
+ RelaxedStandard,
+ StrictStandard
+ };
+
+ explicit LanguageOnePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ // File extension based by default.
+ languageExtension = LanguageOnePageOptions::AutoLanguageExtension;
+ // Language dialect.
+ const QStringList cLanguageVersion = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("cLanguageVersion")});
+ cLanguageDialect = cLanguageVersion.contains(QLatin1String("c89"))
+ ? LanguageOnePageOptions::C89LanguageDialect
+ : LanguageOnePageOptions::C11LanguageDialect;
+
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ // Language conformance.
+ if (flags.contains(QLatin1String("-e")))
+ languageConformance = LanguageOnePageOptions::AllowIarExtension;
+ else if (flags.contains(QLatin1String("--strict")))
+ languageConformance = LanguageOnePageOptions::StrictStandard;
+ else
+ languageConformance = LanguageOnePageOptions::RelaxedStandard;
+ // Exceptions, rtti, static desrtuction.
+ enableExceptions = !flags.contains(QLatin1String("--no_exceptions"));
+ enableRtti = !flags.contains(QLatin1String("--no_rtti"));
+ destroyStaticObjects = !flags.contains(
+ QLatin1String("--no_static_destruction"));
+ allowVla = flags.contains(QLatin1String("--vla"));
+ enableInlineSemantics = flags.contains(QLatin1String("--use_c++_inline"));
+ requirePrototypes = flags.contains(QLatin1String("--require_prototypes"));
+ }
+
+ LanguageExtension languageExtension = AutoLanguageExtension;
+ CLanguageDialect cLanguageDialect = C89LanguageDialect;
+ LanguageConformance languageConformance = AllowIarExtension;
+ // C++ options.
+ int enableExceptions = 0;
+ int enableRtti = 0;
+ int destroyStaticObjects = 0;
+ int allowVla = 0;
+ int enableInlineSemantics = 0;
+ int requirePrototypes = 0;
+};
+
+// Language 2 page options.
+
+struct LanguageTwoPageOptions final
+{
+ enum PlainCharacter {
+ SignedCharacter,
+ UnsignedCharacter
+ };
+
+ enum FloatingPointSemantic {
+ StrictSemantic,
+ RelaxedSemantic
+ };
+
+ explicit LanguageTwoPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ plainCharacter = flags.contains(QLatin1String("--char_is_signed"))
+ ? LanguageTwoPageOptions::SignedCharacter
+ : LanguageTwoPageOptions::UnsignedCharacter;
+ floatingPointSemantic = flags.contains(QLatin1String("--relaxed_fp"))
+ ? LanguageTwoPageOptions::RelaxedSemantic
+ : LanguageTwoPageOptions::StrictSemantic;
+ }
+
+ PlainCharacter plainCharacter = SignedCharacter;
+ FloatingPointSemantic floatingPointSemantic = StrictSemantic;
+};
+
+// Optimizations page options.
+
+struct OptimizationsPageOptions final
+{
+ // Optimizations level radio-buttons with
+ // combo-box on "level" widget.
+
+ enum Strategy {
+ StrategyBalanced,
+ StrategySize,
+ StrategySpeed
+ };
+
+ enum Level {
+ LevelNone,
+ LevelLow,
+ LevelMedium,
+ LevelHigh
+ };
+
+ enum LevelSlave {
+ LevelSlave0,
+ LevelSlave1,
+ LevelSlave2,
+ LevelSlave3
+ };
+
+ explicit OptimizationsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString optimization = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("optimization"));
+ if (optimization == QLatin1String("none")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategyBalanced;
+ optimizationLevel = OptimizationsPageOptions::LevelNone;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave0;
+ } else if (optimization == QLatin1String("fast")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySpeed;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ } else if (optimization == QLatin1String("small")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySize;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ }
+
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ enableCommonSubexpressionElimination = !flags.contains(
+ QLatin1String("--no_cse"));
+ enableLoopUnroll = !flags.contains(
+ QLatin1String("--no_unroll"));
+ enableFunctionInlining = !flags.contains(
+ QLatin1String("--no_inline"));
+ enableCodeMotion = !flags.contains(
+ QLatin1String("--no_code_motion"));
+ enableTypeBasedAliasAnalysis = !flags.contains(
+ QLatin1String("--no_tbaa"));
+ enableStaticClustering = !flags.contains(
+ QLatin1String("--no_clustering"));
+ enableInstructionScheduling = !flags.contains(
+ QLatin1String("--no_scheduling"));
+ enableVectorization = flags.contains(
+ QLatin1String("--vectorize"));
+ disableSizeConstraints = flags.contains(
+ QLatin1String("--no_size_constraints"));
+ }
+
+ Strategy optimizationStrategy = StrategyBalanced;
+ Level optimizationLevel = LevelNone;
+ LevelSlave optimizationLevelSlave = LevelSlave0;
+ // Eight bit-field flags on "enabled optimizations" widget.
+ int enableCommonSubexpressionElimination = 0; // Common sub-expression elimination.
+ int enableLoopUnroll = 0; // Loop unrolling.
+ int enableFunctionInlining = 0; // Function inlining.
+ int enableCodeMotion = 0; // Code motion.
+ int enableTypeBasedAliasAnalysis = 0; // Type-based alias analysis.
+ int enableStaticClustering = 0; // Static clustering.
+ int enableInstructionScheduling = 0; // Instruction scheduling.
+ int enableVectorization = 0; // Vectorization.
+
+ // Separate "no size constraints" checkbox.
+ int disableSizeConstraints = 0;
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ for (const QString &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ treatWarningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int treatWarningsAsErrors = 0;
+};
+
+// Code page options.
+
+struct CodePageOptions final
+{
+ enum ProcessorMode {
+ CpuArmMode,
+ CpuThumbMode
+ };
+
+ explicit CodePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ const QString cpuModeValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--cpu_mode"));
+ if (cpuModeValue == QLatin1String("thumb"))
+ cpuMode = CodePageOptions::CpuThumbMode;
+ else if (cpuModeValue == QLatin1String("arm"))
+ cpuMode = CodePageOptions::CpuArmMode;
+
+ generateReadOnlyPosIndependentCode = flags.contains(
+ QLatin1String("--ropi"));
+ generateReadWritePosIndependentCode = flags.contains(
+ QLatin1String("--rwpi"));
+ disableDynamicReadWriteInitialization = flags.contains(
+ QLatin1String("--no_rw_dynamic_init"));
+ disableCodeMemoryDataReads = flags.contains(
+ QLatin1String("--no_literal_pool"));
+ }
+
+ ProcessorMode cpuMode = CpuThumbMode;
+ int generateReadOnlyPosIndependentCode = 0;
+ int generateReadWritePosIndependentCode = 0;
+ int disableDynamicReadWriteInitialization = 0;
+ int disableCodeMemoryDataReads = 0;
+};
+
+} // namespace
+
+// ArmCompilerSettingsGroup
+
+ArmCompilerSettingsGroup::ArmCompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ICCARM"));
+ setArchiveVersion(kCompilerArchiveVersion);
+ setDataVersion(kCompilerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildOutputPage(qbsProduct);
+ buildLanguageOnePage(qbsProduct);
+ buildLanguageTwoPage(qbsProduct);
+ buildOptimizationsPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+ buildCodePage(qbsProduct);
+}
+
+void ArmCompilerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'CCDebugInfo' item (Generate debug info).
+ addOptionsGroup(QByteArrayLiteral("CCDebugInfo"),
+ {opts.debugInfo});
+}
+
+void ArmCompilerSettingsGroup::buildLanguageOnePage(
+ const ProductData &qbsProduct)
+{
+ const LanguageOnePageOptions opts(qbsProduct);
+ // Add 'IccLang' item with 'auto-extension based'
+ // value (Language: C/C++/Auto).
+ addOptionsGroup(QByteArrayLiteral("IccLang"),
+ {opts.languageExtension});
+ // Add 'IccCDialect' item (C dialect: c89/99/11).
+ addOptionsGroup(QByteArrayLiteral("IccCDialect"),
+ {opts.cLanguageDialect});
+ // Add 'CCExt' item (Language conformance: IAR/relaxed/strict).
+ addOptionsGroup(QByteArrayLiteral("CCLangConformance"),
+ {opts.languageConformance});
+ // Add 'IccExceptions2' item (Enable exceptions).
+ addOptionsGroup(QByteArrayLiteral("IccExceptions2"),
+ {opts.enableExceptions});
+ // Add 'IccRTTI2' item (Enable RTTI).
+ addOptionsGroup(QByteArrayLiteral("IccRTTI2"),
+ {opts.enableRtti});
+ // Add 'IccStaticDestr' item (Destroy static objects).
+ addOptionsGroup(QByteArrayLiteral("IccStaticDestr"),
+ {opts.destroyStaticObjects});
+ // Add 'IccAllowVLA' item (Allow VLA).
+ addOptionsGroup(QByteArrayLiteral("IccAllowVLA"),
+ {opts.allowVla});
+ // Add 'IccCppInlineSemantics' item (C++ inline semantics).
+ addOptionsGroup(QByteArrayLiteral("IccCppInlineSemantics"),
+ {opts.enableInlineSemantics});
+ // Add 'CCRequirePrototypes' item (Require prototypes).
+ addOptionsGroup(QByteArrayLiteral("CCRequirePrototypes"),
+ {opts.requirePrototypes});
+}
+
+void ArmCompilerSettingsGroup::buildLanguageTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LanguageTwoPageOptions opts(qbsProduct);
+ // Add 'CCSignedPlainChar' item (Plain char is: signed/unsigned).
+ addOptionsGroup(QByteArrayLiteral("CCSignedPlainChar"),
+ {opts.plainCharacter});
+ // Add 'IccFloatSemantics' item
+ // (Floating-point semantic: strict/relaxed).
+ addOptionsGroup(QByteArrayLiteral("IccFloatSemantics"),
+ {opts.floatingPointSemantic});
+}
+
+void ArmCompilerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ const OptimizationsPageOptions opts(qbsProduct);
+ // Add 'CCOptStrategy', 'CCOptLevel'
+ // and 'CCOptLevelSlave' items (Level).
+ addOptionsGroup(QByteArrayLiteral("CCOptStrategy"),
+ {opts.optimizationStrategy});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevel"),
+ {opts.optimizationLevel});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevelSlave"),
+ {opts.optimizationLevelSlave});
+ // Add 'CCAllowList' item (Enabled optimizations: 6 check boxes).
+ const QString transformations = QStringLiteral("%1%2%3%4%5%6%7%8")
+ .arg(opts.enableCommonSubexpressionElimination)
+ .arg(opts.enableLoopUnroll)
+ .arg(opts.enableFunctionInlining)
+ .arg(opts.enableCodeMotion)
+ .arg(opts.enableTypeBasedAliasAnalysis)
+ .arg(opts.enableStaticClustering)
+ .arg(opts.enableInstructionScheduling)
+ .arg(opts.enableVectorization);
+ addOptionsGroup(QByteArrayLiteral("CCAllowList"),
+ {transformations});
+ // Add 'CCOptimizationNoSizeConstraints' item (No size constraints).
+ addOptionsGroup(QByteArrayLiteral("CCOptimizationNoSizeConstraints"),
+ {opts.disableSizeConstraints});
+}
+
+void ArmCompilerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'CCDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("CCDefines"),
+ opts.defineSymbols);
+ // Add 'CCIncludePath2' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("CCIncludePath2"),
+ opts.includePaths);
+}
+
+void ArmCompilerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'CCDiagWarnAreErr' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("CCDiagWarnAreErr"),
+ {opts.treatWarningsAsErrors});
+}
+
+void ArmCompilerSettingsGroup::buildCodePage(
+ const ProductData &qbsProduct)
+{
+ const CodePageOptions opts(qbsProduct);
+ // Add 'IProcessorMode2' item (Processor mode: arm/thumb).
+ addOptionsGroup(QByteArrayLiteral("IProcessorMode2"),
+ {opts.cpuMode});
+ // Add 'CCPosIndRopi' item (Code and read-only data "ropi").
+ addOptionsGroup(QByteArrayLiteral("CCPosIndRopi"),
+ {opts.generateReadOnlyPosIndependentCode});
+ // Add 'CCPosIndRwpi' item (Read/write data "rwpi").
+ addOptionsGroup(QByteArrayLiteral("CCPosIndRwpi"),
+ {opts.generateReadWritePosIndependentCode});
+ // Add 'CCPosIndNoDynInit' item (No dynamic read/write initialization).
+ addOptionsGroup(QByteArrayLiteral("CCPosIndNoDynInit"),
+ {opts.disableDynamicReadWriteInitialization});
+ // Add 'CCNoLiteralPool' item (No data reads in code memory).
+ addOptionsGroup(QByteArrayLiteral("CCNoLiteralPool"),
+ {opts.disableCodeMemoryDataReads});
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.h
new file mode 100644
index 000000000..6137bc976
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armcompilersettingsgroup_v8.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMCOMPILERSETTINGSGROUP_V8_H
+#define QBS_IAREWARMCOMPILERSETTINGSGROUP_V8_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmCompilerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit ArmCompilerSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildLanguageOnePage(const ProductData &qbsProduct);
+ void buildLanguageTwoPage(const ProductData &qbsProduct);
+ void buildOptimizationsPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory, const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildCodePage(const ProductData &qbsProduct);
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMCOMPILERSETTINGSGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp
new file mode 100644
index 000000000..911873cf4
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp
@@ -0,0 +1,551 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armgeneralsettingsgroup_v8.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+constexpr int kGeneralArchiveVersion = 3;
+constexpr int kGeneralDataVersion = 30;
+
+namespace {
+
+struct CpuCoreEntry final
+{
+ enum CpuCoreCode {
+ Arm7tdmi = 0,
+ Arm7tdmis = 1,
+ Arm710t = 2,
+ Arm720t = 3,
+ Arm740t = 4,
+ Arm7ejs = 5,
+ Arm9tdmi = 6,
+ Arm920t = 7,
+ Arm922t = 8,
+ Arm940t = 9,
+ Arm9e = 10,
+ Arm9es = 11,
+ Arm926ejs = 12,
+ Arm946es = 13,
+ Arm966es = 14,
+ Arm968es = 15,
+ Arm10e = 16,
+ Arm1020e = 17,
+ Arm1022e = 18,
+ Arm1026ejs = 19,
+ Arm1136j = 20,
+ Arm1136js = 21,
+ Arm1176j = 24,
+ Arm1176js = 25,
+ Xscale = 32,
+ XscaleIr7 = 33,
+ CortexM0 = 34,
+ CortexM0Plus = 35,
+ CortexM1 = 36,
+ CortexMs1 = 37,
+ CortexM3 = 38,
+ CortexM4 = 39,
+ CortexM7 = 41,
+ CortexR4 = 42,
+ CortexR5 = 44,
+ CortexR7 = 46,
+ CortexR8 = 48,
+ CortexR52 = 49,
+ CortexA5 = 50,
+ CortexA7 = 52,
+ CortexA8 = 53,
+ CortexA9 = 54,
+ CortexA15 = 55,
+ CortexA17 = 56,
+ CortexM23 = 58,
+ CortexM33 = 59
+ };
+
+ // Required to compile in MSVC2015.
+ CpuCoreEntry(CpuCoreCode cc, QByteArray tf)
+ : coreCode(cc), targetFlag(std::move(tf))
+ {}
+
+ CpuCoreCode coreCode = Arm7tdmi;
+ QByteArray targetFlag;
+};
+
+// Dictionary of known ARM CPU cores and its compiler options.
+static const CpuCoreEntry cpusDict[] = {
+ {CpuCoreEntry::Arm7tdmi, "arm7tdmi"}, // same as 'sc100'
+ {CpuCoreEntry::Arm7tdmis, "arm7tdmi-s"},
+ {CpuCoreEntry::Arm710t, "arm710t"},
+ {CpuCoreEntry::Arm720t, "arm720t"},
+ {CpuCoreEntry::Arm740t, "arm740t"},
+ {CpuCoreEntry::Arm7ejs, "arm7ej-s"},
+ {CpuCoreEntry::Arm9tdmi, "arm9tdmi"},
+ {CpuCoreEntry::Arm920t, "arm920t"},
+ {CpuCoreEntry::Arm922t, "arm922t"},
+ {CpuCoreEntry::Arm940t, "arm940t"},
+ {CpuCoreEntry::Arm9e, "arm9e"},
+ {CpuCoreEntry::Arm9es, "arm9e-s"},
+ {CpuCoreEntry::Arm926ejs, "arm926ej-s"},
+ {CpuCoreEntry::Arm946es, "arm946e-s"},
+ {CpuCoreEntry::Arm966es, "arm966e-s"},
+ {CpuCoreEntry::Arm968es, "arm968e-s"},
+ {CpuCoreEntry::Arm10e, "arm10e"},
+ {CpuCoreEntry::Arm1020e, "arm1020e"},
+ {CpuCoreEntry::Arm1022e, "arm1022e"},
+ {CpuCoreEntry::Arm1026ejs, "arm1026ej-s"},
+ {CpuCoreEntry::Arm1136j, "arm1136j"},
+ {CpuCoreEntry::Arm1136js, "arm1136j-s"},
+ {CpuCoreEntry::Arm1176j, "arm1176j"},
+ {CpuCoreEntry::Arm1176js, "arm1176j-s"},
+ {CpuCoreEntry::Xscale, "xscale"},
+ {CpuCoreEntry::XscaleIr7, "xscale-ir7"},
+ {CpuCoreEntry::CortexM0, "cortex-m0"},
+ {CpuCoreEntry::CortexM0Plus, "cortex-m0+"}, // same as 'sc000'
+ {CpuCoreEntry::CortexM1, "cortex-m1"},
+ {CpuCoreEntry::CortexMs1, "cortex-ms1"},
+ {CpuCoreEntry::CortexM3, "cortex-m3"}, // same as 'sc300'
+ {CpuCoreEntry::CortexM4, "cortex-m4"},
+ {CpuCoreEntry::CortexM7, "cortex-m7"},
+ {CpuCoreEntry::CortexR4, "cortex-r4"},
+ {CpuCoreEntry::CortexR5, "cortex-r5"},
+ {CpuCoreEntry::CortexR7, "cortex-r7"},
+ {CpuCoreEntry::CortexR8, "cortex-r8"},
+ {CpuCoreEntry::CortexR52, "cortex-r52"},
+ {CpuCoreEntry::CortexA5, "cortex-a5"},
+ {CpuCoreEntry::CortexA7, "cortex-a7"},
+ {CpuCoreEntry::CortexA8, "cortex-a8"},
+ {CpuCoreEntry::CortexA9, "cortex-a9"},
+ {CpuCoreEntry::CortexA15, "cortex-a15"},
+ {CpuCoreEntry::CortexA17, "cortex-a17"},
+ {CpuCoreEntry::CortexM23, "cortex-m23"},
+ {CpuCoreEntry::CortexM33, "cortex-m33"},
+};
+
+struct FpuCoreEntry final
+{
+ enum FpuRegistersCount {
+ NoFpuRegisters,
+ Fpu16Registers,
+ Fpu32Registers
+ };
+
+ enum FpuCoreCode {
+ NoVfp = 0,
+ Vfp2 = 2,
+ Vfp3d16 = 3,
+ Vfp3 = 3,
+ Vfp4sp = 4,
+ Vfp4d16 = 5,
+ Vfp4 = 5,
+ Vfp5sp = 6,
+ Vfp5d16 = 7,
+ Vfp9s = 8
+ };
+
+ // Required to compile in MSVC2015.
+ FpuCoreEntry(FpuCoreCode cc, FpuRegistersCount rc,
+ QByteArray tf)
+ : coreCode(cc), regsCount(rc), targetFlag(std::move(tf))
+ {}
+
+ FpuCoreCode coreCode = NoVfp;
+ FpuRegistersCount regsCount = NoFpuRegisters;
+ QByteArray targetFlag;
+};
+
+// Dictionary of known ARM FPU cores and its compiler options.
+static const FpuCoreEntry fpusDict[] = {
+ {FpuCoreEntry::Vfp2, FpuCoreEntry::NoFpuRegisters, "vfpv2"},
+ {FpuCoreEntry::Vfp3d16, FpuCoreEntry::Fpu16Registers, "vfpv3_d16"},
+ {FpuCoreEntry::Vfp3, FpuCoreEntry::Fpu32Registers, "vfpv3"},
+ {FpuCoreEntry::Vfp4sp, FpuCoreEntry::Fpu16Registers, "vfpv4_sp"},
+ {FpuCoreEntry::Vfp4d16, FpuCoreEntry::Fpu16Registers, "vfpv4_d16"},
+ {FpuCoreEntry::Vfp4, FpuCoreEntry::Fpu32Registers, "vfpv4"},
+ {FpuCoreEntry::Vfp5sp, FpuCoreEntry::Fpu16Registers, "vfpv5_sp"},
+ {FpuCoreEntry::Vfp5d16, FpuCoreEntry::Fpu16Registers, "vfpv5_d16"},
+ {FpuCoreEntry::Vfp9s, FpuCoreEntry::NoFpuRegisters, "vfp9-s"},
+};
+
+// Target page options.
+
+struct TargetPageOptions final
+{
+ enum Endianness {
+ LittleEndian,
+ BigEndian
+ };
+
+ explicit TargetPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags")});
+ // Detect target CPU code.
+ const QString cpuValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--cpu"))
+ .toLower();
+ const auto cpuEnd = std::cend(cpusDict);
+ const auto cpuIt = std::find_if(std::cbegin(cpusDict), cpuEnd,
+ [cpuValue](
+ const CpuCoreEntry &entry) {
+ return entry.targetFlag == cpuValue.toLatin1();
+ });
+ if (cpuIt != cpuEnd)
+ targetCpu = cpuIt->coreCode;
+ // Detect target FPU code.
+ const QString fpuValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--fpu"))
+ .toLower();
+ const auto fpuEnd = std::cend(fpusDict);
+ const auto fpuIt = std::find_if(std::cbegin(fpusDict), fpuEnd,
+ [fpuValue](
+ const FpuCoreEntry &entry) {
+ return entry.targetFlag == fpuValue.toLatin1();
+ });
+ if (fpuIt != fpuEnd) {
+ targetFpu = fpuIt->coreCode;
+ targetFpuRegs = fpuIt->regsCount;
+ }
+ // Detect endian.
+ const QString prop = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("endianness"));
+ if (prop == QLatin1String("big"))
+ endianness = TargetPageOptions::BigEndian;
+ else if (prop == QLatin1String("little"))
+ endianness = TargetPageOptions::LittleEndian;
+ }
+
+ CpuCoreEntry::CpuCoreCode targetCpu = CpuCoreEntry::Arm7tdmi;
+ FpuCoreEntry::FpuCoreCode targetFpu = FpuCoreEntry::NoVfp;
+ FpuCoreEntry::FpuRegistersCount targetFpuRegs = FpuCoreEntry::NoFpuRegisters;
+ Endianness endianness = LittleEndian;
+};
+
+// Library 1 page options.
+
+struct LibraryOnePageOptions final
+{
+ enum PrintfFormatter {
+ PrintfAutoFormatter,
+ PrintfFullFormatter,
+ PrintfLargeFormatter,
+ PrintfSmallFormatter,
+ PrintfTinyFormatter
+ };
+
+ enum ScanfFormatter {
+ ScanfAutoFormatter,
+ ScanfFullFormatter,
+ ScanfLargeFormatter,
+ ScanfSmallFormatter
+ };
+
+ explicit LibraryOnePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) {
+ if (*flagIt != QLatin1String("--redirect"))
+ continue;
+ ++flagIt;
+ if (flagIt->startsWith(QLatin1String("_printf="),
+ Qt::CaseInsensitive)) {
+ const QString prop = flagIt->split(
+ QLatin1Char('=')).at(1).toLower();
+ if (prop == QLatin1String("_printffullnomb"))
+ printfFormatter = LibraryOnePageOptions::PrintfFullFormatter;
+ else if (prop == QLatin1String("_printflargenomb"))
+ printfFormatter = LibraryOnePageOptions::PrintfLargeFormatter;
+ else if (prop == QLatin1String("_printfsmallnomb"))
+ printfFormatter = LibraryOnePageOptions::PrintfSmallFormatter;
+ else if (prop == QLatin1String("_printftiny"))
+ printfFormatter = LibraryOnePageOptions::PrintfTinyFormatter;
+ } else if (flagIt->startsWith(QLatin1String("_scanf="),
+ Qt::CaseInsensitive)) {
+ const QString prop = flagIt->split(
+ QLatin1Char('=')).at(1).toLower();;
+ if (prop == QLatin1String("_scanffullnomb"))
+ scanfFormatter = LibraryOnePageOptions::ScanfFullFormatter;
+ else if (prop == QLatin1String("_scanflargenomb"))
+ scanfFormatter = LibraryOnePageOptions::ScanfLargeFormatter;
+ else if (prop == QLatin1String("_scanfsmallnomb"))
+ scanfFormatter = LibraryOnePageOptions::ScanfSmallFormatter;
+ }
+ }
+ }
+
+ PrintfFormatter printfFormatter = PrintfAutoFormatter;
+ ScanfFormatter scanfFormatter = ScanfAutoFormatter;
+};
+
+// Library 2 page options.
+
+struct LibraryTwoPageOptions final
+{
+ enum HeapType {
+ AutomaticHeap,
+ AdvancedHeap,
+ BasicHeap,
+ NoFreeHeap
+ };
+
+ explicit LibraryTwoPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ if (flags.contains(QLatin1String("--advanced_heap")))
+ heapType = LibraryTwoPageOptions::AdvancedHeap;
+ else if (flags.contains(QLatin1String("--basic_heap")))
+ heapType = LibraryTwoPageOptions::BasicHeap;
+ else if (flags.contains(QLatin1String("--no_free_heap")))
+ heapType = LibraryTwoPageOptions::NoFreeHeap;
+ else
+ heapType = LibraryTwoPageOptions::AutomaticHeap;
+ }
+
+ HeapType heapType = AutomaticHeap;
+};
+
+// Library configuration page options.
+
+struct LibraryConfigPageOptions final
+{
+ enum RuntimeLibrary {
+ NoLibrary,
+ NormalLibrary,
+ FullLibrary,
+ CustomLibrary
+ };
+
+ enum ThreadSupport {
+ NoThread,
+ EnableThread
+ };
+
+ enum LowLevelInterface {
+ NoInterface,
+ SemihostedInterface
+ };
+
+ explicit LibraryConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ const QFileInfo dlibFileInfo(IarewUtils::flagValue(
+ flags, QStringLiteral("--dlib_config")));
+ if (!dlibFileInfo.exists()) {
+ dlibType = LibraryConfigPageOptions::NoLibrary;
+ } else {
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QString dlibFilePath = dlibFileInfo.absoluteFilePath();
+ if (dlibFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ if (dlibFilePath.endsWith(QLatin1String("dlib_config_normal.h"),
+ Qt::CaseInsensitive)) {
+ dlibType = LibraryConfigPageOptions::NormalLibrary;
+ } else if (dlibFilePath.endsWith(
+ QLatin1String("dlib_config_full.h"),
+ Qt::CaseInsensitive)) {
+ dlibType = LibraryConfigPageOptions::FullLibrary;
+ } else {
+ dlibType = LibraryConfigPageOptions::CustomLibrary;
+ }
+
+ dlibConfigPath = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, dlibFilePath);
+ } else {
+ dlibType = LibraryConfigPageOptions::CustomLibrary;
+ dlibConfigPath = IarewUtils::projectRelativeFilePath(
+ baseDirectory, dlibFilePath);
+ }
+ }
+
+ threadSupport = flags.contains(QLatin1String("--threaded_lib"))
+ ? LibraryConfigPageOptions::EnableThread
+ : LibraryConfigPageOptions::NoThread;
+ lowLevelInterface = flags.contains(QLatin1String("--semihosting"))
+ ? LibraryConfigPageOptions::SemihostedInterface
+ : LibraryConfigPageOptions::NoInterface;
+ }
+
+ RuntimeLibrary dlibType = NoLibrary;
+ QString dlibConfigPath;
+ ThreadSupport threadSupport = NoThread;
+ LowLevelInterface lowLevelInterface = NoInterface;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ binaryType = IarewUtils::outputBinaryType(qbsProduct);
+ binaryDirectory = gen::utils::binaryOutputDirectory(
+ baseDirectory, qbsProduct);
+ objectDirectory = gen::utils::objectsOutputDirectory(
+ baseDirectory, qbsProduct);
+ listingDirectory = gen::utils::listingOutputDirectory(
+ baseDirectory, qbsProduct);
+ }
+
+ IarewUtils::OutputBinaryType binaryType = IarewUtils::ApplicationOutputType;
+ QString binaryDirectory;
+ QString objectDirectory;
+ QString listingDirectory;
+};
+
+} // namespace
+
+// ArmGeneralSettingsGroup
+
+ArmGeneralSettingsGroup::ArmGeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("General"));
+ setArchiveVersion(kGeneralArchiveVersion);
+ setDataVersion(kGeneralDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildTargetPage(qbsProduct);
+ buildLibraryOptionsOnePage(qbsProduct);
+ buildLibraryOptionsTwoPage(qbsProduct);
+ buildLibraryConfigPage(buildRootDirectory, qbsProduct);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void ArmGeneralSettingsGroup::buildTargetPage(
+ const ProductData &qbsProduct)
+{
+ const TargetPageOptions opts(qbsProduct);
+ // Add 'GBECoreSlave', 'CoreVariant', 'GFPUCoreSlave2' items
+ // (Processor variant chooser).
+ addOptionsGroup(QByteArrayLiteral("GBECoreSlave"),
+ {opts.targetCpu}, 26);
+ addOptionsGroup(QByteArrayLiteral("CoreVariant"),
+ {opts.targetCpu}, 26);
+ addOptionsGroup(QByteArrayLiteral("GFPUCoreSlave2"),
+ {opts.targetCpu}, 26);
+ // Add 'FPU2', 'NrRegs' item (Floating point settings chooser).
+ addOptionsGroup(QByteArrayLiteral("FPU2"),
+ {opts.targetFpu}, 0);
+ addOptionsGroup(QByteArrayLiteral("NrRegs"),
+ {opts.targetFpuRegs}, 0);
+ // Add 'GEndianMode' item (Endian mode chooser).
+ addOptionsGroup(QByteArrayLiteral("GEndianMode"),
+ {opts.endianness});
+}
+
+void ArmGeneralSettingsGroup::buildLibraryOptionsOnePage(
+ const ProductData &qbsProduct)
+{
+ const LibraryOnePageOptions opts(qbsProduct);
+ // Add 'OGPrintfVariant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("OGPrintfVariant"),
+ {opts.printfFormatter});
+ // Add 'OGScanfVariant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("OGScanfVariant"),
+ {opts.scanfFormatter});
+}
+
+void ArmGeneralSettingsGroup::buildLibraryOptionsTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LibraryTwoPageOptions opts(qbsProduct);
+ // Add 'OgLibHeap' item (Heap selection:
+ // auto/advanced/basic/nofree).
+ addOptionsGroup(QByteArrayLiteral("OgLibHeap"),
+ {opts.heapType});
+}
+
+void ArmGeneralSettingsGroup::buildLibraryConfigPage(
+ const QString baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GRuntimeLibSelect', 'GRuntimeLibSelectSlave'
+ // and 'RTConfigPath2' items
+ // (Link with runtime: none/normal/full/custom).
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelect"),
+ {opts.dlibType});
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelectSlave"),
+ {opts.dlibType});
+ addOptionsGroup(QByteArrayLiteral("RTConfigPath2"),
+ {opts.dlibConfigPath});
+ // Add 'GRuntimeLibThreads'item
+ // (Enable thread support in library).
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibThreads"),
+ {opts.threadSupport});
+ // Add 'GenLowLevelInterface' item (Library low-level
+ // interface: none/semihosted/breakpoint).
+ addOptionsGroup(QByteArrayLiteral("GenLowLevelInterface"),
+ {opts.lowLevelInterface});
+}
+
+void ArmGeneralSettingsGroup::buildOutputPage(
+ const QString baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GOutputBinary' item
+ // (Output file: executable/library).
+ addOptionsGroup(QByteArrayLiteral("GOutputBinary"),
+ {opts.binaryType});
+ // Add 'ExePath' item
+ // (Executable/binaries output directory).
+ addOptionsGroup(QByteArrayLiteral("ExePath"),
+ {opts.binaryDirectory});
+ // Add 'ObjPath' item
+ // (Object files output directory).
+ addOptionsGroup(QByteArrayLiteral("ObjPath"),
+ {opts.objectDirectory});
+ // Add 'ListPath' item
+ // (List files output directory).
+ addOptionsGroup(QByteArrayLiteral("ListPath"),
+ {opts.listingDirectory});
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h
new file mode 100644
index 000000000..420e98008
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMGENERALSETTINGSGROUP_V8_H
+#define QBS_IAREWARMGENERALSETTINGSGROUP_V8_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmGeneralSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit ArmGeneralSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildTargetPage(const ProductData &qbsProduct);
+ void buildLibraryOptionsOnePage(const ProductData &qbsProduct);
+ void buildLibraryOptionsTwoPage(const ProductData &qbsProduct);
+ void buildLibraryConfigPage(const QString baseDirectory,
+ const ProductData &qbsProduct);
+ void buildOutputPage(const QString baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMGENERALSETTINGSGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.cpp
new file mode 100644
index 000000000..7e29c2788
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "armlinkersettingsgroup_v8.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+constexpr int kLinkerArchiveVersion = 0;
+constexpr int kLinkerDataVersion = 20;
+
+namespace {
+
+// Config page options.
+
+struct ConfigPageOptions final
+{
+ explicit ConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ // Accumulate config definitions (if exists).
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ configDefines = IarewUtils::flagValues(
+ flags, QStringLiteral("--config_def"));
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+
+ // Enumerate all product linker config files
+ // (which are set trough 'linkerscript' tag).
+ const auto qbsGroups = qbsProduct.groups();
+ for (const auto &qbsGroup : qbsGroups) {
+ if (!qbsGroup.isEnabled())
+ continue;
+ const auto qbsArtifacts = qbsGroup.sourceArtifacts();
+ for (const auto &qbsArtifact : qbsArtifacts) {
+ const auto qbsTags = qbsArtifact.fileTags();
+ if (!qbsTags.contains(QLatin1String("linkerscript")))
+ continue;
+ const QString fullConfigPath = qbsArtifact.filePath();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ configFilePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ configFilePaths.push_back(path);
+ }
+ }
+ }
+
+ // Enumerate all product linker config files
+ // (which are set trough '--config' option).
+ const QVariantList configPathValues = IarewUtils::flagValues(
+ flags, QStringLiteral("--config"));
+ for (const auto &configPathValue : configPathValues) {
+ const QString fullConfigPath = configPathValue.toString();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList configFilePaths;
+ QVariantList configDefines;
+};
+
+// Library page options.
+
+struct LibraryPageOptions final
+{
+ explicit LibraryPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+
+ entryPoint = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("entryPoint"));
+
+ // Add libraries search paths.
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("libraryPaths")});
+ for (const QString &libraryPath : libraryPaths) {
+ const QFileInfo libraryPathInfo(libraryPath);
+ const QString fullLibrarySearchPath =
+ libraryPathInfo.absoluteFilePath();
+ if (fullLibrarySearchPath.startsWith(
+ toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory,fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ }
+ }
+
+ // Add static libraries paths.
+ const QStringList staticLibrariesProps =
+ gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("staticLibraries")});
+ for (const QString &staticLibrary : staticLibrariesProps) {
+ const QFileInfo staticLibraryInfo(staticLibrary);
+ if (staticLibraryInfo.isAbsolute()) {
+ const QString fullStaticLibraryPath =
+ staticLibraryInfo.absoluteFilePath();
+ if (fullStaticLibraryPath.startsWith(
+ toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullStaticLibraryPath);
+ staticLibraries.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullStaticLibraryPath);
+ staticLibraries.push_back(path);
+ }
+ } else {
+ staticLibraries.push_back(staticLibrary);
+ }
+ }
+
+ // Add static libraries from product dependencies.
+ for (const ProductData &qbsProductDep : qbsProductDeps) {
+ const QString depBinaryPath = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory,
+ qbsProductDep);
+ staticLibraries.push_back(depBinaryPath);
+ }
+
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ enableRuntimeLibsSearch = !flags.contains(
+ QLatin1String("--no_library_search"));
+ }
+
+ QString entryPoint;
+ QVariantList staticLibraries;
+ QVariantList librarySearchPaths;
+ int enableRuntimeLibsSearch = 0;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ debugInfo = !flags.contains(QLatin1String("--strip"));
+ outputFile = gen::utils::targetBinary(qbsProduct);
+ }
+
+ int debugInfo = 0;
+ QString outputFile;
+};
+
+// Input page options.
+
+struct InputPageOptions final
+{
+ explicit InputPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ keepSymbols = IarewUtils::flagValues(flags, QStringLiteral("--keep"));
+ }
+
+ QVariantList keepSymbols;
+};
+
+// List page options.
+
+struct ListPageOptions final
+{
+ enum ListingAction {
+ NoListing,
+ GenerateListing
+ };
+
+ explicit ListPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ generateMap = gen::utils::cppBooleanModuleProperty(
+ qbsProps, QStringLiteral("generateLinkerMapFile"))
+ ? ListPageOptions::GenerateListing
+ : ListPageOptions::NoListing;
+ }
+
+ ListingAction generateMap = GenerateListing;
+};
+
+// Optimizations page options.
+
+struct OptimizationsPageOptions final
+{
+ explicit OptimizationsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ inlineSmallRoutines = flags.contains(QLatin1String("--inline"));
+ mergeDuplicateSections = flags.contains(
+ QLatin1String("--merge_duplicate_sections"));
+ virtualFuncElimination = flags.contains(QLatin1String("--vfe"));
+ }
+
+ int inlineSmallRoutines = 0;
+ int mergeDuplicateSections = 0;
+ int virtualFuncElimination = 0;
+};
+
+// Advanced page options.
+
+struct AdvancedPageOptions final
+{
+ explicit AdvancedPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ allowExceptions = !flags.contains(QLatin1String("--no_exceptions"));
+ }
+
+ int allowExceptions = 0;
+};
+
+// Defines page options.
+
+struct DefinesPageOptions final
+{
+ explicit DefinesPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ defineSymbols = IarewUtils::flagValues(
+ flags, QStringLiteral("--define_symbol"));
+ }
+
+ QVariantList defineSymbols;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ treatWarningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int treatWarningsAsErrors = 0;
+};
+
+} // namespace
+
+// ArmLinkerSettingsGroup
+
+ArmLinkerSettingsGroup::ArmLinkerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ setName(QByteArrayLiteral("ILINK"));
+ setArchiveVersion(kLinkerArchiveVersion);
+ setDataVersion(kLinkerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildConfigPage(buildRootDirectory, qbsProduct);
+ buildLibraryPage(buildRootDirectory, qbsProduct, qbsProductDeps);
+ buildOutputPage(qbsProduct);
+ buildInputPage(qbsProduct);
+ buildListPage(qbsProduct);
+ buildOptimizationsPage(qbsProduct);
+ buildAdvancedPage(qbsProduct);
+ buildDefinesPage(qbsProduct);
+
+ // Should be called as latest stage!
+ buildExtraOptionsPage(qbsProduct);
+}
+
+void ArmLinkerSettingsGroup::buildConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ ConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'IlinkConfigDefines' item
+ // (Configuration file symbol definitions).
+ addOptionsGroup(QByteArrayLiteral("IlinkConfigDefines"),
+ opts.configDefines);
+
+ if (opts.configFilePaths.count() > 0) {
+ // Note: IAR IDE does not allow to specify a multiple config files,
+ // although the IAR linker support it. So, we use followig 'trick':
+ // we take a first config file and to add it as usual to required items;
+ // and then an other remainders we forward to the "Extra options page".
+ const QVariant configPath = opts.configFilePaths.takeFirst();
+ // Add 'IlinkIcfOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("IlinkIcfOverride"),
+ {1});
+ // Add 'IlinkIcfFile' item (Linker configuration file).
+ addOptionsGroup(QByteArrayLiteral("IlinkIcfFile"),
+ {configPath});
+
+ // Add remainder configuration files to the "Extra options page".
+ if (!opts.configFilePaths.isEmpty()) {
+ for (QVariant &configPath : opts.configFilePaths)
+ configPath = QLatin1String("--config ")
+ + configPath.toString();
+
+ m_extraOptions << opts.configFilePaths;
+ }
+ }
+}
+
+void ArmLinkerSettingsGroup::buildLibraryPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ LibraryPageOptions opts(baseDirectory, qbsProduct, qbsProductDeps);
+ // Add 'IlinkOverrideProgramEntryLabel' item
+ // (Override default program entry).
+ addOptionsGroup(QByteArrayLiteral("IlinkOverrideProgramEntryLabel"),
+ {1});
+ const int select = opts.entryPoint.isEmpty() ? 1 : 0;
+ addOptionsGroup(QByteArrayLiteral("IlinkProgramEntryLabelSelect"),
+ {select});
+ // Add 'IlinkProgramEntryLabel' item (Entry point name).
+ addOptionsGroup(QByteArrayLiteral("IlinkProgramEntryLabel"),
+ {opts.entryPoint});
+
+ if (!opts.staticLibraries.isEmpty()) {
+ // Add 'IlinkAdditionalLibs' item (Additional libraries).
+ addOptionsGroup(QByteArrayLiteral("IlinkAdditionalLibs"),
+ opts.staticLibraries);
+ }
+
+ // Add 'IlinkAutoLibEnable' item
+ // (Automatic runtime library selection).
+ addOptionsGroup(QByteArrayLiteral("IlinkAutoLibEnable"),
+ {opts.enableRuntimeLibsSearch});
+
+ // Add library searh directories to the
+ // "Extra options page", because IAR IDE
+ // has not other options to add this paths.
+ for (QVariant &libraryPath : opts.librarySearchPaths)
+ libraryPath = QLatin1String("-L ") + libraryPath.toString();
+
+ m_extraOptions << opts.librarySearchPaths;
+}
+
+void ArmLinkerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'IlinkDebugInfoEnable' item
+ // (Include debug information in output).
+ addOptionsGroup(QByteArrayLiteral("IlinkDebugInfoEnable"),
+ {opts.debugInfo});
+ // Add 'IlinkOutputFile' item (Output filename).
+ addOptionsGroup(QByteArrayLiteral("IlinkOutputFile"),
+ {opts.outputFile});
+}
+
+void ArmLinkerSettingsGroup::buildInputPage(
+ const ProductData &qbsProduct)
+{
+ const InputPageOptions opts(qbsProduct);
+ // Add 'IlinkKeepSymbols' item ().
+ addOptionsGroup(QByteArrayLiteral("IlinkKeepSymbols"),
+ opts.keepSymbols);
+}
+
+void ArmLinkerSettingsGroup::buildListPage(
+ const ProductData &qbsProduct)
+{
+ const ListPageOptions opts(qbsProduct);
+ // Add 'IlinkMapFile' item (Generate linker map file).
+ addOptionsGroup(QByteArrayLiteral("IlinkMapFile"),
+ {opts.generateMap});
+}
+
+void ArmLinkerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ const OptimizationsPageOptions opts(qbsProduct);
+ // Add 'IlinkOptInline' item (Inline small routines).
+ addOptionsGroup(QByteArrayLiteral("IlinkOptInline"),
+ {opts.inlineSmallRoutines});
+ // Add 'IlinkOptMergeDuplSections'item
+ // (Merge duplicate sections).
+ addOptionsGroup(QByteArrayLiteral("IlinkOptMergeDuplSections"),
+ {opts.mergeDuplicateSections});
+ // Add 'IlinkOptUseVfe' item
+ // (Perform C++ virtual functions elimination).
+ addOptionsGroup(QByteArrayLiteral("IlinkOptUseVfe"),
+ {opts.virtualFuncElimination});
+}
+
+void ArmLinkerSettingsGroup::buildAdvancedPage(
+ const ProductData &qbsProduct)
+{
+ const AdvancedPageOptions opts(qbsProduct);
+ // Add 'IlinkOptExceptionsAllow' item (Allow C++ exceptions).
+ addOptionsGroup(QByteArrayLiteral("IlinkOptExceptionsAllow"),
+ {opts.allowExceptions});
+}
+
+void ArmLinkerSettingsGroup::buildDefinesPage(
+ const ProductData &qbsProduct)
+{
+ const DefinesPageOptions opts(qbsProduct);
+ // Add 'IlinkDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("IlinkDefines"),
+ {opts.defineSymbols});
+}
+
+void ArmLinkerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'IlinkWarningsAreErrors' item
+ // (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("IlinkWarningsAreErrors"),
+ {opts.treatWarningsAsErrors});
+}
+
+void ArmLinkerSettingsGroup::buildExtraOptionsPage(
+ const ProductData &qbsProduct)
+{
+ Q_UNUSED(qbsProduct)
+
+ // Add 'IlinkUseExtraOptions' and 'IlinkExtraOptions' items.
+ addOptionsGroup(QByteArrayLiteral("IlinkUseExtraOptions"),
+ {1});
+ addOptionsGroup(QByteArrayLiteral("IlinkExtraOptions"),
+ m_extraOptions);
+}
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.h
new file mode 100644
index 000000000..e86297e6e
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/arm/armlinkersettingsgroup_v8.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWARMLINKERSETTINGSGROUP_V8_H
+#define QBS_IAREWARMLINKERSETTINGSGROUP_V8_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace arm {
+namespace v8 {
+
+class ArmLinkerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit ArmLinkerSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildLibraryPage(const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildInputPage(const ProductData &qbsProduct);
+ void buildListPage(const ProductData &qbsProduct);
+ void buildOptimizationsPage(const ProductData &qbsProduct);
+ void buildAdvancedPage(const ProductData &qbsProduct);
+ void buildDefinesPage(const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildExtraOptionsPage(const ProductData &qbsProduct);
+
+ QVariantList m_extraOptions;
+};
+
+} // namespace v8
+} // namespace arm
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWARMLINKERSETTINGSGROUP_V8_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.cpp
new file mode 100644
index 000000000..4e002d13f
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrarchiversettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+constexpr int kArchiverArchiveVersion = 2;
+constexpr int kArchiverDataVersion = 0;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ outputFile = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory, qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+} // namespace
+
+// AvrArchiverSettingsGroup
+
+AvrArchiverSettingsGroup::AvrArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("XAR"));
+ setArchiveVersion(kArchiverArchiveVersion);
+ setDataVersion(kArchiverDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void AvrArchiverSettingsGroup::buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'XAROutOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("XAROutOverride"),
+ {1});
+ // Add 'OutputFile' item (Output filename).
+ addOptionsGroup(QByteArrayLiteral("OutputFile"),
+ {opts.outputFile});
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.h
new file mode 100644
index 000000000..2ff667e1d
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrarchiversettingsgroup_v7.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRARCHIVERSETTINGSGROUP_V7_H
+#define QBS_IAREWAVRARCHIVERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrArchiverSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit AvrArchiverSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRARCHIVERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.cpp
new file mode 100644
index 000000000..08e86be53
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrassemblersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+constexpr int kAssemblerArchiveVersion = 5;
+constexpr int kAssemblerDataVersion = 11;
+
+namespace {
+
+// Language page options.
+
+struct LanguagePageOptions final
+{
+ enum MacroQuoteCharacter {
+ AngleBracketsQuote,
+ RoundBracketsQuote,
+ SquareBracketsQuote,
+ FigureBracketsQuote
+ };
+
+ explicit LanguagePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("assemblerFlags")});
+ enableSymbolsCaseSensitive = flags.contains(QLatin1String("-s+"));
+ enableMultibyteSupport = flags.contains(QLatin1String("-n"));
+
+ if (flags.contains(QLatin1String("-M<>")))
+ macroQuoteCharacter = LanguagePageOptions::AngleBracketsQuote;
+ else if (flags.contains(QLatin1String("-M()")))
+ macroQuoteCharacter = LanguagePageOptions::RoundBracketsQuote;
+ else if (flags.contains(QLatin1String("-M[]")))
+ macroQuoteCharacter = LanguagePageOptions::SquareBracketsQuote;
+ else if (flags.contains(QLatin1String("-M{}")))
+ macroQuoteCharacter = LanguagePageOptions::FigureBracketsQuote;
+ }
+
+ MacroQuoteCharacter macroQuoteCharacter = AngleBracketsQuote;
+ int enableSymbolsCaseSensitive = 0;
+ int enableMultibyteSupport = 0;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ for (const auto &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString warningLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ if (warningLevel == QLatin1String("all")) {
+ enableWarnings = 0;
+ enableAllWarnings = 0;
+ } else if (warningLevel == QLatin1String("none")) {
+ enableWarnings = 1;
+ enableAllWarnings = 0;
+ } else {
+ enableWarnings = 0;
+ enableAllWarnings = 1;
+ }
+ }
+
+ int enableWarnings = 0;
+ int enableAllWarnings = 0;
+};
+
+} // namespace
+
+// AvrAssemblerSettingsGroup
+
+AvrAssemblerSettingsGroup::AvrAssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("AAVR"));
+ setArchiveVersion(kAssemblerArchiveVersion);
+ setDataVersion(kAssemblerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildLanguagePage(qbsProduct);
+ buildOutputPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+}
+
+void AvrAssemblerSettingsGroup::buildLanguagePage(
+ const ProductData &qbsProduct)
+{
+ const LanguagePageOptions opts(qbsProduct);
+ // Add 'ACaseSensitivity' item (User symbols are case sensitive).
+ addOptionsGroup(QByteArrayLiteral("ACaseSensitivity"),
+ {opts.enableSymbolsCaseSensitive});
+ // Add 'AsmMultiByteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("AsmMultiByteSupport"),
+ {opts.enableMultibyteSupport});
+ // Add 'MacroChars' item (Macro quote characters: ()/[]/{}/<>).
+ addOptionsGroup(QByteArrayLiteral("MacroChars"),
+ {opts.macroQuoteCharacter}, 0);
+}
+
+void AvrAssemblerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'CDebug' item (Generate debug information).
+ addOptionsGroup(QByteArrayLiteral("CDebug"),
+ {opts.debugInfo});
+}
+
+void AvrAssemblerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'ADefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("ADefines"),
+ opts.defineSymbols);
+ // Add 'AUserIncludes' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("ANewIncludes"),
+ opts.includePaths);
+}
+
+void AvrAssemblerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'AWarnEnable' item (Enable/disable warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnEnable"),
+ {opts.enableWarnings});
+ // Add 'AWarnWhat' item (Enable/disable all warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnWhat"),
+ {opts.enableAllWarnings});
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.h
new file mode 100644
index 000000000..608a42652
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrassemblersettingsgroup_v7.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRASSEMBLERSETTINGSGROUP_V7_H
+#define QBS_IAREWAVRASSEMBLERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrAssemblerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit AvrAssemblerSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildLanguagePage(const ProductData &qbsProduct);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRASSEMBLERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.cpp
new file mode 100644
index 000000000..dbb5c6620
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrarchiversettingsgroup_v7.h"
+#include "avrassemblersettingsgroup_v7.h"
+#include "avrbuildconfigurationgroup_v7.h"
+#include "avrcompilersettingsgroup_v7.h"
+#include "avrgeneralsettingsgroup_v7.h"
+#include "avrlinkersettingsgroup_v7.h"
+
+#include "../../iarewtoolchainpropertygroup.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+AvrBuildConfigurationGroup::AvrBuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup("configuration")
+{
+ // Append configuration name item.
+ const QString cfgName = gen::utils::buildConfigurationName(qbsProject);
+ appendProperty("name", cfgName);
+
+ // Apend toolchain name group item.
+ appendChild<IarewToolchainPropertyGroup>("AVR");
+
+ // Append debug info item.
+ const int debugBuild = gen::utils::debugInformation(qbsProduct);
+ appendProperty("debug", debugBuild);
+
+ // Append settings group items.
+ appendChild<AvrArchiverSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<AvrAssemblerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<AvrCompilerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<AvrGeneralSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<AvrLinkerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+}
+
+bool AvrBuildConfigurationGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Avr
+ && version.majorVersion() == 7;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+AvrBuildConfigurationGroupFactory::create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const
+{
+ const auto group = new AvrBuildConfigurationGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<AvrBuildConfigurationGroup>(group);
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.h
new file mode 100644
index 000000000..618cef4c6
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrbuildconfigurationgroup_v7.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRBUILDCONFIGURATIONGROUP_V7_H
+#define QBS_IAREWAVRBUILDCONFIGURATIONGROUP_V7_H
+
+#include <generators/generatorutils.h>
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrBuildConfigurationGroup final
+ : public gen::xml::PropertyGroup
+{
+private:
+ explicit AvrBuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+ friend class AvrBuildConfigurationGroupFactory;
+};
+
+class AvrBuildConfigurationGroupFactory final
+ : public gen::xml::PropertyGroupFactory
+{
+public:
+ bool canCreate(gen::utils::Architecture arch,
+ const Version &version) const final;
+
+ std::unique_ptr<gen::xml::PropertyGroup> create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const final;
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRBUILDCONFIGURATIONGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.cpp
new file mode 100644
index 000000000..26b6858f1
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.cpp
@@ -0,0 +1,492 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrcompilersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+constexpr int kCompilerArchiveVersion = 6;
+constexpr int kCompilerDataVersion = 17;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ moduleType = flags.contains(QLatin1String("--library_module"))
+ ? OutputPageOptions::LibraryModule
+ : OutputPageOptions::ProgramModule;
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ disableErrorMessages = flags.contains(
+ QLatin1String("--no_ubrof_messages"));
+ }
+
+ int debugInfo = 0;
+ int disableErrorMessages = 0;
+ enum ModuleType { ProgramModule, LibraryModule};
+ ModuleType moduleType = ProgramModule;
+};
+
+// Language one page options.
+
+struct LanguageOnePageOptions final
+{
+ enum LanguageExtension {
+ CLanguageExtension,
+ CxxLanguageExtension,
+ AutoLanguageExtension
+ };
+
+ enum CLanguageDialect {
+ C89LanguageDialect,
+ C99LanguageDialect
+ };
+
+ enum CxxLanguageDialect {
+ EmbeddedCPlusPlus,
+ ExtendedEmbeddedCPlusPlus
+ };
+
+ enum LanguageConformance {
+ AllowIarExtension,
+ RelaxedStandard,
+ StrictStandard
+ };
+
+ explicit LanguageOnePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ // File extension based by default.
+ languageExtension = LanguageOnePageOptions::AutoLanguageExtension;
+ // C language dialect.
+ const QStringList cLanguageVersion = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("cLanguageVersion")});
+ if (cLanguageVersion.contains(QLatin1String("c89")))
+ cLanguageDialect = LanguageOnePageOptions::C89LanguageDialect;
+ else if (cLanguageVersion.contains(QLatin1String("c99")))
+ cLanguageDialect = LanguageOnePageOptions::C99LanguageDialect;
+ // C++ language dialect.
+ if (flags.contains(QLatin1String("--ec++")))
+ cxxLanguageDialect = LanguageOnePageOptions::EmbeddedCPlusPlus;
+ else if (flags.contains(QLatin1String("--eec++")))
+ cxxLanguageDialect = LanguageOnePageOptions::ExtendedEmbeddedCPlusPlus;
+ // Language conformance.
+ if (flags.contains(QLatin1String("-e")))
+ languageConformance = LanguageOnePageOptions::AllowIarExtension;
+ else if (flags.contains(QLatin1String("--strict")))
+ languageConformance = LanguageOnePageOptions::StrictStandard;
+ else
+ languageConformance = LanguageOnePageOptions::RelaxedStandard;
+
+ allowVla = flags.contains(QLatin1String("--vla"));
+ useCppInlineSemantics = flags.contains(
+ QLatin1String("--use_c++_inline"));
+ requirePrototypes = flags.contains(
+ QLatin1String("--require_prototypes"));
+ destroyStaticObjects = !flags.contains(
+ QLatin1String("--no_static_destruction"));
+ }
+
+ LanguageExtension languageExtension = AutoLanguageExtension;
+ CLanguageDialect cLanguageDialect = C89LanguageDialect;
+ CxxLanguageDialect cxxLanguageDialect = EmbeddedCPlusPlus;
+ LanguageConformance languageConformance = AllowIarExtension;
+ int allowVla = 0;
+ int useCppInlineSemantics = 0;
+ int requirePrototypes = 0;
+ int destroyStaticObjects = 0;
+};
+
+// Language two page options.
+
+struct LanguageTwoPageOptions final
+{
+ enum PlainCharacter {
+ SignedCharacter,
+ UnsignedCharacter
+ };
+
+ enum FloatingPointSemantic {
+ StrictSemantic,
+ RelaxedSemantic
+ };
+
+ explicit LanguageTwoPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ plainCharacter = flags.contains(QLatin1String("--char_is_signed"))
+ ? LanguageTwoPageOptions::SignedCharacter
+ : LanguageTwoPageOptions::UnsignedCharacter;
+ floatingPointSemantic = flags.contains(QLatin1String("--relaxed_fp"))
+ ? LanguageTwoPageOptions::RelaxedSemantic
+ : LanguageTwoPageOptions::StrictSemantic;
+ enableMultibyteSupport = flags.contains(
+ QLatin1String("--enable_multibytes"));
+ }
+
+ PlainCharacter plainCharacter = SignedCharacter;
+ FloatingPointSemantic floatingPointSemantic = StrictSemantic;
+ int enableMultibyteSupport = 0;
+};
+
+// Optimizations page options.
+
+struct OptimizationsPageOptions final
+{
+ // Optimizations level radio-buttons with
+ // combo-box on "level" widget.
+ enum Strategy {
+ StrategyBalanced,
+ StrategySize,
+ StrategySpeed
+ };
+
+ enum Level {
+ LevelNone,
+ LevelLow,
+ LevelMedium,
+ LevelHigh
+ };
+
+ enum LevelSlave {
+ LevelSlave0,
+ LevelSlave1,
+ LevelSlave2,
+ LevelSlave3
+ };
+
+ explicit OptimizationsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString optimization = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("optimization"));
+ if (optimization == QLatin1String("none")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategyBalanced;
+ optimizationLevel = OptimizationsPageOptions::LevelNone;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave0;
+ } else if (optimization == QLatin1String("fast")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySpeed;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ } else if (optimization == QLatin1String("small")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySize;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ }
+
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ enableCommonSubexpressionElimination = !flags.contains(
+ QLatin1String("--no_cse"));
+ enableFunctionInlining = !flags.contains(QLatin1String("--no_inline"));
+ enableCodeMotion = !flags.contains(QLatin1String("--no_code_motion"));
+ enableCrossCall = !flags.contains(QLatin1String("--no_cross_call"));
+ enableVariableClustering = !flags.contains(
+ QLatin1String("--no_clustering"));
+ enableTypeBasedAliasAnalysis = !flags.contains(
+ QLatin1String("--no_tbaa"));
+ enableForceCrossCall = flags.contains(
+ QLatin1String("--do_cross_call"));
+ }
+
+ Strategy optimizationStrategy = StrategyBalanced;
+ Level optimizationLevel = LevelNone;
+ LevelSlave optimizationLevelSlave = LevelSlave0;
+ // Six bit-field flags on "enabled optimizations" widget.
+ int enableCommonSubexpressionElimination = 0; // Common sub-expression elimination.
+ int enableFunctionInlining = 0; // Function inlining.
+ int enableCodeMotion = 0; // Code motion.
+ int enableCrossCall = 0; // Cross call optimization.
+ int enableVariableClustering = 0; // Variable clustering.
+ int enableTypeBasedAliasAnalysis = 0; // Type based alias analysis.
+ // Force cross-call optimization.
+ int enableForceCrossCall = 0;
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ for (const QString &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ warningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int warningsAsErrors = 0;
+};
+
+// Code page options.
+
+struct CodePageOptions final
+{
+ explicit CodePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ placeConstantsInRam = flags.contains(QLatin1String("-y"));
+ placeInitializiersInFlash = flags.contains(
+ QLatin1String("--initializiers_in_flash"));
+ forceVariablesGeneration = flags.contains(
+ QLatin1String("--root_variables"));
+ useIccA90CallingConvention = flags.contains(
+ QLatin1String("--version1_calls"));
+ lockRegistersCount = IarewUtils::flagValue(
+ flags, QStringLiteral("--lock_regs")).toInt();
+ }
+
+ int placeConstantsInRam = 0;
+ int placeInitializiersInFlash = 0;
+ int forceVariablesGeneration = 0;
+ int useIccA90CallingConvention = 0;
+ int lockRegistersCount = 0;
+};
+
+} // namespace
+
+// AvrCompilerSettingsGroup
+
+AvrCompilerSettingsGroup::AvrCompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ICCAVR"));
+ setArchiveVersion(kCompilerArchiveVersion);
+ setDataVersion(kCompilerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildOutputPage(qbsProduct);
+ buildLanguageOnePage(qbsProduct);
+ buildLanguageTwoPage(qbsProduct);
+ buildOptimizationsPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+ buildCodePage(qbsProduct);
+}
+
+void AvrCompilerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'CCDebugInfo' item (Generate debug info).
+ addOptionsGroup(QByteArrayLiteral("CCDebugInfo"),
+ {opts.debugInfo});
+ // Add 'CCNoErrorMsg' item (No error messages in output files).
+ addOptionsGroup(QByteArrayLiteral("CCNoErrorMsg"),
+ {opts.disableErrorMessages});
+ // Add 'CCOverrideModuleTypeDefault' item
+ // (Override default module type).
+ addOptionsGroup(QByteArrayLiteral("CCOverrideModuleTypeDefault"),
+ {1});
+ // Add 'CCRadioModuleType' item (Module type: program/library).
+ addOptionsGroup(QByteArrayLiteral("CCRadioModuleType"),
+ {opts.moduleType});
+}
+
+void AvrCompilerSettingsGroup::buildLanguageOnePage(
+ const ProductData &qbsProduct)
+{
+ const LanguageOnePageOptions opts(qbsProduct);
+ // Add 'IccLang' item with 'auto-extension based'
+ // value (Language: C/C++/Auto).
+ addOptionsGroup(QByteArrayLiteral("IccLang"),
+ {opts.languageExtension});
+ // Add 'IccCDialect' item (C dialect: c89/99/11).
+ addOptionsGroup(QByteArrayLiteral("IccCDialect"),
+ {opts.cLanguageDialect});
+ // Add 'IccCppDialect' item (C++ dialect: embedded/extended).
+ addOptionsGroup(QByteArrayLiteral("IccCppDialect"),
+ {opts.cxxLanguageDialect});
+ // Add 'CCExt' item (Language conformance: IAR/relaxed/strict).
+ addOptionsGroup(QByteArrayLiteral("CCExt"),
+ {opts.languageConformance});
+ // Add 'IccAllowVLA' item (Allow VLA).
+ addOptionsGroup(QByteArrayLiteral("IccAllowVLA"),
+ {opts.allowVla});
+ // Add 'IccCppInlineSemantics' item (C++ inline semantics).
+ addOptionsGroup(QByteArrayLiteral("IccCppInlineSemantics"),
+ {opts.useCppInlineSemantics});
+ // Add 'CCRequirePrototypes' item (Require prototypes).
+ addOptionsGroup(QByteArrayLiteral("CCRequirePrototypes"),
+ {opts.requirePrototypes});
+ // Add 'IccStaticDestr' item (Destroy static objects).
+ addOptionsGroup(QByteArrayLiteral("IccStaticDestr"),
+ {opts.destroyStaticObjects});
+}
+
+void AvrCompilerSettingsGroup::buildLanguageTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LanguageTwoPageOptions opts(qbsProduct);
+ // Add 'CCCharIs' item (Plain char is: signed/unsigned).
+ addOptionsGroup(QByteArrayLiteral("CCCharIs"),
+ {opts.plainCharacter});
+ // Add 'IccFloatSemantics' item (Floatic-point
+ // semantics: strict/relaxed conformance).
+ addOptionsGroup(QByteArrayLiteral("IccFloatSemantics"),
+ {opts.floatingPointSemantic});
+ // Add 'CCMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("CCMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+}
+
+void AvrCompilerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ const OptimizationsPageOptions opts(qbsProduct);
+ // Add 'CCOptStrategy', 'CCOptLevel' and
+ // 'CCOptLevelSlave' items (Level).
+ addOptionsGroup(QByteArrayLiteral("CCOptStrategy"),
+ {opts.optimizationStrategy});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevel"),
+ {opts.optimizationLevel});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevelSlave"),
+ {opts.optimizationLevelSlave});
+ // Add 'CCAllowList' item
+ // (Enabled optimizations: 6 check boxes).
+ const QString bitflags = QStringLiteral("%1%2%3%4%5%6")
+ .arg(opts.enableCommonSubexpressionElimination)
+ .arg(opts.enableFunctionInlining)
+ .arg(opts.enableCodeMotion)
+ .arg(opts.enableCrossCall)
+ .arg(opts.enableVariableClustering)
+ .arg(opts.enableTypeBasedAliasAnalysis);
+ addOptionsGroup(QByteArrayLiteral("CCAllowList"),
+ {bitflags});
+ // Add 'CCOptForceCrossCall' item
+ // (Always do cross call optimization).
+ addOptionsGroup(QByteArrayLiteral("CCOptForceCrossCall"),
+ {opts.enableForceCrossCall});
+}
+
+void AvrCompilerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'CCDefines' item (Defines symbols).
+ addOptionsGroup(QByteArrayLiteral("CCDefines"),
+ opts.defineSymbols);
+ // Add 'newCCIncludePaths' item
+ // (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("newCCIncludePaths"),
+ opts.includePaths);
+}
+
+void AvrCompilerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'CCWarnAsError' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("CCWarnAsError"),
+ {opts.warningsAsErrors});
+}
+
+void AvrCompilerSettingsGroup::buildCodePage(
+ const ProductData &qbsProduct)
+{
+ const CodePageOptions opts(qbsProduct);
+ // Add 'CCConstInRAM' item (Place string literals
+ // and constants in initialized RAM).
+ addOptionsGroup(QByteArrayLiteral("CCConstInRAM"),
+ {opts.placeConstantsInRam});
+ // Add 'CCInitInFlash' item (Place aggregate
+ // initializiers in flash memory).
+ addOptionsGroup(QByteArrayLiteral("CCInitInFlash"),
+ {opts.placeInitializiersInFlash});
+ // Add 'CCForceVariables' item (Force generation of
+ // all global and static variables).
+ addOptionsGroup(QByteArrayLiteral("CCForceVariables"),
+ {opts.forceVariablesGeneration});
+ // Add 'CCOldCallConv' item (Use ICCA90 1.x
+ // calling convention).
+ addOptionsGroup(QByteArrayLiteral("CCOldCallConv"),
+ {opts.useIccA90CallingConvention});
+ // Add 'CCLockRegs' item (Number of registers to
+ // lock for global variables).
+ addOptionsGroup(QByteArrayLiteral("CCLockRegs"),
+ {opts.lockRegistersCount});
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.h
new file mode 100644
index 000000000..2d8c53b84
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrcompilersettingsgroup_v7.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRCOMPILERSETTINGSGROUP_V7_H
+#define QBS_IAREWAVRCOMPILERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrCompilerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit AvrCompilerSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildLanguageOnePage(const ProductData &qbsProduct);
+ void buildLanguageTwoPage(const ProductData &qbsProduct);
+ void buildOptimizationsPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildCodePage(const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRCOMPILERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.cpp
new file mode 100644
index 000000000..a4819a90d
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.cpp
@@ -0,0 +1,774 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrgeneralsettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+constexpr int kGeneralArchiveVersion = 12;
+constexpr int kGeneralDataVersion = 10;
+
+namespace {
+
+struct TargetMcuEntry final
+{
+ QByteArray targetName;
+ QByteArray targetFlag;
+};
+
+// Dictionary of known AVR MCU's and its compiler options.
+static const TargetMcuEntry mcusDict[] = {
+ {"AT43USB320A", "at43usb320a"},
+ {"AT43USB325", "at43usb325"},
+ {"AT43USB326", "at43usb326"},
+ {"AT43USB351M", "at43usb351m"},
+ {"AT43USB353M", "at43usb353m"},
+ {"AT43USB355", "at43usb355"},
+ {"AT76C712", "at76c712"},
+ {"AT76C713", "at76c713"},
+ {"AT86RF401", "at86rf401"},
+ {"AT90CAN128", "can128"},
+ {"AT90CAN32", "can32"},
+ {"AT90CAN64", "can64"},
+ {"AT90PWM1", "pwm1"},
+ {"AT90PWM161", "pwm161"},
+ {"AT90PWM2", "pwm2"},
+ {"AT90PWM216", "pwm216"},
+ {"AT90PWM2B", "pwm2b"},
+ {"AT90PWM3", "pwm3"},
+ {"AT90PWM316", "pwm316"},
+ {"AT90PWM3B", "pwm3b"},
+ {"AT90PWM81", "pwm81"},
+ {"AT90S1200", "1200"},
+ {"AT90S2313", "2313"},
+ {"AT90S2323", "2323"},
+ {"AT90S2333", "2333"},
+ {"AT90S2343", "2343"},
+ {"AT90S4414", "4414"},
+ {"AT90S4433", "4433"},
+ {"AT90S4434", "4434"},
+ {"AT90S8515", "8515"},
+ {"AT90S8534", "8534"},
+ {"AT90S8535", "8535"},
+ {"AT90SCR050", "scr050"},
+ {"AT90SCR075", "scr075"},
+ {"AT90SCR100", "scr100"},
+ {"AT90SCR200", "scr200"},
+ {"AT90SCR400", "scr400"},
+ {"AT90USB128", "usb128"},
+ {"AT90USB1286", "usb1286"},
+ {"AT90USB1287", "usb1287"},
+ {"AT90USB162", "usb162"},
+ {"AT90USB64", "usb64"},
+ {"AT90USB646", "usb646"},
+ {"AT90USB647", "usb647"},
+ {"AT90USB82", "usb82"},
+ {"AT94Kxx", "at94k"},
+ {"ATA5272", "ata5272"},
+ {"ATA5505", "ata5505"},
+ {"ATA5700M322", "ata5700m322"},
+ {"ATA5702M322", "ata5702m322"},
+ {"ATA5781", "ata5781"},
+ {"ATA5782", "ata5782"},
+ {"ATA5783", "ata5783"},
+ {"ATA5785", "ata5785"},
+ {"ATA5787", "ata5787"},
+ {"ATA5790", "ata5790"},
+ {"ATA5790N", "ata5790n"},
+ {"ATA5795", "ata5795"},
+ {"ATA5830", "ata5830"},
+ {"ATA5831", "ata5831"},
+ {"ATA5832", "ata5832"},
+ {"ATA5833", "ata5833"},
+ {"ATA5835", "ata5835"},
+ {"ATA6285", "ata6285"},
+ {"ATA6286", "ata6286"},
+ {"ATA6289", "ata6289"},
+ {"ATA8210", "ata8210"},
+ {"ATA8215", "ata8215"},
+ {"ATA8510", "ata8510"},
+ {"ATA8515", "ata8515"},
+ {"ATmX224E", "mx224e"},
+ {"ATmXT112SL", "mxt112sl"},
+ {"ATmXT224", "mxt224"},
+ {"ATmXT224E", "mxt224e"},
+ {"ATmXT336S", "mxt336s"},
+ {"ATmXT540S", "mxt540s"},
+ {"ATmXT540S_RevA", "mxt540s_reva"},
+ {"ATmXTS200", "mxts200"},
+ {"ATmXTS220", "mxts220"},
+ {"ATmXTS220E", "mxts220e"},
+ {"ATmega007", "m007"},
+ {"ATmega103", "m103"},
+ {"ATmega128", "m128"},
+ {"ATmega1280", "m1280"},
+ {"ATmega1281", "m1281"},
+ {"ATmega1284", "m1284"},
+ {"ATmega1284P", "m1284p"},
+ {"ATmega1284RFR2", "m1284rfr2"},
+ {"ATmega128A", "m128a"},
+ {"ATmega128RFA1", "m128rfa1"},
+ {"ATmega128RFA2", "m128rfa2"},
+ {"ATmega128RFR2", "m128rfr2"},
+ {"ATmega16", "m16"},
+ {"ATmega1608", "m1608"},
+ {"ATmega1609", "m1609"},
+ {"ATmega161", "m161"},
+ {"ATmega162", "m162"},
+ {"ATmega163", "m163"},
+ {"ATmega164", "m164"},
+ {"ATmega164A", "m164a"},
+ {"ATmega164P", "m164p"},
+ {"ATmega164PA", "m164pa"},
+ {"ATmega165", "m165"},
+ {"ATmega165A", "m165a"},
+ {"ATmega165P", "m165p"},
+ {"ATmega165PA", "m165pa"},
+ {"ATmega168", "m168"},
+ {"ATmega168A", "m168a"},
+ {"ATmega168P", "m168p"},
+ {"ATmega168PA", "m168pa"},
+ {"ATmega168PB", "m168pb"},
+ {"ATmega169", "m169"},
+ {"ATmega169A", "m169a"},
+ {"ATmega169P", "m169p"},
+ {"ATmega169PA", "m169pa"},
+ {"ATmega16A", "m16a"},
+ {"ATmega16HVA", "m16hva"},
+ {"ATmega16HVA2", "m16hva2"},
+ {"ATmega16HVB", "m16hvb"},
+ {"ATmega16M1", "m16m1"},
+ {"ATmega16U2", "m16u2"},
+ {"ATmega16U4", "m16u4"},
+ {"ATmega2560", "m2560"},
+ {"ATmega2561", "m2561"},
+ {"ATmega2564RFR2", "m2564rfr2"},
+ {"ATmega256RFA2", "m256rfa2"},
+ {"ATmega256RFR2", "m256rfr2"},
+ {"ATmega26HVG", "m26hvg"},
+ {"ATmega32", "m32"},
+ {"ATmega3208", "m3208"},
+ {"ATmega3209", "m3209"},
+ {"ATmega323", "m323"},
+ {"ATmega324", "m324"},
+ {"ATmega324A", "m324a"},
+ {"ATmega324P", "m324p"},
+ {"ATmega324PA", "m324pa"},
+ {"ATmega324PB", "m324pb"},
+ {"ATmega325", "m325"},
+ {"ATmega3250", "m3250"},
+ {"ATmega3250A", "m3250a"},
+ {"ATmega3250P", "m3250p"},
+ {"ATmega3250PA", "m3250pa"},
+ {"ATmega325A", "m325a"},
+ {"ATmega325P", "m325p"},
+ {"ATmega325PA", "m325pa"},
+ {"ATmega328", "m328"},
+ {"ATmega328P", "m328p"},
+ {"ATmega328PB", "m328pb"},
+ {"ATmega329", "m329"},
+ {"ATmega3290", "m3290"},
+ {"ATmega3290A", "m3290a"},
+ {"ATmega3290P", "m3290p"},
+ {"ATmega3290PA", "m3290pa"},
+ {"ATmega329A", "m329a"},
+ {"ATmega329P", "m329p"},
+ {"ATmega329PA", "m329pa"},
+ {"ATmega32A", "m32a"},
+ {"ATmega32C1", "m32c1"},
+ {"ATmega32HVB", "m32hvb"},
+ {"ATmega32M1", "m32m1"},
+ {"ATmega32U2", "m32u2"},
+ {"ATmega32U4", "m32u4"},
+ {"ATmega32U6", "m32u6"},
+ {"ATmega406", "m406"},
+ {"ATmega48", "m48"},
+ {"ATmega4808", "m4808"},
+ {"ATmega4809", "m4809"},
+ {"ATmega48A", "m48a"},
+ {"ATmega48HVF", "m48hvf"},
+ {"ATmega48P", "m48p"},
+ {"ATmega48PA", "m48pa"},
+ {"ATmega48PB", "m48pb"},
+ {"ATmega4HVD", "m4hvd"},
+ {"ATmega603", "m603"},
+ {"ATmega64", "m64"},
+ {"ATmega640", "m640"},
+ {"ATmega644", "m644"},
+ {"ATmega644A", "m644a"},
+ {"ATmega644P", "m644p"},
+ {"ATmega644PA", "m644pa"},
+ {"ATmega644RFR2", "m644rfr2"},
+ {"ATmega645", "m645"},
+ {"ATmega6450", "m6450"},
+ {"ATmega6450A", "m6450a"},
+ {"ATmega6450P", "m6450p"},
+ {"ATmega645A", "m645a"},
+ {"ATmega645P", "m645p"},
+ {"ATmega649", "m649"},
+ {"ATmega6490", "m6490"},
+ {"ATmega6490A", "m6490a"},
+ {"ATmega6490P", "m6490p"},
+ {"ATmega649A", "m649a"},
+ {"ATmega649P", "m649p"},
+ {"ATmega64A", "m64a"},
+ {"ATmega64C1", "m64c1"},
+ {"ATmega64HVE", "m256rfa2"},
+ {"ATmega64HVE", "m64hve"},
+ {"ATmega64HVE2", "m64hve2"},
+ {"ATmega64M1", "m64m1"},
+ {"ATmega64RFA2", "m64rfa2"},
+ {"ATmega64RFR2", "m64rfr2"},
+ {"ATmega8", "m8"},
+ {"ATmega808", "m808"},
+ {"ATmega809", "m809"},
+ {"ATmega83", "m83"},
+ {"ATmega8515", "m8515"},
+ {"ATmega8535", "m8535"},
+ {"ATmega88", "m88"},
+ {"ATmega88A", "m88a"},
+ {"ATmega88P", "m88p"},
+ {"ATmega88PA", "m88pa"},
+ {"ATmega88PB", "m88pb"},
+ {"ATmega8A", "m8a"},
+ {"ATmega8HVA", "m8hva"},
+ {"ATmega8HVD", "m8hvd"},
+ {"ATmega8U2", "m8u2"},
+ {"ATtiny10", "tiny10"},
+ {"ATtiny102", "tiny102"},
+ {"ATtiny104", "tiny104"},
+ {"ATtiny11", "tiny11"},
+ {"ATtiny12", "tiny12"},
+ {"ATtiny13", "tiny13"},
+ {"ATtiny13A", "tiny13a"},
+ {"ATtiny15", "tiny15"},
+ {"ATtiny1604", "tiny1604"},
+ {"ATtiny1606", "tiny1606"},
+ {"ATtiny1607", "tiny1607"},
+ {"ATtiny1614", "tiny1614"},
+ {"ATtiny1616", "tiny1616"},
+ {"ATtiny1617", "tiny1617"},
+ {"ATtiny1634", "tiny1634"},
+ {"ATtiny167", "tiny167"},
+ {"ATtiny20", "tiny20"},
+ {"ATtiny202", "tiny202"},
+ {"ATtiny204", "tiny204"},
+ {"ATtiny212", "tiny212"},
+ {"ATtiny214", "tiny214"},
+ {"ATtiny22", "tiny22"},
+ {"ATtiny2313", "tiny2313"},
+ {"ATtiny2313A", "tiny2313a"},
+ {"ATtiny23U", "tiny23u"},
+ {"ATtiny24", "tiny24"},
+ {"ATtiny24A", "tiny24a"},
+ {"ATtiny25", "tiny25"},
+ {"ATtiny26", "tiny26"},
+ {"ATtiny261", "tiny261"},
+ {"ATtiny261A", "tiny261a"},
+ {"ATtiny28", "tiny28"},
+ {"ATtiny3214", "tiny3214"},
+ {"ATtiny3216", "tiny3216"},
+ {"ATtiny3217", "tiny3217"},
+ {"ATtiny4", "tiny4"},
+ {"ATtiny40", "tiny40"},
+ {"ATtiny402", "tiny402"},
+ {"ATtiny404", "tiny404"},
+ {"ATtiny406", "tiny406"},
+ {"ATtiny412", "tiny412"},
+ {"ATtiny414", "tiny414"},
+ {"ATtiny416", "tiny416"},
+ {"ATtiny417", "tiny417"},
+ {"ATtiny4313", "tiny4313"},
+ {"ATtiny43U", "tiny43u"},
+ {"ATtiny44", "tiny44"},
+ {"ATtiny441", "tiny441"},
+ {"ATtiny44A", "tiny44a"},
+ {"ATtiny45", "tiny45"},
+ {"ATtiny461", "tiny461"},
+ {"ATtiny461A", "tiny461a"},
+ {"ATtiny474", "tiny474"},
+ {"ATtiny48", "tiny48"},
+ {"ATtiny5", "tiny5"},
+ {"ATtiny80", "tiny80"},
+ {"ATtiny804", "tiny804"},
+ {"ATtiny806", "tiny806"},
+ {"ATtiny807", "tiny807"},
+ {"ATtiny80_pre_2015", "tiny80_pre_2015"},
+ {"ATtiny814", "tiny814"},
+ {"ATtiny816", "tiny816"},
+ {"ATtiny817", "tiny817"},
+ {"ATtiny828", "tiny828"},
+ {"ATtiny84", "tiny84"},
+ {"ATtiny840", "tiny840"},
+ {"ATtiny841", "tiny841"},
+ {"ATtiny84A", "tiny84a"},
+ {"ATtiny85", "tiny85"},
+ {"ATtiny861", "tiny861"},
+ {"ATtiny861A", "tiny861a"},
+ {"ATtiny87", "tiny87"},
+ {"ATtiny88", "tiny88"},
+ {"ATtiny9", "tiny9"},
+ {"ATxmega128A1", "xm128a1"},
+ {"ATxmega128A1U", "xm128a1u"},
+ {"ATxmega128A3", "xm128a3"},
+ {"ATxmega128A3U", "xm128a3u"},
+ {"ATxmega128A4", "xm128a4"},
+ {"ATxmega128A4U", "xm128a4u"},
+ {"ATxmega128B1", "xm128b1"},
+ {"ATxmega128B3", "xm128b3"},
+ {"ATxmega128C3", "xm128c3"},
+ {"ATxmega128D3", "xm128d3"},
+ {"ATxmega128D4", "xm128d4"},
+ {"ATxmega16A4", "xm16a4"},
+ {"ATxmega16A4U", "xm16a4u"},
+ {"ATxmega16C4", "xm16c4"},
+ {"ATxmega16D4", "xm16d4"},
+ {"ATxmega16E5", "xm16e5"},
+ {"ATxmega192A1", "xm192a1"},
+ {"ATxmega192A3", "xm192a3"},
+ {"ATxmega192A3U", "xm192a3u"},
+ {"ATxmega192C3", "xm192c3"},
+ {"ATxmega192D3", "xm192d3"},
+ {"ATxmega256A1", "xm256a1"},
+ {"ATxmega256A3", "xm256a3"},
+ {"ATxmega256A3B", "xm256a3b"},
+ {"ATxmega256A3BU", "xm256a3bu"},
+ {"ATxmega256A3U", "xm256a3u"},
+ {"ATxmega256B1", "xm256b1"},
+ {"ATxmega256C3", "xm256c3"},
+ {"ATxmega256D3", "xm256d3"},
+ {"ATxmega32A4", "xm32a4"},
+ {"ATxmega32A4U", "xm32a4u"},
+ {"ATxmega32C3", "xm32c3"},
+ {"ATxmega32C4", "xm32c4"},
+ {"ATxmega32D3", "xm32d3"},
+ {"ATxmega32D4", "xm32d4"},
+ {"ATxmega32D4P", "xm32d4p"},
+ {"ATxmega32E5", "xm32e5"},
+ {"ATxmega32X1", "xm32x1"},
+ {"ATxmega384A1", "xm384a1"},
+ {"ATxmega384C3", "xm384c3"},
+ {"ATxmega384D3", "xm384d3"},
+ {"ATxmega64A1", "xm64a1"},
+ {"ATxmega64A1U", "xm64a1u"},
+ {"ATxmega64A3", "xm64a3"},
+ {"ATxmega64A3U", "xm64a3u"},
+ {"ATxmega64A4", "xm64a4"},
+ {"ATxmega64A4U", "xm64a4u"},
+ {"ATxmega64B1", "xm64b1"},
+ {"ATxmega64B3", "xm64b3"},
+ {"ATxmega64C3", "xm64c3"},
+ {"ATxmega64D3", "xm64d3"},
+ {"ATxmega64D4", "xm64d4"},
+ {"ATxmega8E5", "xm8e5"},
+ {"M3000", "m3000"},
+ {"MaxBSE", "maxbse"},
+};
+
+// Target page options.
+
+struct TargetPageOptions final
+{
+ enum MemoryModel {
+ TinyModel,
+ SmallModel,
+ LargeModel,
+ HugeModel
+ };
+
+ explicit TargetPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags")});
+ // Detect target MCU record.
+ const QString mcuValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--cpu")).toLower();
+ targetMcu = mcuStringFromFlagValue(mcuValue);
+ // Detect target memory model.
+ const QString modelValue = IarewUtils::flagValue(
+ flags, QStringLiteral("-m"));
+ if (modelValue == QLatin1Char('t'))
+ memoryModel = TargetPageOptions::TinyModel;
+ else if (modelValue == QLatin1Char('s'))
+ memoryModel = TargetPageOptions::SmallModel;
+ else if (modelValue == QLatin1Char('l'))
+ memoryModel = TargetPageOptions::LargeModel;
+ else if (modelValue == QLatin1Char('h'))
+ memoryModel = TargetPageOptions::HugeModel;
+ // Detect target EEPROM util size.
+ eepromUtilSize = IarewUtils::flagValue(
+ flags, QStringLiteral("--eeprom_size")).toInt();
+ }
+
+ static QString mcuStringFromFlagValue(const QString &mcuValue)
+ {
+ const auto targetBegin = std::cbegin(mcusDict);
+ const auto targetEnd = std::cend(mcusDict);
+ const auto targetIt = std::find_if(targetBegin, targetEnd,
+ [mcuValue](
+ const TargetMcuEntry &entry) {
+ return entry.targetFlag == mcuValue.toLatin1();
+ });
+ if (targetIt != targetEnd) {
+ return QStringLiteral("%1\t%2")
+ .arg(QString::fromLatin1(targetIt->targetFlag),
+ QString::fromLatin1(targetIt->targetName));
+ }
+ return {};
+ }
+
+ QString targetMcu;
+ MemoryModel memoryModel = TinyModel;
+ int eepromUtilSize = 0;
+};
+
+// System page options.
+
+struct SystemPageOptions final
+{
+ explicit SystemPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverLinkerFlags"),
+ QStringLiteral("defines")});
+ cstackSize = IarewUtils::flagValue(
+ flags, QStringLiteral("_..X_CSTACK_SIZE")).toInt();
+ rstackSize = IarewUtils::flagValue(
+ flags, QStringLiteral("_..X_RSTACK_SIZE")).toInt();
+ }
+
+ int cstackSize = 0;
+ int rstackSize = 0;
+};
+
+// Library options page options.
+
+struct LibraryOptionsPageOptions final
+{
+ enum PrintfFormatter {
+ PrintfAutoFormatter = 0,
+ PrintfFullFormatter = 1,
+ PrintfFullNoMultibytesFormatter = 2,
+ PrintfLargeFormatter = 3,
+ PrintfLargeNoMultibytesFormatter = 4,
+ PrintfSmallFormatter = 6,
+ PrintfSmallNoMultibytesFormatter = 7,
+ PrintfTinyFormatter = 8
+ };
+
+ enum ScanfFormatter {
+ ScanfAutoFormatter = 0,
+ ScanfFullFormatter = 1,
+ ScanfFullNoMultibytesFormatter = 2,
+ ScanfLargeFormatter = 3,
+ ScanfLargeNoMultibytesFormatter = 4,
+ ScanfSmallFormatter = 6,
+ ScanfSmallNoMultibytesFormatter = 7
+ };
+
+ explicit LibraryOptionsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ for (const QString &flag : flags) {
+ if (flag.endsWith(QLatin1String("_printf"), Qt::CaseInsensitive)) {
+ const QString prop = flag.split(QLatin1Char('=')).at(0).toLower();
+ if (prop == QLatin1String("-e_printffull"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfFullFormatter;
+ else if (prop == QLatin1String("-e_printffullnomb"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("-e_printflarge"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfLargeFormatter;
+ else if (prop == QLatin1String("-e_printflargenomb"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfLargeNoMultibytesFormatter;
+ else if (prop == QLatin1String("-e_printfsmall"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfSmallFormatter;
+ else if (prop == QLatin1String("-e_printfsmallnomb"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfSmallNoMultibytesFormatter;
+ else if (prop == QLatin1String("-printftiny"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfTinyFormatter;
+ } else if (flag.endsWith(QLatin1String("_scanf"), Qt::CaseInsensitive)) {
+ const QString prop = flag.split(QLatin1Char('=')).at(0).toLower();
+ if (prop == QLatin1String("-e_scanffull"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfFullFormatter;
+ else if (prop == QLatin1String("-e_scanffullnomb"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("-e_scanflarge"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfLargeFormatter;
+ else if (prop == QLatin1String("-e_scanflargenomb"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfLargeNoMultibytesFormatter;
+ else if (prop == QLatin1String("-e_scanfsmall"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfSmallFormatter;
+ else if (prop == QLatin1String("-e_scanfsmallnomb"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfSmallNoMultibytesFormatter;
+ }
+ }
+ }
+
+ PrintfFormatter printfFormatter = PrintfAutoFormatter;
+ ScanfFormatter scanfFormatter = ScanfAutoFormatter;
+};
+
+// Library configuration page options.
+
+struct LibraryConfigPageOptions final
+{
+ enum RuntimeLibrary {
+ NoLibrary,
+ NormalDlibLibrary,
+ FullDlibLibrary,
+ CustomDlibLibrary,
+ ClibLibrary,
+ CustomClibLibrary,
+ ThirdPartyLibrary
+ };
+
+ explicit LibraryConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("staticLibraries")});
+ const auto libraryBegin = libraryPaths.cbegin();
+ const auto libraryEnd = libraryPaths.cend();
+
+ if (flags.contains(QLatin1String("--dlib"))) {
+ const QString dlibToolkitPath =
+ IarewUtils::dlibToolkitRootPath(qbsProduct);
+ const QFileInfo configInfo(IarewUtils::flagValue(
+ flags,
+ QStringLiteral("--dlib_config")));
+ const QString configFilePath = configInfo.absoluteFilePath();
+ if (configFilePath.startsWith(dlibToolkitPath,
+ Qt::CaseInsensitive)) {
+ if (configFilePath.endsWith(QLatin1String("-n.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::NormalDlibLibrary;
+ } else if (configFilePath.endsWith(QLatin1String("-f.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::FullDlibLibrary;
+ } else {
+ libraryType = LibraryConfigPageOptions::CustomDlibLibrary;
+ }
+
+ configPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, configFilePath);
+
+ // Find dlib library inside of IAR toolkit directory.
+ const auto libraryIt = std::find_if(libraryBegin, libraryEnd,
+ [dlibToolkitPath](
+ const QString &libraryPath) {
+ return libraryPath.startsWith(dlibToolkitPath);
+ });
+ if (libraryIt != libraryEnd) {
+ // This means that dlib library is 'standard' (placed inside
+ // of IAR toolkit directory).
+ libraryPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, *libraryIt);
+ }
+ } else {
+ // This means that dlib library is 'custom'
+ // (but we don't know its path).
+ libraryType = LibraryConfigPageOptions::CustomDlibLibrary;
+ configPath = IarewUtils::projectRelativeFilePath(
+ baseDirectory, configFilePath);
+ }
+ } else if (flags.contains(QLatin1String("--clib"))) {
+ const QString clibToolkitPath =
+ IarewUtils::clibToolkitRootPath(qbsProduct);
+ // Find clib library inside of IAR toolkit directory.
+ const auto libraryIt = std::find_if(libraryBegin, libraryEnd,
+ [clibToolkitPath](
+ const QString &libraryPath) {
+ return libraryPath.startsWith(clibToolkitPath);
+ });
+ if (libraryIt != libraryEnd) {
+ // This means that clib library is 'standard' (placed inside
+ // of IAR toolkit directory).
+ libraryType = LibraryConfigPageOptions::ClibLibrary;
+ libraryPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, *libraryIt);
+ } else {
+ // This means that clib library is 'custom'
+ // (but we don't know its path).
+ libraryType = LibraryConfigPageOptions::CustomClibLibrary;
+ }
+ } else {
+ libraryType = LibraryConfigPageOptions::NoLibrary;
+ }
+ }
+
+ RuntimeLibrary libraryType = NoLibrary;
+ QString configPath;
+ QString libraryPath;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ binaryType = IarewUtils::outputBinaryType(qbsProduct);
+ binaryDirectory = gen::utils::binaryOutputDirectory(
+ baseDirectory, qbsProduct);
+ objectDirectory = gen::utils::objectsOutputDirectory(
+ baseDirectory, qbsProduct);
+ listingDirectory = gen::utils::listingOutputDirectory(
+ baseDirectory, qbsProduct);
+ }
+
+ IarewUtils::OutputBinaryType binaryType = IarewUtils::ApplicationOutputType;
+ QString binaryDirectory;
+ QString objectDirectory;
+ QString listingDirectory;
+};
+
+} // namespace
+
+// AvrGeneralSettingsGroup
+
+AvrGeneralSettingsGroup::AvrGeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("General"));
+ setArchiveVersion(kGeneralArchiveVersion);
+ setDataVersion(kGeneralDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildTargetPage(qbsProduct);
+ buildSystemPage(qbsProduct);
+ buildLibraryOptionsPage(qbsProduct);
+ buildLibraryConfigPage(buildRootDirectory, qbsProduct);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void AvrGeneralSettingsGroup::buildTargetPage(
+ const ProductData &qbsProduct)
+{
+ const TargetPageOptions opts(qbsProduct);
+ // Add 'GenDeviceSelectMenu' item
+ // (Processor configuration chooser).
+ addOptionsGroup(QByteArrayLiteral("GenDeviceSelectMenu"),
+ {opts.targetMcu});
+ // Add 'Variant Memory' item
+ // (Memory model: tiny/small/large/huge).
+ addOptionsGroup(QByteArrayLiteral("Variant Memory"),
+ {opts.memoryModel});
+ // Add 'GGEepromUtilSize' item
+ // (Utilize inbuilt EEPROM size, in bytes).
+ addOptionsGroup(QByteArrayLiteral("GGEepromUtilSize"),
+ {opts.eepromUtilSize});
+}
+
+void AvrGeneralSettingsGroup::buildSystemPage(
+ const ProductData &qbsProduct)
+{
+ const SystemPageOptions opts (qbsProduct);
+ // Add 'SCCStackSize' item (Data stack
+ // - CSTACK size in bytes).
+ addOptionsGroup(QByteArrayLiteral("SCCStackSize"),
+ {opts.cstackSize});
+ // Add 'SCRStackSize' item (Return address stack
+ // - RSTACK depth in bytes).
+ addOptionsGroup(QByteArrayLiteral("SCRStackSize"),
+ {opts.rstackSize});
+}
+
+void AvrGeneralSettingsGroup::buildLibraryOptionsPage(
+ const ProductData &qbsProduct)
+{
+ const LibraryOptionsPageOptions opts(qbsProduct);
+ // Add 'Output variant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("Output variant"),
+ {opts.printfFormatter});
+ // Add 'Input variant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("Input variant"),
+ {opts.scanfFormatter});
+}
+
+void AvrGeneralSettingsGroup::buildLibraryConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GRuntimeLibSelect' and 'GRuntimeLibSelectSlave' items
+ // (Link with runtime: none/dlib/clib/etc).
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelect"),
+ {opts.libraryType});
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelectSlave"),
+ {opts.libraryType});
+ // Add 'RTConfigPath' item (Runtime configuration file).
+ addOptionsGroup(QByteArrayLiteral("RTConfigPath"),
+ {opts.configPath});
+ // Add 'RTLibraryPath' item (Runtime library file).
+ addOptionsGroup(QByteArrayLiteral("RTLibraryPath"),
+ {opts.libraryPath});
+}
+
+void AvrGeneralSettingsGroup::buildOutputPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GOutputBinary' item (Output file: executable/library).
+ addOptionsGroup(QByteArrayLiteral("GOutputBinary"),
+ {opts.binaryType});
+ // Add 'ExePath' item (Executable/binaries output directory).
+ addOptionsGroup(QByteArrayLiteral("ExePath"),
+ {opts.binaryDirectory});
+ // Add 'ObjPath' item (Object files output directory).
+ addOptionsGroup(QByteArrayLiteral("ObjPath"),
+ {opts.objectDirectory});
+ // Add 'ListPath' item (List files output directory).
+ addOptionsGroup(QByteArrayLiteral("ListPath"),
+ {opts.listingDirectory});
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.h
new file mode 100644
index 000000000..5411eeae8
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrgeneralsettingsgroup_v7.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRGENERALSETTINGSGROUP_V7_H
+#define QBS_IAREWAVRGENERALSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrGeneralSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit AvrGeneralSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildTargetPage(const ProductData &qbsProduct);
+ void buildSystemPage(const ProductData &qbsProduct);
+ void buildLibraryOptionsPage(const ProductData &qbsProduct);
+ void buildLibraryConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRGENERALSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.cpp
new file mode 100644
index 000000000..59ba515d9
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.cpp
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "avrlinkersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+constexpr int kLinkerArchiveVersion = 3;
+constexpr int kLinkerDataVersion = 16;
+
+namespace {
+
+// Config page options.
+
+struct ConfigPageOptions final
+{
+ explicit ConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+
+ entryPoint = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("entryPoint"));
+
+ // Enumerate all product linker config files
+ // (which are set trough 'linkerscript' tag).
+ const auto qbsGroups = qbsProduct.groups();
+ for (const auto &qbsGroup : qbsGroups) {
+ const auto qbsArtifacts = qbsGroup.sourceArtifacts();
+ for (const auto &qbsArtifact : qbsArtifacts) {
+ const auto qbsTags = qbsArtifact.fileTags();
+ if (!qbsTags.contains(QLatin1String("linkerscript")))
+ continue;
+ const QString fullConfigPath = qbsArtifact.filePath();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ configFilePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ configFilePaths.push_back(path);
+ }
+ }
+ }
+
+ // Enumerate all product linker config files
+ // (which are set trough '-f' option).
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ const QVariantList configPathValues = IarewUtils::flagValues(
+ flags, QStringLiteral("-f"));
+ for (const QVariant &configPathValue : configPathValues) {
+ const QString fullConfigPath = configPathValue.toString();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ }
+ }
+
+ // Add libraries search paths.
+ const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("libraryPaths")});
+ for (const QString &libraryPath : libraryPaths) {
+ const QFileInfo libraryPathInfo(libraryPath);
+ const QString fullLibrarySearchPath =
+ libraryPathInfo.absoluteFilePath();
+ if (fullLibrarySearchPath.startsWith(toolkitPath,
+ Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ }
+ }
+
+ // Add static libraries paths.
+ const QStringList staticLibrariesProps =
+ gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("staticLibraries")});
+ for (const QString &staticLibrary : staticLibrariesProps) {
+ const QFileInfo staticLibraryInfo(staticLibrary);
+ if (staticLibraryInfo.isAbsolute()) {
+ const QString fullStaticLibraryPath =
+ staticLibraryInfo.absoluteFilePath();
+ if (fullStaticLibraryPath.startsWith(toolkitPath,
+ Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullStaticLibraryPath);
+ staticLibraries.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullStaticLibraryPath);
+ staticLibraries.push_back(path);
+ }
+ } else {
+ staticLibraries.push_back(staticLibrary);
+ }
+ }
+
+ // Add static libraries from product dependencies.
+ for (const ProductData &qbsProductDep : qbsProductDeps) {
+ const QString depBinaryPath = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory,
+ qbsProductDep);
+ staticLibraries.push_back(depBinaryPath);
+ }
+ }
+
+ QVariantList configFilePaths;
+ QVariantList librarySearchPaths;
+ QVariantList staticLibraries;
+ QString entryPoint;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ outputFile = gen::utils::targetBinary(qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+// List page options.
+
+struct ListPageOptions final
+{
+ enum ListingAction {
+ NoListing,
+ GenerateListing
+ };
+
+ explicit ListPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ generateMap = gen::utils::cppBooleanModuleProperty(
+ qbsProps, QStringLiteral("generateLinkerMapFile"))
+ ? ListPageOptions::GenerateListing
+ : ListPageOptions::NoListing;
+ }
+
+ ListingAction generateMap = NoListing;
+};
+
+// Define page options.
+
+struct DefinePageOptions final
+{
+ explicit DefinePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ // Enumerate all linker defines.
+ for (const QString &flag : flags) {
+ if (!flag.startsWith(QLatin1String("-D")))
+ continue;
+ const auto symbol = flag.mid(2);
+ // Ignore system-defined macroses.
+ if (symbol.startsWith(QLatin1String("_..X_HEAP_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_TINY_HEAP_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_NEAR_HEAP_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_FAR_HEAP_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_HUGE_HEAP_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_CSTACK_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_RSTACK_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_FLASH_CODE_END"))
+ || symbol.startsWith(QLatin1String("_..X_FLASH_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_CSTACK_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_CSTACK_END"))
+ || symbol.startsWith(QLatin1String("_..X_RSTACK_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_RSTACK_END"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_SRAM_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_SRAM_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_ROM_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_ROM_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_NV_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_EXT_NV_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_SRAM_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_SRAM_SIZE"))
+ || symbol.startsWith(QLatin1String("_..X_RSTACK_BASE"))
+ || symbol.startsWith(QLatin1String("_..X_RSTACK_SIZE"))
+ ) {
+ continue;
+ }
+ defineSymbols.push_back(symbol);
+ }
+ }
+
+ QVariantList defineSymbols;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString warningLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ suppressAllWarnings = (warningLevel == QLatin1String("none"));
+ }
+
+ int suppressAllWarnings = 0;
+};
+
+} // namespace
+
+// AvrLinkerSettingsGroup
+
+AvrLinkerSettingsGroup::AvrLinkerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ setName(QByteArrayLiteral("XLINK"));
+ setArchiveVersion(kLinkerArchiveVersion);
+ setDataVersion(kLinkerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildConfigPage(buildRootDirectory, qbsProduct, qbsProductDeps);
+ buildOutputPage(qbsProduct);
+ buildListPage(qbsProduct);
+ buildDefinePage(qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+
+ // Should be called as latest stage!
+ buildExtraOptionsPage(qbsProduct);
+}
+
+void AvrLinkerSettingsGroup::buildConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ ConfigPageOptions opts(baseDirectory, qbsProduct, qbsProductDeps);
+
+ if (opts.configFilePaths.count() > 0) {
+ // Note: IAR IDE does not allow to specify a multiple config files,
+ // although the IAR linker support it. So, we use followig 'trick':
+ // we take a first config file and to add it as usual to required items;
+ // and then an other remainders we forward to the "Extra options page".
+ const QVariant configPath = opts.configFilePaths.takeFirst();
+ // Add 'XclOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("XclOverride"),
+ {1});
+ // Add 'XclFile' item (Linke configuration file).
+ addOptionsGroup(QByteArrayLiteral("XclFile"),
+ {configPath});
+
+ // Add remainder configuration files to the "Extra options page".
+ if (!opts.configFilePaths.isEmpty()) {
+ for (QVariant &configPath : opts.configFilePaths)
+ configPath = QLatin1String("-f ") + configPath.toString();
+
+ m_extraOptions << opts.configFilePaths;
+ }
+ }
+
+ if (opts.staticLibraries.count() > 0)
+ m_extraOptions << opts.staticLibraries;
+
+ if (!opts.entryPoint.isEmpty()) {
+ // Add 'xcProgramEntryLabel' item (Entry symbol).
+ addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabel"),
+ {opts.entryPoint});
+ // Add 'xcOverrideProgramEntryLabel' item
+ // (Override default program entry).
+ addOptionsGroup(QByteArrayLiteral("xcOverrideProgramEntryLabel"),
+ {1});
+ // Add 'xcProgramEntryLabelSelect' item.
+ addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabelSelect"),
+ {0});
+ }
+
+ // Add 'XIncludes' item (Libraries search paths).
+ addOptionsGroup(QByteArrayLiteral("XIncludes"),
+ opts.librarySearchPaths);
+}
+
+void AvrLinkerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'XOutOverride' item (Override default output file).
+ addOptionsGroup(QByteArrayLiteral("XOutOverride"),
+ {1});
+ // Add 'OutputFile' item (Output file name).
+ addOptionsGroup(QByteArrayLiteral("OutputFile"),
+ {opts.outputFile});
+}
+
+void AvrLinkerSettingsGroup::buildListPage(
+ const ProductData &qbsProduct)
+{
+ const ListPageOptions opts(qbsProduct);
+ // Add 'XList' item (Generate linker listing).
+ addOptionsGroup(QByteArrayLiteral("XList"),
+ {opts.generateMap});
+}
+
+void AvrLinkerSettingsGroup::buildDefinePage(
+ const ProductData &qbsProduct)
+{
+ const DefinePageOptions opts(qbsProduct);
+ // Add 'XDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("XDefines"),
+ opts.defineSymbols);
+}
+
+void AvrLinkerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'SuppressAllWarn' item (Suppress all warnings).
+ addOptionsGroup(QByteArrayLiteral("SuppressAllWarn"),
+ {opts.suppressAllWarnings});
+}
+
+void AvrLinkerSettingsGroup::buildExtraOptionsPage(const ProductData &qbsProduct)
+{
+ Q_UNUSED(qbsProduct)
+
+ if (!m_extraOptions.isEmpty()) {
+ // Add 'XExtraOptionsCheck' (Use command line options).
+ addOptionsGroup(QByteArrayLiteral("XExtraOptionsCheck"),
+ {1});
+ // Add 'XExtraOptions' item (Command line options).
+ addOptionsGroup(QByteArrayLiteral("XExtraOptions"),
+ m_extraOptions);
+ }
+}
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.h
new file mode 100644
index 000000000..5427937b7
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/avr/avrlinkersettingsgroup_v7.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWAVRLINKERSETTINGSGROUP_V7_H
+#define QBS_IAREWAVRLINKERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace avr {
+namespace v7 {
+
+class AvrLinkerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit AvrLinkerSettingsGroup(const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildListPage(const ProductData &qbsProduct);
+ void buildDefinePage(const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildExtraOptionsPage(const ProductData &qbsProduct);
+
+ QVariantList m_extraOptions;
+};
+
+} // namespace v7
+} // namespace avr
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWAVRLINKERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.cpp
new file mode 100644
index 000000000..38264c653
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51archiversettingsgroup_v10.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+constexpr int kArchiverArchiveVersion = 2;
+constexpr int kArchiverDataVersion = 1;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ outputFile = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory, qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+} // namespace
+
+// Mcs51ArchiverSettingsGroup
+
+Mcs51ArchiverSettingsGroup::Mcs51ArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("XAR"));
+ setArchiveVersion(kArchiverArchiveVersion);
+ setDataVersion(kArchiverDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void Mcs51ArchiverSettingsGroup::buildOutputPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'XAROverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("XAROverride"),
+ {1});
+ // Add 'XAROutput2' item (Output filename).
+ addOptionsGroup(QByteArrayLiteral("XAROutput2"),
+ {opts.outputFile});
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.h
new file mode 100644
index 000000000..21c66433d
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51archiversettingsgroup_v10.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51ARCHIVERSETTINGSGROUP_V10_H
+#define QBS_IAREWMCS51ARCHIVERSETTINGSGROUP_V10_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51ArchiverSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Mcs51ArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51ARCHIVERSETTINGSGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.cpp
new file mode 100644
index 000000000..a840b29c6
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51assemblersettingsgroup_v10.h"
+
+//#include "../../iarewproperty.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+constexpr int kAssemblerArchiveVersion = 2;
+constexpr int kAssemblerDataVersion = 6;
+
+namespace {
+
+// Language page options.
+
+struct LanguagePageOptions final
+{
+ enum MacroQuoteCharacter {
+ AngleBracketsQuote,
+ RoundBracketsQuote,
+ SquareBracketsQuote,
+ FigureBracketsQuote
+ };
+
+ explicit LanguagePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("assemblerFlags")});
+ enableSymbolsCaseSensitive = flags.contains(QLatin1String("-s+"));
+ enableMultibyteSupport = flags.contains(QLatin1String("-n"));
+
+ if (flags.contains(QLatin1String("-M<>")))
+ macroQuoteCharacter = LanguagePageOptions::AngleBracketsQuote;
+ else if (flags.contains(QLatin1String("-M()")))
+ macroQuoteCharacter = LanguagePageOptions::RoundBracketsQuote;
+ else if (flags.contains(QLatin1String("-M[]")))
+ macroQuoteCharacter = LanguagePageOptions::SquareBracketsQuote;
+ else if (flags.contains(QLatin1String("-M{}")))
+ macroQuoteCharacter = LanguagePageOptions::FigureBracketsQuote;
+ }
+
+ MacroQuoteCharacter macroQuoteCharacter = AngleBracketsQuote;
+ int enableSymbolsCaseSensitive = 0;
+ int enableMultibyteSupport = 0;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ for (const auto &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString warningLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ if (warningLevel == QLatin1String("all")) {
+ enableWarnings = 0;
+ enableAllWarnings = 0;
+ } else if (warningLevel == QLatin1String("none")) {
+ enableWarnings = 1;
+ enableAllWarnings = 0;
+ } else {
+ enableWarnings = 0;
+ enableAllWarnings = 1;
+ }
+ }
+
+ int enableWarnings = 0;
+ int enableAllWarnings = 0;
+};
+
+} // namespace
+
+// Mcs51AssemblerSettingsGroup
+
+Mcs51AssemblerSettingsGroup::Mcs51AssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("A8051"));
+ setArchiveVersion(kAssemblerArchiveVersion);
+ setDataVersion(kAssemblerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildLanguagePage(qbsProduct);
+ buildOutputPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+}
+
+void Mcs51AssemblerSettingsGroup::buildLanguagePage(
+ const ProductData &qbsProduct)
+{
+ const LanguagePageOptions opts(qbsProduct);
+ // Add 'ACaseSensitivity' item (User symbols are case sensitive).
+ addOptionsGroup(QByteArrayLiteral("ACaseSensitivity"),
+ {opts.enableSymbolsCaseSensitive});
+ // Add 'Asm multibyte support' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("Asm multibyte support"),
+ {opts.enableMultibyteSupport});
+ // Add 'MacroChars' item (Macro quote characters: ()/[]/{}/<>).
+ addOptionsGroup(QByteArrayLiteral("MacroChars"),
+ {!opts.macroQuoteCharacter}, 0);
+}
+
+void Mcs51AssemblerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'Debug' item (Generate debug information).
+ addOptionsGroup(QByteArrayLiteral("Debug"),
+ {opts.debugInfo});
+}
+
+void Mcs51AssemblerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'ADefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("ADefines"),
+ opts.defineSymbols);
+ // Add 'Include directories' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("Include directories"),
+ opts.includePaths);
+}
+
+void Mcs51AssemblerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'AWarnEnable' item (Enable/disable warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnEnable"),
+ {opts.enableWarnings});
+ // Add 'AWarnWhat' item (Enable/disable all warnings).
+ addOptionsGroup(QByteArrayLiteral("AWarnWhat"),
+ {opts.enableAllWarnings});
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.h
new file mode 100644
index 000000000..bb9f4b613
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51assemblersettingsgroup_v10.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51ASSEMBLERSETTINGSGROUP_V10_H
+#define QBS_IAREWMCS51ASSEMBLERSETTINGSGROUP_V10_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51AssemblerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Mcs51AssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildLanguagePage(const ProductData &qbsProduct);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51ASSEMBLERSETTINGSGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.cpp
new file mode 100644
index 000000000..ba86bc54d
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51archiversettingsgroup_v10.h"
+#include "mcs51assemblersettingsgroup_v10.h"
+#include "mcs51buildconfigurationgroup_v10.h"
+#include "mcs51compilersettingsgroup_v10.h"
+#include "mcs51generalsettingsgroup_v10.h"
+#include "mcs51linkersettingsgroup_v10.h"
+
+#include "../../iarewtoolchainpropertygroup.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+Mcs51BuildConfigurationGroup::Mcs51BuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup("configuration")
+{
+ // Append configuration name item.
+ const QString cfgName = gen::utils::buildConfigurationName(qbsProject);
+ appendProperty("name", cfgName);
+
+ // Apend toolchain name group item.
+ appendChild<IarewToolchainPropertyGroup>("8051");
+
+ // Append debug info item.
+ const int debugBuild = gen::utils::debugInformation(qbsProduct);
+ appendProperty("debug", debugBuild);
+
+ // Append settings group items.
+ appendChild<Mcs51ArchiverSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Mcs51AssemblerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Mcs51CompilerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Mcs51GeneralSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Mcs51LinkerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+}
+
+bool Mcs51BuildConfigurationGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Mcs51
+ && version.majorVersion() == 10;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+Mcs51BuildConfigurationGroupFactory::create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const
+{
+ const auto group = new Mcs51BuildConfigurationGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<Mcs51BuildConfigurationGroup>(group);
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.h
new file mode 100644
index 000000000..edd16d5d7
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51buildconfigurationgroup_v10.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51BUILDCONFIGURATIONGROUP_V10_H
+#define QBS_IAREWMCS51BUILDCONFIGURATIONGROUP_V10_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51BuildConfigurationGroup final
+ : public gen::xml::PropertyGroup
+{
+private:
+ explicit Mcs51BuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+ friend class Mcs51BuildConfigurationGroupFactory;
+};
+
+class Mcs51BuildConfigurationGroupFactory final
+ : public gen::xml::PropertyGroupFactory
+{
+public:
+ bool canCreate(gen::utils::Architecture arch,
+ const Version &version) const final;
+
+ std::unique_ptr<gen::xml::PropertyGroup> create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const final;
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51BUILDCONFIGURATIONGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.cpp
new file mode 100644
index 000000000..649350a98
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.cpp
@@ -0,0 +1,476 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51compilersettingsgroup_v10.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+constexpr int kCompilerArchiveVersion = 7;
+constexpr int kCompilerDataVersion = 12;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ enum ModuleType {
+ ProgramModule,
+ LibraryModule
+ };
+
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ moduleType = flags.contains(QLatin1String("--library_module"))
+ ? OutputPageOptions::LibraryModule
+ : OutputPageOptions::ProgramModule;
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+ ModuleType moduleType = ProgramModule;
+};
+
+// Language one page options.
+
+struct LanguageOnePageOptions final
+{
+ enum LanguageExtension {
+ CLanguageExtension,
+ CxxLanguageExtension,
+ AutoLanguageExtension
+ };
+
+ enum CLanguageDialect {
+ C89LanguageDialect,
+ C99LanguageDialect
+ };
+
+ enum CxxLanguageDialect {
+ EmbeddedCPlusPlus,
+ ExtendedEmbeddedCPlusPlus
+ };
+
+ enum LanguageConformance {
+ AllowIarExtension,
+ RelaxedStandard,
+ StrictStandard
+ };
+
+ explicit LanguageOnePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ // File extension based by default.
+ languageExtension = LanguageOnePageOptions::AutoLanguageExtension;
+ // C language dialect.
+ const QStringList cLanguageVersion = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("cLanguageVersion")});
+ cLanguageDialect = cLanguageVersion.contains(QLatin1String("c89"))
+ ? LanguageOnePageOptions::C89LanguageDialect
+ : LanguageOnePageOptions::C99LanguageDialect;
+ // C++ language dialect.
+ if (flags.contains(QLatin1String("--ec++")))
+ cxxLanguageDialect = LanguageOnePageOptions::EmbeddedCPlusPlus;
+ else if (flags.contains(QLatin1String("--eec++")))
+ cxxLanguageDialect = LanguageOnePageOptions::ExtendedEmbeddedCPlusPlus;
+ // Language conformance.
+ if (flags.contains(QLatin1String("-e")))
+ languageConformance = LanguageOnePageOptions::AllowIarExtension;
+ else if (flags.contains(QLatin1String("--strict")))
+ languageConformance = LanguageOnePageOptions::StrictStandard;
+ else
+ languageConformance = LanguageOnePageOptions::RelaxedStandard;
+
+ allowVla = flags.contains(QLatin1String("--vla"));
+ useCppInlineSemantics = flags.contains(
+ QLatin1String("--use_c++_inline"));
+ requirePrototypes = flags.contains(
+ QLatin1String("--require_prototypes"));
+ destroyStaticObjects = !flags.contains(
+ QLatin1String("--no_static_destruction"));
+ }
+
+ LanguageExtension languageExtension = AutoLanguageExtension;
+ CLanguageDialect cLanguageDialect = C89LanguageDialect;
+ CxxLanguageDialect cxxLanguageDialect = EmbeddedCPlusPlus;
+ LanguageConformance languageConformance = AllowIarExtension;
+ int allowVla = 0;
+ int useCppInlineSemantics = 0;
+ int requirePrototypes = 0;
+ int destroyStaticObjects = 0;
+};
+
+// Language two page options.
+
+struct LanguageTwoPageOptions final
+{
+ enum PlainCharacter {
+ SignedCharacter,
+ UnsignedCharacter
+ };
+
+ enum FloatingPointSemantic {
+ StrictSemantic,
+ RelaxedSemantic
+ };
+
+ explicit LanguageTwoPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ plainCharacter = flags.contains(
+ QLatin1String("--char_is_signed"))
+ ? LanguageTwoPageOptions::SignedCharacter
+ : LanguageTwoPageOptions::UnsignedCharacter;
+ floatingPointSemantic = flags.contains(
+ QLatin1String("--relaxed_fp"))
+ ? LanguageTwoPageOptions::RelaxedSemantic
+ : LanguageTwoPageOptions::StrictSemantic;
+ enableMultibyteSupport = flags.contains(
+ QLatin1String("--enable_multibytes"));
+ }
+
+ PlainCharacter plainCharacter = SignedCharacter;
+ FloatingPointSemantic floatingPointSemantic = StrictSemantic;
+ int enableMultibyteSupport = 0;
+};
+
+// Optimizations page options.
+
+struct OptimizationsPageOptions final
+{
+ // Optimizations level radio-buttons with combo-box
+ // on "level" widget.
+ enum Strategy {
+ StrategyBalanced,
+ StrategySize,
+ StrategySpeed
+ };
+
+ enum Level {
+ LevelNone,
+ LevelLow,
+ LevelMedium,
+ LevelHigh
+ };
+
+ enum LevelSlave {
+ LevelSlave0,
+ LevelSlave1,
+ LevelSlave2,
+ LevelSlave3
+ };
+
+ explicit OptimizationsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString optimization = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("optimization"));
+ if (optimization == QLatin1String("none")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategyBalanced;
+ optimizationLevel = OptimizationsPageOptions::LevelNone;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave0;
+ } else if (optimization == QLatin1String("fast")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySpeed;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ } else if (optimization == QLatin1String("small")) {
+ optimizationStrategy = OptimizationsPageOptions::StrategySize;
+ optimizationLevel = OptimizationsPageOptions::LevelHigh;
+ optimizationLevelSlave = OptimizationsPageOptions::LevelSlave3;
+ }
+
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ enableCommonSubexpressionElimination = !flags.contains(
+ QLatin1String("--no_cse"));
+ enableLoopUnroll = !flags.contains(QLatin1String("--no_unroll"));
+ enableFunctionInlining = !flags.contains(QLatin1String("--no_inline"));
+ enableCodeMotion = !flags.contains(QLatin1String("--no_code_motion"));
+ enableTypeBasedAliasAnalysis = !flags.contains(
+ QLatin1String("--no_tbaa"));
+ enableCrossCall = !flags.contains(QLatin1String("--no_cross_call"));
+ disableRegisterBanks = flags.contains(
+ QLatin1String("--disable_register_banks"));
+
+ disableSizeConstrains = flags.contains(
+ QLatin1String("--no_size_constraints"));
+ }
+
+ Strategy optimizationStrategy = StrategyBalanced;
+ Level optimizationLevel = LevelNone;
+ LevelSlave optimizationLevelSlave = LevelSlave0;
+ // Seven bit-field flags on "enabled transformations" widget.
+ int enableCommonSubexpressionElimination = 0; // Common sub-expression elimination.
+ int enableLoopUnroll = 0; // Loop unrolling.
+ int enableFunctionInlining = 0; // Function inlining.
+ int enableCodeMotion = 0; // Code motion.
+ int enableTypeBasedAliasAnalysis = 0; // Type based alias analysis.
+ int enableCrossCall = 0; // Cross call optimization.
+ int disableRegisterBanks = 0; // Disabled register banks.
+ int disableSizeConstrains = 0; // No size constraints.
+};
+
+// Preprocessor page options.
+
+struct PreprocessorPageOptions final
+{
+ explicit PreprocessorPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ // TODO: Need to exclude the pre-defined maroses which are handled
+ // in 'General Options'.
+ defineSymbols = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ const QStringList fullIncludePaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ const QString dlibToolkitPath = IarewUtils::dlibToolkitRootPath(qbsProduct);
+ for (const QString &fullIncludePath : fullIncludePaths) {
+ const QFileInfo includeFileInfo(fullIncludePath);
+ const QString includeFilePath = includeFileInfo.absoluteFilePath();
+ // Exclude dlib config includes because it already handled in
+ // 'General Options->Library configuration page'.
+ if (includeFilePath.startsWith(dlibToolkitPath))
+ continue;
+ if (includeFilePath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, includeFilePath);
+ includePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, includeFilePath);
+ includePaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList defineSymbols;
+ QVariantList includePaths;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ warningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int warningsAsErrors = 0;
+};
+
+// Code page options.
+
+struct CodePageOptions final
+{
+ explicit CodePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ paddingForRomMonitorBreakpoints = flags.contains(
+ QLatin1String("--rom_mon_bp_padding"));
+ excludeUbrofMessagesInOutput = flags.contains(
+ QLatin1String("--no_ubrof_messages"));
+ }
+
+ int paddingForRomMonitorBreakpoints = 0;
+ int excludeUbrofMessagesInOutput = 0;
+};
+
+} // namespace
+
+// Mcs51CompilerSettingsGroup
+
+Mcs51CompilerSettingsGroup::Mcs51CompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ICC8051"));
+ setArchiveVersion(kCompilerArchiveVersion);
+ setDataVersion(kCompilerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildOutputPage(qbsProduct);
+ buildLanguageOnePage(qbsProduct);
+ buildLanguageTwoPage(qbsProduct);
+ buildOptimizationsPage(qbsProduct);
+ buildPreprocessorPage(buildRootDirectory, qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+}
+
+void Mcs51CompilerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'CCDebugInfo' item (Generate debug info).
+ addOptionsGroup(QByteArrayLiteral("CCDebugInfo"),
+ {opts.debugInfo});
+ // Add 'CCOverrideModuleTypeDefault' item
+ // (Override default module type).
+ addOptionsGroup(QByteArrayLiteral("CCOverrideModuleTypeDefault"),
+ {1});
+ // Add 'CCRadioModuleType' item (Module type: program/library).
+ addOptionsGroup(QByteArrayLiteral("CCRadioModuleType"),
+ {opts.moduleType});
+}
+
+void Mcs51CompilerSettingsGroup::buildLanguageOnePage(
+ const ProductData &qbsProduct)
+{
+ const LanguageOnePageOptions opts(qbsProduct);
+ // Add 'IccLang' item with 'auto-extension based'
+ // value (Language: C/C++/Auto).
+ addOptionsGroup(QByteArrayLiteral("IccLang"),
+ {opts.languageExtension});
+ // Add 'IccCDialect' item (C dialect: c89/99/11).
+ addOptionsGroup(QByteArrayLiteral("IccCDialect"),
+ {opts.cLanguageDialect});
+ // Add 'IccCppDialect' item (C++ dialect: embedded/extended).
+ addOptionsGroup(QByteArrayLiteral("IccCppDialect"),
+ {opts.cxxLanguageDialect});
+ // Add 'CCExt' item (Language conformance: IAR/relaxed/strict).
+ addOptionsGroup(QByteArrayLiteral("LangConform"),
+ {opts.languageConformance});
+ // Add 'IccAllowVLA' item (Allow VLA).
+ addOptionsGroup(QByteArrayLiteral("IccAllowVLA"),
+ {opts.allowVla});
+ // Add 'IccCppInlineSemantics' item (C++ inline semantics).
+ addOptionsGroup(QByteArrayLiteral("IccCppInlineSemantics"),
+ {opts.useCppInlineSemantics});
+ // Add 'CCRequirePrototypes' item (Require prototypes).
+ addOptionsGroup(QByteArrayLiteral("CCRequirePrototypes"),
+ {opts.requirePrototypes});
+ // Add 'IccStaticDestr' item (Destroy static objects).
+ addOptionsGroup(QByteArrayLiteral("IccStaticDestr"),
+ {opts.destroyStaticObjects});
+}
+
+void Mcs51CompilerSettingsGroup::buildLanguageTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LanguageTwoPageOptions opts(qbsProduct);
+ // Add 'CharIs' item (Plain char is: signed/unsigned).
+ addOptionsGroup(QByteArrayLiteral("CharIs"),
+ {opts.plainCharacter});
+ // Add 'IccFloatSemantics' item
+ // (Floatic-point semantics: strict/relaxed conformance).
+ addOptionsGroup(QByteArrayLiteral("IccFloatSemantics"),
+ {opts.floatingPointSemantic});
+ // Add 'CCMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("CCMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+}
+
+void Mcs51CompilerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ const OptimizationsPageOptions opts(qbsProduct);
+ // Add 'CCOptStrategy', 'CCOptLevel' and
+ // 'CCOptLevelSlave' items (Level).
+ addOptionsGroup(QByteArrayLiteral("CCOptStrategy"),
+ {opts.optimizationStrategy});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevel"),
+ {opts.optimizationLevel});
+ addOptionsGroup(QByteArrayLiteral("CCOptLevelSlave"),
+ {opts.optimizationLevelSlave});
+ // Add 'CCAllowList2' item (Enabled transformations: 7 check boxes).
+ const QString transformations = QStringLiteral("%1%2%3%4%5%6%7")
+ .arg(opts.enableCommonSubexpressionElimination)
+ .arg(opts.enableLoopUnroll)
+ .arg(opts.enableFunctionInlining)
+ .arg(opts.enableCodeMotion)
+ .arg(opts.enableTypeBasedAliasAnalysis)
+ .arg(opts.enableCrossCall)
+ .arg(opts.disableRegisterBanks);
+ addOptionsGroup(QByteArrayLiteral("CCAllowList2"),
+ {transformations});
+ // Add 'NoSizeConstraints' item (No size constraints).
+ addOptionsGroup(QByteArrayLiteral("NoSizeConstraints"),
+ {opts.disableSizeConstrains});
+}
+
+void Mcs51CompilerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'CCDefines' item (Defines symbols).
+ addOptionsGroup(QByteArrayLiteral("CCDefines"),
+ opts.defineSymbols);
+ // Add 'CCIncludePath2' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("CCIncludePath2"),
+ opts.includePaths);
+}
+
+void Mcs51CompilerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'CCDiagWarnAreErr' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("CCDiagWarnAreErr"),
+ {opts.warningsAsErrors});
+}
+
+void Mcs51CompilerSettingsGroup::buildCodePage(
+ const ProductData &qbsProduct)
+{
+ const CodePageOptions opts(qbsProduct);
+ // Add 'RomMonBpPadding' item (Padding for ROM-monitor breakpoints).
+ addOptionsGroup(QByteArrayLiteral("RomMonBpPadding"),
+ {opts.paddingForRomMonitorBreakpoints});
+ // Add 'NoUBROFMessages' item (No UBROF messages in output files).
+ addOptionsGroup(QByteArrayLiteral("NoUBROFMessages"),
+ {opts.excludeUbrofMessagesInOutput});
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.h
new file mode 100644
index 000000000..e68a7628f
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51compilersettingsgroup_v10.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51COMPILERSETTINGSGROUP_V10_H
+#define QBS_IAREWMCS51COMPILERSETTINGSGROUP_V10_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51CompilerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Mcs51CompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildLanguageOnePage(const ProductData &qbsProduct);
+ void buildLanguageTwoPage(const ProductData &qbsProduct);
+ void buildOptimizationsPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildCodePage(const ProductData &qbsProduct);
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51COMPILERSETTINGSGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.cpp
new file mode 100644
index 000000000..43c160045
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.cpp
@@ -0,0 +1,1014 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51generalsettingsgroup_v10.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+constexpr int kGeneralArchiveVersion = 4;
+constexpr int kGeneralDataVersion = 9;
+
+namespace {
+
+// Target page options.
+
+struct TargetPageOptions final
+{
+ enum CpuCore {
+ CorePlain = 1,
+ CoreExtended1,
+ CoreExtended2
+ };
+
+ enum CodeModel {
+ CodeModelNear = 1,
+ CodeModelBanked,
+ CodeModelFar,
+ CodeModelBankedExtended2
+ };
+
+ enum DataModel {
+ DataModelTiny = 0,
+ DataModelSmall,
+ DataModelLarge,
+ DataModelGeneric,
+ DataModelFarGeneric,
+ DataModelFar
+ };
+
+ enum ConstantsMemoryPlacement {
+ RamMemoryPlace = 0,
+ RomMemoryPlace,
+ CodeMemoryPlace
+ };
+
+ enum CallingConvention {
+ DataOverlayConvention = 0,
+ IDataOverlayConvention,
+ IDataReentrantConvention,
+ PDataReentrantConvention,
+ XDataReentrantConvention,
+ ExtendedStackReentrantConvention
+ };
+
+ explicit TargetPageOptions(const ProductData &qbsProduct)
+ {
+ chipInfoPath = detectChipInfoPath(qbsProduct);
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Should be parsed before the 'code_model' and
+ // 'data_model' options, as that options are depends on it.
+ const QString core = IarewUtils::flagValue(
+ flags, QStringLiteral("--core"))
+ .toLower();
+ if (core == QLatin1String("plain")) {
+ cpuCore = TargetPageOptions::CorePlain;
+ } else if (core == QLatin1String("extended1")) {
+ cpuCore = TargetPageOptions::CoreExtended1;
+ } else if (core == QLatin1String("extended2")) {
+ cpuCore = TargetPageOptions::CoreExtended2;
+ } else {
+ // If the core variant is not set, then choose the
+ // default values (see the compiler datasheet for
+ // '--core' option).
+ cpuCore = TargetPageOptions::CorePlain;
+ }
+
+ const QString cm = IarewUtils::flagValue(
+ flags, QStringLiteral("--code_model"))
+ .toLower();
+ if (cm == QLatin1String("near")) {
+ codeModel = TargetPageOptions::CodeModelNear;
+ } else if (cm == QLatin1String("banked")) {
+ codeModel = TargetPageOptions::CodeModelBanked;
+ } else if (cm == QLatin1String("far")) {
+ codeModel = TargetPageOptions::CodeModelFar;
+ } else if (cm == QLatin1String("banked_ext2")) {
+ codeModel = TargetPageOptions::CodeModelBankedExtended2;
+ } else {
+ // If the code model is not set, then choose the
+ // default values (see the compiler datasheet for
+ // '--code_model' option).
+ if (cpuCore == TargetPageOptions::CorePlain)
+ codeModel = TargetPageOptions::CodeModelNear;
+ else if (cpuCore == TargetPageOptions::CoreExtended1)
+ codeModel = TargetPageOptions::CodeModelFar;
+ else if (cpuCore == TargetPageOptions::CoreExtended2)
+ codeModel = TargetPageOptions::CodeModelBankedExtended2;
+ }
+
+ const QString dm = IarewUtils::flagValue(
+ flags, QStringLiteral("--data_model")).toLower();
+ if (dm == QLatin1String("tiny")) {
+ dataModel = TargetPageOptions::DataModelTiny;
+ } else if (dm == QLatin1String("small")) {
+ dataModel = TargetPageOptions::DataModelSmall;
+ } else if (dm == QLatin1String("large")) {
+ dataModel = TargetPageOptions::DataModelLarge;
+ } else if (dm == QLatin1String("generic")) {
+ dataModel = TargetPageOptions::DataModelGeneric;
+ } else if (dm == QLatin1String("far_generic")) {
+ dataModel = TargetPageOptions::DataModelFarGeneric;
+ } else if (dm == QLatin1String("far")) {
+ dataModel = TargetPageOptions::DataModelFar;
+ } else {
+ // If the data model is not set, then choose the
+ // default values (see the compiler datasheet for
+ // '--data_model' option).
+ if (cpuCore == TargetPageOptions::CorePlain)
+ dataModel = TargetPageOptions::DataModelSmall;
+ else if (cpuCore == TargetPageOptions::CoreExtended1)
+ dataModel = TargetPageOptions::DataModelFar;
+ else if (cpuCore == TargetPageOptions::CoreExtended2)
+ dataModel = TargetPageOptions::DataModelLarge;
+ }
+
+ useExtendedStack = flags.contains(QLatin1String("--extended_stack"));
+
+ const int regsCount = IarewUtils::flagValue(
+ flags, QStringLiteral("--nr_virtual_regs"))
+ .toInt();
+ enum { MinVRegsCount = 8, MaxVRegsCount = 32, VRegsOffset = 8 };
+ // The registers index starts with 0: 0 - means 8 registers,
+ // 1 - means 9 registers and etc. Any invalid values we interpret
+ // as a default value in 8 registers.
+ virtualRegisters = (regsCount < MinVRegsCount || regsCount > MaxVRegsCount)
+ ? 0 : (regsCount - VRegsOffset);
+
+ const QString constPlace = IarewUtils::flagValue(
+ flags, QStringLiteral("--place_constants"))
+ .toLower();
+ if (constPlace == QLatin1String("data")) {
+ constPlacement = TargetPageOptions::RamMemoryPlace;
+ } else if (constPlace == QLatin1String("data_rom")) {
+ constPlacement = TargetPageOptions::RomMemoryPlace;
+ } else if (constPlace == QLatin1String("code")) {
+ constPlacement = TargetPageOptions::CodeMemoryPlace;
+ } else {
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--place_constants' option).
+ constPlacement = TargetPageOptions::RamMemoryPlace;
+ }
+
+ const QString cc = IarewUtils::flagValue(
+ flags, QStringLiteral("--calling_convention")).toLower();
+ if (cc == QLatin1String("data_overlay")) {
+ callingConvention = TargetPageOptions::DataOverlayConvention;
+ } else if (cc == QLatin1String("idata_overlay")) {
+ callingConvention = TargetPageOptions::IDataOverlayConvention;
+ } else if (cc == QLatin1String("idata_reentrant")) {
+ callingConvention = TargetPageOptions::IDataReentrantConvention;
+ } else if (cc == QLatin1String("pdata_reentrant")) {
+ callingConvention = TargetPageOptions::PDataReentrantConvention;
+ } else if (cc == QLatin1String("xdata_reentrant")) {
+ callingConvention = TargetPageOptions::XDataReentrantConvention;
+ } else if (cc == QLatin1String("ext_stack_reentrant")) {
+ callingConvention = TargetPageOptions::ExtendedStackReentrantConvention;
+ } else {
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--calling_convention' option).
+ callingConvention = TargetPageOptions::IDataReentrantConvention;
+ }
+ }
+
+ // Trying to indirectly detect and build the chip config path,
+ // which uses to show a device name in "Device information" group box.
+ static QString detectChipInfoPath(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+
+ QVariantList configPaths;
+
+ // Enumerate all product linker config files
+ // (which are set trough '-f' option).
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ configPaths << IarewUtils::flagValues(flags, QStringLiteral("-f"));
+
+ // Enumerate all product linker config files
+ // (which are set trough 'linkerscript' tag).
+ const auto qbsGroups = qbsProduct.groups();
+ for (const auto &qbsGroup : qbsGroups) {
+ const auto qbsArtifacts = qbsGroup.sourceArtifacts();
+ for (const auto &qbsArtifact : qbsArtifacts) {
+ const auto qbsTags = qbsArtifact.fileTags();
+ if (!qbsTags.contains(QLatin1String("linkerscript")))
+ continue;
+ const auto configPath = qbsArtifact.filePath();
+ // Skip duplicates.
+ if (configPaths.contains(configPath))
+ continue;
+ configPaths << qbsArtifact.filePath();
+ }
+ }
+
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+ for (const QVariant &configPath : configPaths) {
+ const QString fullConfigPath = configPath.toString();
+ // We interested only in a config paths shipped inside of a toolkit.
+ if (!fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive))
+ continue;
+ // Extract the chip name from the linker script name.
+ const int underscoreIndex = fullConfigPath.lastIndexOf(QLatin1Char('_'));
+ if (underscoreIndex == -1)
+ continue;
+ const int dotIndex = fullConfigPath.lastIndexOf(QLatin1Char('.'));
+ if (dotIndex == -1)
+ continue;
+ if (dotIndex <= underscoreIndex)
+ continue;
+ const QString chipName = fullConfigPath.mid(
+ underscoreIndex + 1,
+ dotIndex - underscoreIndex - 1);
+ // Construct full chip info path.
+ const QFileInfo fullChipInfoPath(QFileInfo(fullConfigPath).absolutePath()
+ + QLatin1Char('/') + chipName
+ + QLatin1String(".i51"));
+ if (fullChipInfoPath.exists())
+ return fullChipInfoPath.absoluteFilePath();
+ }
+
+ return {};
+ }
+
+ QString chipInfoPath;
+ CpuCore cpuCore = CorePlain;
+ CodeModel codeModel = CodeModelNear;
+ DataModel dataModel = DataModelTiny;
+ int useExtendedStack = 0;
+ int virtualRegisters = 0;
+ ConstantsMemoryPlacement constPlacement = RamMemoryPlace;
+ CallingConvention callingConvention = DataOverlayConvention;
+};
+
+// System page options.
+
+struct StackHeapPageOptions final
+{
+ explicit StackHeapPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList defineSymbols = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+ const QStringList linkerFlags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverLinkerFlags")});
+
+ idataStack = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_IDATA_STACK_SIZE"));
+ if (idataStack.isEmpty())
+ idataStack = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_IDATA_STACK_SIZE"));
+ if (idataStack.isEmpty())
+ idataStack = QLatin1String("0x40"); // Default IDATA stack size.
+ pdataStack = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_PDATA_STACK_SIZE"));
+ if (pdataStack.isEmpty())
+ pdataStack = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_PDATA_STACK_SIZE"));
+ if (pdataStack.isEmpty())
+ pdataStack = QLatin1String("0x80"); // Default PDATA stack size.
+ xdataStack = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_XDATA_STACK_SIZE"));
+ if (xdataStack.isEmpty())
+ xdataStack = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_XDATA_STACK_SIZE"));
+ if (xdataStack.isEmpty())
+ xdataStack = QLatin1String("0xEFF"); // Default XDATA stack size.
+ extendedStack = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_EXTENDED_STACK_SIZE"));
+ if (extendedStack.isEmpty())
+ extendedStack = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_EXTENDED_STACK_SIZE"));
+ if (extendedStack.isEmpty())
+ extendedStack = QLatin1String("0x3FF"); // Default EXTENDED stack size.
+
+ xdataHeap = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_XDATA_HEAP_SIZE"));
+ if (xdataHeap.isEmpty())
+ xdataHeap = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_XDATA_HEAP_SIZE"));
+ if (xdataHeap.isEmpty())
+ xdataHeap = QLatin1String("0xFF"); // Default XDATA heap size.
+ farHeap = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_FAR_HEAP_SIZE"));
+ if (farHeap.isEmpty())
+ farHeap = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_FAR_HEAP_SIZE"));
+ if (farHeap.isEmpty())
+ farHeap = QLatin1String("0xFFF"); // Default FAR heap size.
+ far22Heap = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_FAR22_HEAP_SIZE"));
+ if (far22Heap.isEmpty())
+ far22Heap = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_FAR22_HEAP_SIZE"));
+ if (far22Heap.isEmpty())
+ far22Heap = QLatin1String("0xFFF"); // Default FAR22 heap size.
+ hugeHeap = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_HUGE_HEAP_SIZE"));
+ if (hugeHeap.isEmpty())
+ hugeHeap = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_HUGE_HEAP_SIZE"));
+ if (hugeHeap.isEmpty())
+ hugeHeap = QLatin1String("0xFFF"); // Default HUGE heap size.
+
+ extStackAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?ESP"));
+ if (extStackAddress.isEmpty())
+ extStackAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?ESP"));
+ if (extStackAddress.isEmpty())
+ extStackAddress = QLatin1String("0x9B"); // Default extended stack pointer address.
+ extStackMask = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?ESP_MASK"));
+ if (extStackMask.isEmpty())
+ extStackMask = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?ESP_MASK"));
+ if (extStackMask.isEmpty())
+ extStackMask = QLatin1String("0x03"); // Default extended stack pointer mask.
+ }
+
+ // Stack sizes.
+ QString idataStack;
+ QString pdataStack;
+ QString xdataStack;
+ QString extendedStack;
+ // Heap sizes.
+ QString xdataHeap;
+ QString farHeap;
+ QString far22Heap;
+ QString hugeHeap;
+ // Extended stack.
+ QString extStackAddress;
+ QString extStackMask;
+ int extStackOffset = 0;
+ int extStackStartAddress = 0;
+};
+
+// Data pointer page options.
+
+struct DptrPageOptions final
+{
+ enum DptrSize {
+ Dptr16,
+ Dptr24
+ };
+
+ enum DptrVisibility {
+ DptrShadowed,
+ DptrSeparate
+ };
+
+ enum SwitchMethod {
+ DptrIncludeMethod,
+ DptrMaskMethod
+ };
+
+ explicit DptrPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ const QString core = IarewUtils::flagValue(
+ flags, QStringLiteral("--core"));
+
+ const QString dptr = IarewUtils::flagValue(
+ flags, QStringLiteral("--dptr"));
+ enum ValueIndex { SizeIndex, NumbersIndex,
+ VisibilityIndex, SwitchMethodIndex };
+ const QStringList dptrparts = dptr.split(QLatin1Char(','));
+ for (auto index = 0; index < dptrparts.count(); ++index) {
+ const QString part = dptrparts.at(index).toLower();
+ switch (index) {
+ case SizeIndex:
+ if (part == QLatin1String("16")) {
+ dptrSize = DptrPageOptions::Dptr16;
+ } else if (part == QLatin1String("24")) {
+ dptrSize = DptrPageOptions::Dptr24;
+ } else {
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--dptr' option).
+ if (core == QLatin1String("extended1"))
+ dptrSize = DptrPageOptions::Dptr24;
+ else
+ dptrSize = DptrPageOptions::Dptr16;
+ }
+ break;
+ case NumbersIndex: {
+ const int count = part.toInt();
+ if (count < 1 || count > 8) {
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--dptr' option).
+ if (core == QLatin1String("extended1"))
+ dptrsCountIndex = 1; // 2 DPTR's
+ else
+ dptrsCountIndex = 0; // 1 DPTR's
+ } else {
+ dptrsCountIndex = (count - 1); // DPTR's count - 1
+ }
+ }
+ break;
+ case VisibilityIndex:
+ if (part == QLatin1String("shadowed"))
+ dptrVisibility = DptrPageOptions::DptrShadowed;
+ else if (part == QLatin1String("separate"))
+ dptrVisibility = DptrPageOptions::DptrSeparate;
+ else
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--dptr' option).
+ dptrVisibility = DptrPageOptions::DptrSeparate;
+ break;
+ case SwitchMethodIndex:
+ if (part == QLatin1String("inc")) {
+ dptrSwitchMethod = DptrPageOptions::DptrIncludeMethod;
+ } else if (part.startsWith(QLatin1String("xor"))) {
+ dptrSwitchMethod = DptrPageOptions::DptrMaskMethod;
+ const int firstIndex = part.indexOf(QLatin1Char('('));
+ const int lastIndex = part.indexOf(QLatin1Char(')'));
+ dptrMask = part.mid(firstIndex + 1, part.size() - lastIndex);
+ } else {
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '--dptr' option).
+ if (core == QLatin1String("extended1")) {
+ dptrSwitchMethod = DptrPageOptions::DptrIncludeMethod;
+ } else if (core == QLatin1String("plain")) {
+ dptrSwitchMethod = DptrPageOptions::DptrMaskMethod;
+ dptrMask = QLatin1String("0x01");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ const QStringList defineSymbols = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+ const QStringList linkerFlags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverLinkerFlags")});
+
+ dptrPbank = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?PBANK"));
+ if (dptrPbank.isEmpty())
+ dptrPbank = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?PBANK"));
+ if (dptrPbank.isEmpty())
+ dptrPbank = QLatin1String("0x93"); // Default 8-15 regs address.
+ dptrPbankExt = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?PBANK_EXT"));
+ if (dptrPbankExt.isEmpty())
+ dptrPbankExt = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?PBANK_EXT"));
+
+ dpsAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPS"));
+ if (dpsAddress.isEmpty())
+ dpsAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPS"));
+ dpcAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPC"));
+ if (dpcAddress.isEmpty())
+ dpcAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPC"));
+
+ for (auto index = 0; index < 8; ++index) {
+ if (index == 0) {
+ QString dpxAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPX"));
+ if (dpxAddress.isEmpty())
+ dpxAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPX"));
+ if (!dpxAddress.isEmpty())
+ dpxAddress.prepend(QLatin1String("-D?DPX="));
+ if (!dptrAddresses.contains(dpxAddress))
+ dptrAddresses.push_back(dpxAddress);
+ } else {
+ QString dplAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPL%1").arg(index));
+ if (dplAddress.isEmpty())
+ dplAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPL%1").arg(index));
+ if (!dplAddress.isEmpty())
+ dplAddress.prepend(QStringLiteral("-D?DPL%1=").arg(index));
+ if (!dptrAddresses.contains(dplAddress))
+ dptrAddresses.push_back(dplAddress);
+
+ QString dphAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPH%1").arg(index));
+ if (dphAddress.isEmpty())
+ dphAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPH%1").arg(index));
+ if (!dphAddress.isEmpty())
+ dphAddress.prepend(QStringLiteral("-D?DPH%1=").arg(index));
+ if (!dptrAddresses.contains(dphAddress))
+ dptrAddresses.push_back(dphAddress);
+
+ QString dpxAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?DPX%1").arg(index));
+ if (dpxAddress.isEmpty())
+ dpxAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?DPX%1").arg(index));
+ if (!dpxAddress.isEmpty())
+ dpxAddress.prepend(QStringLiteral("-D?DPX%1=").arg(index));
+ if (!dptrAddresses.contains(dpxAddress))
+ dptrAddresses.push_back(dpxAddress);
+ }
+ }
+ }
+
+ int dptrsCountIndex = 0;
+ DptrSize dptrSize = Dptr16;
+ DptrVisibility dptrVisibility = DptrShadowed;
+ SwitchMethod dptrSwitchMethod = DptrIncludeMethod;
+ QString dptrMask;
+ QString dptrPbank;
+ QString dptrPbankExt;
+ QString dpsAddress;
+ QString dpcAddress;
+ QStringList dptrAddresses;
+};
+
+// Code bank page options.
+
+struct CodeBankPageOptions final
+{
+ explicit CodeBankPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList defineSymbols = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+ const QStringList linkerFlags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverLinkerFlags")});
+
+ banksCount = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_NR_OF_BANKS"));
+ if (banksCount.isEmpty())
+ banksCount = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_NR_OF_BANKS"));
+ if (banksCount.isEmpty())
+ banksCount = QLatin1String("0x03");
+ registerAddress = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?CBANK"));
+ if (registerAddress.isEmpty())
+ registerAddress = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?CBANK"));
+ if (registerAddress.isEmpty())
+ registerAddress = QLatin1String("0xF0");
+ registerMask = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("?CBANK_MASK"));
+ if (registerMask.isEmpty())
+ registerMask = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D?CBANK_MASK"));
+ if (registerMask.isEmpty())
+ registerMask = QLatin1String("0xFF");
+ bankStart = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_CODEBANK_START"));
+ if (bankStart.isEmpty())
+ bankStart = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_CODEBANK_START"));
+ if (bankStart.isEmpty())
+ bankStart = QLatin1String("0x8000");
+ bankEnd = IarewUtils::flagValue(
+ defineSymbols, QStringLiteral("_CODEBANK_END"));
+ if (bankEnd.isEmpty())
+ bankEnd = IarewUtils::flagValue(
+ linkerFlags, QStringLiteral("-D_CODEBANK_END"));
+ if (bankEnd.isEmpty())
+ bankEnd = QLatin1String("0xFFFF");
+ }
+
+ QString banksCount;
+ QString registerAddress;
+ QString registerMask;
+ QString bankStart;
+ QString bankEnd;
+};
+
+// Library options page options.
+
+struct LibraryOptionsPageOptions final
+{
+ enum PrintfFormatter {
+ PrintfAutoFormatter = 0,
+ PrintfLargeFormatter = 3,
+ PrintfMediumFormatter = 5,
+ PrintfSmallFormatter = 6
+ };
+
+ enum ScanfFormatter {
+ ScanfAutoFormatter = 0,
+ ScanfLargeFormatter = 3,
+ ScanfMediumFormatter = 5
+ };
+
+ explicit LibraryOptionsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ for (const QString &flag : flags) {
+ if (flag.endsWith(QLatin1String("_formatted_write"),
+ Qt::CaseInsensitive)) {
+ const QString prop = flag.split(
+ QLatin1Char('=')).at(0).toLower();
+ if (prop == QLatin1String("-e_large_write"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfLargeFormatter;
+ else if (prop == QLatin1String("-e_medium_write"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfMediumFormatter;
+ else if (prop == QLatin1String("-e_small_write"))
+ printfFormatter = LibraryOptionsPageOptions::PrintfSmallFormatter;
+ else
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '_formatted_write' option).
+ printfFormatter = LibraryOptionsPageOptions::PrintfMediumFormatter;
+ } else if (flag.endsWith(QLatin1String("_formatted_read"),
+ Qt::CaseInsensitive)) {
+ const QString prop = flag.split(QLatin1Char('='))
+ .at(0).toLower();
+ if (prop == QLatin1String("-e_large_read"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfLargeFormatter;
+ else if (prop == QLatin1String("-e_medium_read"))
+ scanfFormatter = LibraryOptionsPageOptions::ScanfMediumFormatter;
+ else
+ // If this option is not set, then choose the
+ // default value (see the compiler datasheet for
+ // '_formatted_read' option).
+ scanfFormatter = LibraryOptionsPageOptions::ScanfMediumFormatter;
+ }
+ }
+ }
+
+ PrintfFormatter printfFormatter = PrintfAutoFormatter;
+ ScanfFormatter scanfFormatter = ScanfAutoFormatter;
+};
+
+// Library configuration page options.
+
+struct LibraryConfigPageOptions final
+{
+ enum RuntimeLibrary {
+ NoLibrary,
+ NormalDlibLibrary,
+ CustomDlibLibrary,
+ ClibLibrary,
+ CustomClibLibrary
+ };
+
+ explicit LibraryConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("staticLibraries")});
+ const auto libraryBegin = libraryPaths.cbegin();
+ const auto libraryEnd = libraryPaths.cend();
+
+ const QFileInfo dlibConfigInfo(IarewUtils::flagValue(
+ flags, QStringLiteral("--dlib_config")));
+ const QString dlibConfigFilePath = dlibConfigInfo.absoluteFilePath();
+ if (!dlibConfigFilePath.isEmpty()) {
+ const QString dlibToolkitPath = IarewUtils::dlibToolkitRootPath(
+ qbsProduct);
+ if (dlibConfigFilePath.startsWith(dlibToolkitPath,
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::NormalDlibLibrary;
+ configPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, dlibConfigFilePath);
+
+ // Find dlib library inside of IAR toolkit directory.
+ const auto libraryIt = std::find_if(libraryBegin, libraryEnd,
+ [dlibToolkitPath](
+ const QString &libraryPath) {
+ return libraryPath.startsWith(dlibToolkitPath);
+ });
+ if (libraryIt != libraryEnd) {
+ // This means that dlib library is 'standard' (placed inside
+ // of IAR toolkit directory).
+ libraryPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, *libraryIt);
+ }
+ } else {
+ // This means that dlib library is 'custom'
+ // (but we don't know its path).
+ libraryType = LibraryConfigPageOptions::CustomDlibLibrary;
+ configPath = IarewUtils::projectRelativeFilePath(
+ baseDirectory, dlibConfigFilePath);
+ }
+ } else {
+ // Find clib library inside of IAR toolkit directory.
+ const QString clibToolkitPath = IarewUtils::clibToolkitRootPath(
+ qbsProduct);
+ const auto libraryIt = std::find_if(libraryBegin, libraryEnd,
+ [clibToolkitPath](
+ const QString &libraryPath) {
+ return libraryPath.startsWith(clibToolkitPath);
+ });
+ if (libraryIt != libraryEnd) {
+ // This means that clib library is 'standard' (placed inside
+ // of IAR toolkit directory).
+ libraryType = LibraryConfigPageOptions::ClibLibrary;
+ libraryPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, *libraryIt);
+ } else {
+ // This means that no any libraries are used .
+ libraryType = LibraryConfigPageOptions::NoLibrary;
+ }
+ }
+ }
+
+ RuntimeLibrary libraryType = NoLibrary;
+ QString configPath;
+ QString libraryPath;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ binaryType = IarewUtils::outputBinaryType(qbsProduct);
+ binaryDirectory = gen::utils::binaryOutputDirectory(
+ baseDirectory, qbsProduct);
+ objectDirectory = gen::utils::objectsOutputDirectory(
+ baseDirectory, qbsProduct);
+ listingDirectory = gen::utils::listingOutputDirectory(
+ baseDirectory, qbsProduct);
+ }
+
+ IarewUtils::OutputBinaryType binaryType = IarewUtils::ApplicationOutputType;
+ QString binaryDirectory;
+ QString objectDirectory;
+ QString listingDirectory;
+};
+
+} // namespace
+
+// Mcs51GeneralSettingsGroup
+
+Mcs51GeneralSettingsGroup::Mcs51GeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("General"));
+ setArchiveVersion(kGeneralArchiveVersion);
+ setDataVersion(kGeneralDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildTargetPage(qbsProduct);
+ buildStackHeapPage(qbsProduct);
+ buildDataPointerPage(qbsProduct);
+ buildCodeBankPage(qbsProduct);
+ buildLibraryOptionsPage(qbsProduct);
+ buildLibraryConfigPage(buildRootDirectory, qbsProduct);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void Mcs51GeneralSettingsGroup::buildTargetPage(
+ const ProductData &qbsProduct)
+{
+ const TargetPageOptions opts(qbsProduct);
+ // Add 'OGChipConfigPath' item (Device: <chip name>).
+ addOptionsGroup(QByteArrayLiteral("OGChipConfigPath"),
+ {opts.chipInfoPath});
+
+ // Add 'CPU Core' and 'CPU Core Slave' items
+ // (CPU core: plain/extended{1|2}).
+ addOptionsGroup(QByteArrayLiteral("CPU Core"),
+ {opts.cpuCore});
+ addOptionsGroup(QByteArrayLiteral("CPU Core Slave"),
+ {opts.cpuCore});
+ // Add 'Code Memory Model' and 'Code Memory Model slave' items
+ // (Code model: near/banked/far/banked extended).
+ addOptionsGroup(QByteArrayLiteral("Code Memory Model"),
+ {opts.codeModel});
+ addOptionsGroup(QByteArrayLiteral("Code Memory Model slave"),
+ {opts.codeModel});
+ // Add 'Data Memory Model' and 'Data Memory Model slave' items
+ // (Data model: tiny/small/large/generic/far).
+ addOptionsGroup(QByteArrayLiteral("Data Memory Model"),
+ {opts.dataModel});
+ addOptionsGroup(QByteArrayLiteral("Data Memory Model slave"),
+ {opts.dataModel});
+ // Add 'Use extended stack' and 'Use extended stack slave' items
+ // (Use extended stack).
+ addOptionsGroup(QByteArrayLiteral("Use extended stack"),
+ {opts.useExtendedStack});
+ addOptionsGroup(QByteArrayLiteral("Use extended stack slave"),
+ {opts.useExtendedStack});
+ // Add 'Workseg Size' item (Number of virtual registers: 8...32).
+ addOptionsGroup(QByteArrayLiteral("Workseg Size"),
+ {opts.virtualRegisters});
+ // Add 'Constant Placement' item
+ // (Location of constants and strings: ram/rom/code memories).
+ addOptionsGroup(QByteArrayLiteral("Constant Placement"),
+ {opts.constPlacement});
+ // Add 'Calling convention' item (Calling convention).
+ addOptionsGroup(QByteArrayLiteral("Calling convention"),
+ {opts.callingConvention});
+}
+
+void Mcs51GeneralSettingsGroup::buildStackHeapPage(
+ const ProductData &qbsProduct)
+{
+ const StackHeapPageOptions opts(qbsProduct);
+ // Add 'General Idata Stack Size' item (Stack size: IDATA).
+ addOptionsGroup(QByteArrayLiteral("General Idata Stack Size"),
+ {opts.idataStack});
+ // Add 'General Pdata Stack Size' item (Stack size: PDATA).
+ addOptionsGroup(QByteArrayLiteral("General Pdata Stack Size"),
+ {opts.pdataStack});
+ // Add 'General Xdata Stack Size' item (Stack size: XDATA).
+ addOptionsGroup(QByteArrayLiteral("General Xdata Stack Size"),
+ {opts.xdataStack});
+ // Add 'General Ext Stack Size' item (Stack size: Extended).
+ addOptionsGroup(QByteArrayLiteral("General Ext Stack Size"),
+ {opts.extendedStack});
+
+ // Add 'General Xdata Heap Size' item (Heap size: XDATA).
+ addOptionsGroup(QByteArrayLiteral("General Xdata Heap Size"),
+ {opts.xdataHeap});
+ // Add 'General Far Heap Size' item (Heap size: Far).
+ addOptionsGroup(QByteArrayLiteral("General Far Heap Size"),
+ {opts.farHeap});
+ // Add 'General Far22 Heap Size' item (Heap size: Far22).
+ addOptionsGroup(QByteArrayLiteral("General Far22 Heap Size"),
+ {opts.far22Heap});
+ // Add 'General Huge Heap Size' item (Heap size: Huge).
+ addOptionsGroup(QByteArrayLiteral("General Huge Heap Size"),
+ {opts.hugeHeap});
+
+ // Add 'Extended stack address' item
+ // (Extended stack pointer address).
+ addOptionsGroup(QByteArrayLiteral("Extended stack address"),
+ {opts.extStackAddress});
+ // Add 'Extended stack mask' item (Extended stack pointer mask).
+ addOptionsGroup(QByteArrayLiteral("Extended stack mask"),
+ {opts.extStackMask});
+ // Add 'Extended stack is offset' item
+ // (Extended stack pointer is an offset).
+ addOptionsGroup(QByteArrayLiteral("Extended stack is offset"),
+ {opts.extStackOffset});
+}
+
+void Mcs51GeneralSettingsGroup::buildDataPointerPage(
+ const ProductData &qbsProduct)
+{
+ const DptrPageOptions opts(qbsProduct);
+ // Add 'Nr of Datapointers' item (Number of DPTRs: 1...8).
+ addOptionsGroup(QByteArrayLiteral("Nr of Datapointers"),
+ {opts.dptrsCountIndex});
+ // Add 'Datapointer Size' item (DPTR size: 16/24).
+ addOptionsGroup(QByteArrayLiteral("Datapointer Size"),
+ {opts.dptrSize});
+ // Add 'Sfr Visibility' item (DPTR address: shadowed/separate).
+ addOptionsGroup(QByteArrayLiteral("Sfr Visibility"),
+ {opts.dptrVisibility});
+ // Add 'Switch Method' item (Switch method: inc/mask).
+ addOptionsGroup(QByteArrayLiteral("Switch Method"),
+ {opts.dptrSwitchMethod});
+ // Add 'Mask Value' item (Switch method mask).
+ addOptionsGroup(QByteArrayLiteral("Mask Value"),
+ {opts.dptrMask});
+ // Add 'PDATA 8-15 register address' item (Page register
+ // address (for bits 8-15).
+ addOptionsGroup(QByteArrayLiteral("PDATA 8-15 register address"),
+ {opts.dptrPbank});
+ // Add 'PDATA 16-31 register address' item (Page register
+ // address (for bits 16-31).
+ addOptionsGroup(QByteArrayLiteral("PDATA 16-31 register address"),
+ {opts.dptrPbankExt});
+ // Add 'DPS Address' item (Selected DPTR register).
+ addOptionsGroup(QByteArrayLiteral("DPS Address"),
+ {opts.dpsAddress});
+ // Add 'DPC Address' item (Separate DPTR control register).
+ addOptionsGroup(QByteArrayLiteral("DPC Address"),
+ {opts.dpcAddress});
+ // Add 'DPTR Addresses' item (DPTR addresses: Low/High/Ext).
+ const QString dptrAddresses = opts.dptrAddresses.join(QLatin1Char(' '));
+ addOptionsGroup(QByteArrayLiteral("DPTR Addresses"),
+ {dptrAddresses});
+}
+
+void Mcs51GeneralSettingsGroup::buildCodeBankPage(
+ const ProductData &qbsProduct)
+{
+ const CodeBankPageOptions opts(qbsProduct);
+ // Add 'CodeBankReg' item (Register address).
+ addOptionsGroup(QByteArrayLiteral("CodeBankReg"),
+ {opts.registerAddress});
+ // Add 'CodeBankRegMask' item (Register mask).
+ addOptionsGroup(QByteArrayLiteral("CodeBankRegMask"),
+ {opts.registerMask});
+ // Add 'CodeBankNrOfs' item (Number of banks).
+ addOptionsGroup(QByteArrayLiteral("CodeBankNrOfs"),
+ {opts.banksCount});
+ // Add 'CodeBankStart' item (Bank start).
+ addOptionsGroup(QByteArrayLiteral("CodeBankStart"),
+ {opts.bankStart});
+ // Add 'CodeBankSize' item (Bank end).
+ addOptionsGroup(QByteArrayLiteral("CodeBankSize"),
+ {opts.bankEnd});
+}
+
+void Mcs51GeneralSettingsGroup::buildLibraryOptionsPage(
+ const ProductData &qbsProduct)
+{
+ const LibraryOptionsPageOptions opts(qbsProduct);
+ // Add 'Output variant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("Output variant"),
+ {opts.printfFormatter});
+ // Add 'Input variant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("Input variant"),
+ {opts.scanfFormatter});
+}
+
+void Mcs51GeneralSettingsGroup::buildLibraryConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GRuntimeLibSelect2' and 'GRuntimeLibSelectSlave2' items
+ // (Link with runtime: none/dlib/clib/etc).
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelect2"),
+ {opts.libraryType});
+ addOptionsGroup(QByteArrayLiteral("GRuntimeLibSelectSlave2"),
+ {opts.libraryType});
+ // Add 'RTConfigPath' item (Runtime configuration file).
+ addOptionsGroup(QByteArrayLiteral("RTConfigPath"),
+ {opts.configPath});
+ // Add 'RTLibraryPath' item (Runtime library file).
+ addOptionsGroup(QByteArrayLiteral("RTLibraryPath"),
+ {opts.libraryPath});
+}
+
+void Mcs51GeneralSettingsGroup::buildOutputPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GOutputBinary' item (Output file: executable/library).
+ addOptionsGroup(QByteArrayLiteral("GOutputBinary"),
+ {opts.binaryType});
+ // Add 'ExePath' item (Executable/binaries output directory).
+ addOptionsGroup(QByteArrayLiteral("ExePath"),
+ {opts.binaryDirectory});
+ // Add 'ObjPath' item (Object files output directory).
+ addOptionsGroup(QByteArrayLiteral("ObjPath"),
+ {opts.objectDirectory});
+ // Add 'ListPath' item (List files output directory).
+ addOptionsGroup(QByteArrayLiteral("ListPath"),
+ {opts.listingDirectory});
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.h
new file mode 100644
index 000000000..1805a87af
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51generalsettingsgroup_v10.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51GENERALSETTINGSGROUP_V10_H
+#define QBS_IAREWMCS51GENERALSETTINGSGROUP_V10_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51GeneralSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Mcs51GeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildTargetPage(const ProductData &qbsProduct);
+ void buildStackHeapPage(const ProductData &qbsProduct);
+ void buildDataPointerPage(const ProductData &qbsProduct);
+ void buildCodeBankPage(const ProductData &qbsProduct);
+ void buildLibraryOptionsPage(const ProductData &qbsProduct);
+ void buildLibraryConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51GENERALSETTINGSGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.cpp b/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.cpp
new file mode 100644
index 000000000..a88ac22e1
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.cpp
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "mcs51linkersettingsgroup_v10.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+constexpr int kLinkerArchiveVersion = 4;
+constexpr int kLinkerDataVersion = 21;
+
+namespace {
+
+// Config page options.
+
+struct ConfigPageOptions final
+{
+ explicit ConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
+
+ entryPoint = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("entryPoint"));
+
+ // Enumerate all product linker config files
+ // (which are set trough 'linkerscript' tag).
+ const auto qbsGroups = qbsProduct.groups();
+ for (const auto &qbsGroup : qbsGroups) {
+ const auto qbsArtifacts = qbsGroup.sourceArtifacts();
+ for (const auto &qbsArtifact : qbsArtifacts) {
+ const auto qbsTags = qbsArtifact.fileTags();
+ if (!qbsTags.contains(QLatin1String("linkerscript")))
+ continue;
+ const QString fullConfigPath = qbsArtifact.filePath();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ configFilePaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ configFilePaths.push_back(path);
+ }
+ }
+ }
+
+ // Enumerate all product linker config files
+ // (which are set trough '-f' option).
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ const QVariantList configPathValues = IarewUtils::flagValues(
+ flags, QStringLiteral("-f"));
+ for (const QVariant &configPathValue : configPathValues) {
+ const QString fullConfigPath = configPathValue.toString();
+ if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ } else {
+ const QString path =IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullConfigPath);
+ if (!configFilePaths.contains(path))
+ configFilePaths.push_back(path);
+ }
+ }
+
+ // Add libraries search paths.
+ const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("libraryPaths")});
+ for (const QString &libraryPath : libraryPaths) {
+ const QFileInfo libraryPathInfo(libraryPath);
+ const QString fullLibrarySearchPath = libraryPathInfo.absoluteFilePath();
+ if (fullLibrarySearchPath.startsWith(toolkitPath,
+ Qt::CaseInsensitive)) {
+ const QString path = IarewUtils::toolkitRelativeFilePath(
+ toolkitPath, fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ } else {
+ const QString path = IarewUtils::projectRelativeFilePath(
+ baseDirectory, fullLibrarySearchPath);
+ librarySearchPaths.push_back(path);
+ }
+ }
+ }
+
+ QVariantList configFilePaths;
+ QVariantList librarySearchPaths;
+ QString entryPoint;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ outputFile = gen::utils::targetBinary(qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+// List page options.
+
+struct ListPageOptions final
+{
+ enum ListingAction {
+ NoListing,
+ GenerateListing
+ };
+
+ explicit ListPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ generateMap = gen::utils::cppBooleanModuleProperty(
+ qbsProps, QStringLiteral("generateLinkerMapFile"))
+ ? ListPageOptions::GenerateListing
+ : ListPageOptions::NoListing;
+ }
+
+ ListingAction generateMap = NoListing;
+};
+
+// Define page options.
+
+struct DefinePageOptions final
+{
+ explicit DefinePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ // Enumerate all linker defines.
+ for (const QString &flag : flags) {
+ if (!flag.startsWith(QLatin1String("-D")))
+ continue;
+ const QString symbol = flag.mid(2);
+ // Ignore system-defined macroses, because its already
+ // handled in "General Options" page.
+ if (symbol.startsWith(QLatin1Char('?'))
+ || symbol.startsWith(QLatin1Char('_'))
+ ) {
+ continue;
+ }
+ defineSymbols.push_back(symbol);
+ }
+ }
+
+ QVariantList defineSymbols;
+};
+
+// Diagnostics page options.
+
+struct DiagnosticsPageOptions final
+{
+ explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QString warningLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ suppressAllWarnings = (warningLevel == QLatin1String("none"));
+ }
+
+ int suppressAllWarnings = 0;
+};
+
+} // namespace
+
+// Mcs51LinkerSettingsGroup
+
+Mcs51LinkerSettingsGroup::Mcs51LinkerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("XLINK"));
+ setArchiveVersion(kLinkerArchiveVersion);
+ setDataVersion(kLinkerDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+
+ buildConfigPage(buildRootDirectory, qbsProduct);
+ buildOutputPage(qbsProduct);
+ buildListPage(qbsProduct);
+ buildDefinePage(qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+
+ // Should be called as latest stage!
+ buildExtraOptionsPage(qbsProduct);
+}
+
+void Mcs51LinkerSettingsGroup::buildConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ ConfigPageOptions opts(baseDirectory, qbsProduct);
+
+ if (opts.configFilePaths.count() > 0) {
+ // Note: IAR IDE does not allow to specify a multiple config files,
+ // although the IAR linker support it. So, we use followig 'trick':
+ // we take a first config file and to add it as usual to required items;
+ // and then an other remainders we forward to the "Extra options page".
+ const QVariant configPath = opts.configFilePaths.takeFirst();
+ // Add 'XclOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("XclOverride"),
+ {1});
+ // Add 'XclFile' item (Linke configuration file).
+ addOptionsGroup(QByteArrayLiteral("XclFile"),
+ {configPath});
+
+ // Add remainder configuration files to the "Extra options page".
+ if (!opts.configFilePaths.isEmpty()) {
+ for (QVariant &configPath : opts.configFilePaths)
+ configPath = QLatin1String("-f ") + configPath.toString();
+
+ m_extraOptions << opts.configFilePaths;
+ }
+ }
+
+ // Add 'xcProgramEntryLabel' item (Entry symbol).
+ addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabel"),
+ {opts.entryPoint});
+ // Add 'xcOverrideProgramEntryLabel' item
+ // (Override default program entry).
+ addOptionsGroup(QByteArrayLiteral("xcOverrideProgramEntryLabel"),
+ {1});
+ // Add 'xcProgramEntryLabelSelect' item.
+ addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabelSelect"),
+ {0});
+
+ // Add 'XIncludes' item (Libraries search paths).
+ addOptionsGroup(QByteArrayLiteral("XIncludes"),
+ opts.librarySearchPaths);
+}
+
+void Mcs51LinkerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'XOutOverride' item (Override default output file).
+ addOptionsGroup(QByteArrayLiteral("XOutOverride"),
+ {1});
+ // Add 'OutputFile' item (Output file name).
+ addOptionsGroup(QByteArrayLiteral("OutputFile"),
+ {opts.outputFile});
+}
+
+void Mcs51LinkerSettingsGroup::buildListPage(
+ const ProductData &qbsProduct)
+{
+ const ListPageOptions opts(qbsProduct);
+ // Add 'XList' item (Generate linker listing).
+ addOptionsGroup(QByteArrayLiteral("XList"),
+ {opts.generateMap});
+}
+
+void Mcs51LinkerSettingsGroup::buildDefinePage(
+ const ProductData &qbsProduct)
+{
+ const DefinePageOptions opts(qbsProduct);
+ // Add 'XDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("XDefines"),
+ opts.defineSymbols);
+}
+
+void Mcs51LinkerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'SuppressAllWarn' item (Suppress all warnings).
+ addOptionsGroup(QByteArrayLiteral("SuppressAllWarn"),
+ {opts.suppressAllWarnings});
+}
+
+void Mcs51LinkerSettingsGroup::buildExtraOptionsPage(
+ const ProductData &qbsProduct)
+{
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ for (const QString &flag : flags) {
+ if (flag.startsWith(QLatin1String("-Z")))
+ m_extraOptions.push_back(flag);
+ }
+
+ if (!m_extraOptions.isEmpty()) {
+ // Add 'Linker Extra Options Check' (Use command line options).
+ addOptionsGroup(QByteArrayLiteral("Linker Extra Options Check"),
+ {1});
+ // Add 'Linker Extra Options Edit' item (Command line options).
+ addOptionsGroup(QByteArrayLiteral("Linker Extra Options Edit"),
+ m_extraOptions);
+ }
+}
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.h b/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.h
new file mode 100644
index 000000000..fec80e5e6
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/mcs51/mcs51linkersettingsgroup_v10.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWMCS51LINKERSETTINGSGROUP_V10_H
+#define QBS_IAREWMCS51LINKERSETTINGSGROUP_V10_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace mcs51 {
+namespace v10 {
+
+class Mcs51LinkerSettingsGroupPrivate;
+
+class Mcs51LinkerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Mcs51LinkerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildOutputPage(const ProductData &qbsProduct);
+ void buildListPage(const ProductData &qbsProduct);
+ void buildDefinePage(const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+ void buildExtraOptionsPage(const ProductData &qbsProduct);
+
+ QVariantList m_extraOptions;
+};
+
+} // namespace v10
+} // namespace mcs51
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMCS51LINKERSETTINGSGROUP_V10_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.cpp
new file mode 100644
index 000000000..1258412d8
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "msp430archiversettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+constexpr int kArchiverArchiveVersion = 4;
+constexpr int kArchiverDataVersion = 0;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ outputFile = QLatin1String("$PROJ_DIR$/")
+ + gen::utils::targetBinaryPath(baseDirectory, qbsProduct);
+ }
+
+ QString outputFile;
+};
+
+} // namespace
+
+//Msp430ArchiverSettingsGroup
+
+Msp430ArchiverSettingsGroup::Msp430ArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("XAR"));
+ setArchiveVersion(kArchiverArchiveVersion);
+ setDataVersion(kArchiverDataVersion);
+ setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
+
+ const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+}
+
+void Msp430ArchiverSettingsGroup::buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'XAROutOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("XAROutOverride"),
+ {1});
+ //