aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.dockerignore3
-rw-r--r--.travis.yml84
-rw-r--r--VERSION2
-rw-r--r--doc/appendix/json-api.qdoc817
-rw-r--r--doc/appendix/qbs-porting.qdoc2
-rw-r--r--doc/config/style/qt5-sidebar.html3
-rw-r--r--doc/doc.qbs5
-rw-r--r--doc/qbs.qdoc60
-rw-r--r--doc/reference/cli/builtin/cli-session.qdoc54
-rw-r--r--doc/reference/cli/cli-options.qdocinc2
-rw-r--r--doc/reference/commands.qdoc9
-rw-r--r--doc/reference/items/convenience/autotestrunner.qdoc16
-rw-r--r--docker-compose.yml37
-rw-r--r--docker/bionic/Dockerfile180
-rwxr-xr-xdocker/bionic/entrypoint.sh96
-rw-r--r--docker/stretch/Dockerfile165
-rw-r--r--examples/baremetal/at90can128olimex/redblink/redblink.qbs2
-rw-r--r--examples/baremetal/baremetal.qbs4
-rw-r--r--examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs5
-rw-r--r--examples/baremetal/msp430f5529/msp430f5529.qbs58
-rw-r--r--examples/baremetal/msp430f5529/redblink/README.md9
-rw-r--r--examples/baremetal/msp430f5529/redblink/gpio.c76
-rw-r--r--examples/baremetal/msp430f5529/redblink/gpio.h65
-rw-r--r--examples/baremetal/msp430f5529/redblink/main.c72
-rw-r--r--examples/baremetal/msp430f5529/redblink/redblink.qbs129
-rw-r--r--examples/baremetal/msp430f5529/redblink/system.c65
-rw-r--r--examples/baremetal/msp430f5529/redblink/system.h64
-rw-r--r--examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs2
-rw-r--r--examples/baremetal/stm8s103f3/redblink/README.md8
-rw-r--r--examples/baremetal/stm8s103f3/redblink/gpio.c68
-rw-r--r--examples/baremetal/stm8s103f3/redblink/gpio.h65
-rw-r--r--examples/baremetal/stm8s103f3/redblink/main.c69
-rw-r--r--examples/baremetal/stm8s103f3/redblink/redblink.qbs111
-rw-r--r--examples/baremetal/stm8s103f3/redblink/system.h84
-rw-r--r--examples/baremetal/stm8s103f3/stm8s103f3.qbs58
-rw-r--r--examples/collidingmice/collidingmice.qbs4
-rwxr-xr-xscripts/build-qbs-with-qbs.sh33
-rwxr-xr-xscripts/install-qt.sh305
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js2
-rw-r--r--share/qbs/imports/qbs/Probes/IarProbe.qbs33
-rw-r--r--share/qbs/imports/qbs/Probes/KeilProbe.qbs3
-rw-r--r--share/qbs/imports/qbs/Probes/SdccProbe.qbs10
-rw-r--r--share/qbs/imports/qbs/base/AutotestRunner.qbs8
-rw-r--r--share/qbs/module-providers/Qt/templates/core.qbs4
-rw-r--r--share/qbs/modules/autotest/autotest.qbs1
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs39
-rw-r--r--share/qbs/modules/cpp/MingwBaseModule.qbs115
-rw-r--r--share/qbs/modules/cpp/gcc.js35
-rw-r--r--share/qbs/modules/cpp/iar.js415
-rw-r--r--share/qbs/modules/cpp/iar.qbs106
-rw-r--r--share/qbs/modules/cpp/keil.js363
-rw-r--r--share/qbs/modules/cpp/keil.qbs92
-rw-r--r--share/qbs/modules/cpp/msvc.js43
-rw-r--r--share/qbs/modules/cpp/sdcc.js167
-rw-r--r--share/qbs/modules/cpp/sdcc.qbs26
-rw-r--r--share/qbs/modules/cpp/windows-clang-mingw.qbs98
-rw-r--r--share/qbs/modules/cpp/windows-mingw.qbs88
-rw-r--r--share/qbs/modules/cpp/windows-msvc-base.qbs48
-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.cpp751
-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
-rw-r--r--tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs9
-rw-r--r--tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs7
-rw-r--r--tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-profile-item.qbs19
-rw-r--r--tests/auto/api/testdata/timeout-js/timeout.qbs20
-rw-r--r--tests/auto/api/testdata/timeout-process/main.cpp37
-rw-r--r--tests/auto/api/testdata/timeout-process/timeout.qbs34
-rw-r--r--tests/auto/api/tst_api.cpp62
-rw-r--r--tests/auto/api/tst_api.h4
-rw-r--r--tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs2
-rw-r--r--tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp2
-rw-r--r--tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs20
-rw-r--r--tests/auto/blackbox/testdata/autotest-timeout/test-main.cpp37
-rw-r--r--tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs4
-rw-r--r--tests/auto/blackbox/testdata/autotests/autotests.qbs7
-rw-r--r--tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs17
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/file1.cpp1
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/file2.cpp1
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/lib.cpp1
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/lib.h1
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/modules/mymodule/mymodule.qbs5
-rw-r--r--tests/auto/blackbox/testdata/qbs-session/qbs-session.qbs25
-rw-r--r--tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs9
-rw-r--r--tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs15
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp697
-rw-r--r--tests/auto/blackbox/tst_blackbox.h4
-rw-r--r--tests/auto/blackbox/tst_blackboxjoblimits.cpp2
-rw-r--r--tests/auto/shared.h10
329 files changed, 28500 insertions, 1221 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 000000000..a949bb5a2
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+*
+!docker/*
+!scripts/*
diff --git a/.travis.yml b/.travis.yml
index cead59a79..ad6fbaaaf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,16 +8,22 @@ language: cpp
git:
submodules: false
+env:
+ global:
+ - QT_INSTALL_DIR=~/Qt
+ - QT_VERSION=5.12.5
+ - QTCREATOR_VERSION=4.9.2
+
stages:
- name: Build Qbs and and run autotests
jobs:
include:
- - &build-on-stretch
+ - &build-on-bionic
stage: Build Qbs and and run autotests
- name: With Qbs on Debian stretch (linux_amd64)
+ name: With Qbs on Ubuntu bionic (linux_gcc64)
env:
- SERVICE=stretch
+ SERVICE=bionic
services:
- docker
before_install:
@@ -25,7 +31,75 @@ jobs:
script:
- docker-compose run --rm ${SERVICE} scripts/build-qbs-with-qbs.sh
- - <<: *build-on-stretch
- name: With QMake on Debian stretch (linux_amd64)
+ - <<: *build-on-bionic
+ name: With QMake on Ubuntu bionic (linux_gcc64)
script:
- docker-compose run --rm ${SERVICE} scripts/build-qbs-with-qmake.sh
+
+ - <<: *build-on-bionic
+ name: With Qbs on Ubuntu bionic (mingw32_w64)
+ script:
+ - docker-compose run --rm ${SERVICE} qbs build profile:qt-mingw32_w64
+
+ - &build-on-macos
+ stage: Build Qbs and and run autotests
+ name: With Qbs on macOS (xcode 10.3)
+ os: osx
+ osx_image: xcode10.3
+ addons:
+ homebrew:
+ packages:
+ - p7zip
+ update: true
+ env:
+ # Address sanitizer slows autotests down too much.
+ # We would hit the maximum build time on Travis.
+ BUILD_OPTIONS=modules.qbsbuildconfig.enableAddressSanitizer:false
+ QMAKE_PATH=${QT_INSTALL_DIR}/${QT_VERSION}/clang_64/bin/qmake
+ PATH="${QT_INSTALL_DIR}/Qt Creator.app/Contents/MacOS:${PATH}"
+ QBS_BUILD_PROFILE=qt
+ before_install:
+ - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QT_VERSION} qtbase qtdeclarative qttools qtscript
+ - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QTCREATOR_VERSION} qtcreator
+ - pip2 install --user beautifulsoup4 lxml
+ script:
+ - qbs setup-toolchains --detect
+ - qbs setup-qt ${QMAKE_PATH} qt
+ - qbs config qt.baseProfile xcode-macosx-x86_64
+ - qbs config defaultProfile qt
+ - scripts/build-qbs-with-qbs.sh
+
+ - &build-on-windows
+ stage: Build Qbs and and run autotests
+ name: With Qbs on Windows (Visual Studio 2017)
+ os: windows
+ env:
+ # Need to build in release mode. Otherwise autotests would be too slow.
+ BUILD_OPTIONS="config:release"
+ QT_INSTALL_DIR=C:/Qt
+ QMAKE_PATH=${QT_INSTALL_DIR}/${QT_VERSION}/msvc2017_64/bin/qmake.exe
+ PATH="/c/Qt/Tools/QtCreator/bin:${PATH}"
+ WITH_DOCS=0
+ QBS_BUILD_PROFILE=qt
+ before_install:
+ # Disable unnecessary background services which tend to consume
+ # a lot of resources
+ - powershell -Command 'Set-MpPreference -DisableRealtimeMonitoring $true'
+ - powershell -Command 'Set-MpPreference -DisableArchiveScanning $true'
+ - powershell -Command 'Set-MpPreference -DisableBehaviorMonitoring $true'
+ - powershell -Command 'sc.exe config TrustedInstaller start=disabled; sc.exe stop TrustedInstaller'
+ - powershell -Command 'sc.exe config wuauserv start=disabled; sc.exe stop wuauserv'
+ - powershell -Command 'Add-MpPreference -ExclusionPath C:\'
+ - powershell -Command 'Add-MpPreference -ExclusionProcess qbs.exe'
+ - powershell -Command 'Add-MpPreference -ExclusionProcess cl.exe'
+ - powershell -Command 'Add-MpPreference -ExclusionProcess link.exe'
+
+ # Install Qbs and Qt
+ - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QT_VERSION} --toolchain win64_msvc2017_64 qtbase qtdeclarative qttools qtscript
+ - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QTCREATOR_VERSION} qtcreator
+ script:
+ - qbs setup-toolchains --detect
+ - qbs setup-qt ${QMAKE_PATH} qt
+ - qbs config qt.baseProfile MSVC2017-x86
+ - qbs config defaultProfile qt
+ - scripts/build-qbs-with-qbs.sh
diff --git a/VERSION b/VERSION
index 850e74240..141f2e805 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.14.0
+1.15.0
diff --git a/doc/appendix/json-api.qdoc b/doc/appendix/json-api.qdoc
new file mode 100644
index 000000000..f8840de37
--- /dev/null
+++ b/doc/appendix/json-api.qdoc
@@ -0,0 +1,817 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage index.html
+ \previouspage porting-to-qbs.html
+ \nextpage attributions.html
+ \page json-api.html
+
+ \title Appendix C: The JSON API
+
+ This API is the recommended way to provide \QBS support to an IDE.
+ It is accessible via the \l{session} command.
+
+ \section1 Packet Format
+
+ All information is exchanged via \e packets, which have the following
+ structure:
+ \code
+ packet = "qbsmsg:" <payload length> [<meta data>] <line feed> <payload>
+ \endcode
+ First comes a fixed string indentifying the start of a packet, followed
+ by the size of the actual data in bytes. After that, further meta data
+ might follow. There is none currently, but future extensions might add
+ some. A line feed character marks the end of the meta data section
+ and is followed immediately by the payload, which is a single JSON object
+ encoded in Base64 format. We call this object a \e message.
+
+ \section1 Messages
+
+ The message data is UTF8-encoded.
+
+ Most messages are either \e requests or \e replies. Requests are messages
+ sent to \QBS via the session's standard input channel. Replies are messages
+ sent by \QBS via the session's standard output channel. A reply always
+ corresponds to one specific request. Every request (with the exception
+ of the \l{quit-message}{quit request}) expects exactly one reply. A reply implies
+ that the requested operation has finished. At the very least, it carries
+ information about whether the operation succeeded, and often contains
+ additional data specific to the respective request.
+
+ Every message object has a \c type property, which is a string that uniquely
+ identifies the message type.
+
+ All requests block the session for other requests, including those of the
+ same type. For instance, if client code wishes to restart building the
+ project with different parameters, it first has to send a
+ \l{cancel-message}{cancel} request, wait for the current build job's reply,
+ and only then can it request another build. The only other message beside
+ \l{cancel-message}{cancel} that can legally be sent while a request
+ is currently being handled is the \l{quit-message}{quit} message.
+
+ A reply object may carry an \c error property, indicating that the respective
+ operation has failed. If this property is not present, the request was successful.
+ The format of the \c error property is described \l{ErrorInfo}{here}.
+
+ In the remainder of this page, we describe the structure of all messages
+ that can be sent to and received from \QBS, respectively. The property
+ tables may have a column titled \e Mandatory, whose values indicate whether
+ the respective message property is always present. If this column is missing,
+ all properties of the respective message are mandatory, unless otherwise
+ noted.
+
+ \section1 The \c hello Message
+
+ This message is sent by \QBS exactly once, right after the session was started.
+ It is the only message from \QBS that is not a response to a request.
+ The value of the \c type property is \c "hello", the other properties are
+ as follows:
+ \table
+ \header \li Property \li Type
+ \row \li api-level \li int
+ \row \li api-compat-level \li int
+ \endtable
+
+ The value of \c api-level is increased whenever the API is extended, for instance
+ by adding new messages or properties.
+
+ The value of \c api-compat-level is increased whenever incompatible changes
+ are being done to this API. A tool written for API level \c n should refuse
+ to work with a \QBS version with an API compatibility level greater than \c n,
+ because it cannot guarantee proper behavior. This value will not change unless
+ it is absolutely necessary.
+
+ The value of \c api-compat-level is always less than or equal to the
+ value of \c api-level.
+
+ \section1 Resolving a Project
+
+ To instruct \QBS to load a project from disk, a request of type
+ \c resolve-project is sent. The other properties are:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li build-root \li \l FilePath \li yes
+ \row \li configuration-name \li string \li no
+ \row \li data-mode \li \l DataMode \li no
+ \row \li dry-run \li bool \li no
+ \row \li environment \li \l Environment \li no
+ \row \li error-handling-mode \li string \li no
+ \row \li fallback-provider-enabled \li bool \li no
+ \row \li force-probe-execution \li bool \li no
+ \row \li log-time \li bool \li no
+ \row \li log-level \li \l LogLevel \li no
+ \row \li module-properties \li list of strings \li no
+ \row \li overridden-properties \li object \li no
+ \row \li project-file-path \li FilePath \li if resolving from scratch
+ \row \li restore-behavior \li string \li no
+ \row \li settings-directory \li string \li no
+ \row \li top-level-profile \li string \li no
+ \row \li wait-lock-build-graph \li bool \li no
+ \endtable
+
+ The \c environment property defines the environment to be used for resolving
+ the project, as well as for all subsequent \QBS operations on this project.
+
+ The \c error-handling-mode specifies how \QBS should deal with issues
+ in project files, such as assigning to an unknown property. The possible
+ values are \c "strict" and \c "relaxed". In strict mode, \QBS will
+ immediately abort and set the reply's \c error property accordingly.
+ In relaxed mode, \QBS will continue to resolve the project if possible.
+ A \l{warning-message}{warning message} will be emitted for every error that
+ was encountered, and the reply's \c error property will \e not be set.
+ The default error handling mode is \c "strict".
+
+ If the \c log-time property is \c true, then \QBS will emit \l log-data messages
+ containing information about which part of the operation took how much time.
+
+ The \c module-properties property lists the names of the module properties
+ which should be contained in the \l{ProductData}{product data} that
+ will be sent in the reply message. For instance, if the project to be resolved
+ is C++-based and the client code is interested in which C++ version the
+ code uses, then \c module-properties would contain \c{"cpp.cxxLanguageVersion"}.
+
+ The \c overridden-properties property is used to override the values of
+ module, product or project properties. The possible ways to specify
+ keys are described \l{Overriding Property Values from the Command Line}{here}.
+
+ The \c restore-behavior property specifies if and how to make use of
+ an existing build graph. The value \c "restore-only" indicates that
+ a build graph should be loaded from disk and used as-is. In this mode,
+ it is an error if the build graph file does not exist.
+ The value \c "resolve-only" indicates that the project should be resolved
+ from scratch and that an existing build graph should be ignored. In this mode,
+ it is an error if the \c "project-file-path" property is not present.
+ The default value is \c "restore-and-track-changes", which uses an
+ existing build graph if possible and re-resolves the project if no
+ build graph was found or if the parameters are different from the ones
+ used when the project was last resolved.
+
+ The \c top-level-profile property specifies which \QBS profile to use
+ for resolving the project. It corresponds to the \c profile key when
+ using the \l resolve command.
+
+ All other properties correspond to command line options of the \l resolve
+ command, and their semantics are described there.
+
+ When the project has been resolved, \QBS will reply with a \c project-resolved
+ message. The possible properties are:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li error \li \l ErrorInfo \li no
+ \row \li project-data \li \l TopLevelProjectData \li no
+ \endtable
+
+ The \c error-info property is present if and only if the operation
+ failed. The \c project-data property is present if and only if
+ the conditions stated by the request's \c data-mode property
+ are fulfilled.
+
+ All other project-related requests need a resolved project to operate on.
+ If there is none, they will fail.
+
+ There is at most one resolved project per session. If client code wants to
+ open several projects or one project in different configurations, it needs
+ to start additional sessions.
+
+ \section1 Building a Project
+
+ To build a project, a request of type \c build-project is sent. The other properties,
+ none of which are mandatory, are listed below:
+ \table
+ \header \li Property \li Type
+ \row \li active-file-tags \li string list
+ \row \li changed-files \li \l FilePath list
+ \row \li check-outputs \li bool
+ \row \li check-timestamps \li bool
+ \row \li clean-install-root \li bool
+ \row \li data-mode \li \l DataMode
+ \row \li dry-run \li bool
+ \row \li command-echo-mode \li string
+ \row \li enforce-project-job-limits \li bool
+ \row \li files-to-consider \li \l FilePath list
+ \row \li install \li bool
+ \row \li job-limits \li list of objects
+ \row \li keep-going \li bool
+ \row \li log-level \li \l LogLevel
+ \row \li log-time \li bool
+ \row \li max-job-count \li int
+ \row \li module-properties \li list of strings
+ \row \li products \li list of strings or \c "all"
+ \endtable
+
+ All boolean properties except \c install default to \c false.
+
+ The \c active-file-tags and \c files-to-consider are used to limit the
+ build to certain output tags and/or source files.
+ For instance, if only C/C++ object files should get built, then
+ \c active-file-tags would be set to \c "obj".
+
+ The objects in a \c job-limits array consist of a string property \c pool
+ and an int property \c limit.
+
+ If the \c log-time property is \c true, then \QBS will emit \l log-data messages
+ containing information about which part of the operation took how much time.
+
+ If \c products is an array, the elements must correspond to the
+ \c full-display-name property of previously retrieved \l ProductData,
+ and only these products will get built.
+ If \c products is the string \c "all", then all products in the project will
+ get built.
+ If \c products is not present, then products whose
+ \l{Product::builtByDefault}{builtByDefault} property is \c false will
+ be skipped.
+
+ The \c module-properties property has the same meaning as in the
+ \l{Resolving a Project}{resolve-project} request.
+
+ All other properties correspond to options of the \l build command.
+
+ When the build has finished, \QBS will reply with a \c project-built
+ message. The possible properties are:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li error \li \l ErrorInfo \li no
+ \row \li project-data \li \l TopLevelProjectData \li no
+ \endtable
+
+ The \c error-info property is present if and only if the operation
+ failed. The \c project-data property is present if and only if
+ the conditions stated by the request's \c data-mode property
+ are fulfilled.
+
+ Unless the \c command-echo-mode value is \c "silent", a message of type
+ \c command-description is emitted for every command to be executed.
+ It consists of two string properties \c highlight and \c message,
+ where \c message is the message to present to the user and \c highlight
+ is a hint on how to display the message. It corresponds to the
+ \l{Command and JavaScriptCommand}{Command} property of the same name.
+
+ For finished process commands, a message of type \c process-result
+ might be emitted. The other properties are:
+ \table
+ \header \li Property \li Type
+ \row \li arguments \li list of strings
+ \row \li error \li string
+ \row \li executable-file-path \li \l FilePath
+ \row \li exit-code \li int
+ \row \li stderr \li list of strings
+ \row \li stdout \li list of strings
+ \row \li success \li bool
+ \row \li working-directory \li \l FilePath
+ \endtable
+
+ The \c error string is one of \c "failed-to-start", \c "crashed", \c "timed-out",
+ \c "write-error", \c "read-error" and \c "unknown-error".
+ Its value is not meaningful unless \c success is \c false.
+
+ The \c stdout and \c stderr properties describe the process's standard
+ output and standard error output, respectively, split into lines.
+
+ The \c success property is \c true if the process finished without errors
+ and an exit code of zero.
+
+ The other properties describe the exact command that was executed.
+
+ This message is only emitted if the process failed or it has printed data
+ to one of the output channels.
+
+ \section1 Cleaning a Project
+
+ To remove a project's build artifacts, a request of type \c clean-project
+ is sent. The other properties are:
+ \table
+ \header \li Property \li Type
+ \row \li dry-run \li bool
+ \row \li keep-going \li bool
+ \row \li log-level \li \l LogLevel
+ \row \li log-time \li bool
+ \row \li products \li list of strings
+ \endtable
+
+ The elements of the \c products array correspond to a \c full-display-name
+ of a \l ProductData. If this property is present, only the respective
+ products' artifacts are removed.
+
+ If the \c log-time property is \c true, then \QBS will emit \l log-data messages
+ containing information about which part of the operation took how much time.
+
+ All other properties correspond to options of the \l clean command.
+
+ None of these properties are mandatory.
+
+ After all artifacts have been removed, \QBS replies with a
+ \c project-cleaned message. If the operation was successful, this message
+ has no properties. Otherwise, a property \c error of type \l ErrorInfo
+ indicates what went wrong.
+
+ \section1 Installing a Project
+
+ Installing is normally part of the \l{Building a Project}{build}
+ process. To do it in a separate step, the \c install property
+ is set to \c false when building and a dedicated \c install-project
+ message is sent. The other properties are:
+ \table
+ \header \li Property \li Type
+ \row \li clean-install-root \li bool
+ \row \li dry-run \li bool
+ \row \li install-root \li \l FilePath
+ \row \li keep-going \li bool
+ \row \li log-level \li \l LogLevel
+ \row \li log-time \li bool
+ \row \li products \li list of strings
+ \row \li use-sysroot \li bool
+ \endtable
+
+ The elements of the \c products array correspond to a \c full-display-name
+ of a \l ProductData. If this property is present, only the respective
+ products' artifacts are installed.
+
+ If the \c log-time property is \c true, then \QBS will emit \l log-data messages
+ containing information about which part of the operation took how much time.
+
+ If the \c use-sysroot property is \c true and \c install-root is not present,
+ then the install root will be \l{qbs::sysroot}{qbs.sysroot}.
+
+ All other properties correspond to options of the \l install command.
+
+ None of these properties are mandatory.
+
+ \target cancel-message
+ \section1 Canceling an Operation
+
+ Potentially long-running operations can be aborted using the \c cancel-job
+ request. This message does not have any properties. There is no dedicated
+ reply message; instead, the usual reply for the request associated with
+ the currently running operation will be sent, with the \c error property
+ set to indicate that it was canceled.
+
+ If there is no operation in progress, this request will have no effect.
+ In particular, if it arrives after the operation that it was supposed to
+ cancel has already finished (i.e. there is a race condition), the reply
+ received by client code will not contain a cancellation-related error.
+
+ \section1 Adding and Removing Source Files
+
+ Source files can be added to and removed from \QBS project files with
+ the \c add-files and \c remove-files messages, respectively. These two
+ requests have the same set of properties:
+ \table
+ \header \li Property \li Type
+ \row \li files \li \l FilePath list
+ \row \li group \li string
+ \row \li product \li string
+ \endtable
+
+ The \c files property specifies which files should be added or removed.
+
+ The \c product property corresponds to the \c full-display-name of
+ a \l ProductData and specifies to which product to apply the operation.
+
+ The \c group property corresponds to the \c name of a \l GroupData
+ and specifies to which group in the product to apply the operation.
+
+ After the operation has finished, \QBS replies with a \c files-added
+ and \c files-removed message, respectively. Again, the properties are
+ the same:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li error \li \l ErrorInfo \li no
+ \row \li failed-files \li \l FilePath list \li no
+ \row \li project-data \li \l TopLevelProjectData \li no
+ \endtable
+
+ If the \c error property is present, the operation has at least
+ partially failed and \c failed-files will list the files
+ that could not be added or removed.
+
+ If the project data has changed as a result of the operation
+ (which it should unless the operation failed completely), then
+ the \c project-data property will contain the updated project data.
+
+ \section1 The \c get-run-environment Message
+
+ This request retrieves the full run environment for a specific
+ executable product, taking into account the
+ \l{Module::setupRunEnvironment}{setupRunEnvironment} scripts
+ of all modules pulled in by the product. The properties are as follows:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li base-environment \li \l Environment \li no
+ \row \li config \li list of strings \li no
+ \row \li product \li string \li yes
+ \endtable
+
+ The \c base-environment property defines the environment into which
+ the \QBS-specific values should be merged.
+
+ The \c config property corresponds to the \l{--setup-run-env-config}
+ option of the \l run command.
+
+ The \c product property specifies the product whose environment to
+ retrieve. The value must correspond to the \c full-display-name
+ of some \l ProductData in the project.
+
+ \QBS will reply with a \c run-environment message. In case of failure,
+ it will contain a property \c error of type \l ErrorInfo, otherwise
+ it will contain a property \c full-environment of type \l Environment.
+
+ \section1 The \c get-generated-files-for-sources Message
+
+ This request allows client code to retrieve information about
+ which artifacts are generated from a given source file.
+ Its sole property is a list \c products, whose elements are objects
+ with the two properties \c full-display-name and \c requests.
+ The first identifies the product to which the requests apply, and
+ it must match the property of the same name in a \l ProductData
+ in the project.
+ The latter is a list of objects with the following properties:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li source-file \li \l FilePath \li yes
+ \row \li tags \li list of strings \li no
+ \row \li recursive \li bool \li no
+ \endtable
+
+ The \c source-file property specifies a source file in the respective
+ product.
+
+ The \c tags property constrains the possible file tags of the generated
+ files to be matched. This is relevant if a source files serves as input
+ to more than one rule or the rule generates more than one type of output.
+
+ If the \c recursive property is \c true, files indirectly generated
+ from the source file will also be returned. The default is \c false.
+ For instance, íf this property is enabled for a C++ source file,
+ the final link target (e.g. a library or an application executable)
+ will be returned in addition to the object file.
+
+ \QBS will reply with a \c generated-files-for-sources message, whose
+ structure is similar to the request. It also has a single object list
+ property \c products, whose elements consist of a string property
+ \c full-display-name and an object list property \c results.
+ The properties of these objects are:
+ \table
+ \header \li Property \li Type
+ \row \li source-file \li \l FilePath
+ \row \li generated-files \li \l FilePath list
+ \endtable
+
+ The \c source-file property corresponds to an entry of the same name
+ in the request, and the \c generated-files are the files which are
+ generated by \QBS rules that take the source file as an input,
+ taking the constraints specified in the request into account.
+
+ Source files for which the list would be empty are not listed.
+ Similarly, products for which the \c results list would be empty
+ are also omitted.
+
+ \note The results may be incomplete if the project has not been fully built.
+
+ \section1 Closing a Project
+
+ A project is closed with a \c release-project message. This request has
+ no properties.
+
+ \QBS will reply with a \c project-released message. If no project was open,
+ the reply will contain an \c error property of type \l ErrorInfo.
+
+ \target quit-message
+ \section1 Closing the Session
+
+ To close the session, a \c quit message is sent. This request has no
+ properties.
+
+ \QBS will cancel all currently running operations and then close itself.
+ No reply will be sent.
+
+ \section1 Progress Messages
+
+ While a request is being handled, \QBS may emit progress information in order
+ to enable client code to display a progress bar.
+
+ \target task-started
+ \section2 The \c task-started Message
+
+ This is always the first progress-related message for a specific request.
+ It appears at most once per request.
+ It consists of a string property \c description, whose value can be displayed
+ to users, and an integer property \c max-progress that indicates which
+ progress value corresponds to 100 per cent.
+
+ \target task-progress
+ \section2 The \c task-progress Message
+
+ This message updates the progress via an integer property \c progress.
+
+ \target new-max-progress
+ \section2 The \c new-max-progress Message
+
+ This message is emitted if the original estimated maximum progress has
+ to be corrected. Its integer property \c max-progress updates the
+ value from a preceding \l task-started message.
+
+ \section1 Messages for Users
+
+ There are two types of messages that purely contain information to be
+ presented to users.
+
+ \target log-data
+ \section2 The \c log-data Message
+
+ This object has a string property \c message, which is the text to be
+ shown to the user.
+
+ \target warning-message
+ \section2 The \c warning Message
+
+ This message has a single property \c warning of type \l ErrorInfo.
+
+ \section1 The \c protocol-error Message
+
+ \QBS sends this message as a reply to a request with an unknown \c type.
+ It contains an \c error property of type \l ErrorInfo.
+
+ \section1 Project Data
+
+ If a request can alter the build graph data, the associated reply may contain
+ a \c project-data property whose value is of type \l TopLevelProjectData.
+
+ \section2 TopLevelProjectData
+
+ This data type represents the entire project. It has the same properties
+ as \l PlainProjectData. If it is part of a \c project-resolved message,
+ these additional properties are also present:
+ \table
+ \header \li Property \li Type
+ \row \li build-directory \li \l FilePath
+ \row \li build-graph-file-path \li \l FilePath
+ \row \li build-system-files \li \l FilePath list
+ \row \li overridden-properties \li object
+ \row \li profile-data \li object
+ \endtable
+
+ The value of \c build-directory is the top-level build directory.
+
+ The \c build-graph-file-path value is the path to the build graph file.
+
+ The \c build-system-files value contains all \QBS project files, including
+ modules and JavaScript helper files.
+
+ The value of \c overridden-properties is the one that was passed in when
+ the project was last \l{Resolving a Project}{resolved}.
+
+ The \c profile-data property maps the names of the profiles used in the project
+ to the respective property maps. Unless profile multiplexing is used, this
+ object will contain exactly one property.
+
+ \section2 PlainProjectData
+
+ This data type describes a \l Project item. The properties are as follows:
+ \table
+ \header \li Property \li Type
+ \row \li is-enabled \li bool
+ \row \li location \li \l FilePath
+ \row \li name \li string
+ \row \li products \li \l ProductData list
+ \row \li sub-projects \li \l PlainProjectData list
+ \endtable
+
+ The \c is-enabled property corresponds to the project's
+ \l{Project::condition}{condition}.
+
+ The \c location property is the exact position in a \QBS project file
+ where the corresponding \l Project item was defined.
+
+ The \c products and \c sub-projects are what the project has pulled in via
+ its \l{Project::references}{references} property.
+
+ \section2 ProductData
+
+ This data type describes a \l Product item. The properties are as follows:
+ \table
+ \header \li Property \li Type
+ \row \li build-directory \li \l FilePath
+ \row \li dependencies \li list of strings
+ \row \li full-display-name \li string
+ \row \li generated-artifacts \li \l ArtifactData list
+ \row \li groups \li \l GroupData list
+ \row \li is-enabled \li bool
+ \row \li is-multiplexed \li bool
+ \row \li is-runnable \li bool
+ \row \li location \li \l Location
+ \row \li module-properties \li \l ModulePropertiesData
+ \row \li multiplex-configuration-id \li string
+ \row \li name \li string
+ \row \li properties \li object
+ \row \li target-executable \li \l FilePath
+ \row \li target-name \li string
+ \row \li type \li list of strings
+ \row \li version \li string
+ \endtable
+
+ The \c dependencies are the names of products that occur in the (enabled)
+ \l Depends items of this product.
+
+ The \c generated-artifacts are files that are created by the \l{Rule}{rules}
+ in this product.
+
+ The \c groups list corresponds to the \l Group items in this product.
+ In addition, a "pseudo-group" is created for the \l{Product::files}{files}
+ property of the product itself. Its name is the same as the product's.
+
+ The \c is-enabled property corresponds to the product's
+ \l{Product::condition}{condition}. A product may also get disabled
+ if it contains errors and \QBS was was instructed to operate in relaxed mode
+ when the project was \l{Resolving a Project}{resolved}.
+
+ The \c is-multiplexed property is true if and only if the product is
+ \l{Multiplexing}{multiplexed} over one ore more properties.
+
+ The \c is-runnable property indicates whether one of the product's
+ target artifacts is an executable file.
+ In that case, the file is available via the \c target-executable property.
+
+ The \c location property is the exact position in a \QBS project file
+ where the corresponding \l Product item was defined.
+
+ The \c module-properties object provides the values of the module properties
+ that were requested when the project was \l{Resolving a Project}{resolved}.
+
+ The \c name property is the value given in the \l{Product::name}{Product item},
+ whereas \c full-display-name is a name that uniquely identifies the
+ product in the entire project, even in the presence of multiplexing.
+ In the absence of multiplexing, it is the same as \c name. In either case,
+ it is suitable for being presented to users.
+
+ See the \l Product item documentation for a description of the other
+ properties.
+
+ \section2 GroupData
+
+ This data type describes a \l Group item. The properties are:
+ \table
+ \header \li Property \li Type
+ \row \li is-enabled \li bool
+ \row \li location \li \l Location
+ \row \li module-properties \li \l ModulePropertiesData
+ \row \li name \li string
+ \row \li prefix \li string
+ \row \li source-artifacts \li \l ArtifactData list
+ \row \li source-artifacts-from-wildcards \li \l ArtifactData list
+ \endtable
+
+ The \c is-enabled property corresponds to the groups's
+ \l{Group::condition}{condition}. However, if the group's product
+ is disabled, this property will always be \c false.
+
+ The \c location property is the exact position in a \QBS project file
+ where the corresponding \l Group item occurs.
+
+ The \c module-properties object provides the values of the module properties
+ that were requested when the project was \l{Resolving a Project}{resolved}.
+ If no module properties are set on the Group level and the value would therefore
+ be the same as in the group's product, then this property is omitted.
+
+ The \c source-artifacts list corresponds the the files listed verbatim
+ in the group's \l{Group::files}{files} property.
+
+ The \c source-artifacts-from-wildcards list represents the the files
+ expanded from wildcard entries in the group's \l{Group::files}{files} property.
+
+ See the \l Group item documentation for a description of the other
+ properties.
+
+ \section2 ArtifactData
+
+ This data type represents files that occur in the project, either as sources
+ or as outputs of a rules. \QBS project files, on the other hand, are not
+ artifacts. The properties are:
+ \table
+ \header \li Property \li Type
+ \row \li file-path \li \l FilePath
+ \row \li file-tags \li list of strings
+ \row \li install-data \li object
+ \row \li is-executable \li bool
+ \row \li is-generated \li bool
+ \row \li is-target \li bool
+ \row \li module-properties \li \l ModulePropertiesData
+ \endtable
+
+ The \c install-data property is an object whose \c is-installable property
+ indicates whether the artifact gets installed. If so, then the \l FilePath
+ properties \c install-file-path and \c install-root provide further
+ information.
+
+ The \c is-target property is true if the artifact is a target artifact
+ of its product, that is, \c is-generated is true and \c file-tags
+ intersects with the \l{Product::type}{product type}.
+
+ The \c module-properties object provides the values of the module properties
+ that were requested when the project was \l{Resolving a Project}{resolved}.
+ This property is only present for generated artifacts. For source artifacts,
+ the value can be retrieved from their \l{GroupData}{group}.
+
+ The other properties should be self-explanatory.
+
+ \section2 ModulePropertiesData
+
+ This data type maps fully qualified module property names to their
+ respective values.
+
+ \section1 Other Custom Data Types
+
+ There are a number of custom data types that serve as building blocks in
+ various messages. They are described below.
+
+ \section2 FilePath
+
+ A \e FilePath is a string that describes a file or directory. FilePaths are
+ always absolute and use forward slashes for separators, regardless of
+ the host operating system.
+
+ \section2 Location
+
+ A \e Location is an object representing a file path and possibly also a position
+ within the respective file. It consists of the following properties:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li file-path \li \l FilePath \li yes
+ \row \li line \li int \li no
+ \row \li column \li int \li no
+ \endtable
+
+ \section2 ErrorInfo
+
+ An \e ErrorInfo is an object representing error information. Its sole property
+ \c items is an array of objects with the following structure:
+ \table
+ \header \li Property \li Type \li Mandatory
+ \row \li \c message \li string \li yes
+ \row \li location \li \l Location \li no
+ \endtable
+
+ \section2 DataMode
+
+ This is the type of the \c data-mode property in a
+ \l{Resolving a project}{resolve} or \l{Building a project}{build}
+ request. It is used to indicate under which circumstances
+ the reply message should include the project data. The possible
+ values have string type and are as follows:
+ \list
+ \li \c "never": Do not attach project data to the reply.
+ \li \c "always": Do attach project data to the reply.
+ \li \c "only-if-changed": Attach project data to the reply only
+ if it is different from the current
+ project data.
+ \endlist
+ The default value is \c "never".
+
+ \section2 LogLevel
+
+ This is the type of the \c log-level property that can occur
+ in various requests. It is used to indicate whether the client would like
+ to receive \l log-data and/or \l{warning-message}{warning} messages.
+ The possible values have string type and are as follows:
+ \list
+ \li "error": Do not log anything.
+ \li "warning": \QBS may emit \l{warning-message}{warnings}, but no
+ \l log-data messages.
+ \li "info": In addition to warnings, \QBS may emit informational
+ \l log-data messages.
+ \li "debug": \QBS may emit debug output. No messages will be generated;
+ instead, the standard error output channel will be used.
+ \endlist
+ The default value is \c "info".
+
+ \section2 Environment
+
+ This data type describes a set of environment variables. It is an object
+ whose keys are names of environment variables and whose values are
+ the values of these environment variables.
+
+*/
diff --git a/doc/appendix/qbs-porting.qdoc b/doc/appendix/qbs-porting.qdoc
index e17d7b0ac..ba697d7be 100644
--- a/doc/appendix/qbs-porting.qdoc
+++ b/doc/appendix/qbs-porting.qdoc
@@ -29,7 +29,7 @@
\contentspage index.html
\previouspage building-qbs.html
\page porting-to-qbs.html
- \nextpage attributions.html
+ \nextpage json-api.html
\title Appendix B: Migrating from Other Build Systems
diff --git a/doc/config/style/qt5-sidebar.html b/doc/config/style/qt5-sidebar.html
index 99690bd01..3df5d1bbf 100644
--- a/doc/config/style/qt5-sidebar.html
+++ b/doc/config/style/qt5-sidebar.html
@@ -12,6 +12,7 @@
<li><a href="reference.html">Reference</a></li>
<li><a href="building-qbs.html">Appendix A: Building Qbs</a></li>
<li><a href="porting-to-qbs.html">Appendix B: Migrating from Other Build Systems</a></li>
- <li><a href="attributions.html">Appendix C: Code Attributions</a></li>
+ <li><a href="json-api.html">Appendix C: The JSON API</a></li>
+ <li><a href="attributions.html">Appendix D: Code Attributions</a></li>
</ul>
</div>
diff --git a/doc/doc.qbs b/doc/doc.qbs
index 29ccd9938..dd8377c6c 100644
--- a/doc/doc.qbs
+++ b/doc/doc.qbs
@@ -8,7 +8,9 @@ Project {
Product {
name: "qbs documentation"
builtByDefault: false
- type: ["qch", "qbsdoc.qdoc-html-fixed"]
+ type: Qt.core.config.contains("cross_compile") ?
+ ["qbsdoc.qdoc-html-fixed"] : [ "qbsdoc.qdoc-html-fixed", "qch"]
+
property string fixedHtmlDir: FileInfo.joinPaths(buildDirectory, "qdoc-html-fixed")
Depends { name: "Qt.core" }
Depends { name: "qbsbuildconfig" }
@@ -24,6 +26,7 @@ Project {
"qbs-online.qdocconf",
"config/*.qdocconf",
"config/style/qt5-sidebar.html",
+ "appendix/**/*",
"reference/**/*",
"templates/**/*",
"images/**",
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
index d2c703491..08a901365 100644
--- a/doc/qbs.qdoc
+++ b/doc/qbs.qdoc
@@ -87,7 +87,8 @@
\li \l{Appendix A: Building Qbs}
\li \l{Appendix B: Migrating from Other Build Systems}
- \li \l{Appendix C: Licenses and Code Attributions}
+ \li \l{Appendix C: The JSON API}
+ \li \l{Appendix D: Licenses and Code Attributions}
\endlist
*/
@@ -1721,7 +1722,7 @@
integrate \QBS with popular IDEs, such as Microsoft Visual Studio, and to
generate Clang compilation databases.
- \section1 Generating Projects
+ \section1 Generating Microsoft Visual Studio Projects
To generate a project for another build system, such as Microsoft Visual
Studio, use the \l{generate}{qbs generate} command and specify a generator
@@ -1744,6 +1745,57 @@
\l{generate}{qbs generate} in order for the changes to be reflected in your
IDE.
+ \section1 Generating IAR Embedded Workbench Projects
+
+ To generate a project for \l{https://www.iar.com/iar-embedded-workbench/}
+ {IAR Embedded Workbench}, use the \l{generate}{qbs generate} command and specify
+ a generator using the \l{generate-generator}{-g} option. For example:
+
+ \code
+ # For IAREW v8xxxx
+ qbs generate -g iarew8 profile:<your/qbs/profile>
+ qbs generate -g iarew8 -d <path/to/build/directory> -f <path/to/qbs/project> profile:<your/qbs/profile>
+ \endcode
+
+ \note You need to specify a specific QBS profile, which is required for a generator
+ to fetch a target architecture to generate the project.
+
+ \note IAR EW generator creates a native target project.
+
+ Supported IAR EW generators are listed in a table below:
+
+ \table
+ \header \li Generator \li IAR EW Version \li Target Architecture
+ \row \li iarew8 \li All 8.x.y versions \li ARM
+ \row \li iarew7 \li All 7.x.y versions \li AVR, MSP430
+ \row \li iarew10 \li All 10.x.y versions \li 8051 (aka MCS51)
+ \row \li iarew3 \li All 3.x.y versions \li STM8
+ \endtable
+
+ \section1 KEIL uVision Projects
+
+ To generate a project for \l{https://www2.keil.com/mdk5/uvision/}
+ {KEIL uVision}, use the \l{generate}{qbs generate} command and specify
+ a generator using the \l{generate-generator}{-g} option. For example:
+
+ \code
+ # For KEIL UV5
+ qbs generate -g keiluv5 profile:<your/qbs/profile>
+ qbs generate -g keiluv5 -d <path/to/build/directory> -f <path/to/qbs/project> profile:<your/qbs/profile>
+ \endcode
+
+ \note You need to specify a specific QBS profile, which is required for a generator
+ to fetch a target architecture to generate the project.
+
+ \note KEIL UV generator creates a native target project.
+
+ Supported KEIL UV generators are listed in a table below:
+
+ \table
+ \header \li Generator \li KEIL UV Version \li Target Architecture
+ \row \li keiluv5 \li All 5.x.y versions \li 8051 (aka MCS51), ARM
+ \endtable
+
\section1 Generating Clang Compilation Databases
To generate a \l{JSON Compilation Database Format Specification}
@@ -1915,10 +1967,10 @@
/*!
\contentspage index.html
- \previouspage porting-to-qbs.html
+ \previouspage json-api.html
\page attributions.html
- \title Appendix C: Licenses and Code Attributions
+ \title Appendix D: Licenses and Code Attributions
\section1 Licenses
diff --git a/doc/reference/cli/builtin/cli-session.qdoc b/doc/reference/cli/builtin/cli-session.qdoc
new file mode 100644
index 000000000..62999a82e
--- /dev/null
+++ b/doc/reference/cli/builtin/cli-session.qdoc
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage cli.html
+ \page cli-session.html
+ \ingroup cli
+
+ \title session
+ \brief Starts a session for interacting with an IDE
+
+ \section1 Synopsis
+
+ \code
+ qbs session
+ \endcode
+
+ \section1 Description
+
+ Starts a session, communicating via standard input and standard output.
+
+ In this mode, \QBS takes commands from standard input and sends replies
+ to standard output, using a \l{Appendix C: The JSON API}{JSON-based API}.
+
+ This is the recommended \QBS interface for IDEs. It can be used to retrieve
+ information about a project and interact with it in various ways, such
+ as building it, collecting the list of executables, adding new source files
+ and so on.
+
+*/
diff --git a/doc/reference/cli/cli-options.qdocinc b/doc/reference/cli/cli-options.qdocinc
index d4c3280a2..b02ce68ea 100644
--- a/doc/reference/cli/cli-options.qdocinc
+++ b/doc/reference/cli/cli-options.qdocinc
@@ -201,6 +201,7 @@
\list
\li \c clangdb
\li \c visualstudio2015
+ \li \c iarew8
\endlist
The available generators are listed if you run the \c {qbs generate} command
@@ -441,6 +442,7 @@
//! [setup-run-env-config]
+ \target --setup-run-env-config
\section2 \c --setup-run-env-config
A comma-separated list of strings. They will show up in the \c config
diff --git a/doc/reference/commands.qdoc b/doc/reference/commands.qdoc
index eb93e8f7a..d34c20cb7 100644
--- a/doc/reference/commands.qdoc
+++ b/doc/reference/commands.qdoc
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 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.
@@ -116,6 +117,14 @@
\li A flag that controls whether the \c description is printed. Set it to \c true for commands that
users need not know about. \note If this property is \c false, then \c description must
not be empty.
+ \row
+ \li \c timeout
+ \li int
+ \li -1
+ \li Time limit for the command execution in seconds. If the command does not finish within
+ the timeout, it is cancelled. In case of a \c Command, the process is requested to
+ terminate. If it does not terminate within three seconds, it is killed. A value below
+ or equal to 0 means no timeout.
\endtable
\section2 Command Properties
diff --git a/doc/reference/items/convenience/autotestrunner.qdoc b/doc/reference/items/convenience/autotestrunner.qdoc
index defb2814e..e8690ffe2 100644
--- a/doc/reference/items/convenience/autotestrunner.qdoc
+++ b/doc/reference/items/convenience/autotestrunner.qdoc
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 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.
@@ -67,6 +68,21 @@
qbs build -p autotest-runner
\endcode
\endlist
+
+ \section2 Relevant Job Pools
+ \target autotestrunner-job-pools
+
+ \table
+ \header
+ \li Pool
+ \li Since
+ \li Description
+ \row
+ \li \c{"autotest-runner"}
+ \li 1.15
+ \li The job pool used to run the tests.
+ \endtable
+
*/
/*!
diff --git a/docker-compose.yml b/docker-compose.yml
index bff8f5d87..16d9e361a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,17 +1,32 @@
-version: "3.3"
+version: "3.7"
+
+x-default-service: &linux
+ working_dir: /qbs
+ volumes:
+ - .:/qbs
+ network_mode: bridge
+ cap_add:
+ - SYS_PTRACE
services:
+ bionic:
+ << : *linux
+ hostname: bionic
+ image: ${DOCKER_USER:-qbsbuild}/qbsdev:bionic-5.12.5_1.13.1-1
+ build:
+ dockerfile: docker/bionic/Dockerfile
+ context: .
+ args:
+ QT_VERSION: 5.12.5
+ QTCREATOR_VERSION: 4.9.2
+
stretch:
+ << : *linux
+ hostname: stretch
image: ${DOCKER_USER:-qbsbuild}/qbsdev:stretch
build:
- dockerfile: Dockerfile
- context: docker/stretch/
+ dockerfile: docker/stretch/Dockerfile
+ context: .
args:
- QT_VERSION: 5.11.3
- QBS_VERSION: 1.13.0
- working_dir: /qbs
- volumes:
- - .:/qbs
- network_mode: bridge
- cap_add:
- - SYS_PTRACE
+ QT_VERSION: 5.12.4
+ QTCREATOR_VERSION: 4.9.2
diff --git a/docker/bionic/Dockerfile b/docker/bionic/Dockerfile
new file mode 100644
index 000000000..7522c47cd
--- /dev/null
+++ b/docker/bionic/Dockerfile
@@ -0,0 +1,180 @@
+#
+# Downloads and builds Qt from source. We do it in a
+# separate stage to keep the number of dependencies low in
+# the final Docker image.
+#
+FROM ubuntu:bionic as build-qt-mingw32_w64
+ARG QT_VERSION
+
+RUN apt-get update -qq && \
+ apt-get install -qq -y --no-install-recommends \
+ build-essential \
+ ca-certificates \
+ libclang-3.9-dev \
+ libgl1-mesa-dev \
+ mingw-w64 \
+ python \
+ xz-utils \
+ wget
+
+ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
+
+RUN mkdir -p /qt/source && \
+ wget -nv --continue --tries=20 --waitretry=10 --retry-connrefused \
+ --no-dns-cache --timeout 300 -qO- \
+ https://download.qt.io/official_releases/qt/${QT_VERSION%??}/${QT_VERSION}/single/qt-everywhere-src-${QT_VERSION}.tar.xz \
+ | tar --strip-components=1 -C /qt/source -xJf-
+
+RUN mkdir -p qt/build && \
+ cd qt/build && \
+ ../source/configure \
+ -prefix /opt/Qt/${QT_VERSION}/mingw32_w64 \
+ -release \
+ -shared \
+ -opensource \
+ -confirm-license \
+ -nomake examples \
+ -nomake tests \
+ -xplatform win32-g++ \
+ -opengl desktop \
+ -device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- \
+ -qt-sqlite -qt-libpng \
+ -no-cups -no-dbus -no-pch \
+ -no-feature-accessibility \
+ -skip qtactiveqt \
+ -skip qt3d \
+ -skip qtcanvas3d \
+ -skip qtcharts \
+ -skip qtconnectivity \
+ -skip qtdatavis3d \
+ -skip qtdeclarative \
+ -skip qtdoc \
+ -skip qtgamepad \
+ -skip qtgraphicaleffects \
+ -skip qtimageformats \
+ -skip qtlocation \
+ -skip qtmultimedia \
+ -skip qtnetworkauth \
+ -skip qtquickcontrols \
+ -skip qtquickcontrols2 \
+ -skip qtpurchasing \
+ -skip qtremoteobjects \
+ -skip qtscxml \
+ -skip qtsensors \
+ -skip qtserialbus \
+ -skip qtserialport \
+ -skip qtspeech \
+ -skip qtsvg \
+ -skip qttranslations \
+ -skip qtwayland \
+ -skip qtvirtualkeyboard \
+ -skip qtwebchannel \
+ -skip qtwebengine \
+ -skip qtwebsockets \
+ -skip qtwebview \
+ -skip qtwinextras \
+ -skip qtxmlpatterns \
+ -skip qtx11extras
+
+# Build and transform stdout into . to reduce the noise
+RUN cd qt/build && \
+ make -j $(nproc --all) | stdbuf -o0 tr -cd '\n' | stdbuf -o0 tr '\n' '.' && \
+ make install
+
+#
+# Install Qt and Qbs for Linux and combine that with Qt for Windows from the
+# previous stage
+#
+FROM ubuntu:bionic
+LABEL Description="Ubuntu development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality"
+ARG QT_VERSION
+ARG QTCREATOR_VERSION
+
+# Allow colored output on command line.
+ENV TERM=xterm-color
+
+#
+# Make it possible to change UID/GID in the entrypoint script. The docker
+# container usually runs as root user on Linux hosts. When the Docker container
+# mounts a folder on the host and creates files there, those files would be
+# owned by root instead of the current user. Thus we create a user here who's
+# UID will be changed in the entrypoint script to match the UID of the current
+# host user.
+#
+ARG USER_UID=1000
+ARG USER_NAME=devel
+RUN apt-get update -qq && \
+ apt-get install -qq -y \
+ ca-certificates \
+ gosu \
+ sudo && \
+ groupadd -g ${USER_UID} ${USER_NAME} && \
+ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \
+ usermod -a -G sudo ${USER_NAME} && \
+ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers
+
+COPY docker/bionic/entrypoint.sh /sbin/entrypoint.sh
+ENTRYPOINT ["/sbin/entrypoint.sh"]
+
+# Qbs build dependencies
+RUN apt-get update -qq && \
+ apt-get install -qq -y --no-install-recommends \
+ build-essential \
+ ca-certificates \
+ curl \
+ git \
+ libclang-3.9 \
+ libdbus-1-3 \
+ libfreetype6 \
+ libfontconfig1 \
+ libgl1-mesa-dev \
+ libgl1-mesa-glx \
+ pkg-config \
+ help2man \
+ python-pip \
+ p7zip-full && \
+ pip install beautifulsoup4 lxml # for building the documentation
+
+ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
+
+
+#
+# Install Qt and Qbs for Linux from qt.io
+#
+COPY scripts/install-qt.sh install-qt.sh
+
+RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qtscript qttools qtx11extras icu && \
+ ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \
+ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh
+
+ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH}
+
+
+#
+# Install Qt installation from build stage
+#
+COPY --from=build-qt-mingw32_w64 /opt/Qt/${QT_VERSION}/mingw32_w64 /opt/Qt/${QT_VERSION}/mingw32_w64
+
+#
+# Install mingw toolchain to cross build for Windows and select
+# POSIX API to make use of threading support in the stl. That
+# is required by Qbs.
+#
+RUN apt-get install -qq -y --no-install-recommends \
+ mingw-w64 && \
+ printf "1\n" | update-alternatives --config x86_64-w64-mingw32-g++
+
+
+# Configure Qbs
+USER $USER_NAME
+RUN qbs-setup-toolchains /usr/bin/g++ gcc && \
+ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \
+ qbs config profiles.qt-gcc_64.baseProfile gcc && \
+ qbs config defaultProfile qt-gcc_64 && \
+ \
+ qbs-setup-toolchains /usr/bin/x86_64-w64-mingw32-g++ mingw && \
+ qbs-setup-qt /opt/Qt/${QT_VERSION}/mingw32_w64/bin/qmake qt-mingw32_w64 && \
+ qbs config profiles.qt-mingw32_w64.baseProfile mingw
+
+# Switch back to root user for the entrypoint script.
+USER root
diff --git a/docker/bionic/entrypoint.sh b/docker/bionic/entrypoint.sh
new file mode 100755
index 000000000..40bc5acb9
--- /dev/null
+++ b/docker/bionic/entrypoint.sh
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+set -e
+
+#############################################################################
+##
+## Copyright (C) 2019 Richard Weickelt <richard@weickelt.de>
+## 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$
+##
+#############################################################################
+
+#
+# Entrypoint script when starting the container. The script checks the current
+# working directory and changes the uid/gid of developer/users to match whatever
+# is found in the working directory. This is useful to match the user and group
+# of mounted volumes into the container
+
+#
+# If not root, re-run script as root to fix ids
+#
+if [ "$(id -u)" != "0" ]; then
+ exec gosu root /sbin/entrypoint.sh "$@"
+fi
+
+#
+# Try to determine the uid of the working directory and adjust the current
+# user's uid/gid accordingly.
+#
+USER_GID=${USER_GID:-$(stat -c "%g" .)}
+USER_UID=${USER_UID:-$(stat -c "%u" .)}
+USER_NAME=${USER_NAME:-devel}
+USER_GROUP=${USER_GROUP:-devel}
+EXEC=""
+export HOME=/home/${USER_NAME}
+
+#
+# This is a problem on Linux hosts when we mount a folder from the
+# user file system and write artifacts into that. Thus, we downgrade
+# the current user and make sure that the uid and gid matches the one
+# of the mounted project folder.
+#
+# This work-around is not needed on Windows hosts as Windows doesn't
+# have such a concept.
+#
+if [ "${USER_UID}" != "0" ]; then
+ if [ "$(id -u ${USER_NAME})" != "${USER_UID}" ]; then
+ usermod -o -u ${USER_UID} ${USER_NAME}
+ # After changing the user's uid, all files in user's home directory
+ # automatically get the new uid.
+ fi
+ current_gid=$(id -g ${USER_NAME})
+ if [ "$(id -g ${USER_NAME})" != "${USER_GID}" ]; then
+ groupmod -o -g ${USER_GID} ${USER_GROUP}
+ # Set the new gid on all files in the home directory that still have the
+ # old gid.
+ find /home/${USER_NAME} -gid "${current_gid}" ! -type l -exec chgrp ${USER_GID} {} \;
+ fi
+fi
+EXEC="exec gosu ${USER_NAME}:${USER_GROUP}"
+
+if [ -z "$1" ]; then
+ ${EXEC} bash -l
+else
+ ${EXEC} bash -l -c "$*"
+fi
diff --git a/docker/stretch/Dockerfile b/docker/stretch/Dockerfile
index d7258f97f..736bd1ef7 100644
--- a/docker/stretch/Dockerfile
+++ b/docker/stretch/Dockerfile
@@ -3,123 +3,14 @@
# installer. We do it in a separate stage to keep the number of dependencies low
# in the final Docker image.
#
-FROM debian:9 as build-qt-linux-x86_64
-ARG QT_VERSION
-
-# Downloader dependencies
-RUN apt-get update -qq && \
- apt-get install -qq -y --no-install-recommends \
- ca-certificates \
- xz-utils \
- wget
-
-# Download
-RUN mkdir -p /qt/source && \
- wget -nv --continue --tries=20 --waitretry=10 --retry-connrefused \
- --no-dns-cache --timeout 300 -qO- \
- https://download.qt.io/official_releases/qt/${QT_VERSION%??}/${QT_VERSION}/single/qt-everywhere-src-${QT_VERSION}.tar.xz \
- | tar --strip-components=1 -C /qt/source -xJf-
-
-# Build dependencies
-RUN apt-get update -qq && \
- apt-get install -qq -y --no-install-recommends \
- autoconf \
- automake \
- autopoint \
- binutils \
- bison \
- build-essential \
- flex \
- intltool \
- libclang-3.9-dev \
- libgdk-pixbuf2.0-dev \
- libffi-dev \
- libfontconfig1-dev \
- libfreetype6-dev \
- libgmp-dev \
- libicu-dev \
- libmpc-dev \
- libmpfr-dev \
- libtool \
- libtool-bin \
- libx11-dev \
- libxext-dev \
- libxfixes-dev \
- libxi-dev \
- libxrender-dev \
- libxcb1-dev \
- libx11-xcb-dev \
- libxcb-glx0-dev \
- libz-dev \
- python \
- openssl
-
-ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
-
-# Build Qt
-RUN mkdir -p qt/build && \
- cd qt/build && \
- ../source/configure \
- -prefix /opt/qt5-linux-x86_64 \
- -release \
- -shared \
- -opensource \
- -confirm-license \
- -nomake examples \
- -nomake tests \
- -platform linux-g++ \
- -no-use-gold-linker \
- -R . \
- -sysconfdir /etc/xdg \
- -qt-freetype -qt-harfbuzz -qt-pcre -qt-sqlite -qt-xcb -qt-zlib \
- -no-cups -no-dbus -no-pch -no-libudev \
- -no-feature-accessibility -no-opengl \
- -skip qtactiveqt \
- -skip qt3d \
- -skip qtcanvas3d \
- -skip qtcharts \
- -skip qtconnectivity \
- -skip qtdatavis3d \
- -skip qtdoc \
- -skip qtgamepad \
- -skip qtgraphicaleffects \
- -skip qtimageformats \
- -skip qtlocation \
- -skip qtmultimedia \
- -skip qtnetworkauth \
- -skip qtquickcontrols \
- -skip qtquickcontrols2 \
- -skip qtpurchasing \
- -skip qtremoteobjects \
- -skip qtscxml \
- -skip qtsensors \
- -skip qtserialbus \
- -skip qtspeech \
- -skip qtsvg \
- -skip qttranslations \
- -skip qtwayland \
- -skip qtvirtualkeyboard \
- -skip qtwebchannel \
- -skip qtwebengine \
- -skip qtwebsockets \
- -skip qtwebview \
- -skip qtwinextras \
- -skip qtxmlpatterns \
- -skip qtx11extras
-
-RUN cd qt/build && \
- make -j $(nproc --all) | stdbuf -o0 tr -cd '\n' | stdbuf -o0 tr '\n' '.' && \
- make install
-
-# Build a stable Qbs release
FROM debian:9
LABEL Description="Debian development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality"
-ARG QBS_VERSION=1.13.0
+ARG QT_VERSION
+ARG QTCREATOR_VERSION
# Allow colored output on command line.
ENV TERM=xterm-color
-
#
# Make it possible to change UID/GID in the entrypoint script. The docker
# container usually runs as root user on Linux hosts. When the Docker container
@@ -131,7 +22,8 @@ ENV TERM=xterm-color
ARG USER_UID=1000
ARG USER_NAME=devel
RUN apt-get update -qq && \
- apt-get install -qq -y \
+ apt-get install -qq -y --no-install-recommends \
+ ca-certificates \
gosu \
sudo && \
groupadd -g ${USER_UID} ${USER_NAME} && \
@@ -139,46 +31,43 @@ RUN apt-get update -qq && \
usermod -a -G sudo ${USER_NAME} && \
echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers
-COPY entrypoint.sh entrypoint.sh
+COPY docker/stretch/entrypoint.sh entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
-# Qbs build dependencies
-RUN apt-get update -qq && \
- apt-get install -qq -y --no-install-recommends \
+
+# Build and run dependencies for Qbs
+RUN apt-get install -qq -y --no-install-recommends \
build-essential \
- ca-certificates \
+ curl \
git \
+ help2man \
libclang-3.9 \
- libicu57 \
- pkg-config \
+ libdbus-1-3 \
+ libgl1-mesa-glx \
+ libfreetype6 \
+ libfontconfig1 \
+ libgl1-mesa-dev \
make \
- help2man \
+ pkg-config \
python-pip \
- wget && \
+ p7zip-full && \
pip install beautifulsoup4 lxml # for building the documentation
-# Install Qt installation from build stage
-COPY --from=build-qt-linux-x86_64 /opt/qt5-linux-x86_64 /opt/qt5-linux-x86_64
-ENV PATH=/opt/qt5-linux-x86_64/bin:${PATH}
-RUN echo "export PATH=/opt/qt5-linux-x86_64/bin:\${PATH}" > /etc/profile.d/qt.sh
+ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
+
+COPY scripts/install-qt.sh install-qt.sh
+
+RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qtscript qttools qtx11extras icu && \
+ ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \
+ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh
-# Download and build Qbs
-RUN mkdir -p /qbs && \
- wget -nv --continue --tries=20 --waitretry=10 --retry-connrefused \
- --no-dns-cache --timeout 300 -qO- \
- http://download.qt.io/official_releases/qbs/${QBS_VERSION}/qbs-src-${QBS_VERSION}.tar.gz \
- | tar --strip-components=1 -C /qbs -xzf- && \
- cd /qbs && \
- qmake -r qbs.pro && \
- make -j $(nproc --all) && \
- make install INSTALL_ROOT=/ && \
- rm -rf /qbs
+ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH}
# Configure Qbs
USER $USER_NAME
RUN qbs-setup-toolchains --detect && \
- qbs-setup-qt /opt/qt5-linux-x86_64/bin/qmake qt5-linux-x86_64 && \
- qbs config defaultProfile qt5-linux-x86_64
+ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt && \
+ qbs config defaultProfile qt
# Switch back to root user for the entrypoint script.
USER root
diff --git a/examples/baremetal/at90can128olimex/redblink/redblink.qbs b/examples/baremetal/at90can128olimex/redblink/redblink.qbs
index bbc0d7261..84323e3c1 100644
--- a/examples/baremetal/at90can128olimex/redblink/redblink.qbs
+++ b/examples/baremetal/at90can128olimex/redblink/redblink.qbs
@@ -57,7 +57,7 @@ CppApplication {
return qbs.toolchain.contains("gcc")
|| qbs.toolchain.contains("iar")
}
- name: "redblink"
+ name: "at90can128olimex-redblink"
cpp.cLanguageVersion: "c99"
cpp.positionIndependentCode: false
diff --git a/examples/baremetal/baremetal.qbs b/examples/baremetal/baremetal.qbs
index 08d41793f..37a46bbf5 100644
--- a/examples/baremetal/baremetal.qbs
+++ b/examples/baremetal/baremetal.qbs
@@ -55,6 +55,8 @@ Project {
references: [
"stm32f4discovery/stm32f4discovery.qbs",
"at90can128olimex/at90can128olimex.qbs",
- "cc2540usbdongle/cc2540usbdongle.qbs"
+ "cc2540usbdongle/cc2540usbdongle.qbs",
+ "stm8s103f3/stm8s103f3.qbs",
+ "msp430f5529/msp430f5529.qbs",
]
}
diff --git a/examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs b/examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs
index eb0be6b34..e8aa3d1fd 100644
--- a/examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs
+++ b/examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs
@@ -58,7 +58,7 @@ CppApplication {
|| qbs.toolchain.contains("keil")
|| qbs.toolchain.contains("sdcc")
}
- name: "greenblink"
+ name: "cc2540usbdongle-greenblink"
cpp.positionIndependentCode: false
//
@@ -111,8 +111,7 @@ CppApplication {
Properties {
condition: qbs.toolchain.contains("sdcc")
- cpp.commonCompilerFlags: ["-mmcs51"]
- }
+ }
//
// Common code.
diff --git a/examples/baremetal/msp430f5529/msp430f5529.qbs b/examples/baremetal/msp430f5529/msp430f5529.qbs
new file mode 100644
index 000000000..7f9799208
--- /dev/null
+++ b/examples/baremetal/msp430f5529/msp430f5529.qbs
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs
+
+Project {
+ name: "Examples for msp430f5529 board"
+ references: [
+ "redblink/redblink.qbs"
+ ]
+}
diff --git a/examples/baremetal/msp430f5529/redblink/README.md b/examples/baremetal/msp430f5529/redblink/README.md
new file mode 100644
index 000000000..3affbaf7e
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/README.md
@@ -0,0 +1,9 @@
+This examples demonstrates how to build a bare-metal application using
+different MSP430 toolchains. It is designed for the MSP-EXP430F5529LP
+target board (based on msp430f5529 chip) and simply flashes the red
+LED on the board.
+
+The following toolchains are supported:
+
+ * IAR Embedded Workbench
+ * GCC
diff --git a/examples/baremetal/msp430f5529/redblink/gpio.c b/examples/baremetal/msp430f5529/redblink/gpio.c
new file mode 100644
index 000000000..3e7f181aa
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/gpio.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gpio.h"
+
+#if defined(__ICC430__)
+#include <msp430f5529.h>
+#elif defined(__GNUC__)
+#include <msp430f5529.h>
+#else
+#error "Unsupported toolchain"
+#endif
+
+// LED pin number.
+#define GPIO_RED_LED_PIN_POS (0u)
+// LED port direction.
+#define GPIO_RED_LED_PORT_DIR (P1DIR)
+// LED output port.
+#define GPIO_RED_LED_PORT_OUT (P1OUT)
+
+void gpio_init_red_led(void)
+{
+ GPIO_RED_LED_PORT_DIR |= (1u << GPIO_RED_LED_PIN_POS);
+}
+
+void gpio_toggle_red_led(void)
+{
+ GPIO_RED_LED_PORT_OUT ^= (1u << GPIO_RED_LED_PIN_POS);
+}
diff --git a/examples/baremetal/msp430f5529/redblink/gpio.h b/examples/baremetal/msp430f5529/redblink/gpio.h
new file mode 100644
index 000000000..246eab860
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/gpio.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GPIO_H
+#define GPIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpio_init_red_led(void);
+void gpio_toggle_red_led(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPIO_H
diff --git a/examples/baremetal/msp430f5529/redblink/main.c b/examples/baremetal/msp430f5529/redblink/main.c
new file mode 100644
index 000000000..f1ad54adf
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/main.c
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gpio.h"
+#include "system.h"
+
+#include <stdint.h>
+
+static void some_delay(uint32_t counts)
+{
+ for (uint32_t index = 0u; index < counts; ++index)
+ __asm("nop");
+}
+
+int main(void)
+{
+ system_init();
+
+ gpio_init_red_led();
+
+ while (1) {
+ gpio_toggle_red_led();
+ some_delay(10000u);
+ }
+}
diff --git a/examples/baremetal/msp430f5529/redblink/redblink.qbs b/examples/baremetal/msp430f5529/redblink/redblink.qbs
new file mode 100644
index 000000000..0f056e101
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/redblink.qbs
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs
+
+CppApplication {
+ condition: {
+ if (!qbs.architecture.contains("msp430"))
+ return false;
+ return qbs.toolchain.contains("iar")
+ || qbs.toolchain.contains("gcc")
+ }
+ name: "msp430f5529-redblink"
+ cpp.cLanguageVersion: "c99"
+ cpp.positionIndependentCode: false
+
+ //
+ // IAR-specific properties and sources.
+ //
+
+ Properties {
+ condition: qbs.toolchain.contains("iar")
+ cpp.driverFlags: ["--core=430X"]
+ cpp.entryPoint: "__program_start"
+ cpp.driverLinkerFlags: [
+ "-D_STACK_SIZE=A0",
+ "-D_DATA16_HEAP_SIZE=A0",
+ "-D_DATA20_HEAP_SIZE=50",
+ ]
+ cpp.staticLibraries: [
+ // Explicitly link with the runtime dlib library (which contains
+ // all required startup code and other stuff).
+ cpp.toolchainInstallPath + "/../lib/dlib/dl430xlsfn.r43"
+ ]
+ }
+
+ Group {
+ condition: qbs.toolchain.contains("iar")
+ name: "IAR"
+ prefix: "iar/"
+ Group {
+ name: "Linker Script"
+ prefix: cpp.toolchainInstallPath + "/../config/linker/"
+ fileTags: ["linkerscript"]
+ // Explicitly use the default linker scripts for current target.
+ files: ["lnk430f5529.xcl", "multiplier32.xcl"]
+ }
+ }
+
+ //
+ // GCC-specific properties and soucres.
+ //
+
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ property path supportFilesPath
+ // A path to the MSP430 support files, which are
+ // provided by the Texas Instruments separately:
+ // e.g. 'c:/msp430-gcc-support-files/include/'
+ cpp.includePaths: supportFilesPath
+ cpp.libraryPaths: supportFilesPath
+ cpp.driverFlags: ["-mmcu=msp430f5529"]
+ }
+
+ //
+ // Common code.
+ //
+
+ Group {
+ name: "Gpio"
+ files: ["gpio.c", "gpio.h"]
+ }
+
+ Group {
+ name: "System"
+ files: ["system.c", "system.h"]
+ }
+
+ files: [
+ "main.c",
+ ]
+}
diff --git a/examples/baremetal/msp430f5529/redblink/system.c b/examples/baremetal/msp430f5529/redblink/system.c
new file mode 100644
index 000000000..0e0e6901c
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/system.c
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "system.h"
+
+#if defined(__ICC430__)
+#include <msp430f5529.h>
+#elif defined(__GNUC__)
+#include <msp430f5529.h>
+#else
+#error "Unsupported toolchain"
+#endif
+
+void system_init(void)
+{
+ // Stop watchdog timer.
+ WDTCTL = WDTPW + WDTHOLD;
+}
diff --git a/examples/baremetal/msp430f5529/redblink/system.h b/examples/baremetal/msp430f5529/redblink/system.h
new file mode 100644
index 000000000..468ef1082
--- /dev/null
+++ b/examples/baremetal/msp430f5529/redblink/system.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void system_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_H
diff --git a/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs b/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
index 9b131fa71..5ccf8b3b0 100644
--- a/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
+++ b/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
@@ -58,7 +58,7 @@ CppApplication {
|| qbs.toolchain.contains("iar")
|| qbs.toolchain.contains("keil")
}
- name: "blueblink"
+ name: "stm32f4discovery-blueblink"
cpp.cLanguageVersion: "c99"
cpp.positionIndependentCode: false
diff --git a/examples/baremetal/stm8s103f3/redblink/README.md b/examples/baremetal/stm8s103f3/redblink/README.md
new file mode 100644
index 000000000..2c76e918e
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/README.md
@@ -0,0 +1,8 @@
+This example demonstrates how to build a bare-metal application using
+different STM8 toolchains. It is designed for the STM8 target board
+(based on STMicroelectronics stm8s103f3 MCU) and simply flashes the
+red LED on the board.
+
+The following toolchains are supported:
+
+ * IAR Embedded Workbench
diff --git a/examples/baremetal/stm8s103f3/redblink/gpio.c b/examples/baremetal/stm8s103f3/redblink/gpio.c
new file mode 100644
index 000000000..cc68c732c
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/gpio.c
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gpio.h"
+#include "system.h"
+
+// A LED is connected to the pin #5 of Port B.
+#define GPIO_RED_LED_PIN_POS (0x20u)
+
+void gpio_init_red_led(void)
+{
+ PB_ODR = 0x00; // Turn off all pins.
+ PB_DDR = GPIO_RED_LED_PIN_POS; // Configure Pin as output.
+ PB_CR1 = GPIO_RED_LED_PIN_POS; // Set Pin to Push-Pull.
+ PB_CR2 = GPIO_RED_LED_PIN_POS; // Set Pin to Push-Pull.
+}
+
+void gpio_toggle_red_led(void)
+{
+ PB_ODR ^= GPIO_RED_LED_PIN_POS;
+}
diff --git a/examples/baremetal/stm8s103f3/redblink/gpio.h b/examples/baremetal/stm8s103f3/redblink/gpio.h
new file mode 100644
index 000000000..246eab860
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/gpio.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GPIO_H
+#define GPIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpio_init_red_led(void);
+void gpio_toggle_red_led(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPIO_H
diff --git a/examples/baremetal/stm8s103f3/redblink/main.c b/examples/baremetal/stm8s103f3/redblink/main.c
new file mode 100644
index 000000000..63c1c0aec
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/main.c
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gpio.h"
+#include "system.h"
+
+static void some_delay(unsigned long counts)
+{
+ unsigned long index = 0u;
+ for (index = 0u; index < counts; ++index)
+ system_nop();
+}
+
+int main(void)
+{
+ gpio_init_red_led();
+
+ while (1) {
+ gpio_toggle_red_led();
+ some_delay(20000u);
+ }
+}
diff --git a/examples/baremetal/stm8s103f3/redblink/redblink.qbs b/examples/baremetal/stm8s103f3/redblink/redblink.qbs
new file mode 100644
index 000000000..197bae8ae
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/redblink.qbs
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs
+
+CppApplication {
+ condition: {
+ if (!qbs.architecture.contains("stm8"))
+ return false;
+ return qbs.toolchain.contains("iar")
+ || qbs.toolchain.contains("sdcc")
+ }
+ name: "stm8s103f3-redblink"
+ cpp.positionIndependentCode: false
+
+ //
+ // IAR-specific properties and sources.
+ //
+
+ Properties {
+ condition: qbs.toolchain.contains("iar")
+ cpp.commonCompilerFlags: ["-e"]
+ cpp.driverLinkerFlags: [
+ "--config_def", "_CSTACK_SIZE=0x100",
+ "--config_def", "_HEAP_SIZE=0x100",
+ ]
+ }
+
+ Group {
+ condition: qbs.toolchain.contains("iar")
+ name: "IAR"
+ prefix: "iar/"
+ Group {
+ name: "Linker Script"
+ prefix: cpp.toolchainInstallPath + "/../config/"
+ fileTags: ["linkerscript"]
+ files: ["lnkstm8s103f3.icf"]
+ }
+ }
+
+ //
+ // SDCC-specific properties and sources.
+ //
+
+ Properties {
+ condition: qbs.toolchain.contains("sdcc")
+ }
+
+ //
+ // Common code.
+ //
+
+ Group {
+ name: "Gpio"
+ files: ["gpio.c", "gpio.h"]
+ }
+
+ Group {
+ name: "System"
+ files: ["system.h"]
+ }
+
+ files: ["main.c"]
+}
diff --git a/examples/baremetal/stm8s103f3/redblink/system.h b/examples/baremetal/stm8s103f3/redblink/system.h
new file mode 100644
index 000000000..463123ce2
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/redblink/system.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Define required registers of Port B (where the LED is connected):
+// * PB_ODR - Output Data Register.
+// * PB_DDR - Data Direction Register.
+// * PB_CR1 - Control Register #1.
+// * PB_CR2 - Control Register #2.
+
+#if defined(__ICCSTM8__)
+# define system_nop() __asm("nop")
+__near __no_init volatile unsigned char PB_ODR @ 0x5005;
+__near __no_init volatile unsigned char PB_DDR @ 0x5007;
+__near __no_init volatile unsigned char PB_CR1 @ 0x5008;
+__near __no_init volatile unsigned char PB_CR2 @ 0x5009;
+#elif defined (__SDCC_stm8)
+# define system_nop() __asm nop __endasm
+#define PB_ODR *(volatile unsigned char *)0x5005
+#define PB_DDR *(volatile unsigned char *)0x5007
+#define PB_CR1 *(volatile unsigned char *)0x5008
+#define PB_CR2 *(volatile unsigned char *)0x5009
+#else
+#error "Unsupported toolchain"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_H
diff --git a/examples/baremetal/stm8s103f3/stm8s103f3.qbs b/examples/baremetal/stm8s103f3/stm8s103f3.qbs
new file mode 100644
index 000000000..922c4c1f0
--- /dev/null
+++ b/examples/baremetal/stm8s103f3/stm8s103f3.qbs
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qbs.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs
+
+Project {
+ name: "Examples for stm8s103f3 board"
+ references: [
+ "redblink/redblink.qbs"
+ ]
+}
diff --git a/examples/collidingmice/collidingmice.qbs b/examples/collidingmice/collidingmice.qbs
index 312f6b0ab..52231882e 100644
--- a/examples/collidingmice/collidingmice.qbs
+++ b/examples/collidingmice/collidingmice.qbs
@@ -50,7 +50,7 @@
import qbs 1.0
-Application {
+CppApplication {
name : "CollidingMice"
Depends { name: "Qt.widgets" }
property bool isBundle: qbs.targetOS.contains("darwin") && bundle.isBundle
@@ -64,7 +64,7 @@ Application {
Group {
fileTagsFilter: isBundle ? ["bundle.content"] : ["application"]
qbs.install: true
- qbs.installPrefix: isBundle ? "Applications" : "bin"
+ qbs.installDir: isBundle ? "Applications" : (qbs.targetOS.contains("windows") ? "" : "bin")
qbs.installSourceBase: product.buildDirectory
}
}
diff --git a/scripts/build-qbs-with-qbs.sh b/scripts/build-qbs-with-qbs.sh
index deb3a138b..6b6f6d2a9 100755
--- a/scripts/build-qbs-with-qbs.sh
+++ b/scripts/build-qbs-with-qbs.sh
@@ -40,12 +40,6 @@
set -e
#
-# It might be desired to keep settings for Qbs testing
-# in a separate folder.
-#
-export QBS_AUTOTEST_SETTINGS_DIR="${QBS_AUTOTEST_SETTINGS_DIR:-/tmp/qbs-settings}"
-
-#
# Qbs is built with the address sanitizer enabled.
# Suppress findings in some parts of Qbs / dependencies.
#
@@ -60,6 +54,7 @@ BUILD_OPTIONS="\
modules.qbsbuildconfig.enableProjectFileUpdates:true \
modules.qbsbuildconfig.enableUnitTests:true \
project.withExamples:true \
+ ${BUILD_OPTIONS}
"
#
@@ -67,7 +62,11 @@ BUILD_OPTIONS="\
#
qbs resolve ${BUILD_OPTIONS}
qbs build ${BUILD_OPTIONS}
-qbs build -p "qbs documentation" ${BUILD_OPTIONS}
+
+WITH_DOCS=${WITH_DOCS:-1}
+if [ "$WITH_DOCS" -ne 0 ]; then
+ qbs build -p "qbs documentation" ${BUILD_OPTIONS}
+fi
#
# Set up profiles for the freshly built Qbs if not
@@ -76,6 +75,7 @@ qbs build -p "qbs documentation" ${BUILD_OPTIONS}
if [ -z "${QBS_AUTOTEST_PROFILE}" ]; then
export QBS_AUTOTEST_PROFILE=autotestprofile
+ export QBS_AUTOTEST_SETTINGS_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'qbs-settings'`
RUN_OPTIONS="\
--settings-dir ${QBS_AUTOTEST_SETTINGS_DIR} \
@@ -89,9 +89,16 @@ if [ -z "${QBS_AUTOTEST_PROFILE}" ]; then
${RUN_OPTIONS} \
"${QMAKE_PATH:-$(which qmake)}" ${QBS_AUTOTEST_PROFILE}
- qbs run -p qbs_app ${BUILD_OPTIONS} -- config \
- ${RUN_OPTIONS} \
- ${QBS_AUTOTEST_PROFILE}.baseProfile gcc
+ # Make sure that the Qt profile uses the same toolchain profile
+ # that was used for building in case a custom QBS_BUILD_PROFILE
+ # was set. Otherwise setup-qt automatically uses the default
+ # toolchain profile.
+ if [ ! -z "${QBS_BUILD_PROFILE}" ]; then
+ QBS_BUILD_BASE_PROFILE=$(qbs config ${QBS_BUILD_PROFILE}.baseProfile | cut -d: -f2)
+ qbs run -p qbs_app ${BUILD_OPTIONS} -- config \
+ ${RUN_OPTIONS} \
+ ${QBS_AUTOTEST_PROFILE}.baseProfile ${QBS_BUILD_BASE_PROFILE}
+ fi
# QBS_AUTOTEST_PROFILE has been added to the environment
# which requires a resolve step
@@ -99,6 +106,10 @@ if [ -z "${QBS_AUTOTEST_PROFILE}" ]; then
fi
#
-# Run all autotests with QBS_AUTOTEST_PROFILE
+# Run all autotests with QBS_AUTOTEST_PROFILE. Some test cases might run for
+# over 10 minutes. Output an empty line every 9:50 minutes to prevent a 10min
+# timeout on Travis CI.
#
+(while true; do echo "" && sleep 590; done) &
+trap "kill $!" EXIT
qbs build -p "autotest-runner" ${BUILD_OPTIONS}
diff --git a/scripts/install-qt.sh b/scripts/install-qt.sh
new file mode 100755
index 000000000..c395cb6a7
--- /dev/null
+++ b/scripts/install-qt.sh
@@ -0,0 +1,305 @@
+#!/usr/bin/env bash
+#############################################################################
+##
+## Copyright (C) 2019 Richard Weickelt.
+## 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$
+##
+#############################################################################
+set -eu
+
+function help() {
+ cat <<EOF
+usage: install-qt [options] [components]
+
+Examples
+ ./install-qt.sh --version 5.12.4 qtbase
+ ./install-qt.sh --version 5.12.4 --target android --toolchain android_arm64_v8a qtbase
+
+Positional arguments
+ components
+ SDK components to be installed. All possible components
+ can be found in the online repository at https://download.qt.io,
+ for instance: qtbase, qtdeclarative, qtscript, qttools, icu, ...
+
+ In addition to Qt packages, qtcreator is also accepted.
+
+ The actual availability of packages may differ depending on
+ target and toolchain.
+
+Options
+ --directory <directory>
+ Root directory where to install the components.
+ Maps to C:/Qt on Windows, /opt/Qt on Linux, /usr/local/Qt on Mac
+ by default.
+
+ --host <host-os>
+ The host operating system. Can be one of linux_x64, mac_x64,
+ windows_x86. Auto-detected by default.
+
+ --target <target-platform>
+ The desired target platform. Can be one of desktop, android, ios.
+ The default value is desktop.
+
+ --toolchain <toolchain-type>
+ The toolchain that has been used to build the binaries.
+ Possible values depend on --host and --target, respectively:
+
+ linux_x64
+ android
+ android_armv7, android_arm64_v8a
+ desktop
+ gcc_64 (default)
+
+ mac_x64
+ android
+ android_armv7, android_arm64_v8a
+ desktop
+ clang_64 (default),
+ ios
+ ios
+
+ windows_x86
+ android
+ android_armv7, android_arm64_v8a
+ desktop
+ win64_mingw73, win64_msvc2017_64 (default)
+
+ --version <version>
+ The desired Qt version. Currently supported are all versions
+ above 5.9.0.
+
+EOF
+}
+
+TARGET_PLATFORM=desktop
+COMPONENTS=
+VERSION=
+
+case "$OSTYPE" in
+ *linux*)
+ HOST_OS=linux_x64
+ INSTALL_DIR=/opt/Qt
+ TOOLCHAIN=gcc_64
+ ;;
+ *darwin*)
+ HOST_OS=mac_x64
+ INSTALL_DIR=/usr/local/Qt
+ TOOLCHAIN=clang_64
+ ;;
+ msys)
+ HOST_OS=windows_x86
+ INSTALL_DIR=/c/Qt
+ TOOLCHAIN=win64_msvc2015_64
+ ;;
+ *)
+ HOST_OS=
+ INSTALL_DIR=
+ ;;
+esac
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --directory|-d)
+ INSTALL_DIR="$2"
+ shift
+ ;;
+ --host)
+ HOST_OS="$2"
+ shift
+ ;;
+ --target)
+ TARGET_PLATFORM="$2"
+ shift
+ ;;
+ --toolchain)
+ TOOLCHAIN="$2"
+ shift
+ ;;
+ --version)
+ VERSION="$2"
+ shift
+ ;;
+ --help|-h)
+ help
+ exit 0
+ ;;
+ *)
+ COMPONENTS="${COMPONENTS} $1"
+ ;;
+ esac
+ shift
+done
+
+if [ -z "${HOST_OS}" ]; then
+ echo "No --host specified or auto-detection failed." >&2
+ exit 1
+fi
+
+if [ -z "${INSTALL_DIR}" ]; then
+ echo "No --directory specified or auto-detection failed." >&2
+ exit 1
+fi
+
+if [ -z "${VERSION}" ]; then
+ echo "No --version specified." >&2
+ exit 1
+fi
+
+if [ -z "${COMPONENTS}" ]; then
+ echo "No components specified." >&2
+ exit 1
+fi
+
+case "$TARGET_PLATFORM" in
+ android)
+ ;;
+ ios)
+ ;;
+ desktop)
+ ;;
+ *)
+ echo "Error: TARGET_PLATFORM=${TARGET_PLATFORM} is not valid." >&2
+ exit 1
+ ;;
+esac
+
+DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'install-qt'`
+
+#
+# The repository structure is a mess. Try different URL variants
+#
+function compute_url(){
+ local COMPONENT=$1
+ local CURL="curl -s -L"
+ local BASE_URL="http://download.qt.io/online/qtsdkrepository/${HOST_OS}/${TARGET_PLATFORM}"
+
+ if [[ "${COMPONENT}" =~ "qtcreator" ]]; then
+
+ REMOTE_BASE="tools_qtcreator/qt.tools.qtcreator"
+ REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "${VERSION}[0-9\-]*${COMPONENT}\.7z" | tail -1)"
+
+ if [ ! -z "${REMOTE_PATH}" ]; then
+ echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}"
+ return 0
+ fi
+
+ else
+ # New repository format (>=5.9.6)
+ REMOTE_BASE="qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${TOOLCHAIN}"
+ REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep "${COMPONENT}" | tail -1)"
+ echo "$BASE_URL/$REMOTE_BASE/$REMOTE_PATH" >&2
+
+ if [ ! -z "${REMOTE_PATH}" ]; then
+ echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}"
+ return 0
+ fi
+
+ REMOTE_BASE="qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}"
+ REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep "${COMPONENT}" | tail -1)"
+
+ if [ ! -z "${REMOTE_PATH}" ]; then
+ echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}"
+ return 0
+ fi
+
+ # Older repository format (>=5.9.0)
+ REMOTE_BASE="qt5_${VERSION//./}/qt.${VERSION//./}.${TOOLCHAIN}"
+ REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep "${COMPONENT}" | tail -1)"
+
+ if [ ! -z "${REMOTE_PATH}" ]; then
+ echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}"
+ return 0
+ fi
+
+ REMOTE_BASE="qt5_${VERSION//./}/qt.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}"
+ REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep "${COMPONENT}" | tail -1)"
+
+ if [ ! -z "${REMOTE_PATH}" ]; then
+ echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}"
+ return 0
+ fi
+
+ fi
+
+ echo "Could not determine a remote URL for ${COMPONENT} with version ${VERSION}">&2
+ exit 1
+}
+
+mkdir -p ${INSTALL_DIR}
+
+for COMPONENT in ${COMPONENTS}; do
+
+ URL="$(compute_url ${COMPONENT})"
+
+ echo "Downloading ${COMPONENT}..." >&2
+ curl --progress-bar -L -o ${DOWNLOAD_DIR}/package.7z ${URL} >&2
+ 7z x -y -o${INSTALL_DIR} ${DOWNLOAD_DIR}/package.7z >/dev/null 2>&1
+ rm -f ${DOWNLOAD_DIR}/package.7z
+
+ #
+ # conf file is needed for qmake
+ #
+ if [ "${COMPONENT}" == "qtbase" ]; then
+ if [[ "${TOOLCHAIN}" =~ "win64_mingw" ]]; then
+ SUBDIR="${TOOLCHAIN/win64_/}_64"
+ elif [[ "${TOOLCHAIN}" =~ "win32_mingw" ]]; then
+ SUBDIR="${TOOLCHAIN/win32_/}_32"
+ elif [[ "${TOOLCHAIN}" =~ "win64_msvc" ]]; then
+ SUBDIR="${TOOLCHAIN/win64_/}"
+ elif [[ "${TOOLCHAIN}" =~ "win32_msvc" ]]; then
+ SUBDIR="${TOOLCHAIN/win32_/}"
+ else
+ SUBDIR="${TOOLCHAIN}"
+ fi
+
+ CONF_FILE="${INSTALL_DIR}/${VERSION}/${SUBDIR}/bin/qt.conf"
+ echo "[Paths]" > ${CONF_FILE}
+ echo "Prefix = .." >> ${CONF_FILE}
+
+ # Adjust the license to be able to run qmake
+ # sed with -i requires intermediate file on Mac OS
+ PRI_FILE="${INSTALL_DIR}/${VERSION}/${SUBDIR}/mkspecs/qconfig.pri"
+ sed -i.bak 's/Enterprise/OpenSource/g' "${PRI_FILE}"
+ sed -i.bak 's/licheck.*//g' "${PRI_FILE}"
+ rm "${PRI_FILE}.bak"
+
+ # Print the directory so that the caller can
+ # adjust the PATH variable.
+ echo $(dirname "${CONF_FILE}")
+ elif [[ "${COMPONENT}" =~ "qtcreator" ]]; then
+ echo "${INSTALL_DIR}/Tools/QtCreator/bin"
+ fi
+
+done
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index 84d62a556..5c1fb1ae5 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -566,6 +566,8 @@ function guessArchitecture(m) {
architecture = "avr";
} else if (hasAnyOf(m, ["__AVR32__"])) {
architecture = "avr32";
+ } else if (hasAnyOf(m, ["__MSP430__"])) {
+ architecture = "msp430";
}
}
diff --git a/share/qbs/imports/qbs/Probes/IarProbe.qbs b/share/qbs/imports/qbs/Probes/IarProbe.qbs
index 6e7fb7d64..d261e9065 100644
--- a/share/qbs/imports/qbs/Probes/IarProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/IarProbe.qbs
@@ -65,34 +65,25 @@ PathProbe {
compilerFilePath, tag);
}
- // FIXME: Do we need dump the default paths for both C
- // and C++ languages?
- var defaultPaths = IAR.dumpDefaultPaths(
- compilerFilePath, languages[0]);
-
var macros = compilerDefinesByLanguage["c"]
|| compilerDefinesByLanguage["cpp"];
architecture = IAR.guessArchitecture(macros);
endianness = IAR.guessEndianness(macros);
- includePaths = defaultPaths.includePaths;
- var version = parseInt(macros["__VER__"], 10);
+ // FIXME: Do we need dump the default paths for both C
+ // and C++ languages?
+ var defaultPaths = IAR.dumpDefaultPaths(
+ compilerFilePath, languages[0]);
- if (architecture === "arm") {
- versionMajor = parseInt(version / 1000000);
- versionMinor = parseInt(version / 1000) % 1000;
- versionPatch = parseInt(version) % 1000;
- } else if (architecture === "mcs51") {
- versionMajor = parseInt(version / 100);
- versionMinor = parseInt(version % 100);
- versionPatch = 0;
- } else if (architecture === "avr") {
- versionMajor = parseInt(version / 100);
- versionMinor = parseInt(version % 100);
- versionPatch = 0;
- }
+ includePaths = defaultPaths.includePaths;
- found = version && architecture && endianness;
+ var version = IAR.guessVersion(macros, architecture);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = version && architecture && endianness;
+ }
}
}
diff --git a/share/qbs/imports/qbs/Probes/KeilProbe.qbs b/share/qbs/imports/qbs/Probes/KeilProbe.qbs
index 1955fe480..34afecb64 100644
--- a/share/qbs/imports/qbs/Probes/KeilProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/KeilProbe.qbs
@@ -81,8 +81,7 @@ PathProbe {
versionMajor = version.major;
versionMinor = version.minor;
versionPatch = version.patch;
+ found = version.found && architecture && endianness;
}
-
- found = version.found && architecture && endianness;
}
}
diff --git a/share/qbs/imports/qbs/Probes/SdccProbe.qbs b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
index b5f7d384e..3595bb158 100644
--- a/share/qbs/imports/qbs/Probes/SdccProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
@@ -64,10 +64,10 @@ PathProbe {
var defaultPaths = SDCC.dumpDefaultPaths(compilerFilePath, architecture);
includePaths = defaultPaths.includePaths;
- versionMajor = parseInt(macros["__SDCC_VERSION_MAJOR"], 10);
- versionMinor = parseInt(macros["__SDCC_VERSION_MINOR"], 10);
- versionPatch = parseInt(macros["__SDCC_VERSION_PATCH"], 10);
-
- found = macros["SDCC"];
+ var version = SDCC.guessVersion(macros);
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = version.found;
}
}
diff --git a/share/qbs/imports/qbs/base/AutotestRunner.qbs b/share/qbs/imports/qbs/base/AutotestRunner.qbs
index ab9ba15f7..62ba7740b 100644
--- a/share/qbs/imports/qbs/base/AutotestRunner.qbs
+++ b/share/qbs/imports/qbs/base/AutotestRunner.qbs
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -42,6 +43,7 @@ Product {
property stringList wrapper: []
property string workingDir
property stringList auxiliaryInputs
+ property int timeout: -1
Depends {
productTypes: "autotest"
@@ -74,6 +76,7 @@ Product {
: FileInfo.path(commandFilePath);
var arguments = product.arguments;
var allowFailure = false;
+ var timeout = product.timeout;
if (input.autotest) {
// FIXME: We'd like to let the user override with an empty list, but
// qbscore turns undefined lists into empty ones at the moment.
@@ -83,6 +86,9 @@ Product {
if (input.autotest.workingDir)
workingDir = input.autotest.workingDir;
allowFailure = input.autotest.allowFailure;
+
+ if (input.autotest.timeout !== undefined)
+ timeout = input.autotest.timeout;
}
var fullCommandLine = product.wrapper
.concat([commandFilePath])
@@ -91,6 +97,8 @@ Product {
cmd.description = "Running test " + input.fileName;
cmd.environment = product.environment;
cmd.workingDirectory = workingDir;
+ cmd.timeout = timeout;
+ cmd.jobPool = "autotest-runner";
if (allowFailure)
cmd.maxExitCode = 32767;
return cmd;
diff --git a/share/qbs/module-providers/Qt/templates/core.qbs b/share/qbs/module-providers/Qt/templates/core.qbs
index 98bc0c4d3..8e990db22 100644
--- a/share/qbs/module-providers/Qt/templates/core.qbs
+++ b/share/qbs/module-providers/Qt/templates/core.qbs
@@ -105,6 +105,10 @@ Module {
condition: moduleConfig.contains("use_gold_linker")
cpp.linkerVariant: "gold"
}
+ Properties {
+ condition: !moduleConfig.contains("use_gold_linker") && qbs.toolchain.contains("gcc")
+ cpp.linkerVariant: original
+ }
cpp.cxxLanguageVersion: Utilities.versionCompare(version, "5.7.0") >= 0 ? "c++11" : original
cpp.enableCompilerDefinesByLanguage: ["cpp"].concat(
diff --git a/share/qbs/modules/autotest/autotest.qbs b/share/qbs/modules/autotest/autotest.qbs
index ba280169e..c8a1c5180 100644
--- a/share/qbs/modules/autotest/autotest.qbs
+++ b/share/qbs/modules/autotest/autotest.qbs
@@ -2,4 +2,5 @@ Module {
property stringList arguments
property bool allowFailure: false
property string workingDir
+ property int timeout
}
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index f9537884e..5ededc512 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -135,14 +135,14 @@ CppModule {
: undefined
property string binutilsPath: binutilsProbe.found ? binutilsProbe.path : toolchainInstallPath
- assemblerName: 'as'
+ assemblerName: 'as' + compilerExtension
compilerName: cxxCompilerName
- linkerName: 'ld'
- property string archiverName: 'ar'
- property string nmName: 'nm'
- property string objcopyName: "objcopy"
- property string stripName: "strip"
- property string dsymutilName: "dsymutil"
+ linkerName: 'ld' + compilerExtension
+ property string archiverName: 'ar' + compilerExtension
+ property string nmName: 'nm' + compilerExtension
+ property string objcopyName: "objcopy" + compilerExtension
+ property string stripName: "strip" + compilerExtension
+ property string dsymutilName: "dsymutil" + compilerExtension
property string lipoName
property string sysroot: qbs.sysroot
property string syslibroot: sysroot
@@ -227,18 +227,12 @@ CppModule {
if (product.version === undefined)
return undefined;
- if (!Gcc.isNumericProductVersion(product.version)) {
- // Dynamic library version numbers like "A" or "B" are common on Apple platforms, so
- // don't restrict the product version to a componentized version number here.
- if (cpp.imageFormat === "macho")
- return product.version;
-
- throw("product.version must be a string in the format x[.y[.z[.w]] "
- + "where each component is an integer");
- }
+ var coreVersion = product.version.match("^([0-9]+\.){0,3}[0-9]+");
+ if (!coreVersion)
+ return undefined;
var maxVersionParts = 3;
- var versionParts = product.version.split('.').slice(0, maxVersionParts);
+ var versionParts = coreVersion[0].split('.').slice(0, maxVersionParts);
// pad if necessary
for (var i = versionParts.length; i < maxVersionParts; ++i)
@@ -246,11 +240,12 @@ CppModule {
return versionParts.join('.');
}
+
property string soVersion: {
- var v = internalVersion;
- if (!Gcc.isNumericProductVersion(v))
+ if (!internalVersion)
return "";
- return v.split('.')[0];
+
+ return internalVersion.split('.')[0];
}
property var buildEnv: {
@@ -429,7 +424,7 @@ CppModule {
+ PathTools.bundleExecutableFilePath(product)
}
}];
- if (product.qbs.toolchain.contains("mingw")) {
+ if (product.cpp.imageFormat === "pe") {
artifacts.push({
fileTags: ["dynamiclibrary_import"],
filePath: FileInfo.joinPaths(product.destinationDirectory,
@@ -447,7 +442,7 @@ CppModule {
}
if (product.cpp.shouldCreateSymlinks && (!product.bundle || !product.bundle.isBundle)) {
- var maxVersionParts = Gcc.isNumericProductVersion(product.version) ? 3 : 1;
+ var maxVersionParts = product.cpp.internalVersion ? 3 : 1;
for (var i = 0; i < maxVersionParts; ++i) {
var symlink = {
filePath: product.destinationDirectory + "/"
diff --git a/share/qbs/modules/cpp/MingwBaseModule.qbs b/share/qbs/modules/cpp/MingwBaseModule.qbs
new file mode 100644
index 000000000..60ad28b08
--- /dev/null
+++ b/share/qbs/modules/cpp/MingwBaseModule.qbs
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** 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.
+**
+****************************************************************************/
+
+import qbs.TextFile
+import qbs.Utilities
+import qbs.WindowsUtils
+
+import "setuprunenv.js" as SetupRunEnv
+
+GenericGCC {
+ condition: false
+
+ staticLibraryPrefix: "lib"
+ staticLibrarySuffix: ".a"
+ dynamicLibrarySuffix: ".dll"
+ executableSuffix: ".exe"
+ debugInfoSuffix: ".debug"
+ imageFormat: "pe"
+ windowsApiCharacterSet: "unicode"
+ platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
+ .concat("WIN32")
+
+ Properties {
+ condition: product.multiplexByQbsProperties.contains("buildVariants")
+ && qbs.buildVariants && qbs.buildVariants.length > 1
+ && qbs.buildVariant !== "release"
+ && product.type.containsAny(["staticlibrary", "dynamiclibrary"])
+ variantSuffix: "d"
+ }
+
+ FileTagger {
+ patterns: ["*.manifest"]
+ fileTags: ["native.pe.manifest"]
+ }
+
+ FileTagger {
+ patterns: ["*.rc"]
+ fileTags: ["rc"]
+ }
+
+ Rule {
+ inputs: ["native.pe.manifest"]
+ multiplex: true
+
+ outputFileTags: ["rc"]
+ outputArtifacts: {
+ if (product.type.containsAny(["application", "dynamiclibrary"])) {
+ return [{
+ filePath: input.completeBaseName + ".rc",
+ fileTags: ["rc"]
+ }];
+ }
+ return [];
+ }
+
+ prepare: {
+ var inputList = inputs["native.pe.manifest"];
+ // TODO: Emulate manifest merging like Microsoft's mt.exe tool does
+ if (inputList.length !== 1) {
+ throw("The MinGW toolchain does not support manifest merging; " +
+ "you may only specify a single manifest file to embed into your assembly.");
+ }
+
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.productType = product.type;
+ cmd.inputFilePath = inputList[0].filePath;
+ cmd.outputFilePath = output.filePath;
+ cmd.sourceCode = function() {
+ var tf;
+ try {
+ tf = new TextFile(outputFilePath, TextFile.WriteOnly);
+ if (productType.contains("application"))
+ tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID
+ else if (productType.contains("dynamiclibrary"))
+ tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID
+ tf.write("24 "); // RT_MANIFEST
+ tf.writeLine(Utilities.cStringQuote(inputFilePath));
+ } finally {
+ if (tf)
+ tf.close();
+ }
+ };
+ return [cmd];
+ }
+ }
+}
+
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
index 6936beb5e..0913b27d0 100644
--- a/share/qbs/modules/cpp/gcc.js
+++ b/share/qbs/modules/cpp/gcc.js
@@ -78,7 +78,7 @@ function collectLibraryDependencies(product, isDarwin) {
var publicDeps = {};
var objects = [];
var objectByFilePath = {};
- var tagForLinkingAgainstSharedLib = product.qbs.toolchain.contains("mingw")
+ var tagForLinkingAgainstSharedLib = product.cpp.imageFormat === "pe"
? "dynamiclibrary_import" : "dynamiclibrary";
function addObject(obj, addFunc) {
@@ -278,12 +278,11 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat
}
if (isDarwin) {
- var internalVersion = product.cpp.internalVersion;
- if (internalVersion && isNumericProductVersion(internalVersion))
- args.push("-current_version", internalVersion);
+ if (product.cpp.internalVersion)
+ args.push("-current_version", product.cpp.internalVersion);
escapableLinkerFlags.push("-install_name", UnixUtils.soname(product,
primaryOutput.fileName));
- } else {
+ } else if (product.cpp.imageFormat === "elf") {
escapableLinkerFlags.push("-soname=" + UnixUtils.soname(product,
primaryOutput.fileName));
}
@@ -295,7 +294,7 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat
if (primaryOutput.fileTags.containsAny(["dynamiclibrary", "loadablemodule"])) {
if (isDarwin)
escapableLinkerFlags.push("-headerpad_max_install_names");
- else
+ else if (product.cpp.imageFormat === "elf")
escapableLinkerFlags.push("--as-needed");
}
@@ -344,13 +343,15 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat
return rpath;
}
- function isNotSystemRunPath(p) {
- return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p)
- && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p)));
- };
- for (i in rpaths) {
- if (isNotSystemRunPath(rpaths[i]))
- escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i]));
+ if (!product.qbs.targetOS.contains("windows")) {
+ function isNotSystemRunPath(p) {
+ return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p)
+ && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p)));
+ };
+ for (i in rpaths) {
+ if (isNotSystemRunPath(rpaths[i]))
+ escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i]));
+ }
}
if (product.cpp.entryPoint)
@@ -854,7 +855,7 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
}
var positionIndependentCode = input.cpp.positionIndependentCode;
- if (positionIndependentCode && !product.qbs.toolchain.contains("mingw"))
+ if (positionIndependentCode && !product.qbs.targetOS.contains("windows"))
args.push('-fPIC');
var cppFlags = input.cpp.cppFlags;
@@ -1035,7 +1036,7 @@ function linkerEnvVars(config, inputs)
function setResponseFileThreshold(command, product)
{
- if (product.qbs.toolchain.contains("mingw") && product.qbs.hostOS.contains("windows"))
+ if (product.qbs.targetOS.contains("windows") && product.qbs.hostOS.contains("windows"))
command.responseFileThreshold = 10000;
}
@@ -1432,10 +1433,6 @@ function debugInfoArtifacts(product, variants, debugInfoTagSuffix) {
return artifacts;
}
-function isNumericProductVersion(version) {
- return version && version.match(/^([0-9]+\.){0,3}[0-9]+$/);
-}
-
function dumpMacros(env, compilerFilePath, args, nullDevice, tag) {
var p = new Process();
try {
diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js
index 33093c0a3..436bdb8ee 100644
--- a/share/qbs/modules/cpp/iar.js
+++ b/share/qbs/modules/cpp/iar.js
@@ -36,33 +36,182 @@ var ModUtils = require("qbs.ModUtils");
var Process = require("qbs.Process");
var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
-var Utilities = require("qbs.Utilities");
-var WindowsUtils = require("qbs.WindowsUtils");
-function guessArchitecture(macros)
-{
+function compilerName(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ return "iccarm";
+ case "mcs51":
+ return "icc8051";
+ case "avr":
+ return "iccavr";
+ case "stm8":
+ return "iccstm8";
+ case "msp430":
+ return "icc430";
+ }
+ throw "Unable to deduce compiler name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function assemblerName(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ return "iasmarm";
+ case "mcs51":
+ return "a8051";
+ case "avr":
+ return "aavr";
+ case "stm8":
+ return "iasmstm8";
+ case "msp430":
+ return "a430";
+ }
+ throw "Unable to deduce assembler name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function linkerName(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ return "ilinkarm";
+ case "stm8":
+ return "ilinkstm8";
+ case "mcs51":
+ case "avr":
+ case "msp430":
+ return "xlink";
+ }
+ throw "Unable to deduce linker name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function archiverName(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ case "stm8":
+ return "iarchive";
+ case "mcs51":
+ case "avr":
+ case "msp430":
+ return "xlib";
+ }
+ throw "Unable to deduce archiver name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function staticLibrarySuffix(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ case "stm8":
+ return ".a";
+ case "mcs51":
+ return ".r51";
+ case "avr":
+ return ".r90";
+ case "msp430":
+ return ".r43";
+ }
+ throw "Unable to deduce static library suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function executableSuffix(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ case "stm8":
+ return ".out";
+ case "mcs51":
+ return qbs.debugInformation ? ".d51" : ".a51";
+ case "avr":
+ return qbs.debugInformation ? ".d90" : ".a90";
+ case "msp430":
+ return qbs.debugInformation ? ".d43" : ".a43";
+ }
+ throw "Unable to deduce executable suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function objectSuffix(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ case "stm8":
+ return ".o";
+ case "mcs51":
+ return ".r51";
+ case "avr":
+ return ".r90";
+ case "msp430":
+ return ".r43";
+ }
+ throw "Unable to deduce object file suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function imageFormat(qbs) {
+ switch (qbs.architecture) {
+ case "arm":
+ case "stm8":
+ return "elf";
+ case "mcs51":
+ case "avr":
+ case "msp430":
+ return "ubrof";
+ }
+ throw "Unable to deduce image format for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function guessArchitecture(macros) {
if (macros["__ICCARM__"] === "1")
return "arm";
else if (macros["__ICC8051__"] === "1")
return "mcs51";
else if (macros["__ICCAVR__"] === "1")
return "avr";
+ else if (macros["__ICCSTM8__"] === "1")
+ return "stm8";
+ else if (macros["__ICC430__"] === "1")
+ return "msp430";
}
-function guessEndianness(macros)
-{
+function guessEndianness(macros) {
if (macros["__LITTLE_ENDIAN__"] === "1")
return "little";
return "big"
}
-function cppLanguageOption(compilerFilePath)
+function guessVersion(macros, architecture)
{
+ var version = parseInt(macros["__VER__"], 10);
+ switch (architecture) {
+ case "arm":
+ return { major: parseInt(version / 1000000),
+ minor: parseInt(version / 1000) % 1000,
+ patch: parseInt(version) % 1000,
+ found: true }
+ case "mcs51":
+ case "avr":
+ case "stm8":
+ case "msp430":
+ return { major: parseInt(version / 100),
+ minor: parseInt(version % 100),
+ patch: 0,
+ found: true }
+ }
+}
+
+function cppLanguageOption(compilerFilePath) {
var baseName = FileInfo.baseName(compilerFilePath);
- if (baseName === "iccarm")
+ switch (baseName) {
+ case "iccarm":
return "--c++";
- if (baseName === "icc8051" || baseName === "iccavr")
+ case "icc8051":
+ case "iccavr":
+ case "iccstm8":
+ case "icc430":
return "--ec++";
+ }
throw "Unable to deduce C++ language option for unsupported compiler: '"
+ FileInfo.toNativeSeparators(compilerFilePath) + "'";
}
@@ -191,12 +340,48 @@ function collectLibraryDependencies(product) {
}
function compilerFlags(project, product, input, output, explicitlyDependsOn) {
- // Determine which C-language we"re compiling.
+ // Determine which C-language we're compiling.
var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
var args = [];
+
+ // Input.
args.push(input.filePath);
+ // Output.
+ args.push("-o", output.filePath);
+
+ // Defines.
+ var allDefines = [];
+ var platformDefines = input.cpp.platformDefines;
+ if (platformDefines)
+ allDefines = allDefines.uniqueConcat(platformDefines);
+ var defines = input.cpp.defines;
+ if (defines)
+ allDefines = allDefines.uniqueConcat(defines);
+ args = args.concat(allDefines.map(function(define) { return "-D" + define }));
+
+ // Includes.
+ var allIncludePaths = [];
+ var includePaths = input.cpp.includePaths;
+ if (includePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
+ var systemIncludePaths = input.cpp.systemIncludePaths;
+ if (systemIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
+ var compilerIncludePaths = input.cpp.compilerIncludePaths;
+ if (compilerIncludePaths)
+ allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
+ args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
+
+ // Silent output generation flag.
+ args.push("--silent");
+
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("--debug");
+
+ // Optimization flags.
switch (input.cpp.optimization) {
case "small":
args.push("-Ohs");
@@ -209,73 +394,68 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
break;
}
- if (input.cpp.debugInformation)
- args.push("--debug");
-
- var warnings = input.cpp.warningLevel;
- if (warnings === "none") {
+ // Warning level flags.
+ switch (input.cpp.warningLevel) {
+ case "none":
args.push("--no_warnings");
- } else if (warnings === "all") {
+ break;
+ case "all":
args.push("--deprecated_feature_warnings="
+"+attribute_syntax,"
+"+preprocessor_extensions,"
+"+segment_pragmas");
if (tag === "cpp")
args.push("--warn_about_c_style_casts");
+ break;
}
if (input.cpp.treatWarningsAsErrors)
args.push("--warnings_are_errors");
- // Choose byte order.
- var endianness = input.cpp.endianness;
- if (endianness) {
- if (input.qbs.architecture === "arm")
- args.push("--endian=" + endianness);
- }
-
+ // C language version flags.
if (tag === "c") {
- // Language version.
- if (input.cpp.cLanguageVersion === "c89")
+ var knownValues = ["c89"];
+ var cLanguageVersion = Cpp.languageVersion(
+ input.cpp.cLanguageVersion, knownValues, "C");
+ switch (cLanguageVersion) {
+ case "c89":
args.push("--c89");
- } else if (tag === "cpp") {
- if (input.qbs.architecture === "arm") {
+ break;
+ default:
+ // Default C language version is C11/C99 that
+ // depends on the IAR version.
+ break;
+ }
+ }
+
+ // Architecture specific flags.
+ switch (input.qbs.architecture) {
+ case "arm":
+ // Byte order flags.
+ var endianness = input.cpp.endianness;
+ if (endianness)
+ args.push("--endian=" + endianness);
+ if (tag === "cpp") {
+ // Enable C++ language flags.
args.push("--c++");
+ // Exceptions flags.
if (!input.cpp.enableExceptions)
args.push("--no_exceptions");
+ // RTTI flags.
if (!input.cpp.enableRtti)
args.push("--no_rtti");
- } else if (input.qbs.architecture === "mcs51") {
- args.push("--ec++");
- } else if (input.qbs.architecture === "avr") {
- args.push("--ec++");
}
+ break;
+ case "stm8":
+ case "mcs51":
+ case "avr":
+ case "msp430":
+ // Enable C++ language flags.
+ if (tag === "cpp")
+ args.push("--ec++");
+ break;
}
- var allDefines = [];
- var platformDefines = input.cpp.platformDefines;
- if (platformDefines)
- allDefines = allDefines.uniqueConcat(platformDefines);
- var defines = input.cpp.defines;
- if (defines)
- allDefines = allDefines.uniqueConcat(defines);
- args = args.concat(allDefines.map(function(define) { return "-D" + define }));
-
- var allIncludePaths = [];
- var includePaths = input.cpp.includePaths;
- if (includePaths)
- allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
- var systemIncludePaths = input.cpp.systemIncludePaths;
- if (systemIncludePaths)
- allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
- var compilerIncludePaths = input.cpp.compilerIncludePaths;
- if (compilerIncludePaths)
- allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
- args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
-
- args.push("-o", output.filePath);
-
- args.push("--silent"); // Silent operation.
-
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
ModUtils.moduleProperty(input, "flags"),
ModUtils.moduleProperty(input, "platformFlags", tag),
@@ -289,17 +469,14 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
var args = [];
- args.push(input.filePath);
- if (input.cpp.debugInformation)
- args.push("-r");
+ // Input.
+ args.push(input.filePath);
- var warnings = input.cpp.warningLevel;
- if (warnings === "none")
- args.push("-w-");
- else
- args.push("-w+");
+ // Output.
+ args.push("-o", output.filePath);
+ // Includes.
var allIncludePaths = [];
var systemIncludePaths = input.cpp.systemIncludePaths;
if (systemIncludePaths)
@@ -309,10 +486,29 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
- args.push("-o", output.filePath);
+ // Silent output generation flag.
+ args.push(input.qbs.architecture === "stm8" ? "--silent" : "-S");
- args.push("-S"); // Silent operation.
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("-r");
+
+ // Architecture specific flags.
+ switch (input.qbs.architecture) {
+ case "stm8":
+ // Warning level flags.
+ if (input.cpp.warningLevel === "none")
+ args.push("--no_warnings");
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("--warnings_are_errors");
+ break;
+ default:
+ // Warning level flags.
+ args.push("-w" + (input.cpp.warningLevel === "none" ? "-" : "+"));
+ break;
+ }
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
ModUtils.moduleProperty(input, "flags", tag),
ModUtils.moduleProperty(input, "driverFlags", tag));
@@ -320,23 +516,16 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
}
function linkerFlags(project, product, input, outputs) {
- var i;
var args = [];
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Output.
args.push("-o", outputs.application[0].filePath);
- if (product.cpp.generateMapFile) {
- if (product.qbs.architecture === "arm")
- args.push("--map", outputs.map_file[0].filePath);
- else if (product.qbs.architecture === "mcs51")
- args.push("-l", outputs.map_file[0].filePath);
- else if (product.qbs.architecture === "avr")
- args.push("-l", outputs.map_file[0].filePath);
- }
-
+ // Library paths.
var allLibraryPaths = [];
var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
@@ -346,44 +535,50 @@ function linkerFlags(project, product, input, outputs) {
allLibraryPaths = allLibraryPaths.uniqueConcat(distributionLibraryPaths);
args = args.concat(allLibraryPaths.map(function(path) { return '-L' + path }));
+ // Library dependencies.
var libraryDependencies = collectLibraryDependencies(product);
if (libraryDependencies)
args = args.concat(libraryDependencies.map(function(dep) { return dep.filePath }));
- if (product.cpp.debugInformation) {
- if (product.qbs.architecture === "mcs51")
- args.push("-rt");
- else if (product.qbs.architecture === "avr")
- args.push("-rt");
- }
-
+ // Linker scripts.
var linkerScripts = inputs.linkerscript
- ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
- for (i in linkerScripts) {
- if (product.qbs.architecture === "arm")
- args.push("--config", linkerScripts[i]);
- else if (product.qbs.architecture === "mcs51")
- args.push("-f", linkerScripts[i]);
- else if (product.qbs.architecture === "avr")
- args.push("-f", linkerScripts[i]);
- }
-
- if (product.cpp.entryPoint) {
- if (product.qbs.architecture === "arm")
+ ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
+
+ // Architecture specific flags.
+ switch (product.qbs.architecture) {
+ case "arm":
+ case "stm8":
+ // Silent output generation flag.
+ args.push("--silent");
+ // Map file generation flag.
+ if (product.cpp.generateMapFile)
+ args.push("--map", outputs.map_file[0].filePath);
+ // Entry point flag.
+ if (product.cpp.entryPoint)
args.push("--entry", product.cpp.entryPoint);
- else if (product.qbs.architecture === "mcs51")
- args.push("-s", product.cpp.entryPoint);
- else if (product.qbs.architecture === "avr")
+ // Linker scripts flags.
+ linkerScripts.forEach(function(script) { args.push("--config", script); });
+ break;
+ case "mcs51":
+ case "avr":
+ case "msp430":
+ // Silent output generation flag.
+ args.push("-S");
+ // Debug information flag.
+ if (product.cpp.debugInformation)
+ args.push("-rt");
+ // Map file generation flag.
+ if (product.cpp.generateMapFile)
+ args.push("-l", outputs.map_file[0].filePath);
+ // Entry point flag.
+ if (product.cpp.entryPoint)
args.push("-s", product.cpp.entryPoint);
+ // Linker scripts flags.
+ linkerScripts.forEach(function(script) { args.push("-f", script); });
+ break;
}
- if (product.qbs.architecture === "arm")
- args.push("--silent"); // Silent operation.
- else if (product.qbs.architecture === "mcs51")
- args.push("-S"); // Silent operation.
- else if (product.qbs.architecture === "avr")
- args.push("-S"); // Silent operation.
-
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(product, "driverLinkerFlags"));
return args;
}
@@ -391,9 +586,11 @@ function linkerFlags(project, product, input, outputs) {
function archiverFlags(project, product, input, outputs) {
var args = [];
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Output.
args.push("--create");
args.push("-o", outputs.staticlibrary[0].filePath);
@@ -403,7 +600,7 @@ function archiverFlags(project, product, input, outputs) {
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
var compilerPath = input.cpp.compilerPath;
- var cmd = new Command(compilerPath, args)
+ var cmd = new Command(compilerPath, args);
cmd.description = "compiling " + input.fileName;
cmd.highlight = "compiler";
return [cmd];
@@ -412,7 +609,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
var assemblerPath = input.cpp.assemblerPath;
- var cmd = new Command(assemblerPath, args)
+ var cmd = new Command(assemblerPath, args);
cmd.description = "assembling " + input.fileName;
cmd.highlight = "compiler";
return [cmd];
@@ -422,7 +619,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
var primaryOutput = outputs.application[0];
var args = linkerFlags(project, product, input, outputs);
var linkerPath = product.cpp.linkerPath;
- var cmd = new Command(linkerPath, args)
+ var cmd = new Command(linkerPath, args);
cmd.description = "linking " + primaryOutput.fileName;
cmd.highlight = "linker";
return [cmd];
@@ -431,7 +628,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
function prepareArchiver(project, product, inputs, outputs, input, output) {
var args = archiverFlags(project, product, input, outputs);
var archiverPath = product.cpp.archiverPath;
- var cmd = new Command(archiverPath, args)
+ var cmd = new Command(archiverPath, args);
cmd.description = "linking " + output.fileName;
cmd.highlight = "linker";
cmd.stdoutFilterFunction = function(output) {
diff --git a/share/qbs/modules/cpp/iar.qbs b/share/qbs/modules/cpp/iar.qbs
index 6d15781a5..8140a8e73 100644
--- a/share/qbs/modules/cpp/iar.qbs
+++ b/share/qbs/modules/cpp/iar.qbs
@@ -78,99 +78,26 @@ CppModule {
property string cCompilerName: compilerName
property string cxxCompilerName: compilerName
- compilerName: {
- switch (qbs.architecture) {
- case "arm":
- return "iccarm" + compilerExtension;
- case "mcs51":
- return "icc8051" + compilerExtension;
- case "avr":
- return "iccavr" + compilerExtension;
- }
- }
+ compilerName: IAR.compilerName(qbs) + compilerExtension
compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
- assemblerName: {
- switch (qbs.architecture) {
- case "arm":
- return "iasmarm" + compilerExtension;
- case "mcs51":
- return "a8051" + compilerExtension;
- case "avr":
- return "aavr" + compilerExtension;
- }
- }
+ assemblerName: IAR.assemblerName(qbs) + compilerExtension
assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
- linkerName: {
- switch (qbs.architecture) {
- case "arm":
- return "ilinkarm" + compilerExtension;
- case "mcs51":
- return "xlink" + compilerExtension;
- case "avr":
- return "xlink" + compilerExtension;
- }
- }
+ linkerName: IAR.linkerName(qbs) + compilerExtension
linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
- property string archiverName: {
- switch (qbs.architecture) {
- case "arm":
- return "iarchive" + compilerExtension;
- case "mcs51":
- return "xlib" + compilerExtension;
- case "avr":
- return "xlib" + compilerExtension;
- }
- }
+ property string archiverName: IAR.archiverName(qbs) + compilerExtension
property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName)
runtimeLibrary: "static"
- staticLibrarySuffix: {
- switch (qbs.architecture) {
- case "arm":
- return ".a";
- case "mcs51":
- return ".r51";
- case "avr":
- return ".r90";
- }
- }
+ staticLibrarySuffix: IAR.staticLibrarySuffix(qbs)
+ executableSuffix: IAR.executableSuffix(qbs)
- executableSuffix: {
- switch (qbs.architecture) {
- case "arm":
- return ".out";
- case "mcs51":
- return qbs.debugInformation ? ".d51" : ".a51";
- case "avr":
- return qbs.debugInformation ? ".d90" : ".a90";
- }
- }
+ property string objectSuffix: IAR.objectSuffix(qbs)
- property string objectSuffix: {
- switch (qbs.architecture) {
- case "arm":
- return ".o";
- case "mcs51":
- return ".r51";
- case "avr":
- return ".r90";
- }
- }
-
- imageFormat: {
- switch (qbs.architecture) {
- case "arm":
- return "elf";
- case "mcs51":
- return "ubrof";
- case "avr":
- return "ubrof";
- }
- }
+ imageFormat: IAR.imageFormat(qbs)
enableExceptions: false
enableRtti: false
@@ -185,18 +112,11 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: IAR.prepareAssembler.apply(IAR, arguments);
- }
-
- FileTagger {
- condition: qbs.architecture === "arm";
- patterns: "*.s"
- fileTags: ["asm"]
+ prepare: IAR.prepareAssembler.apply(IAR, arguments)
}
FileTagger {
- condition: qbs.architecture === "mcs51";
- patterns: ["*.s51", "*.asm"]
+ patterns: ["*.s", "*.s43", "*.s51", "*.s90", "*.msa", "*.asm"]
fileTags: ["asm"]
}
@@ -211,7 +131,7 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: IAR.prepareCompiler.apply(IAR, arguments);
+ prepare: IAR.prepareCompiler.apply(IAR, arguments)
}
Rule {
@@ -245,7 +165,7 @@ CppModule {
return artifacts;
}
- prepare:IAR.prepareLinker.apply(IAR, arguments);
+ prepare: IAR.prepareLinker.apply(IAR, arguments)
}
Rule {
@@ -261,6 +181,6 @@ CppModule {
PathTools.staticLibraryFilePath(product))
}
- prepare: IAR.prepareArchiver.apply(IAR, arguments);
+ prepare: IAR.prepareArchiver.apply(IAR, arguments)
}
}
diff --git a/share/qbs/modules/cpp/keil.js b/share/qbs/modules/cpp/keil.js
index c19fdd738..4b3665715 100644
--- a/share/qbs/modules/cpp/keil.js
+++ b/share/qbs/modules/cpp/keil.js
@@ -36,19 +36,104 @@ var ModUtils = require("qbs.ModUtils");
var Process = require("qbs.Process");
var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
-var Utilities = require("qbs.Utilities");
-var WindowsUtils = require("qbs.WindowsUtils");
-function guessArchitecture(macros)
-{
+function compilerName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "c51";
+ case "arm":
+ return "armcc";
+ }
+ throw "Unable to deduce compiler name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function assemblerName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "a51";
+ case "arm":
+ return "armasm";
+ }
+ throw "Unable to deduce assembler name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function linkerName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "bl51";
+ case "arm":
+ return "armlink";
+ }
+ throw "Unable to deduce linker name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function archiverName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "lib51";
+ case "arm":
+ return "armar";
+ }
+ throw "Unable to deduce archiver name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function staticLibrarySuffix(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ case "arm":
+ return ".lib";
+ }
+ throw "Unable to deduce static library suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function executableSuffix(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return ".abs";
+ case "arm":
+ return ".axf";
+ }
+ throw "Unable to deduce executable suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function objectSuffix(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return ".obj";
+ case "arm":
+ return ".o";
+ }
+ throw "Unable to deduce object file suffix for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function imageFormat(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ // Keil OMF51 or OMF2 Object Module Format (which is an
+ // extension of the original Intel OMF51).
+ return "omf";
+ case "arm":
+ return "elf";
+ }
+ throw "Unable to deduce image format for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function guessArchitecture(macros) {
if (macros["__C51__"])
return "mcs51";
else if (macros["__CC_ARM"] === 1)
return "arm";
}
-function guessEndianness(macros)
-{
+function guessEndianness(macros) {
if (macros["__C51__"]) {
// The 8051 processors are 8-bit. So, the data with an integer type
// represented by more than one byte is stored as big endian in the
@@ -61,19 +146,18 @@ function guessEndianness(macros)
}
}
-function guessVersion(macros)
-{
+function guessVersion(macros) {
if (macros["__C51__"]) {
- var version = macros["__C51__"];
- return { major: parseInt(version / 100),
- minor: parseInt(version % 100),
+ var mcsVersion = macros["__C51__"];
+ return { major: parseInt(mcsVersion / 100),
+ minor: parseInt(mcsVersion % 100),
patch: 0,
found: true }
} else if (macros["__CC_ARM"]) {
- var version = macros["__ARMCC_VERSION"];
- return { major: parseInt(version / 1000000),
- minor: parseInt(version / 10000) % 100,
- patch: parseInt(version) % 10000,
+ var armVersion = macros["__ARMCC_VERSION"];
+ return { major: parseInt(armVersion / 1000000),
+ minor: parseInt(armVersion / 10000) % 100,
+ patch: parseInt(armVersion) % 10000,
found: true }
}
}
@@ -132,26 +216,18 @@ function dumpMacros(compilerFilePath, tag, nullDevice) {
var map1 = dumpC51CompilerMacros(compilerFilePath, tag, nullDevice);
var map2 = dumpArmCompilerMacros(compilerFilePath, tag, nullDevice);
var map = {};
- for (var attrname in map1)
- map[attrname] = map1[attrname];
- for (var attrname in map2)
- map[attrname] = map2[attrname];
+ for (var key1 in map1)
+ map[key1] = map1[key1];
+ for (var key2 in map2)
+ map[key2] = map2[key2];
return map;
}
function dumpDefaultPaths(compilerFilePath, architecture) {
- var includePaths = [];
-
- if (architecture === "mcs51") {
- var path = compilerFilePath.replace(/bin[\\\/](.*)$/i, "inc");
- includePaths.push(path);
- } else if (architecture === "arm") {
- var path = compilerFilePath.replace(/bin[\\\/](.*)$/i, "include");
- includePaths.push(path);
- }
-
+ var incDir = (architecture === "arm") ? "include" : "inc";
+ var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, incDir);
return {
- "includePaths": includePaths
+ "includePaths": [includePath]
};
}
@@ -247,9 +323,8 @@ function filterStdOutput(cmd) {
}
function compilerFlags(project, product, input, output, explicitlyDependsOn) {
- // Determine which C-language we"re compiling.
+ // Determine which C-language we're compiling.
var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
- var architecture = input.qbs.architecture;
var args = [];
var allDefines = [];
@@ -271,10 +346,29 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
if (compilerIncludePaths)
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
+ var architecture = input.qbs.architecture;
if (architecture === "mcs51") {
+ // Input.
args.push(FileInfo.toWindowsSeparators(input.filePath));
+
+ // Output.
args.push("OBJECT (" + FileInfo.toWindowsSeparators(output.filePath) + ")");
+ // Defines.
+ if (allDefines.length > 0)
+ args = args.concat("DEFINE (" + allDefines.join(",") + ")");
+
+ // Includes.
+ if (allIncludePaths.length > 0) {
+ var adjusted = adjustPathsToWindowsSeparators(allIncludePaths);
+ args = args.concat("INCDIR (" + adjusted.join(";") + ")");
+ }
+
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("DEBUG");
+
+ // Optimization level flags.
switch (input.cpp.optimization) {
case "small":
args.push("OPTIMIZE (SIZE)");
@@ -287,28 +381,36 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
break;
}
- if (input.cpp.debugInformation)
- args.push("DEBUG");
-
- var warnings = input.cpp.warningLevel;
- if (warnings === "none") {
+ // Warning level flags.
+ switch (input.cpp.warningLevel) {
+ case "none":
args.push("WARNINGLEVEL (0)");
- } else if (warnings === "all") {
+ break;
+ case "all":
args.push("WARNINGLEVEL (2)");
args.push("FARWARNING");
- }
-
- if (allDefines.length > 0)
- args = args.concat("DEFINE (" + allDefines.join(",") + ")");
-
- if (allIncludePaths.length > 0) {
- var adjusted = adjustPathsToWindowsSeparators(allIncludePaths);
- args = args.concat("INCDIR (" + adjusted.join(";") + ")");
+ break;
}
} else if (architecture === "arm") {
+ // Input.
args.push("-c", input.filePath);
+
+ // Output.
args.push("-o", output.filePath);
+ // Defines.
+ args = args.concat(allDefines.map(function(define) { return '-D' + define }));
+
+ // Includes.
+ args = args.concat(allIncludePaths.map(function(include) { return '-I' + include }));
+
+ // Debug information flags.
+ if (input.cpp.debugInformation) {
+ args.push("--debug");
+ args.push("-g");
+ }
+
+ // Optimization level flags.
switch (input.cpp.optimization) {
case "small":
args.push("-Ospace")
@@ -321,43 +423,57 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
break;
}
- if (input.cpp.debugInformation) {
- args.push("--debug");
- args.push("-g");
- }
-
- var warnings = input.cpp.warningLevel;
- if (warnings === "none") {
+ // Warning level flags.
+ switch (input.cpp.warningLevel) {
+ case "none":
args.push("-W");
- } else if (warnings === "all") {
+ break;
+ default:
// By default all warnings are enabled.
+ break;
}
if (tag === "c") {
- // Note: Here we use the '==' operator because the '==='
- // operator does not work!
- if (input.cpp.cLanguageVersion == "c99")
+ // C language version flags.
+ var knownCLanguageValues = ["c99", "c90"];
+ var cLanguageVersion = Cpp.languageVersion(
+ input.cpp.cLanguageVersion, knownCLanguageValues, "C");
+ switch (cLanguageVersion) {
+ case "c99":
args.push("--c99");
+ break;
+ case "c90":
+ args.push("--c90");
+ break;
+ }
} else if (tag === "cpp") {
- args.push("--cpp");
- // Note: Here we use the '==' operator because the '==='
- // operator does not work!
- if (input.cpp.cxxLanguageVersion == "c++11")
+ // C++ language version flags.
+ var knownCppLanguageValues = ["c++11", "c++03"];
+ var cppLanguageVersion = Cpp.languageVersion(
+ input.cpp.cxxLanguageVersion, knownCppLanguageValues, "C++");
+ switch (cppLanguageVersion) {
+ case "c++11":
args.push("--cpp11");
+ break;
+ default:
+ // Default C++ language is C++03.
+ args.push("--cpp");
+ break;
+ }
+ // Exceptions flags.
var enableExceptions = input.cpp.enableExceptions;
if (enableExceptions !== undefined)
args.push(enableExceptions ? "--exceptions" : "--no_exceptions");
+ // RTTI flags.
var enableRtti = input.cpp.enableRtti;
if (enableRtti !== undefined)
args.push(enableRtti ? "--rtti" : "--no_rtti");
}
-
- args = args.concat(allDefines.map(function(define) { return '-D' + define }));
- args = args.concat(allIncludePaths.map(function(include) { return '-I' + include }));
}
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
ModUtils.moduleProperty(input, "flags"),
ModUtils.moduleProperty(input, "platformFlags", tag),
@@ -367,9 +483,8 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
}
function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
- // Determine which C-language we"re compiling
+ // Determine which C-language we're compiling
var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
- var architecture = input.qbs.architecture;
var args = [];
var allDefines = [];
@@ -391,37 +506,35 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
if (compilerIncludePaths)
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
+ var architecture = input.qbs.architecture;
if (architecture === "mcs51") {
+ // Input.
args.push(FileInfo.toWindowsSeparators(input.filePath));
- args.push("OBJECT (" + FileInfo.toWindowsSeparators(output.filePath) + ")");
- if (input.cpp.debugInformation)
- args.push("DEBUG");
+ // Output.
+ args.push("OBJECT (" + FileInfo.toWindowsSeparators(output.filePath) + ")");
+ // Defines.
if (allDefines.length > 0)
args = args.concat("DEFINE (" + allDefines.join(",") + ")");
+ // Includes.
if (allIncludePaths.length > 0) {
var adjusted = adjustPathsToWindowsSeparators(allIncludePaths);
args = args.concat("INCDIR (" + adjusted.join(";") + ")");
}
+
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("DEBUG");
} else if (architecture === "arm") {
+ // Input.
args.push(input.filePath);
- args.push("-o", output.filePath);
-
- if (input.cpp.debugInformation) {
- args.push("--debug");
- args.push("-g");
- }
- var warnings = input.cpp.warningLevel;
- if (warnings === "none")
- args.push("--no_warn");
-
- var endianness = input.cpp.endianness;
- if (endianness)
- args.push((endianness === "little") ? "--littleend" : "--bigend");
+ // Output.
+ args.push("-o", output.filePath);
+ // Defines.
allDefines.forEach(function(define) {
var parts = define.split("=");
args.push("--pd");
@@ -433,9 +546,26 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
args.push(parts[0] + " SETA " + parts[1]);
});
+ // Includes.
args = args.concat(allIncludePaths.map(function(include) { return '-I' + include }));
+
+ // Debug information flags.
+ if (input.cpp.debugInformation) {
+ args.push("--debug");
+ args.push("-g");
+ }
+
+ // Warning level flags.
+ if (input.cpp.warningLevel === "none")
+ args.push("--no_warn");
+
+ // Byte order flags.
+ var endianness = input.cpp.endianness;
+ if (endianness)
+ args.push((endianness === "little") ? "--littleend" : "--bigend");
}
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
ModUtils.moduleProperty(input, "flags", tag),
ModUtils.moduleProperty(input, "driverFlags", tag));
@@ -444,89 +574,116 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
function linkerFlags(project, product, input, outputs) {
var args = [];
- var architecture = product.qbs.architecture;
+ var architecture = product.qbs.architecture;
if (architecture === "mcs51") {
+ // Note: The C51 linker does not distinguish an object files and
+ // a libraries, it interpret all this stuff as an input objects,
+ // so, we need to pass it together in one string.
+
var allObjectPaths = [];
function addObjectPath(obj) {
allObjectPaths.push(obj.filePath);
}
+ // Inputs.
if (inputs.obj)
inputs.obj.map(function(obj) { addObjectPath(obj) });
- var libraryDependencies = collectLibraryDependencies(product);
- libraryDependencies.forEach(function(dep) { addObjectPath(dep); })
+ // Library dependencies.
+ var libraryObjects = collectLibraryDependencies(product);
+ libraryObjects.forEach(function(dep) { addObjectPath(dep); })
+ // Add all input objects as arguments (application and library object files).
var adjusted = adjustPathsToWindowsSeparators(allObjectPaths);
args = args.concat(adjusted.join(","));
- // We need to wrap an output file name with quotes. Otherwise
+ // Output.
+ // Note: We need to wrap an output file name with quotes. Otherwise
// the linker will ignore a specified file name.
args.push("TO", '"' + FileInfo.toWindowsSeparators(outputs.application[0].filePath) + '"');
+ // Map file generation flag.
if (!product.cpp.generateMapFile)
args.push("NOMAP");
} else if (architecture === "arm") {
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Output.
args.push("--output", outputs.application[0].filePath);
- if (product.cpp.generateMapFile)
- args.push("--list", outputs.map_file[0].filePath);
-
+ // Library paths.
var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
args.push("--userlibpath=" + libraryPaths.join(","));
+ // Library dependencies.
var libraryDependencies = collectLibraryDependencies(product);
args = args.concat(libraryDependencies.map(function(dep) { return dep.filePath; }));
- var linkerScripts = inputs.linkerscript
- ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
- for (i in linkerScripts)
- args.push("--scatter", linkerScripts[i]);
+ // Debug information flag.
+ var debugInformation = product.cpp.debugInformation;
+ if (debugInformation !== undefined)
+ args.push(debugInformation ? "--debug" : "--no_debug");
+ // Map file generation flag.
+ if (product.cpp.generateMapFile)
+ args.push("--list", outputs.map_file[0].filePath);
+
+ // Entry point flag.
if (product.cpp.entryPoint)
args.push("--entry", product.cpp.entryPoint);
- var debugInformation = product.cpp.debugInformation;
- if (debugInformation !== undefined)
- args.push(debugInformation ? "--debug" : "--no_debug");
+ // Linker scripts flags.
+ var linkerScripts = inputs.linkerscript
+ ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
+ linkerScripts.forEach(function(script) { args.push("--scatter", script); });
}
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(product, "driverLinkerFlags"));
return args;
}
function archiverFlags(project, product, input, outputs) {
var args = [];
- var architecture = product.qbs.architecture;
+ var architecture = product.qbs.architecture;
if (architecture === "mcs51") {
+ // Library creation command.
args.push("TRANSFER");
- var allObjectPaths = [];
+ var allObjectPaths = [];
function addObjectPath(obj) {
allObjectPaths.push(obj.filePath);
}
+ // Inputs.
if (inputs.obj)
inputs.obj.map(function(obj) { addObjectPath(obj) });
+ // Add all input objects as arguments.
var adjusted = adjustPathsToWindowsSeparators(allObjectPaths);
args = args.concat(adjusted.join(","));
- // We need to wrap a output file name with quotes. Otherwise
+ // Output.
+ // Note: We need to wrap a output file name with quotes. Otherwise
// the linker will ignore a specified file name.
args.push("TO", '"' + FileInfo.toWindowsSeparators(outputs.staticlibrary[0].filePath) + '"');
} else if (architecture === "arm") {
+ // Note: The ARM archiver command line expect the output file
+ // first, and then a set of input objects.
+
+ // Output.
args.push("--create", outputs.staticlibrary[0].filePath);
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Debug information flag.
if (product.cpp.debugInformation)
args.push("--debug_symbols");
}
@@ -538,7 +695,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
var compilerPath = input.cpp.compilerPath;
var architecture = input.cpp.architecture;
- var cmd = new Command(compilerPath, args)
+ var cmd = new Command(compilerPath, args);
cmd.description = "compiling " + input.fileName;
cmd.highlight = "compiler";
cmd.maxExitCode = getMaxExitCode(architecture);
@@ -550,7 +707,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
var assemblerPath = input.cpp.assemblerPath;
- var cmd = new Command(assemblerPath, args)
+ var cmd = new Command(assemblerPath, args);
cmd.description = "assembling " + input.fileName;
cmd.highlight = "compiler";
filterStdOutput(cmd);
@@ -561,7 +718,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
var primaryOutput = outputs.application[0];
var args = linkerFlags(project, product, input, outputs);
var linkerPath = product.cpp.linkerPath;
- var cmd = new Command(linkerPath, args)
+ var cmd = new Command(linkerPath, args);
cmd.description = "linking " + primaryOutput.fileName;
cmd.highlight = "linker";
filterStdOutput(cmd);
@@ -571,7 +728,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
function prepareArchiver(project, product, inputs, outputs, input, output) {
var args = archiverFlags(project, product, input, outputs);
var archiverPath = product.cpp.archiverPath;
- var cmd = new Command(archiverPath, args)
+ var cmd = new Command(archiverPath, args);
cmd.description = "linking " + output.fileName;
cmd.highlight = "linker";
filterStdOutput(cmd);
diff --git a/share/qbs/modules/cpp/keil.qbs b/share/qbs/modules/cpp/keil.qbs
index 10bc39e12..2d29112cd 100644
--- a/share/qbs/modules/cpp/keil.qbs
+++ b/share/qbs/modules/cpp/keil.qbs
@@ -78,85 +78,26 @@ CppModule {
property string cCompilerName: compilerName
property string cxxCompilerName: compilerName
- compilerName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "c51" + compilerExtension;
- case "arm":
- return "armcc" + compilerExtension;
- }
- }
+ compilerName: KEIL.compilerName(qbs) + compilerExtension
compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
- assemblerName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "a51" + compilerExtension;
- case "arm":
- return "armasm" + compilerExtension;
- }
- }
+ assemblerName: KEIL.assemblerName(qbs) + compilerExtension
assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
- linkerName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "bl51" + compilerExtension;
- case "arm":
- return "armlink" + compilerExtension;
- }
- }
+ linkerName: KEIL.linkerName(qbs) + compilerExtension
linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
- property string archiverName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "lib51" + compilerExtension;
- case "arm":
- return "armar" + compilerExtension;
- }
- }
+ property string archiverName: KEIL.archiverName(qbs) + compilerExtension
property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName)
runtimeLibrary: "static"
- staticLibrarySuffix: {
- switch (qbs.architecture) {
- case "mcs51":
- return ".lib";
- case "arm":
- return ".lib";
- }
- }
+ staticLibrarySuffix: KEIL.staticLibrarySuffix(qbs)
+ executableSuffix: KEIL.executableSuffix(qbs)
- executableSuffix: {
- switch (qbs.architecture) {
- case "mcs51":
- return ".abs";
- case "arm":
- return ".axf";
- }
- }
+ property string objectSuffix: KEIL.objectSuffix(qbs)
- property string objectSuffix: {
- switch (qbs.architecture) {
- case "mcs51":
- return ".obj";
- case "arm":
- return ".o";
- }
- }
-
- imageFormat: {
- switch (qbs.architecture) {
- case "mcs51":
- // Keil OMF51 or OMF2 Object Module Format (which is an
- // extension of the original Intel OMF51).
- return "omf";
- case "arm":
- return "elf";
- }
- }
+ imageFormat: KEIL.imageFormat(qbs)
enableExceptions: false
enableRtti: false
@@ -171,18 +112,11 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: KEIL.prepareAssembler.apply(KEIL, arguments);
- }
-
- FileTagger {
- condition: qbs.architecture === "mcs51";
- patterns: ["*.a51", "*.A51"]
- fileTags: ["asm"]
+ prepare: KEIL.prepareAssembler.apply(KEIL, arguments)
}
FileTagger {
- condition: qbs.architecture === "arm";
- patterns: "*.s"
+ patterns: ["*.s", "*.a51", ".asm"]
fileTags: ["asm"]
}
@@ -197,7 +131,7 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: KEIL.prepareCompiler.apply(KEIL, arguments);
+ prepare: KEIL.prepareCompiler.apply(KEIL, arguments)
}
Rule {
@@ -230,7 +164,7 @@ CppModule {
return artifacts;
}
- prepare:KEIL.prepareLinker.apply(KEIL, arguments);
+ prepare: KEIL.prepareLinker.apply(KEIL, arguments)
}
Rule {
@@ -246,6 +180,6 @@ CppModule {
PathTools.staticLibraryFilePath(product))
}
- prepare: KEIL.prepareArchiver.apply(KEIL, arguments);
+ prepare: KEIL.prepareArchiver.apply(KEIL, arguments)
}
}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index 9deffa064..02facf30a 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -542,3 +542,46 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
return commands;
}
+function createRcCommand(binary, input, output, logo) {
+ var platformDefines = input.cpp.platformDefines;
+ var defines = input.cpp.defines;
+ var includePaths = input.cpp.includePaths;
+ var systemIncludePaths = input.cpp.systemIncludePaths;
+
+ var args = [];
+ if (logo === "can-suppress-logo")
+ args.push("/nologo");
+ for (i in platformDefines) {
+ args.push("/d");
+ args.push(platformDefines[i]);
+ }
+ for (i in defines) {
+ args.push("/d");
+ args.push(defines[i]);
+ }
+ for (i in includePaths) {
+ args.push("/I");
+ args.push(includePaths[i]);
+ }
+ for (i in systemIncludePaths) {
+ args.push("/I");
+ args.push(systemIncludePaths[i]);
+ }
+ args = args.concat(["/FO", output.filePath, input.filePath]);
+ var cmd = new Command(binary, args);
+ cmd.description = 'compiling ' + input.fileName;
+ cmd.highlight = 'compiler';
+ cmd.jobPool = "compiler";
+
+ if (logo === "always-shows-logo") {
+ // Remove the first two lines of stdout. That's the logo.
+ cmd.stdoutFilterFunction = function(output) {
+ var idx = 0;
+ for (var i = 0; i < 3; ++i)
+ idx = output.indexOf('\n', idx + 1);
+ return output.substr(idx + 1);
+ }
+ }
+
+ return cmd;
+}
diff --git a/share/qbs/modules/cpp/sdcc.js b/share/qbs/modules/cpp/sdcc.js
index 2f148d2c2..70efa83e8 100644
--- a/share/qbs/modules/cpp/sdcc.js
+++ b/share/qbs/modules/cpp/sdcc.js
@@ -39,23 +39,62 @@ var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");
+function compilerName(qbs) {
+ return "sdcc";
+}
+
+function assemblerName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "sdas8051";
+ case "stm8":
+ return "sdasstm8";
+ }
+ throw "Unable to deduce assembler name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function linkerName(qbs) {
+ switch (qbs.architecture) {
+ case "mcs51":
+ return "sdld";
+ case "stm8":
+ return "sdldstm8";
+ }
+ throw "Unable to deduce linker name for unsupported architecture: '"
+ + qbs.architecture + "'";
+}
+
+function archiverName(qbs) {
+ return "sdcclib";
+}
+
function targetArchitectureFlag(architecture) {
if (architecture === "mcs51")
return "-mmcs51";
+ if (architecture === "stm8")
+ return "-mstm8";
}
-function guessArchitecture(macros)
-{
+function guessArchitecture(macros) {
if (macros["__SDCC_mcs51"] === "1")
return "mcs51";
+ if (macros["__SDCC_stm8"] === "1")
+ return "stm8";
}
-function guessEndianness(macros)
-{
+function guessEndianness(macros) {
// SDCC stores numbers in little-endian format.
return "little";
}
+function guessVersion(macros) {
+ return { major: parseInt(macros["__SDCC_VERSION_MAJOR"], 10),
+ minor: parseInt(macros["__SDCC_VERSION_MINOR"], 10),
+ patch: parseInt(macros["__SDCC_VERSION_PATCH"], 10),
+ found: macros["SDCC"] }
+}
+
function dumpMacros(compilerFilePath, architecture) {
var tempDir = new TemporaryDir();
var fakeIn = new TextFile(tempDir.path() + "/empty-source.c", TextFile.WriteOnly);
@@ -184,39 +223,14 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
var args = [];
+ // Input.
args.push(input.filePath);
+
+ // Output.
args.push("-c");
args.push("-o", output.filePath);
- switch (input.cpp.optimization) {
- case "small":
- args.push("--opt-code-size");
- break;
- case "fast":
- args.push("--opt-code-speed");
- break;
- case "none":
- // SDCC has not option to disable the optimization.
- break;
- }
-
- if (input.cpp.debugInformation)
- args.push("--debug");
-
- var warnings = input.cpp.warningLevel;
- if (warnings === "none")
- args.push("--less-pedantic");
-
- if (input.cpp.treatWarningsAsErrors)
- args.push("--Werror");
-
- if (tag === "c") {
- if (input.cpp.cLanguageVersion === "c89")
- args.push("--std-c89");
- else if (input.cpp.cLanguageVersion === "c11")
- args.push("--std-c11");
- }
-
+ // Defines.
var allDefines = [];
var platformDefines = input.cpp.platformDefines;
if (platformDefines)
@@ -226,6 +240,7 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
allDefines = allDefines.uniqueConcat(defines);
args = args.concat(allDefines.map(function(define) { return "-D" + define }));
+ // Includes.
var allIncludePaths = [];
var includePaths = input.cpp.includePaths;
if (includePaths)
@@ -238,6 +253,49 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) {
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
+ var targetFlag = targetArchitectureFlag(input.cpp.architecture);
+ if (targetFlag)
+ args.push(targetFlag);
+
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("--debug");
+
+ // Optimization level flags.
+ switch (input.cpp.optimization) {
+ case "small":
+ args.push("--opt-code-size");
+ break;
+ case "fast":
+ args.push("--opt-code-speed");
+ break;
+ case "none":
+ // SDCC has not option to disable the optimization.
+ break;
+ }
+
+ // Warning level flags.
+ if (input.cpp.warningLevel === "none")
+ args.push("--less-pedantic");
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("--Werror");
+
+ // C language version flags.
+ if (tag === "c") {
+ var knownValues = ["c11", "c89"];
+ var cLanguageVersion = Cpp.languageVersion(
+ input.cpp.cLanguageVersion, knownValues, "C");
+ switch (cLanguageVersion) {
+ case "c89":
+ args.push("--std-c89");
+ break;
+ case "c11":
+ args.push("--std-c11");
+ break;
+ }
+ }
+
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
ModUtils.moduleProperty(input, "flags"),
ModUtils.moduleProperty(input, "platformFlags", tag),
@@ -252,9 +310,14 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));
var args = [];
+
+ // Input.
args.push(input.filePath);
+
+ // Output.
args.push("-o", output.filePath);
+ // Includes.
var allIncludePaths = [];
var systemIncludePaths = input.cpp.systemIncludePaths;
if (systemIncludePaths)
@@ -264,6 +327,7 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));
+ // Misc flags.
args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
ModUtils.moduleProperty(input, "flags", tag),
ModUtils.moduleProperty(input, "driverFlags", tag));
@@ -273,6 +337,11 @@ function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
function linkerFlags(project, product, input, outputs) {
var args = [];
+ // Target MCU flag.
+ var targetFlag = targetArchitectureFlag(product.cpp.architecture);
+ if (targetFlag)
+ args.push(targetFlag);
+
var allLibraryPaths = [];
var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
@@ -285,6 +354,7 @@ function linkerFlags(project, product, input, outputs) {
var escapableLinkerFlags = [];
+ // Map file generation flag.
if (product.cpp.generateMapFile)
escapableLinkerFlags.push("-m");
@@ -295,38 +365,45 @@ function linkerFlags(project, product, input, outputs) {
var useCompilerDriver = useCompilerDriverLinker(product);
if (useCompilerDriver) {
+ // Output.
args.push("-o", outputs.application[0].filePath);
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Library paths.
args = args.concat(allLibraryPaths.map(function(path) { return "-L" + path }));
+ // Linker scripts.
var scripts = inputs.linkerscript
? inputs.linkerscript.map(function(scr) { return "-f" + scr.filePath; }) : [];
if (scripts)
Array.prototype.push.apply(escapableLinkerFlags, scripts);
} else {
+ // Output.
args.push(outputs.application[0].filePath);
+ // Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
+ // Library paths.
args = args.concat(allLibraryPaths.map(function(path) { return "-k" + path }));
- var scripts = inputs.linkerscript;
- if (scripts) {
- // Note: We need to split the '-f' and the file path to separate
- // lines; otherwise the linking fails.
- scripts.forEach(function(scr) {
- escapableLinkerFlags.push("-f", scr.filePath);
- });
- }
+ // Linker scripts.
+ // Note: We need to split the '-f' and the file path to separate
+ // lines; otherwise the linking fails.
+ inputs.linkerscript.forEach(function(scr) {
+ escapableLinkerFlags.push("-f", scr.filePath);
+ });
}
+ // Library dependencies.
if (libraryDependencies)
args = args.concat(libraryDependencies.map(function(dep) { return "-l" + dep.filePath }));
+ // Misc flags.
var escapedLinkerFlags = escapeLinkerFlags(product, escapableLinkerFlags);
if (escapedLinkerFlags)
Array.prototype.push.apply(args, escapedLinkerFlags);
@@ -345,7 +422,7 @@ function archiverFlags(project, product, input, outputs) {
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
var compilerPath = input.cpp.compilerPath;
- var cmd = new Command(compilerPath, args)
+ var cmd = new Command(compilerPath, args);
cmd.description = "compiling " + input.fileName;
cmd.highlight = "compiler";
return [cmd];
@@ -354,7 +431,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
var assemblerPath = input.cpp.assemblerPath;
- var cmd = new Command(assemblerPath, args)
+ var cmd = new Command(assemblerPath, args);
cmd.description = "assembling " + input.fileName;
cmd.highlight = "compiler";
return [cmd];
@@ -364,7 +441,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
var primaryOutput = outputs.application[0];
var args = linkerFlags(project, product, input, outputs);
var linkerPath = effectiveLinkerPath(product);
- var cmd = new Command(linkerPath, args)
+ var cmd = new Command(linkerPath, args);
cmd.description = "linking " + primaryOutput.fileName;
cmd.highlight = "linker";
return [cmd];
@@ -373,7 +450,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
function prepareArchiver(project, product, inputs, outputs, input, output) {
var args = archiverFlags(project, product, input, outputs);
var archiverPath = product.cpp.archiverPath;
- var cmd = new Command(archiverPath, args)
+ var cmd = new Command(archiverPath, args);
cmd.description = "linking " + output.fileName;
cmd.highlight = "linker";
return [cmd];
diff --git a/share/qbs/modules/cpp/sdcc.qbs b/share/qbs/modules/cpp/sdcc.qbs
index a0d795b40..119a0ba92 100644
--- a/share/qbs/modules/cpp/sdcc.qbs
+++ b/share/qbs/modules/cpp/sdcc.qbs
@@ -80,26 +80,16 @@ CppModule {
property string linkerMode: "automatic"
- compilerName: "sdcc" + compilerExtension
+ compilerName: SDCC.compilerName(qbs) + compilerExtension
compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
- assemblerName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "sdas8051" + compilerExtension;
- }
- }
+ assemblerName: SDCC.assemblerName(qbs) + compilerExtension
assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
- linkerName: {
- switch (qbs.architecture) {
- case "mcs51":
- return "sdld" + compilerExtension;
- }
- }
+ linkerName: SDCC.linkerName(qbs) + compilerExtension
linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
- property string archiverName: "sdcclib" + compilerExtension
+ property string archiverName: SDCC.archiverName(qbs) + compilerExtension
property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName)
runtimeLibrary: "static"
@@ -124,7 +114,7 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: SDCC.prepareAssembler.apply(SDCC, arguments);
+ prepare: SDCC.prepareAssembler.apply(SDCC, arguments)
}
FileTagger {
@@ -150,7 +140,7 @@ CppModule {
+ input.fileName + input.cpp.objectSuffix
}
- prepare: SDCC.prepareCompiler.apply(SDCC, arguments);
+ prepare: SDCC.prepareCompiler.apply(SDCC, arguments)
}
Rule {
@@ -184,7 +174,7 @@ CppModule {
return artifacts;
}
- prepare:SDCC.prepareLinker.apply(SDCC, arguments);
+ prepare: SDCC.prepareLinker.apply(SDCC, arguments)
}
Rule {
@@ -200,6 +190,6 @@ CppModule {
PathTools.staticLibraryFilePath(product))
}
- prepare: SDCC.prepareArchiver.apply(SDCC, arguments);
+ prepare: SDCC.prepareArchiver.apply(SDCC, arguments)
}
}
diff --git a/share/qbs/modules/cpp/windows-clang-mingw.qbs b/share/qbs/modules/cpp/windows-clang-mingw.qbs
new file mode 100644
index 000000000..8389dbf2e
--- /dev/null
+++ b/share/qbs/modules/cpp/windows-clang-mingw.qbs
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** 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.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "msvc.js" as MSVC
+
+import "setuprunenv.js" as SetupRunEnv
+
+MingwBaseModule {
+ condition: qbs.targetOS.contains("windows") &&
+ qbs.toolchain && qbs.toolchain.contains("clang")
+ priority: 0
+
+ // llvm-as and llvm-objopy are not shipped with the official binaries on Windows at the
+ // moment (8.0). We fall back to using the mingw versions in that case.
+ assemblerName: "llvm-as" + compilerExtension
+ assemblerPath: {
+ if (File.exists(base))
+ return base;
+ if (qbs.sysroot)
+ return FileInfo.joinPaths(qbs.sysroot, "bin", "as" + compilerExtension);
+ }
+ objcopyName: "llvm-objcopy" + compilerExtension
+ objcopyPath: {
+ if (File.exists(base))
+ return base;
+ if (qbs.sysroot)
+ return FileInfo.joinPaths(qbs.sysroot, "bin", "objcopy" + compilerExtension);
+ }
+
+ archiverName: "llvm-ar" + compilerExtension
+
+ linkerVariant: "lld"
+ targetVendor: "pc"
+ targetSystem: "windows"
+ targetAbi: "gnu"
+ property string rcFilePath: FileInfo.joinPaths(toolchainInstallPath,
+ "llvm-rc" + compilerExtension)
+
+ setupBuildEnvironment: {
+ if (product.qbs.hostOS.contains("windows") && product.qbs.sysroot) {
+ var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true);
+ v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin"));
+ v.set();
+ }
+ }
+
+ setupRunEnvironment: {
+ if (product.qbs.hostOS.contains("windows") && product.qbs.sysroot) {
+ var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true);
+ v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin"));
+ v.set();
+ SetupRunEnv.setupRunEnvironment(product, config);
+ }
+ }
+
+ Rule {
+ inputs: ["rc"]
+ auxiliaryInputs: ["hpp"]
+
+ Artifact {
+ filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".res"
+ fileTags: ["obj"]
+ }
+
+ prepare: MSVC.createRcCommand(product.cpp.rcFilePath, input, output);
+ }
+}
diff --git a/share/qbs/modules/cpp/windows-mingw.qbs b/share/qbs/modules/cpp/windows-mingw.qbs
index 27382742f..fe9fd4bf8 100644
--- a/share/qbs/modules/cpp/windows-mingw.qbs
+++ b/share/qbs/modules/cpp/windows-mingw.qbs
@@ -28,39 +28,28 @@
**
****************************************************************************/
+import qbs.File
+import qbs.FileInfo
import qbs.ModUtils
-import qbs.TextFile
import qbs.Utilities
-import qbs.WindowsUtils
import "setuprunenv.js" as SetupRunEnv
-GenericGCC {
+MingwBaseModule {
condition: qbs.targetOS.contains("windows") &&
qbs.toolchain && qbs.toolchain.contains("mingw")
priority: 0
- staticLibraryPrefix: "lib"
- staticLibrarySuffix: ".a"
- dynamicLibrarySuffix: ".dll"
- executableSuffix: ".exe"
- debugInfoSuffix: ".debug"
- imageFormat: "pe"
- windowsApiCharacterSet: "unicode"
- platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
- .concat("WIN32")
+
probeEnv: buildEnv
- Properties {
- condition: product.multiplexByQbsProperties.contains("buildVariants")
- && qbs.buildVariants && qbs.buildVariants.length > 1
- && qbs.buildVariant !== "release"
- && product.type.containsAny(["staticlibrary", "dynamiclibrary"])
- variantSuffix: "d"
+ property string windresName: "windres" + compilerExtension
+ property path windresPath: {
+ var filePath = toolchainPrefix + windresName;
+ if (!File.exists(filePath))
+ filePath = FileInfo.joinPaths(toolchainInstallPath, windresName);
+ return filePath;
}
- property string windresName: 'windres'
- property path windresPath: { return toolchainPathPrefix + windresName }
-
setupBuildEnvironment: {
var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true);
v.prepend(product.cpp.toolchainInstallPath);
@@ -74,63 +63,6 @@ GenericGCC {
SetupRunEnv.setupRunEnvironment(product, config);
}
- FileTagger {
- patterns: ["*.manifest"]
- fileTags: ["native.pe.manifest"]
- }
-
- Rule {
- inputs: ["native.pe.manifest"]
- multiplex: true
-
- outputFileTags: ["rc"]
- outputArtifacts: {
- if (product.type.containsAny(["application", "dynamiclibrary"])) {
- return [{
- filePath: input.completeBaseName + ".rc",
- fileTags: ["rc"]
- }];
- }
- return [];
- }
-
- prepare: {
- var inputList = inputs["native.pe.manifest"];
- // TODO: Emulate manifest merging like Microsoft's mt.exe tool does
- if (inputList.length !== 1) {
- throw("The MinGW toolchain does not support manifest merging; " +
- "you may only specify a single manifest file to embed into your assembly.");
- }
-
- var cmd = new JavaScriptCommand();
- cmd.silent = true;
- cmd.productType = product.type;
- cmd.inputFilePath = inputList[0].filePath;
- cmd.outputFilePath = output.filePath;
- cmd.sourceCode = function() {
- var tf;
- try {
- tf = new TextFile(outputFilePath, TextFile.WriteOnly);
- if (productType.contains("application"))
- tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID
- else if (productType.contains("dynamiclibrary"))
- tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID
- tf.write("24 "); // RT_MANIFEST
- tf.writeLine(Utilities.cStringQuote(inputFilePath));
- } finally {
- if (tf)
- tf.close();
- }
- };
- return [cmd];
- }
- }
-
- FileTagger {
- patterns: ["*.rc"]
- fileTags: ["rc"]
- }
-
Rule {
inputs: ["rc"]
auxiliaryInputs: ["hpp"]
diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs
index d36daa99f..ae105abe2 100644
--- a/share/qbs/modules/cpp/windows-msvc-base.qbs
+++ b/share/qbs/modules/cpp/windows-msvc-base.qbs
@@ -291,50 +291,10 @@ CppModule {
}
prepare: {
- var platformDefines = input.cpp.platformDefines;
- var defines = input.cpp.defines;
- var includePaths = input.cpp.includePaths;
- var systemIncludePaths = input.cpp.systemIncludePaths;
- var args = [];
- var i;
- var hasNoLogo = product.cpp.compilerVersionMajor >= 16; // 2010
- if (hasNoLogo)
- args.push("/nologo");
-
- for (i in platformDefines) {
- args.push('/d');
- args.push(platformDefines[i]);
- }
- for (i in defines) {
- args.push('/d');
- args.push(defines[i]);
- }
- for (i in includePaths) {
- args.push('/i');
- args.push(includePaths[i]);
- }
- for (i in systemIncludePaths) {
- args.push('/i');
- args.push(systemIncludePaths[i]);
- }
-
- args = args.concat(['/fo', output.filePath, input.filePath]);
- var cmd = new Command('rc', args);
- cmd.description = 'compiling ' + input.fileName;
- cmd.highlight = 'compiler';
- cmd.jobPool = "compiler";
-
- if (!hasNoLogo) {
- // Remove the first two lines of stdout. That's the logo.
- cmd.stdoutFilterFunction = function(output) {
- var idx = 0;
- for (var i = 0; i < 3; ++i)
- idx = output.indexOf('\n', idx + 1);
- return output.substr(idx + 1);
- }
- }
-
- return cmd;
+ // From MSVC 2010 on, the logo can be suppressed.
+ var logo = product.cpp.compilerVersionMajor >= 16
+ ? "can-suppress-logo" : "always-shows-logo";
+ return MSVC.createRcCommand("rc", input, output, logo);
}
}
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..0b93aff49
--- /dev/null
+++ b/src/app/qbs/session.cpp
@@ -0,0 +1,751 @@
+/****************************************************************************
+**
+** 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>
+
+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()
+{
+ 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..b6b755b70
--- /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("generateMapFile"))
+ ? 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..9fdb57a5a
--- /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("generateMapFile"))
+ ? 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..32b734d4a
--- /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("generateMapFile"))
+ ? 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});
+ // Add 'OutputFile' item (Output filename).
+ addOptionsGroup(QByteArrayLiteral("OutputFile"),
+ {opts.outputFile});
+}
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.h
new file mode 100644
index 000000000..9da8d3445
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430archiversettingsgroup_v7.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_IAREWMSP430ARCHIVERSETTINGSGROUP_V7_H
+#define QBS_IAREWMSP430ARCHIVERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430ArchiverSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Msp430ArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430ARCHIVERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.cpp
new file mode 100644
index 000000000..51108e63c
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** 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 "msp430assemblersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+constexpr int kAssemblerArchiveVersion = 5;
+constexpr int kAssemblerDataVersion = 14;
+
+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;
+ }
+
+ int enableSymbolsCaseSensitive = 1;
+ int enableMultibyteSupport = 0;
+
+ MacroQuoteCharacter macroQuoteCharacter = AngleBracketsQuote;
+};
+
+// 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
+
+//Msp430AssemblerSettingsGroup
+
+Msp430AssemblerSettingsGroup::Msp430AssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("A430"));
+ 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 Msp430AssemblerSettingsGroup::buildLanguagePage(
+ const ProductData &qbsProduct)
+{
+ const LanguagePageOptions opts(qbsProduct);
+ // Add 'ACaseSensitivity' item (User symbols are case sensitive).
+ addOptionsGroup(QByteArrayLiteral("ACaseSensitivity"),
+ {opts.enableSymbolsCaseSensitive});
+ // Add 'AMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("AMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+ // Add 'MacroChars' item (Macro quote characters: ()/[]/{}/<>).
+ addOptionsGroup(QByteArrayLiteral("MacroChars"),
+ {opts.macroQuoteCharacter});
+}
+
+void Msp430AssemblerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'ADebug' item (Generate debug information).
+ addOptionsGroup(QByteArrayLiteral("ADebug"),
+ {opts.debugInfo});
+}
+
+void Msp430AssemblerSettingsGroup::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 Msp430AssemblerSettingsGroup::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 msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.h
new file mode 100644
index 000000000..97a59f4cd
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430assemblersettingsgroup_v7.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_IAREWMSP430ASSEMBLERSETTINGSGROUP_V7_H
+#define QBS_IAREWMSP430ASSEMBLERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430AssemblerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Msp430AssemblerSettingsGroup(
+ 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 msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430ASSEMBLERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.cpp
new file mode 100644
index 000000000..bd80cdd7f
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_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 "msp430archiversettingsgroup_v7.h"
+#include "msp430assemblersettingsgroup_v7.h"
+#include "msp430buildconfigurationgroup_v7.h"
+#include "msp430compilersettingsgroup_v7.h"
+#include "msp430generalsettingsgroup_v7.h"
+#include "msp430linkersettingsgroup_v7.h"
+
+#include "../../iarewtoolchainpropertygroup.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+Msp430BuildConfigurationGroup::Msp430BuildConfigurationGroup(
+ 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>("MSP430");
+
+ // Append debug info item.
+ const int debugBuild = gen::utils::debugInformation(qbsProduct);
+ appendProperty("debug", debugBuild);
+
+ // Append settings group items.
+ appendChild<Msp430ArchiverSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Msp430AssemblerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Msp430CompilerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Msp430GeneralSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Msp430LinkerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+}
+
+bool Msp430BuildConfigurationGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Msp430
+ && version.majorVersion() == 7;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+Msp430BuildConfigurationGroupFactory::create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const
+{
+ const auto group = new Msp430BuildConfigurationGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<Msp430BuildConfigurationGroup>(group);
+}
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_v7.h
new file mode 100644
index 000000000..ba0404c0b
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430buildconfigurationgroup_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_IAREWMSP430BUILDCONFIGURATIONGROUP_V7_H
+#define QBS_IAREWMSP430BUILDCONFIGURATIONGROUP_V7_H
+
+#include <generators/generatorutils.h>
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430BuildConfigurationGroup final
+ : public gen::xml::PropertyGroup
+{
+private:
+ explicit Msp430BuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+ friend class Msp430BuildConfigurationGroupFactory;
+};
+
+class Msp430BuildConfigurationGroupFactory 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 msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430BUILDCONFIGURATIONGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.cpp
new file mode 100644
index 000000000..5728578b9
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.cpp
@@ -0,0 +1,486 @@
+/****************************************************************************
+**
+** 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 "msp430compilersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+constexpr int kCompilerArchiveVersion = 4;
+constexpr int kCompilerDataVersion = 38;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// 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 = C99LanguageDialect;
+ 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"));
+ guardCalls = flags.contains(
+ QLatin1String("--guard_calls"));
+ }
+
+ PlainCharacter plainCharacter = UnsignedCharacter;
+ FloatingPointSemantic floatingPointSemantic = StrictSemantic;
+ int enableMultibyteSupport = 0;
+ int guardCalls = 0;
+};
+
+// Code page options.
+
+struct CodePageOptions final
+{
+ enum Utilization {
+ UtilizationNormalUse,
+ UtilizationRegVarVariables,
+ UtilizationNotUsed
+ };
+
+ explicit CodePageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ // Detect R4 utilization.
+ if (flags.contains(QLatin1String("--lock_r4")))
+ r4utilization = UtilizationNotUsed;
+ else if (flags.contains(QLatin1String("--regvar_r4")))
+ r4utilization = UtilizationRegVarVariables;
+ // Detect R5 utilization.
+ if (flags.contains(QLatin1String("--lock_r5")))
+ r5utilization = UtilizationNotUsed;
+ else if (flags.contains(QLatin1String("--regvar_r54")))
+ r5utilization = UtilizationRegVarVariables;
+ // Detect reduce stack usage.
+ reduceStackUsage = flags.contains(
+ QLatin1String("--reduce_stack_usage"));
+ // Detect 20-bit context save on interrupt.
+ save20BitContextOnInterrupt = flags.contains(
+ QLatin1String("--save_reg20"));
+ }
+
+ Utilization r4utilization = UtilizationNormalUse;
+ Utilization r5utilization = UtilizationNormalUse;
+ int reduceStackUsage = 0;
+ int save20BitContextOnInterrupt = 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);
+
+ disableSizeConstraints = flags.contains(
+ QLatin1String("--no_size_constraints"));
+
+ 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"));
+ }
+
+ Strategy optimizationStrategy = StrategyBalanced;
+ Level optimizationLevel = LevelNone;
+ LevelSlave optimizationLevelSlave = LevelSlave0;
+ // Separate "no size constraints" checkbox.
+ int disableSizeConstraints = 0;
+
+ // Five 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.
+};
+
+// 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;
+};
+
+} // namespace
+
+//Msp430CompilerSettingsGroup
+
+Msp430CompilerSettingsGroup::Msp430CompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ICC430"));
+ 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 Msp430CompilerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'CCDebugInfo' item (Generate debug info).
+ addOptionsGroup(QByteArrayLiteral("CCDebugInfo"),
+ {opts.debugInfo});
+}
+
+void Msp430CompilerSettingsGroup::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 'IccRequirePrototypes' item (Require prototypes).
+ addOptionsGroup(QByteArrayLiteral("CCRequirePrototypes"),
+ {opts.requirePrototypes});
+ // Add 'IccStaticDestr' item (Destroy static objects).
+ addOptionsGroup(QByteArrayLiteral("IccStaticDestr"),
+ {opts.destroyStaticObjects});
+}
+
+void Msp430CompilerSettingsGroup::buildLanguageTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LanguageTwoPageOptions opts(qbsProduct);
+ // Add 'IccCharIs' 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 'IccMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("CCMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+ // Add 'CCGuardCalls' and 'OCGuardCallsSlave' item (Guard calls).
+ addOptionsGroup(QByteArrayLiteral("CCGuardCalls"),
+ {opts.guardCalls});
+}
+
+void Msp430CompilerSettingsGroup::buildCodePage(
+ const ProductData &qbsProduct)
+{
+ const CodePageOptions opts(qbsProduct);
+ // Add 'OCCR4Utilize' item
+ // (R4 utilization: normal/regvar/disabled).
+ addOptionsGroup(QByteArrayLiteral("OCCR4Utilize"),
+ {opts.r4utilization});
+ // Add 'OCCR5Utilize' item
+ // (R5 utilization: normal/regvar/disabled).
+ addOptionsGroup(QByteArrayLiteral("OCCR5Utilize"),
+ {opts.r5utilization});
+ // Add 'ReduceStack' item
+ // (Reduce stack usage).
+ addOptionsGroup(QByteArrayLiteral("ReduceStack"),
+ {opts.reduceStackUsage});
+ // Add 'Save20bit' item
+ // (20-bit context save on interrupt).
+ addOptionsGroup(QByteArrayLiteral("Save20bit"),
+ {opts.save20BitContextOnInterrupt});
+}
+
+void Msp430CompilerSettingsGroup::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 'CCOptimizationNoSizeConstraints' item (no size constraints).
+ addOptionsGroup(QByteArrayLiteral("CCOptimizationNoSizeConstraints"),
+ {opts.disableSizeConstraints});
+
+ // Add 'CCAllowList' item
+ // (Enabled transformations: 5 check boxes).
+ const QString bitflags = QStringLiteral("%1%2%3%4%5%6")
+ .arg(opts.enableCommonSubexpressionElimination)
+ .arg(opts.enableLoopUnroll)
+ .arg(opts.enableFunctionInlining)
+ .arg(opts.enableCodeMotion)
+ .arg(opts.enableTypeBasedAliasAnalysis);
+ addOptionsGroup(QByteArrayLiteral("CCAllowList"),
+ {bitflags});
+}
+
+void Msp430CompilerSettingsGroup::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 Msp430CompilerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'CCDiagWarnAreErr' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("CCDiagWarnAreErr"),
+ {opts.warningsAsErrors});
+}
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.h
new file mode 100644
index 000000000..498100881
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430compilersettingsgroup_v7.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_IAREWMSP430COMPILERSETTINGSGROUP_V7_H
+#define QBS_IAREWMSP430COMPILERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430CompilerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Msp430CompilerSettingsGroup(
+ 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 buildCodePage(const ProductData &qbsProduct);
+ void buildOptimizationsPage(const ProductData &qbsProduct);
+ void buildPreprocessorPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildDiagnosticsPage(const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430COMPILERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.cpp
new file mode 100644
index 000000000..ac1c475d1
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.cpp
@@ -0,0 +1,483 @@
+/****************************************************************************
+**
+** 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 "msp430generalsettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+constexpr int kGeneralArchiveVersion = 21;
+constexpr int kGeneralDataVersion = 34;
+
+namespace {
+
+// Target page options.
+
+struct TargetPageOptions final
+{
+ enum CodeModel {
+ SmallCodeModel,
+ LargeCodeModel
+ };
+
+ enum DataModel {
+ SmallDataModel,
+ MediumDataModel,
+ LargeDataModel
+ };
+
+ enum FloatingPointDoubleSize {
+ DoubleSize32Bits,
+ DoubleSize64Bits
+ };
+
+ enum HardwareMultiplierType {
+ AllowDirectAccessMultiplier,
+ UseOnlyLibraryCallsMultiplier
+ };
+
+ explicit TargetPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags")});
+ // Detect target code model.
+ const QString codeModelValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--code_model"));
+ if (codeModelValue == QLatin1String("small"))
+ codeModel = TargetPageOptions::SmallCodeModel;
+ else if (codeModelValue == QLatin1String("large"))
+ codeModel = TargetPageOptions::LargeCodeModel;
+ // Detect target data model.
+ const QString dataModelValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--data_model"));
+ if (dataModelValue == QLatin1String("small"))
+ dataModel = TargetPageOptions::SmallDataModel;
+ else if (dataModelValue == QLatin1String("medium"))
+ dataModel = TargetPageOptions::MediumDataModel;
+ else if (dataModelValue == QLatin1String("large"))
+ dataModel = TargetPageOptions::LargeDataModel;
+ // Detect floating point double size.
+ const int doubleSize = IarewUtils::flagValue(
+ flags, QStringLiteral("--double")).toInt();
+ if (doubleSize == 32)
+ floatingPointDoubleSize = DoubleSize32Bits;
+ else if (doubleSize == 64)
+ floatingPointDoubleSize = DoubleSize64Bits;
+ // Detect hardware multiplier.
+ const QString multiplier = IarewUtils::flagValue(
+ flags, QStringLiteral("--multiplier"));
+ enableHardwareMultiplier = (multiplier.compare(QLatin1String("16")) == 0
+ || multiplier.compare(QLatin1String("16s")) == 0
+ || multiplier.compare(QLatin1String("32")) == 0);
+ // Detect code and read-only data position-independence.
+ enableRopi = flags.contains(QLatin1String("--ropi"));
+ // No dynamic read-write initialization.
+ disableDynamicReadWriteInitialization = flags.contains(
+ QLatin1String("--no_rw_dynamic_init"));
+
+ // Detect target device name.
+ detectDeviceMenu(qbsProduct);
+ }
+
+ void detectDeviceMenu(const ProductData &qbsProduct)
+ {
+ 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) {
+ 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))
+ continue;
+
+ const QFileInfo configInfo(fullConfigPath);
+ const QString configBase = configInfo.baseName();
+ if (!configBase.startsWith(QLatin1String("lnk")))
+ continue;
+
+ // Remove 'lnk' prefix.
+ const QString deviceName = QStringLiteral("MSP%1")
+ .arg(configBase.mid(3).toUpper());
+
+ deviceMenu = QStringLiteral("%1\t%1").arg(deviceName);
+ return;
+ }
+ }
+
+ // Falling back to generic menu.
+ if (deviceMenu.isEmpty()) {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+ const QString cpuCore = IarewUtils::flagValue(flags, QStringLiteral("--core"));
+ if (cpuCore.isEmpty())
+ return;
+ deviceMenu = QStringLiteral("MSP%1\tGeneric MSP%1 device").arg(cpuCore);
+ return;
+ }
+ }
+
+ CodeModel codeModel = LargeCodeModel;
+ DataModel dataModel = SmallDataModel;
+ FloatingPointDoubleSize floatingPointDoubleSize = DoubleSize32Bits;
+ HardwareMultiplierType hardwareMultiplierType = AllowDirectAccessMultiplier;
+ int enableHardwareMultiplier = 0;
+ int enableRopi = 0;
+ int disableDynamicReadWriteInitialization = 0;
+ QString deviceMenu;
+};
+
+// 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;
+};
+
+// Library configuration page options.
+
+struct LibraryConfigPageOptions final
+{
+ enum RuntimeLibrary {
+ NoLibrary,
+ NormalDLibrary,
+ FullDLibrary,
+ CustomDLibrary,
+ CLibrary, // deprecated
+ CustomCLibrary, // deprecated
+ };
+
+ explicit LibraryConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ const QFileInfo configInfo(IarewUtils::flagValue(
+ flags,
+ QStringLiteral("--dlib_config")));
+ const QString configFilePath = configInfo.absoluteFilePath();
+
+ if (!configFilePath.isEmpty()) {
+ const QString libToolkitPath =
+ IarewUtils::libToolkitRootPath(qbsProduct);
+
+ if (configFilePath.startsWith(libToolkitPath,
+ Qt::CaseInsensitive)) {
+ if (configFilePath.endsWith(QLatin1String("n.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::NormalDLibrary;
+ } else if (configFilePath.endsWith(QLatin1String("f.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::FullDLibrary;
+ } else {
+ libraryType = LibraryConfigPageOptions::CustomDLibrary;
+ }
+
+ configPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, configFilePath);
+ } else {
+ libraryType = LibraryConfigPageOptions::CustomDLibrary;
+
+ configPath = configFilePath;
+ }
+ }
+ }
+
+ RuntimeLibrary libraryType = NormalDLibrary;
+ QString libraryPath;
+ QString configPath;
+};
+
+// Library options page options.
+
+struct LibraryOptionsPageOptions final
+{
+ enum PrintfFormatter {
+ PrintfAutoFormatter = 0,
+ PrintfFullFormatter = 1,
+ PrintfFullNoMultibytesFormatter = 2,
+ PrintfLargeFormatter = 3,
+ PrintfLargeNoMultibytesFormatter = 4,
+ PrintfSmallFormatter = 5,
+ PrintfSmallNoMultibytesFormatter = 6,
+ PrintfTinyFormatter = 7
+ };
+
+ enum ScanfFormatter {
+ ScanfAutoFormatter = 0,
+ ScanfFullFormatter = 1,
+ ScanfFullNoMultibytesFormatter = 2,
+ ScanfLargeFormatter = 3,
+ ScanfLargeNoMultibytesFormatter = 4,
+ ScanfSmallFormatter = 5,
+ ScanfSmallNoMultibytesFormatter = 6
+ };
+
+ explicit LibraryOptionsPageOptions(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->endsWith(QLatin1String("=_printf"),
+ Qt::CaseInsensitive)) {
+ const QString prop = flagIt->split(
+ QLatin1Char('=')).at(0).toLower();
+ if (prop == QLatin1String("_printffull"))
+ printfFormatter = PrintfFullFormatter;
+ else if (prop == QLatin1String("_printffullnomb"))
+ printfFormatter = PrintfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("_printflarge"))
+ printfFormatter = PrintfLargeFormatter;
+ else if (prop == QLatin1String("_printflargenomb"))
+ printfFormatter = PrintfLargeFormatter;
+ else if (prop == QLatin1String("_printfsmall"))
+ printfFormatter = PrintfSmallFormatter;
+ else if (prop == QLatin1String("_printfsmallnomb"))
+ printfFormatter = PrintfSmallNoMultibytesFormatter;
+ else if (prop == QLatin1String("_printftiny"))
+ printfFormatter = PrintfTinyFormatter;
+ } else if (flagIt->endsWith(QLatin1String("=_scanf"),
+ Qt::CaseInsensitive)) {
+ const QString prop = flagIt->split(
+ QLatin1Char('=')).at(0).toLower();
+ if (prop == QLatin1String("_scanffull"))
+ scanfFormatter = ScanfFullFormatter;
+ else if (prop == QLatin1String("_scanffullnomb"))
+ scanfFormatter = ScanfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("_scanflarge"))
+ scanfFormatter = ScanfLargeFormatter;
+ else if (prop == QLatin1String("_scanflargenomb"))
+ scanfFormatter = ScanfLargeFormatter;
+ else if (prop == QLatin1String("_scanfsmall"))
+ scanfFormatter = ScanfSmallFormatter;
+ else if (prop == QLatin1String("_scanfsmallnomb"))
+ scanfFormatter = ScanfSmallNoMultibytesFormatter;
+ }
+ }
+ }
+
+ PrintfFormatter printfFormatter = PrintfAutoFormatter;
+ ScanfFormatter scanfFormatter = ScanfAutoFormatter;
+};
+
+// Stack/heap page options.
+
+struct StackHeapPageOptions final
+{
+ explicit StackHeapPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+
+ // Detect stack size.
+ stackSize = IarewUtils::flagValue(
+ flags, QStringLiteral("-D_STACK_SIZE"));
+ if (stackSize.isEmpty())
+ stackSize = QLatin1String("A0");
+ // Detect data heap16 size.
+ data16HeapSize = IarewUtils::flagValue(
+ flags, QStringLiteral("-D_DATA16_HEAP_SIZE"));
+ if (data16HeapSize.isEmpty())
+ stackSize = QLatin1String("A0");
+ // Detect data heap20 size.
+ data20HeapSize = IarewUtils::flagValue(
+ flags, QStringLiteral("-D_DATA20_HEAP_SIZE"));
+ if (data20HeapSize.isEmpty())
+ stackSize = QLatin1String("50");
+ }
+
+ QString stackSize;
+ QString data16HeapSize;
+ QString data20HeapSize;
+};
+
+} // namespace
+
+//Msp430GeneralSettingsGroup
+
+Msp430GeneralSettingsGroup::Msp430GeneralSettingsGroup(
+ 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);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+ buildLibraryConfigPage(buildRootDirectory, qbsProduct);
+ buildLibraryOptionsPage(qbsProduct);
+ buildStackHeapPage(qbsProduct);
+}
+
+void Msp430GeneralSettingsGroup::buildTargetPage(
+ const ProductData &qbsProduct)
+{
+ const TargetPageOptions opts(qbsProduct);
+ // Add 'OGChipSelectMenu' item
+ // (Device: xxx).
+ addOptionsGroup(QByteArrayLiteral("OGChipSelectMenu"),
+ {opts.deviceMenu});
+
+ // Add 'RadioCodeModelType' item
+ // (Code model: small/large).
+ addOptionsGroup(QByteArrayLiteral("RadioCodeModelType"),
+ {opts.codeModel});
+ // Add 'RadioDataModelType' item
+ // (Data model: small/medium/large).
+ addOptionsGroup(QByteArrayLiteral("RadioDataModelType"),
+ {opts.dataModel});
+ // Add 'OGDouble' item
+ // (Floating point double size: 32/64 bits).
+ addOptionsGroup(QByteArrayLiteral("OGDouble"),
+ {opts.floatingPointDoubleSize});
+ // Add 'Hardware Multiplier' item
+ // (Hardware multiplier).
+ addOptionsGroup(QByteArrayLiteral("Hardware Multiplier"),
+ {opts.enableHardwareMultiplier});
+ if (opts.enableHardwareMultiplier) {
+ // Add 'RadioHardwareMultiplierType' item.
+ addOptionsGroup(QByteArrayLiteral("Hardware RadioHardwareMultiplierType"),
+ {opts.hardwareMultiplierType});
+ }
+ // Add 'Ropi' item.
+ // (Position independence: Code and read-only data).
+ addOptionsGroup(QByteArrayLiteral("Ropi"),
+ {opts.enableRopi});
+ // Add 'NoRwDynamicInit' item.
+ // (Position independence: No dynamic read/write initialization).
+ addOptionsGroup(QByteArrayLiteral("NoRwDynamicInit"),
+ {opts.disableDynamicReadWriteInitialization});
+}
+
+void Msp430GeneralSettingsGroup::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});
+}
+
+void Msp430GeneralSettingsGroup::buildLibraryConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GRuntimeLibSelect' and 'GRuntimeLibSelectSlave' items
+ // (Link with runtime: none/normal/full/custom).
+ 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 Msp430GeneralSettingsGroup::buildLibraryOptionsPage(
+ const ProductData &qbsProduct)
+{
+ const LibraryOptionsPageOptions opts(qbsProduct);
+ // Add 'Output variant' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("Output variant"),
+ {opts.printfFormatter});
+ // Add 'Input variant' item (Scanf formatter).
+ addOptionsGroup(QByteArrayLiteral("Input variant"),
+ {opts.scanfFormatter});
+}
+
+void Msp430GeneralSettingsGroup::buildStackHeapPage(
+ const ProductData &qbsProduct)
+{
+ const StackHeapPageOptions opts(qbsProduct);
+ // Add 'GStackHeapOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("GStackHeapOverride"),
+ {1});
+ // Add 'GStackSize2' item (Stack size).
+ addOptionsGroup(QByteArrayLiteral("GStackSize2"),
+ {opts.stackSize});
+ // Add 'GHeapSize2' item (Heap16 size).
+ addOptionsGroup(QByteArrayLiteral("GHeapSize2"),
+ {opts.data16HeapSize});
+ // Add 'GHeap20Size' item (Heap16 size).
+ addOptionsGroup(QByteArrayLiteral("GHeap20Size"),
+ {opts.data20HeapSize});
+}
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_v7.h
new file mode 100644
index 000000000..35e9e7b32
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430generalsettingsgroup_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_IAREWMSP430GENERALSETTINGSGROUP_V7_H
+#define QBS_IAREWMSP430GENERALSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430GeneralSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Msp430GeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildTargetPage(const ProductData &qbsProduct);
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildLibraryConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildLibraryOptionsPage(const ProductData &qbsProduct);
+ void buildStackHeapPage(const ProductData &qbsProduct);
+};
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430GENERALSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.cpp b/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.cpp
new file mode 100644
index 000000000..c7459dc49
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** 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 "msp430linkersettingsgroup_v7.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+constexpr int kLinkerArchiveVersion = 4;
+constexpr int kLinkerDataVersion = 30;
+
+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);
+
+ // 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);
+ }
+ }
+
+ // Library search paths.
+ librarySearchPaths = gen::utils::cppVariantModuleProperties(
+ qbsProps, {QStringLiteral("libraryPaths")});
+
+ // Entry point.
+ entryPoint = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("entryPoint"));
+ }
+
+ 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("generateMapFile"))
+ ? 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;
+};
+
+} // namespace
+
+//Msp430LinkerSettingsGroup
+
+Msp430LinkerSettingsGroup::Msp430LinkerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ 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);
+
+ // Should be called as latest stage!
+ buildExtraOptionsPage(qbsProduct);
+}
+
+void Msp430LinkerSettingsGroup::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 'xcOverrideProgramEntryLabel' item
+ // (Override default program entry).
+ addOptionsGroup(QByteArrayLiteral("xcOverrideProgramEntryLabel"),
+ {1});
+ // Add 'xcProgramEntryLabel' item (Entry point name).
+ addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabel"),
+ {opts.entryPoint});
+
+ // Add 'XIncludes' item (Entry point name).
+ addOptionsGroup(QByteArrayLiteral("XIncludes"),
+ {opts.librarySearchPaths});
+}
+
+void Msp430LinkerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+
+ // Add 'XOutOverride' item (Output file name).
+ addOptionsGroup(QByteArrayLiteral("XOutOverride"),
+ {1});
+ // Add 'OutputFile' item (Output file name).
+ addOptionsGroup(QByteArrayLiteral("OutputFile"),
+ {opts.outputFile});
+}
+
+void Msp430LinkerSettingsGroup::buildListPage(
+ const ProductData &qbsProduct)
+{
+ const ListPageOptions opts(qbsProduct);
+ // Add 'XList' item (Generate linker map file).
+ addOptionsGroup(QByteArrayLiteral("XList"),
+ {opts.generateMap});
+}
+
+void Msp430LinkerSettingsGroup::buildDefinePage(
+ const ProductData &qbsProduct)
+{
+ const DefinePageOptions opts(qbsProduct);
+ // Add 'XDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("XDefines"),
+ opts.defineSymbols);
+}
+
+void Msp430LinkerSettingsGroup::buildExtraOptionsPage(
+ const ProductData &qbsProduct)
+{
+ Q_UNUSED(qbsProduct)
+
+ if (m_extraOptions.isEmpty())
+ return;
+
+ // Add 'XExtraOptionsCheck' (Use command line options).
+ addOptionsGroup(QByteArrayLiteral("XExtraOptionsCheck"),
+ {1});
+ // Add 'XExtraOptions' item (Command line options).
+ addOptionsGroup(QByteArrayLiteral("XExtraOptions"),
+ m_extraOptions);
+}
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.h b/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.h
new file mode 100644
index 000000000..2b6f11514
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/msp430/msp430linkersettingsgroup_v7.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_IAREWMSP430LINKERSETTINGSGROUP_V7_H
+#define QBS_IAREWMSP430LINKERSETTINGSGROUP_V7_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace msp430 {
+namespace v7 {
+
+class Msp430LinkerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Msp430LinkerSettingsGroup(
+ 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 buildExtraOptionsPage(const ProductData &qbsProduct);
+
+ QVariantList m_extraOptions;
+};
+
+} // namespace v7
+} // namespace msp430
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWMSP430LINKERSETTINGSGROUP_V7_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.cpp
new file mode 100644
index 000000000..b08b70bc5
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.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 "stm8archiversettingsgroup_v3.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+constexpr int kArchiverArchiveVersion = 3;
+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
+
+// Stm8ArchiverSettingsGroup
+
+Stm8ArchiverSettingsGroup::Stm8ArchiverSettingsGroup(
+ 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 Stm8ArchiverSettingsGroup::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 v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.h
new file mode 100644
index 000000000..754add3cb
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8archiversettingsgroup_v3.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_IAREWSTM8ARCHIVERSETTINGSGROUP_V3_H
+#define QBS_IAREWSTM8ARCHIVERSETTINGSGROUP_V3_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8ArchiverSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Stm8ArchiverSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+};
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8ARCHIVERSETTINGSGROUP_V3_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.cpp
new file mode 100644
index 000000000..396ee7db2
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** 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 "stm8assemblersettingsgroup_v3.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+constexpr int kAssemblerArchiveVersion = 3;
+constexpr int kAssemblerDataVersion = 2;
+
+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("--case_insensitive"));
+ enableMultibyteSupport = flags.contains(
+ QLatin1String("--enable_multibytes"));
+ allowFirstColumnMnemonics = flags.contains(
+ QLatin1String("--mnem_first"));
+ allowFirstColumnDirectives = flags.contains(
+ QLatin1String("--dir_first"));
+
+ 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;
+ }
+
+ int enableSymbolsCaseSensitive = 1;
+ int enableMultibyteSupport = 0;
+ int allowFirstColumnMnemonics = 0;
+ int allowFirstColumnDirectives = 0;
+
+ MacroQuoteCharacter macroQuoteCharacter = AngleBracketsQuote;
+};
+
+// 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();
+ warningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int warningsAsErrors = 0;
+};
+
+} // namespace
+
+// Stm8AssemblerSettingsGroup
+
+Stm8AssemblerSettingsGroup::Stm8AssemblerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ASTM8"));
+ 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 Stm8AssemblerSettingsGroup::buildLanguagePage(
+ const ProductData &qbsProduct)
+{
+ const LanguagePageOptions opts(qbsProduct);
+ // Add 'AsmCaseSensitivity' item (User symbols are case sensitive).
+ addOptionsGroup(QByteArrayLiteral("AsmCaseSensitivity"),
+ {opts.enableSymbolsCaseSensitive});
+ // Add 'AsmMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("AsmMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+ // Add 'AsmAllowMnemonics' item (Allow mnemonics in first column).
+ addOptionsGroup(QByteArrayLiteral("AsmAllowMnemonics"),
+ {opts.allowFirstColumnMnemonics});
+ // Add 'AsmAllowDirectives' item (Allow directives in first column).
+ addOptionsGroup(QByteArrayLiteral("AsmAllowDirectives"),
+ {opts.allowFirstColumnDirectives});
+
+ // Add 'AsmMacroChars' item (Macro quote characters: ()/[]/{}/<>).
+ addOptionsGroup(QByteArrayLiteral("AsmMacroChars"),
+ {opts.macroQuoteCharacter});
+}
+
+void Stm8AssemblerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'AsmDebugInfo' item (Generate debug information).
+ addOptionsGroup(QByteArrayLiteral("AsmDebugInfo"),
+ {opts.debugInfo});
+}
+
+void Stm8AssemblerSettingsGroup::buildPreprocessorPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const PreprocessorPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'AsmDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("AsmDefines"),
+ opts.defineSymbols);
+ // Add 'AsmIncludePath' item (Additional include directories).
+ addOptionsGroup(QByteArrayLiteral("AsmIncludePath"),
+ opts.includePaths);
+}
+
+void Stm8AssemblerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'AsmDiagnosticsWarningsAreErrors' item.
+ // (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("AsmDiagnosticsWarningsAreErrors"),
+ {opts.warningsAsErrors});
+}
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.h
new file mode 100644
index 000000000..4d7d0485b
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8assemblersettingsgroup_v3.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_IAREWSTM8ASSEMBLERSETTINGSGROUP_V3_H
+#define QBS_IAREWSTM8ASSEMBLERSETTINGSGROUP_V3_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8AssemblerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Stm8AssemblerSettingsGroup(
+ 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 v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8ASSEMBLERSETTINGSGROUP_V3_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.cpp
new file mode 100644
index 000000000..06167f919
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.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 "stm8archiversettingsgroup_v3.h"
+#include "stm8assemblersettingsgroup_v3.h"
+#include "stm8buildconfigurationgroup_v3.h"
+#include "stm8compilersettingsgroup_v3.h"
+#include "stm8generalsettingsgroup_v3.h"
+#include "stm8linkersettingsgroup_v3.h"
+
+#include "../../iarewtoolchainpropertygroup.h"
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+Stm8BuildConfigurationGroup::Stm8BuildConfigurationGroup(
+ 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>("STM8");
+
+ // Append debug info item.
+ const int debugBuild = gen::utils::debugInformation(qbsProduct);
+ appendProperty("debug", debugBuild);
+
+ // Append settings group items.
+ appendChild<Stm8ArchiverSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Stm8AssemblerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Stm8CompilerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Stm8GeneralSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild<Stm8LinkerSettingsGroup>(
+ qbsProject, qbsProduct, qbsProductDeps);
+}
+
+bool Stm8BuildConfigurationGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Stm8
+ && version.majorVersion() == 3;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+Stm8BuildConfigurationGroupFactory::create(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps) const
+{
+ const auto group = new Stm8BuildConfigurationGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<Stm8BuildConfigurationGroup>(group);
+}
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.h
new file mode 100644
index 000000000..c47819fef
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8buildconfigurationgroup_v3.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_IAREWSTM8BUILDCONFIGURATIONGROUP_V3_H
+#define QBS_IAREWSTM8BUILDCONFIGURATIONGROUP_V3_H
+
+#include <generators/generatorutils.h>
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8BuildConfigurationGroup final
+ : public gen::xml::PropertyGroup
+{
+private:
+ explicit Stm8BuildConfigurationGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+ friend class Stm8BuildConfigurationGroupFactory;
+};
+
+class Stm8BuildConfigurationGroupFactory 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 v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8BUILDCONFIGURATIONGROUP_V3_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.cpp
new file mode 100644
index 000000000..912d94bd0
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.cpp
@@ -0,0 +1,442 @@
+/****************************************************************************
+**
+** 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 "stm8compilersettingsgroup_v3.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+constexpr int kCompilerArchiveVersion = 3;
+constexpr int kCompilerDataVersion = 9;
+
+namespace {
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+ }
+
+ int debugInfo = 0;
+};
+
+// 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 = C99LanguageDialect;
+ 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 = UnsignedCharacter;
+ 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
+ };
+
+ enum VRegsNumber {
+ VRegs12,
+ VRegs16
+ };
+
+ 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);
+
+ disableSizeConstraints = flags.contains(
+ QLatin1String("--no_size_constraints"));
+
+ 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"));
+
+ const auto vregsCount = IarewUtils::flagValue(
+ flags, QStringLiteral("--vregs")).toInt();
+ if (vregsCount == 12)
+ vregsNumber = VRegs12;
+ else if (vregsCount == 16)
+ vregsNumber = VRegs16;
+ }
+
+ Strategy optimizationStrategy = StrategyBalanced;
+ Level optimizationLevel = LevelNone;
+ LevelSlave optimizationLevelSlave = LevelSlave0;
+ // Separate "no size constraints" checkbox.
+ int disableSizeConstraints = 0;
+
+ // Six 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.
+
+ VRegsNumber vregsNumber = VRegs16;
+};
+
+// 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;
+};
+
+} // namespace
+
+// Stm8CompilerSettingsGroup
+
+Stm8CompilerSettingsGroup::Stm8CompilerSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+{
+ Q_UNUSED(qbsProductDeps)
+
+ setName(QByteArrayLiteral("ICCSTM8"));
+ 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 Stm8CompilerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+ // Add 'IccGenerateDebugInfo' item (Generate debug info).
+ addOptionsGroup(QByteArrayLiteral("IccGenerateDebugInfo"),
+ {opts.debugInfo});
+}
+
+void Stm8CompilerSettingsGroup::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 'IccLanguageConformance' item
+ // (Language conformance: IAR/relaxed/strict).
+ addOptionsGroup(QByteArrayLiteral("IccLanguageConformance"),
+ {opts.languageConformance});
+ // Add 'IccAllowVLA' item (Allow VLA).
+ addOptionsGroup(QByteArrayLiteral("IccAllowVLA"),
+ {opts.allowVla});
+ // Add 'IccCppInlineSemantics' item (C++ inline semantics).
+ addOptionsGroup(QByteArrayLiteral("IccCppInlineSemantics"),
+ {opts.useCppInlineSemantics});
+ // Add 'IccRequirePrototypes' item (Require prototypes).
+ addOptionsGroup(QByteArrayLiteral("IccRequirePrototypes"),
+ {opts.requirePrototypes});
+ // Add 'IccStaticDestr' item (Destroy static objects).
+ addOptionsGroup(QByteArrayLiteral("IccStaticDestr"),
+ {opts.destroyStaticObjects});
+}
+
+void Stm8CompilerSettingsGroup::buildLanguageTwoPage(
+ const ProductData &qbsProduct)
+{
+ const LanguageTwoPageOptions opts(qbsProduct);
+ // Add 'IccCharIs' item (Plain char is: signed/unsigned).
+ addOptionsGroup(QByteArrayLiteral("IccCharIs"),
+ {opts.plainCharacter});
+ // Add 'IccFloatSemantics' item (Floatic-point
+ // semantics: strict/relaxed conformance).
+ addOptionsGroup(QByteArrayLiteral("IccFloatSemantics"),
+ {opts.floatingPointSemantic});
+ // Add 'IccMultibyteSupport' item (Enable multibyte support).
+ addOptionsGroup(QByteArrayLiteral("IccMultibyteSupport"),
+ {opts.enableMultibyteSupport});
+}
+
+void Stm8CompilerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ const OptimizationsPageOptions opts(qbsProduct);
+ // Add 'IccOptStrategy', 'IccOptLevel' and
+ // 'CCOptLevelSlave' items (Level).
+ addOptionsGroup(QByteArrayLiteral("IccOptStrategy"),
+ {opts.optimizationStrategy});
+ addOptionsGroup(QByteArrayLiteral("IccOptLevel"),
+ {opts.optimizationLevel});
+ addOptionsGroup(QByteArrayLiteral("IccOptLevelSlave"),
+ {opts.optimizationLevelSlave});
+
+ // Add 'IccOptNoSizeConstraints' iten (no size constraints).
+ addOptionsGroup(QByteArrayLiteral("IccOptNoSizeConstraints"),
+ {opts.disableSizeConstraints});
+
+ // Add 'IccOptAllowList' item
+ // (Enabled optimizations: 6 check boxes).
+ const QString bitflags = QStringLiteral("%1%2%3%4%5%6")
+ .arg(opts.enableCommonSubexpressionElimination)
+ .arg(opts.enableLoopUnroll)
+ .arg(opts.enableFunctionInlining)
+ .arg(opts.enableCodeMotion)
+ .arg(opts.enableTypeBasedAliasAnalysis)
+ .arg(opts.enableCrossCall);
+ addOptionsGroup(QByteArrayLiteral("IccOptAllowList"),
+ {bitflags});
+
+ // Add 'IccNoVregs' item
+ // (Number of virtual registers (12/16).
+ addOptionsGroup(QByteArrayLiteral("IccNoVregs"),
+ {opts.vregsNumber});
+}
+
+void Stm8CompilerSettingsGroup::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 Stm8CompilerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'CCDiagWarnAreErr' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("CCDiagWarnAreErr"),
+ {opts.warningsAsErrors});
+}
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.h
new file mode 100644
index 000000000..29bb5c2b3
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8compilersettingsgroup_v3.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_IAREWSTM8COMPILERSETTINGSGROUP_V3_H
+#define QBS_IAREWSTM8COMPILERSETTINGSGROUP_V3_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8CompilerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Stm8CompilerSettingsGroup(
+ 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);
+};
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8COMPILERSETTINGSGROUP_V3_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.cpp
new file mode 100644
index 000000000..9477bc36e
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** 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 "stm8generalsettingsgroup_v3.h"
+
+#include "../../iarewutils.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+constexpr int kGeneralArchiveVersion = 4;
+constexpr int kGeneralDataVersion = 2;
+
+namespace {
+
+// Target page options.
+
+struct TargetPageOptions final
+{
+ enum CodeModel {
+ SmallCodeModel,
+ MediumCodeModel,
+ LargeCodeModel
+ };
+
+ enum DataModel {
+ SmallDataModel,
+ MediumDataModel,
+ LargeDataModel
+ };
+
+ explicit TargetPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags")});
+ // Detect target code model.
+ const QString codeModelValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--code_model"));
+ if (codeModelValue == QLatin1String("small"))
+ codeModel = TargetPageOptions::SmallCodeModel;
+ else if (codeModelValue == QLatin1String("medium"))
+ codeModel = TargetPageOptions::MediumCodeModel;
+ else if (codeModelValue == QLatin1String("large"))
+ codeModel = TargetPageOptions::LargeCodeModel;
+ // Detect target data model.
+ const QString dataModelValue = IarewUtils::flagValue(
+ flags, QStringLiteral("--data_model"));
+ if (dataModelValue == QLatin1String("small"))
+ dataModel = TargetPageOptions::SmallDataModel;
+ else if (dataModelValue == QLatin1String("medium"))
+ dataModel = TargetPageOptions::MediumDataModel;
+ else if (dataModelValue == QLatin1String("large"))
+ dataModel = TargetPageOptions::LargeDataModel;
+ }
+
+ CodeModel codeModel = MediumCodeModel;
+ DataModel dataModel = MediumDataModel;
+};
+
+// 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;
+};
+
+// Library configuration page options.
+
+struct LibraryConfigPageOptions final
+{
+ enum RuntimeLibrary {
+ NoLibrary,
+ NormalLibrary,
+ FullLibrary,
+ CustomLibrary
+ };
+
+ explicit LibraryConfigPageOptions(const QString &baseDirectory,
+ const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleCompilerFlags(qbsProps);
+
+ const QFileInfo configInfo(IarewUtils::flagValue(
+ flags,
+ QStringLiteral("--dlib_config")));
+ const QString configFilePath = configInfo.absoluteFilePath();
+
+ if (!configFilePath.isEmpty()) {
+ const QString libToolkitPath =
+ IarewUtils::libToolkitRootPath(qbsProduct);
+
+ if (configFilePath.startsWith(libToolkitPath,
+ Qt::CaseInsensitive)) {
+ if (configFilePath.endsWith(QLatin1String("n.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::NormalLibrary;
+ } else if (configFilePath.endsWith(QLatin1String("f.h"),
+ Qt::CaseInsensitive)) {
+ libraryType = LibraryConfigPageOptions::FullLibrary;
+ } else {
+ libraryType = LibraryConfigPageOptions::CustomLibrary;
+ }
+
+ configPath = IarewUtils::toolkitRelativeFilePath(
+ baseDirectory, configFilePath);
+ } else {
+ libraryType = LibraryConfigPageOptions::CustomLibrary;
+
+ configPath = configFilePath;
+ }
+ } else {
+ libraryType = LibraryConfigPageOptions::NoLibrary;
+ }
+ }
+
+ RuntimeLibrary libraryType = NoLibrary;
+ QString configPath;
+};
+
+// Library options page options.
+
+struct LibraryOptionsPageOptions final
+{
+ enum PrintfFormatter {
+ PrintfAutoFormatter = 0,
+ PrintfFullFormatter = 1,
+ PrintfFullNoMultibytesFormatter = 2,
+ PrintfLargeFormatter = 3,
+ PrintfLargeNoMultibytesFormatter = 4,
+ PrintfSmallFormatter = 5,
+ PrintfSmallNoMultibytesFormatter = 6,
+ PrintfTinyFormatter = 7
+ };
+
+ enum ScanfFormatter {
+ ScanfAutoFormatter = 0,
+ ScanfFullFormatter = 1,
+ ScanfFullNoMultibytesFormatter = 2,
+ ScanfLargeFormatter = 3,
+ ScanfLargeNoMultibytesFormatter = 4,
+ ScanfSmallFormatter = 5,
+ ScanfSmallNoMultibytesFormatter = 6
+ };
+
+ explicit LibraryOptionsPageOptions(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("_printffull"))
+ printfFormatter = PrintfFullFormatter;
+ else if (prop == QLatin1String("_printffullnomb"))
+ printfFormatter = PrintfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("_printflarge"))
+ printfFormatter = PrintfLargeFormatter;
+ else if (prop == QLatin1String("_printflargenomb"))
+ printfFormatter = PrintfLargeFormatter;
+ else if (prop == QLatin1String("_printfsmall"))
+ printfFormatter = PrintfSmallFormatter;
+ else if (prop == QLatin1String("_printfsmallnomb"))
+ printfFormatter = PrintfSmallNoMultibytesFormatter;
+ else if (prop == QLatin1String("_printftiny"))
+ printfFormatter = PrintfTinyFormatter;
+ } else if (flagIt->startsWith(QLatin1String("_scanf="),
+ Qt::CaseInsensitive)) {
+ const QString prop = flagIt->split(
+ QLatin1Char('=')).at(1).toLower();
+ if (prop == QLatin1String("_scanffull"))
+ scanfFormatter = ScanfFullFormatter;
+ else if (prop == QLatin1String("_scanffullnomb"))
+ scanfFormatter = ScanfFullNoMultibytesFormatter;
+ else if (prop == QLatin1String("_scanflarge"))
+ scanfFormatter = ScanfLargeFormatter;
+ else if (prop == QLatin1String("_scanflargenomb"))
+ scanfFormatter = ScanfLargeFormatter;
+ else if (prop == QLatin1String("_scanfsmall"))
+ scanfFormatter = ScanfSmallFormatter;
+ else if (prop == QLatin1String("_scanfsmallnomb"))
+ scanfFormatter = ScanfSmallNoMultibytesFormatter;
+ }
+ }
+ }
+
+ PrintfFormatter printfFormatter = PrintfAutoFormatter;
+ ScanfFormatter scanfFormatter = ScanfAutoFormatter;
+};
+
+// Stack/heap page options.
+
+struct StackHeapPageOptions final
+{
+ explicit StackHeapPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ const auto configDefs = IarewUtils::flagValues(
+ flags, QStringLiteral("--config_def"));
+ for (const auto &configDef : configDefs) {
+ const auto def = configDef.toString();
+ if (def.startsWith(QLatin1String("_CSTACK_SIZE="))) {
+ stackSize = def.split(QLatin1Char('=')).at(1);
+ } else if (def.startsWith(QLatin1String("_HEAP_SIZE="))) {
+ heapSize = def.split(QLatin1Char('=')).at(1);
+ }
+ }
+ }
+
+ QString stackSize;
+ QString heapSize;
+};
+
+} // namespace
+
+// Stm8GeneralSettingsGroup
+
+Stm8GeneralSettingsGroup::Stm8GeneralSettingsGroup(
+ 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);
+ buildOutputPage(buildRootDirectory, qbsProduct);
+ buildLibraryConfigPage(buildRootDirectory, qbsProduct);
+ buildLibraryOptionsPage(qbsProduct);
+ buildStackHeapPage(qbsProduct);
+}
+
+void Stm8GeneralSettingsGroup::buildTargetPage(
+ const ProductData &qbsProduct)
+{
+ const TargetPageOptions opts(qbsProduct);
+ // Add 'GenCodeModel' item
+ // (Code model: small/medium/large).
+ addOptionsGroup(QByteArrayLiteral("GenCodeModel"),
+ {opts.codeModel});
+ // Add 'GenDataModel' item
+ // (Data model: small/medium/large).
+ addOptionsGroup(QByteArrayLiteral("GenDataModel"),
+ {opts.dataModel});
+}
+
+void Stm8GeneralSettingsGroup::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});
+}
+
+void Stm8GeneralSettingsGroup::buildLibraryConfigPage(
+ const QString &baseDirectory,
+ const ProductData &qbsProduct)
+{
+ const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
+ // Add 'GenRuntimeLibSelect' and 'GenRuntimeLibSelectSlave' items
+ // (Link with runtime: none/normal/full/custom).
+ addOptionsGroup(QByteArrayLiteral("GenRuntimeLibSelect"),
+ {opts.libraryType});
+ addOptionsGroup(QByteArrayLiteral("GenRuntimeLibSelectSlave"),
+ {opts.libraryType});
+ // Add 'GenRTConfigPath' item (Runtime configuration file).
+ addOptionsGroup(QByteArrayLiteral("GenRTConfigPath"),
+ {opts.configPath});
+}
+
+void Stm8GeneralSettingsGroup::buildLibraryOptionsPage(
+ const ProductData &qbsProduct)
+{
+ const LibraryOptionsPageOptions opts(qbsProduct);
+ // Add 'GenLibOutFormatter' item (Printf formatter).
+ addOptionsGroup(QByteArrayLiteral("GenLibOutFormatter"),
+ {opts.printfFormatter});
+ // Add 'GenLibInFormatter' item (Scanf formatter).
+ addOptionsGroup(QByteArrayLiteral("GenLibInFormatter"),
+ {opts.scanfFormatter});
+}
+
+void Stm8GeneralSettingsGroup::buildStackHeapPage(
+ const ProductData &qbsProduct)
+{
+ const StackHeapPageOptions opts(qbsProduct);
+ // Add 'GenStackSize' item (Stack size).
+ addOptionsGroup(QByteArrayLiteral("GenStackSize"),
+ {opts.stackSize});
+ // Add 'GenHeapSize' item (Heap size).
+ addOptionsGroup(QByteArrayLiteral("GenHeapSize"),
+ {opts.heapSize});
+}
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.h
new file mode 100644
index 000000000..20def0fd5
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8generalsettingsgroup_v3.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_IAREWSTM8GENERALSETTINGSGROUP_V3_H
+#define QBS_IAREWSTM8GENERALSETTINGSGROUP_V3_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8GeneralSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Stm8GeneralSettingsGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps);
+
+private:
+ void buildTargetPage(const ProductData &qbsProduct);
+ void buildOutputPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildLibraryConfigPage(const QString &baseDirectory,
+ const ProductData &qbsProduct);
+ void buildLibraryOptionsPage(const ProductData &qbsProduct);
+ void buildStackHeapPage(const ProductData &qbsProduct);
+};
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8GENERALSETTINGSGROUP_V3_H
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp
new file mode 100644
index 000000000..731c8d91e
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** 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 "stm8linkersettingsgroup_v3.h"
+
+#include "../../iarewutils.h"
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+constexpr int kLinkerArchiveVersion = 5;
+constexpr int kLinkerDataVersion = 4;
+
+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);
+
+ // 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 '-config' option).
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+ const QVariantList configPathValues = IarewUtils::flagValues(
+ flags, QStringLiteral("--config"));
+ 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);
+ }
+ }
+
+ // Enumerate all config definition symbols (except
+ // the CSTACK_SIZE and HEAP_SIZE which are handles
+ // on the general page).
+ configDefinitions = IarewUtils::flagValues(
+ flags, QStringLiteral("--config_def"));
+ configDefinitions.erase(std::remove_if(
+ configDefinitions.begin(),
+ configDefinitions.end(),
+ [](const auto &definition){
+ const auto def = definition.toString();
+ return def.startsWith(QLatin1String("_CSTACK_SIZE"))
+ || def.startsWith(QLatin1String("_HEAP_SIZE"));
+ }), configDefinitions.end());
+ }
+
+ QVariantList configFilePaths;
+ QVariantList configDefinitions;
+};
+
+struct LibraryPageOptions final
+{
+ explicit LibraryPageOptions(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"));
+
+ // 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);
+ }
+ }
+
+ QString entryPoint;
+ QVariantList staticLibraries;
+};
+
+struct OptimizationsPageOptions final
+{
+ explicit OptimizationsPageOptions(const ProductData &qbsProduct)
+ {
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+
+ mergeDuplicateSections = flags.contains(
+ QLatin1String("--merge_duplicate_sections"));
+ }
+
+ bool mergeDuplicateSections = 0;
+};
+
+// Output page options.
+
+struct OutputPageOptions final
+{
+ explicit OutputPageOptions(const ProductData &qbsProduct)
+ {
+ outputFile = gen::utils::targetBinary(qbsProduct);
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
+
+ enableDebugInfo = !flags.contains(QLatin1String("--strip"));
+ }
+
+ QString outputFile;
+ bool enableDebugInfo = 1;
+};
+
+// 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("generateMapFile"))
+ ? 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);
+
+ 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();
+ warningsAsErrors = gen::utils::cppIntegerModuleProperty(
+ qbsProps, QStringLiteral("treatWarningsAsErrors"));
+ }
+
+ int warningsAsErrors = 0;
+};
+
+} // namespace
+
+// Stm8LinkerSettingsGroup
+
+Stm8LinkerSettingsGroup::Stm8LinkerSettingsGroup(
+ 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);
+ buildOptimizationsPage(qbsProduct);
+ buildOutputPage(qbsProduct);
+ buildListPage(qbsProduct);
+ buildDefinePage(qbsProduct);
+ buildDiagnosticsPage(qbsProduct);
+
+ // Should be called as latest stage!
+ buildExtraOptionsPage(qbsProduct);
+}
+
+void Stm8LinkerSettingsGroup::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 'IlinkIcfOverride' item (Override default).
+ addOptionsGroup(QByteArrayLiteral("IlinkIcfOverride"),
+ {1});
+ // Add 'IlinkIcfFile' item (Linke 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;
+ }
+ }
+
+ // Add 'IlinkConfigDefines' item (Configuration file
+ // symbol definitions).
+ addOptionsGroup(QByteArrayLiteral("IlinkConfigDefines"),
+ opts.configDefinitions);
+}
+
+void Stm8LinkerSettingsGroup::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});
+
+ if (opts.entryPoint.isEmpty()) {
+ // Add 'IlinkProgramEntryLabelSelect' item
+ // (Defined by application).
+ addOptionsGroup(QByteArrayLiteral("IlinkProgramEntryLabelSelect"),
+ {1});
+ } else {
+ // Add 'IlinkProgramEntryLabel' item
+ // (Entry symbol).
+ addOptionsGroup(QByteArrayLiteral("IlinkProgramEntryLabel"),
+ {opts.entryPoint});
+ }
+
+ // Add 'IlinkAdditionalLibs' item (Additional libraries).
+ addOptionsGroup(QByteArrayLiteral("IlinkAdditionalLibs"),
+ {opts.staticLibraries});
+}
+
+void Stm8LinkerSettingsGroup::buildOptimizationsPage(
+ const ProductData &qbsProduct)
+{
+ OptimizationsPageOptions opts(qbsProduct);
+
+ // Add 'IlinkOptMergeDuplSections' item
+ // (Merge duplicate sections).
+ addOptionsGroup(QByteArrayLiteral("IlinkOptMergeDuplSections"),
+ {opts.mergeDuplicateSections});
+}
+
+void Stm8LinkerSettingsGroup::buildOutputPage(
+ const ProductData &qbsProduct)
+{
+ const OutputPageOptions opts(qbsProduct);
+
+ // Add 'IlinkOutputFile' item (Output file name).
+ addOptionsGroup(QByteArrayLiteral("IlinkOutputFile"),
+ {opts.outputFile});
+ // Add 'IlinkDebugInfoEnable' item
+ // (Include debug information in output).
+ addOptionsGroup(QByteArrayLiteral("IlinkDebugInfoEnable"),
+ {opts.enableDebugInfo});
+}
+
+void Stm8LinkerSettingsGroup::buildListPage(
+ const ProductData &qbsProduct)
+{
+ const ListPageOptions opts(qbsProduct);
+ // Add 'IlinkMapFile' item (Generate linker map file).
+ addOptionsGroup(QByteArrayLiteral("IlinkMapFile"),
+ {opts.generateMap});
+}
+
+void Stm8LinkerSettingsGroup::buildDefinePage(
+ const ProductData &qbsProduct)
+{
+ const DefinePageOptions opts(qbsProduct);
+ // Add 'IlinkDefines' item (Defined symbols).
+ addOptionsGroup(QByteArrayLiteral("IlinkDefines"),
+ opts.defineSymbols);
+}
+
+void Stm8LinkerSettingsGroup::buildDiagnosticsPage(
+ const ProductData &qbsProduct)
+{
+ const DiagnosticsPageOptions opts(qbsProduct);
+ // Add 'IlinkWarningsAreErrors' item (Treat all warnings as errors).
+ addOptionsGroup(QByteArrayLiteral("IlinkWarningsAreErrors"),
+ {opts.warningsAsErrors});
+}
+
+void Stm8LinkerSettingsGroup::buildExtraOptionsPage(
+ const ProductData &qbsProduct)
+{
+ Q_UNUSED(qbsProduct)
+
+ if (m_extraOptions.isEmpty())
+ return;
+
+ // Add 'IlinkUseExtraOptions' (Use command line options).
+ addOptionsGroup(QByteArrayLiteral("IlinkUseExtraOptions"),
+ {1});
+ // Add 'IlinkExtraOptions' item (Command line options).
+ addOptionsGroup(QByteArrayLiteral("IlinkExtraOptions"),
+ m_extraOptions);
+}
+
+} // namespace v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.h b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.h
new file mode 100644
index 000000000..b214ebe35
--- /dev/null
+++ b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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_IAREWSTM8LINKERSETTINGSGROUP_V3_H
+#define QBS_IAREWSTM8LINKERSETTINGSGROUP_V3_H
+
+#include "../../iarewsettingspropertygroup.h"
+
+namespace qbs {
+namespace iarew {
+namespace stm8 {
+namespace v3 {
+
+class Stm8LinkerSettingsGroup final : public IarewSettingsPropertyGroup
+{
+public:
+ explicit Stm8LinkerSettingsGroup(
+ 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 buildOptimizationsPage(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 v3
+} // namespace stm8
+} // namespace iarew
+} // namespace qbs
+
+#endif // QBS_IAREWSTM8LINKERSETTINGSGROUP_V3_H
diff --git a/src/plugins/generator/iarew/iarew.pro b/src/plugins/generator/iarew/iarew.pro
new file mode 100644
index 000000000..7de474a45
--- /dev/null
+++ b/src/plugins/generator/iarew/iarew.pro
@@ -0,0 +1,133 @@
+include(../../plugins.pri)
+include(../../../shared/json/json.pri)
+
+TARGET = iarewgenerator
+
+QT = core
+
+# Plugin file.
+
+SOURCES += \
+ $$PWD/iarewgeneratorplugin.cpp \
+
+# Common files.
+
+HEADERS += \
+ $$PWD/iarewfileversionproperty.h \
+ $$PWD/iarewgenerator.h \
+ $$PWD/iarewoptionpropertygroup.h \
+ $$PWD/iarewproject.h \
+ $$PWD/iarewprojectwriter.h \
+ $$PWD/iarewsettingspropertygroup.h \
+ $$PWD/iarewsourcefilepropertygroup.h \
+ $$PWD/iarewsourcefilespropertygroup.h \
+ $$PWD/iarewtoolchainpropertygroup.h \
+ $$PWD/iarewutils.h \
+ $$PWD/iarewversioninfo.h \
+ $$PWD/iarewworkspace.h \
+ $$PWD/iarewworkspacewriter.h
+
+SOURCES += \
+ $$PWD/iarewfileversionproperty.cpp \
+ $$PWD/iarewgenerator.cpp \
+ $$PWD/iarewoptionpropertygroup.cpp \
+ $$PWD/iarewproject.cpp \
+ $$PWD/iarewprojectwriter.cpp \
+ $$PWD/iarewsettingspropertygroup.cpp \
+ $$PWD/iarewsourcefilepropertygroup.cpp \
+ $$PWD/iarewsourcefilespropertygroup.cpp \
+ $$PWD/iarewtoolchainpropertygroup.cpp \
+ $$PWD/iarewutils.cpp \
+ $$PWD/iarewversioninfo.cpp \
+ $$PWD/iarewworkspace.cpp \
+ $$PWD/iarewworkspacewriter.cpp
+
+# For ARM architecture.
+
+HEADERS += \
+ $$PWD/archs/arm/armarchiversettingsgroup_v8.h \
+ $$PWD/archs/arm/armassemblersettingsgroup_v8.h \
+ $$PWD/archs/arm/armbuildconfigurationgroup_v8.h \
+ $$PWD/archs/arm/armcompilersettingsgroup_v8.h \
+ $$PWD/archs/arm/armgeneralsettingsgroup_v8.h \
+ $$PWD/archs/arm/armlinkersettingsgroup_v8.h
+
+SOURCES += \
+ $$PWD/archs/arm/armarchiversettingsgroup_v8.cpp \
+ $$PWD/archs/arm/armassemblersettingsgroup_v8.cpp \
+ $$PWD/archs/arm/armbuildconfigurationgroup_v8.cpp \
+ $$PWD/archs/arm/armcompilersettingsgroup_v8.cpp \
+ $$PWD/archs/arm/armgeneralsettingsgroup_v8.cpp \
+ $$PWD/archs/arm/armlinkersettingsgroup_v8.cpp
+
+# For AVR architecture.
+
+HEADERS += \
+ $$PWD/archs/avr/avrarchiversettingsgroup_v7.h \
+ $$PWD/archs/avr/avrassemblersettingsgroup_v7.h \
+ $$PWD/archs/avr/avrbuildconfigurationgroup_v7.h \
+ $$PWD/archs/avr/avrcompilersettingsgroup_v7.h \
+ $$PWD/archs/avr/avrgeneralsettingsgroup_v7.h \
+ $$PWD/archs/avr/avrlinkersettingsgroup_v7.h
+
+SOURCES += \
+ $$PWD/archs/avr/avrarchiversettingsgroup_v7.cpp \
+ $$PWD/archs/avr/avrassemblersettingsgroup_v7.cpp \
+ $$PWD/archs/avr/avrbuildconfigurationgroup_v7.cpp \
+ $$PWD/archs/avr/avrcompilersettingsgroup_v7.cpp \
+ $$PWD/archs/avr/avrgeneralsettingsgroup_v7.cpp \
+ $$PWD/archs/avr/avrlinkersettingsgroup_v7.cpp
+
+# For MCS51 architecture.
+
+HEADERS += \
+ $$PWD/archs/mcs51/mcs51archiversettingsgroup_v10.h \
+ $$PWD/archs/mcs51/mcs51assemblersettingsgroup_v10.h \
+ $$PWD/archs/mcs51/mcs51buildconfigurationgroup_v10.h \
+ $$PWD/archs/mcs51/mcs51compilersettingsgroup_v10.h \
+ $$PWD/archs/mcs51/mcs51generalsettingsgroup_v10.h \
+ $$PWD/archs/mcs51/mcs51linkersettingsgroup_v10.h
+
+SOURCES += \
+ $$PWD/archs/mcs51/mcs51archiversettingsgroup_v10.cpp \
+ $$PWD/archs/mcs51/mcs51assemblersettingsgroup_v10.cpp \
+ $$PWD/archs/mcs51/mcs51buildconfigurationgroup_v10.cpp \
+ $$PWD/archs/mcs51/mcs51compilersettingsgroup_v10.cpp \
+ $$PWD/archs/mcs51/mcs51generalsettingsgroup_v10.cpp \
+ $$PWD/archs/mcs51/mcs51linkersettingsgroup_v10.cpp
+
+# For STM8 architecture.
+
+HEADERS += \
+ $$PWD/archs/stm8/stm8archiversettingsgroup_v3.h \
+ $$PWD/archs/stm8/stm8assemblersettingsgroup_v3.h \
+ $$PWD/archs/stm8/stm8buildconfigurationgroup_v3.h \
+ $$PWD/archs/stm8/stm8compilersettingsgroup_v3.h \
+ $$PWD/archs/stm8/stm8generalsettingsgroup_v3.h \
+ $$PWD/archs/stm8/stm8linkersettingsgroup_v3.h
+
+SOURCES += \
+ $$PWD/archs/stm8/stm8archiversettingsgroup_v3.cpp \
+ $$PWD/archs/stm8/stm8assemblersettingsgroup_v3.cpp \
+ $$PWD/archs/stm8/stm8buildconfigurationgroup_v3.cpp \
+ $$PWD/archs/stm8/stm8compilersettingsgroup_v3.cpp \
+ $$PWD/archs/stm8/stm8generalsettingsgroup_v3.cpp \
+ $$PWD/archs/stm8/stm8linkersettingsgroup_v3.cpp
+
+# For MSP430 architecture.
+
+HEADERS += \
+ $$PWD/archs/msp430/msp430archiversettingsgroup_v7.h \
+ $$PWD/archs/msp430/msp430assemblersettingsgroup_v7.h \
+ $$PWD/archs/msp430/msp430buildconfigurationgroup_v7.h \
+ $$PWD/archs/msp430/msp430compilersettingsgroup_v7.h \
+ $$PWD/archs/msp430/msp430generalsettingsgroup_v7.h \
+ $$PWD/archs/msp430/msp430linkersettingsgroup_v7.h
+
+SOURCES += \
+ $$PWD/archs/msp430/msp430archiversettingsgroup_v7.cpp \
+ $$PWD/archs/msp430/msp430assemblersettingsgroup_v7.cpp \
+ $$PWD/archs/msp430/msp430buildconfigurationgroup_v7.cpp \
+ $$PWD/archs/msp430/msp430compilersettingsgroup_v7.cpp \
+ $$PWD/archs/msp430/msp430generalsettingsgroup_v7.cpp \
+ $$PWD/archs/msp430/msp430linkersettingsgroup_v7.cpp
diff --git a/src/plugins/generator/iarew/iarew.qbs b/src/plugins/generator/iarew/iarew.qbs
new file mode 100644
index 000000000..7b2270426
--- /dev/null
+++ b/src/plugins/generator/iarew/iarew.qbs
@@ -0,0 +1,132 @@
+import qbs
+import "../../qbsplugin.qbs" as QbsPlugin
+
+QbsPlugin {
+ Depends { name: "qbsjson" }
+
+ name: "iarewgenerator"
+
+ files: ["iarewgeneratorplugin.cpp"]
+
+ Group {
+ name: "IAR EW generator common"
+ files: [
+ "iarewfileversionproperty.cpp",
+ "iarewfileversionproperty.h",
+ "iarewgenerator.cpp",
+ "iarewgenerator.h",
+ "iarewoptionpropertygroup.cpp",
+ "iarewoptionpropertygroup.h",
+ "iarewproject.cpp",
+ "iarewproject.h",
+ "iarewprojectwriter.cpp",
+ "iarewprojectwriter.h",
+ "iarewsettingspropertygroup.cpp",
+ "iarewsettingspropertygroup.h",
+ "iarewsourcefilepropertygroup.cpp",
+ "iarewsourcefilepropertygroup.h",
+ "iarewsourcefilespropertygroup.cpp",
+ "iarewsourcefilespropertygroup.h",
+ "iarewtoolchainpropertygroup.cpp",
+ "iarewtoolchainpropertygroup.h",
+ "iarewutils.cpp",
+ "iarewutils.h",
+ "iarewversioninfo.cpp",
+ "iarewversioninfo.h",
+ "iarewworkspace.cpp",
+ "iarewworkspace.h",
+ "iarewworkspacewriter.cpp",
+ "iarewworkspacewriter.h",
+ ]
+ }
+ Group {
+ name: "IAR EW generator for ARM"
+ prefix: "archs/arm/"
+ files: [
+ "armarchiversettingsgroup_v8.cpp",
+ "armarchiversettingsgroup_v8.h",
+ "armassemblersettingsgroup_v8.cpp",
+ "armassemblersettingsgroup_v8.h",
+ "armbuildconfigurationgroup_v8.cpp",
+ "armbuildconfigurationgroup_v8.h",
+ "armcompilersettingsgroup_v8.cpp",
+ "armcompilersettingsgroup_v8.h",
+ "armgeneralsettingsgroup_v8.cpp",
+ "armgeneralsettingsgroup_v8.h",
+ "armlinkersettingsgroup_v8.cpp",
+ "armlinkersettingsgroup_v8.h",
+ ]
+ }
+ Group {
+ name: "IAR EW generator for AVR"
+ prefix: "archs/avr/"
+ files: [
+ "avrarchiversettingsgroup_v7.cpp",
+ "avrarchiversettingsgroup_v7.h",
+ "avrassemblersettingsgroup_v7.cpp",
+ "avrassemblersettingsgroup_v7.h",
+ "avrbuildconfigurationgroup_v7.cpp",
+ "avrbuildconfigurationgroup_v7.h",
+ "avrcompilersettingsgroup_v7.cpp",
+ "avrcompilersettingsgroup_v7.h",
+ "avrgeneralsettingsgroup_v7.cpp",
+ "avrgeneralsettingsgroup_v7.h",
+ "avrlinkersettingsgroup_v7.cpp",
+ "avrlinkersettingsgroup_v7.h",
+ ]
+ }
+ Group {
+ name: "IAR EW generator for MCS51"
+ prefix: "archs/mcs51/"
+ files: [
+ "mcs51archiversettingsgroup_v10.cpp",
+ "mcs51archiversettingsgroup_v10.h",
+ "mcs51assemblersettingsgroup_v10.cpp",
+ "mcs51assemblersettingsgroup_v10.h",
+ "mcs51buildconfigurationgroup_v10.cpp",
+ "mcs51buildconfigurationgroup_v10.h",
+ "mcs51compilersettingsgroup_v10.cpp",
+ "mcs51compilersettingsgroup_v10.h",
+ "mcs51generalsettingsgroup_v10.cpp",
+ "mcs51generalsettingsgroup_v10.h",
+ "mcs51linkersettingsgroup_v10.cpp",
+ "mcs51linkersettingsgroup_v10.h",
+ ]
+ }
+ Group {
+ name: "IAR EW generator for STM8"
+ prefix: "archs/stm8/"
+ files: [
+ "stm8archiversettingsgroup_v3.cpp",
+ "stm8archiversettingsgroup_v3.h",
+ "stm8assemblersettingsgroup_v3.cpp",
+ "stm8assemblersettingsgroup_v3.h",
+ "stm8buildconfigurationgroup_v3.cpp",
+ "stm8buildconfigurationgroup_v3.h",
+ "stm8compilersettingsgroup_v3.cpp",
+ "stm8compilersettingsgroup_v3.h",
+ "stm8generalsettingsgroup_v3.cpp",
+ "stm8generalsettingsgroup_v3.h",
+ "stm8linkersettingsgroup_v3.cpp",
+ "stm8linkersettingsgroup_v3.h",
+ ]
+ }
+ Group {
+ name: "IAR EW generator for MSP430"
+ prefix: "archs/msp430/"
+ files: [
+ "msp430archiversettingsgroup_v7.cpp",
+ "msp430archiversettingsgroup_v7.h",
+ "msp430assemblersettingsgroup_v7.cpp",
+ "msp430assemblersettingsgroup_v7.h",
+ "msp430buildconfigurationgroup_v7.cpp",
+ "msp430buildconfigurationgroup_v7.h",
+ "msp430compilersettingsgroup_v7.cpp",
+ "msp430compilersettingsgroup_v7.h",
+ "msp430generalsettingsgroup_v7.cpp",
+ "msp430generalsettingsgroup_v7.h",
+ "msp430linkersettingsgroup_v7.cpp",
+ "msp430linkersettingsgroup_v7.h",
+ ]
+ }
+}
diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.cpp b/src/plugins/generator/iarew/iarewfileversionproperty.cpp
new file mode 100644
index 000000000..446b385b8
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewfileversionproperty.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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 "iarewfileversionproperty.h"
+#include "iarewversioninfo.h"
+
+namespace qbs {
+
+static QByteArray buildFileVersion(const IarewVersionInfo &versionInfo)
+{
+ switch (versionInfo.marketingVersion()) {
+ case 3:
+ case 7:
+ case 8:
+ case 10:
+ return QByteArrayLiteral('3');
+ default:
+ return {};
+ }
+}
+
+IarewFileVersionProperty::IarewFileVersionProperty(
+ const IarewVersionInfo &versionInfo)
+{
+ setName(QByteArrayLiteral("fileVersion"));
+ const QByteArray fileVersion = buildFileVersion(versionInfo);
+ setValue(fileVersion);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.h b/src/plugins/generator/iarew/iarewfileversionproperty.h
new file mode 100644
index 000000000..d377979fa
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewfileversionproperty.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** 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_IAREWFILEVERSIONPROPERTY_H
+#define QBS_IAREWFILEVERSIONPROPERTY_H
+
+#include <generators/xmlproperty.h>
+
+namespace qbs {
+
+class IarewVersionInfo;
+
+class IarewFileVersionProperty final : public gen::xml::Property
+{
+public:
+ explicit IarewFileVersionProperty(
+ const IarewVersionInfo &versionInfo);
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWFILEVERSIONPROPERTY_H
diff --git a/src/plugins/generator/iarew/iarewgenerator.cpp b/src/plugins/generator/iarew/iarewgenerator.cpp
new file mode 100644
index 000000000..e6b308182
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewgenerator.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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 "iarewgenerator.h"
+#include "iarewproject.h"
+#include "iarewprojectwriter.h"
+#include "iarewworkspace.h"
+#include "iarewworkspacewriter.h"
+
+#include <generators/generatableprojectiterator.h>
+
+#include <logging/logger.h>
+#include <logging/translator.h>
+
+#include <tools/filesaver.h>
+
+namespace qbs {
+
+static QString targetFilePath(const QString &baseName,
+ const QString &baseBuildDirectory)
+{
+ return QDir(baseBuildDirectory).absoluteFilePath(
+ baseName + QStringLiteral(".ewp"));
+}
+
+static QString targetFilePath(const GeneratableProductData &product,
+ const QString &baseBuildDirectory)
+{
+ return targetFilePath(product.name(), baseBuildDirectory);
+}
+
+static void writeProjectFiles(const std::map<QString,
+ std::shared_ptr<IarewProject>> &projects,
+ const Internal::Logger &logger)
+{
+ for (const auto &item : projects) {
+ const QString projectFilePath = item.first;
+ Internal::FileSaver file(projectFilePath.toStdString());
+ if (!file.open())
+ throw ErrorInfo(Internal::Tr::tr("Cannot open %s for writing")
+ .arg(projectFilePath));
+
+ std::shared_ptr<IarewProject> project = item.second;
+ IarewProjectWriter writer(file.device());
+ if (!(writer.write(project.get()) && file.commit()))
+ throw ErrorInfo(Internal::Tr::tr("Failed to generate %1")
+ .arg(projectFilePath));
+
+ logger.qbsInfo() << Internal::Tr::tr("Generated %1").arg(
+ QFileInfo(projectFilePath).fileName());
+ }
+}
+
+static void writeWorkspace(const std::shared_ptr<IarewWorkspace> &wokspace,
+ const QString &workspaceFilePath,
+ const Internal::Logger &logger)
+{
+ Internal::FileSaver file(workspaceFilePath.toStdString());
+ if (!file.open())
+ throw ErrorInfo(Internal::Tr::tr("Cannot open %s for writing")
+ .arg(workspaceFilePath));
+
+ IarewWorkspaceWriter writer(file.device());
+ if (!(writer.write(wokspace.get()) && file.commit()))
+ throw ErrorInfo(Internal::Tr::tr("Failed to generate %1")
+ .arg(workspaceFilePath));
+
+ logger.qbsInfo() << Internal::Tr::tr("Generated %1").arg(
+ QFileInfo(workspaceFilePath).fileName());
+}
+
+IarewGenerator::IarewGenerator(const IarewVersionInfo &versionInfo)
+ : m_versionInfo(versionInfo)
+{
+}
+
+QString IarewGenerator::generatorName() const
+{
+ return QStringLiteral("iarew%1").arg(m_versionInfo.marketingVersion());
+}
+
+void IarewGenerator::reset()
+{
+ m_workspace.reset();
+ m_workspaceFilePath.clear();
+ m_projects.clear();
+}
+
+void IarewGenerator::generate()
+{
+ GeneratableProjectIterator it(project());
+ it.accept(this);
+
+ writeProjectFiles(m_projects, logger());
+ writeWorkspace(m_workspace, m_workspaceFilePath, logger());
+
+ reset();
+}
+
+void IarewGenerator::visitProject(const GeneratableProject &project)
+{
+ const QDir buildDir = project.baseBuildDirectory();
+
+ m_workspaceFilePath = buildDir.absoluteFilePath(
+ project.name() + QStringLiteral(".eww"));
+ m_workspace = std::make_shared<IarewWorkspace>(m_workspaceFilePath);
+}
+
+void IarewGenerator::visitProjectData(const GeneratableProject &project,
+ const GeneratableProjectData &projectData)
+{
+ Q_UNUSED(project)
+ Q_UNUSED(projectData)
+}
+
+void IarewGenerator::visitProduct(const GeneratableProject &project,
+ const GeneratableProjectData &projectData,
+ const GeneratableProductData &productData)
+{
+ Q_UNUSED(projectData);
+ const QString projectFilePath = targetFilePath(
+ productData, project.baseBuildDirectory().absolutePath());
+ const auto targetProject = std::make_shared<IarewProject>(
+ project, productData,
+ m_versionInfo);
+
+ m_projects.insert({projectFilePath, targetProject});
+ m_workspace->addProject(projectFilePath);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewgenerator.h b/src/plugins/generator/iarew/iarewgenerator.h
new file mode 100644
index 000000000..f8c1298f0
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewgenerator.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 QBS_IAREWGENERATOR_H
+#define QBS_IAREWGENERATOR_H
+
+#include "iarewversioninfo.h"
+
+#include <generators/generator.h>
+#include <generators/igeneratableprojectvisitor.h>
+
+namespace qbs {
+
+class IarewProject;
+class IarewWorkspace;
+
+class IarewGenerator final : public ProjectGenerator, private IGeneratableProjectVisitor
+{
+public:
+ explicit IarewGenerator(const IarewVersionInfo &versionInfo);
+
+ QString generatorName() const final;
+ void generate() final;
+
+private:
+ void reset();
+
+ void visitProject(const GeneratableProject &project) final;
+ void visitProjectData(const GeneratableProject &project,
+ const GeneratableProjectData &projectData) final;
+ void visitProduct(const GeneratableProject &project,
+ const GeneratableProjectData &projectData,
+ const GeneratableProductData &productData) final;
+
+ const IarewVersionInfo m_versionInfo;
+ std::shared_ptr<IarewWorkspace> m_workspace;
+ QString m_workspaceFilePath;
+ std::map<QString, std::shared_ptr<IarewProject>> m_projects;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWGENERATOR_H
diff --git a/src/plugins/generator/iarew/iarewgeneratorplugin.cpp b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp
new file mode 100644
index 000000000..9f0798573
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 "iarewgenerator.h"
+#include "iarewversioninfo.h"
+
+#include <tools/projectgeneratormanager.h>
+#include <tools/qbspluginmanager.h>
+
+static void QbsIarewGeneratorPluginLoad()
+{
+ for (const auto &info : qbs::IarewVersionInfo::knownVersions()) {
+ qbs::ProjectGeneratorManager::registerGenerator(
+ std::make_shared<qbs::IarewGenerator>(info));
+ }
+}
+
+static void QbsIarewGeneratorPluginUnload()
+{
+}
+
+#ifndef GENERATOR_EXPORT
+#if defined(WIN32) || defined(_WIN32)
+#define GENERATOR_EXPORT __declspec(dllexport)
+#else
+#define GENERATOR_EXPORT __attribute__((visibility("default")))
+#endif
+#endif
+
+QBS_REGISTER_STATIC_PLUGIN(extern "C" GENERATOR_EXPORT, QbsIarewGeneratorPlugin,
+ QbsIarewGeneratorPluginLoad, QbsIarewGeneratorPluginUnload)
diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp
new file mode 100644
index 000000000..8b9f79f1c
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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 "iarewoptionpropertygroup.h"
+
+namespace qbs {
+
+IarewOptionPropertyGroup::IarewOptionPropertyGroup(
+ QByteArray name, const QVariantList &states, int version)
+ : gen::xml::PropertyGroup(QByteArrayLiteral("option"))
+{
+ // Append name property item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("name"),
+ std::move(name));
+
+ // Append version property item.
+ if (version >= 0)
+ appendChild<gen::xml::Property>(QByteArrayLiteral("version"),
+ std::move(version));
+
+ // Append state property items.
+ for (const auto &state : states) {
+ if (state.isNull())
+ continue;
+ appendChild<gen::xml::Property>(QByteArrayLiteral("state"),
+ std::move(state));
+ }
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.h b/src/plugins/generator/iarew/iarewoptionpropertygroup.h
new file mode 100644
index 000000000..d24fe3a9d
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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_IAREWOPTIONPROPERTYGROUP_H
+#define QBS_IAREWOPTIONPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+//#include <QtCore/qvariant.h>
+
+namespace qbs {
+
+class IarewOptionPropertyGroup final
+ : public gen::xml::PropertyGroup
+{
+public:
+ explicit IarewOptionPropertyGroup(
+ QByteArray name, const QVariantList &states,
+ int version = -1);
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWOPTIONPROPERTYGROUP_H
diff --git a/src/plugins/generator/iarew/iarewproject.cpp b/src/plugins/generator/iarew/iarewproject.cpp
new file mode 100644
index 000000000..3e6a03ac2
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewproject.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** 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 "iarewfileversionproperty.h"
+#include "iarewproject.h"
+#include "iarewsourcefilespropertygroup.h"
+#include "iarewutils.h"
+#include "iarewversioninfo.h"
+
+#include "archs/arm/armbuildconfigurationgroup_v8.h"
+#include "archs/avr/avrbuildconfigurationgroup_v7.h"
+#include "archs/mcs51/mcs51buildconfigurationgroup_v10.h"
+#include "archs/stm8/stm8buildconfigurationgroup_v3.h"
+#include "archs/msp430/msp430buildconfigurationgroup_v7.h"
+
+#include <logging/translator.h>
+
+namespace qbs {
+
+IarewProject::IarewProject(const GeneratableProject &genProject,
+ const GeneratableProductData &genProduct,
+ const IarewVersionInfo &versionInfo)
+{
+ Q_ASSERT(genProject.projects.size() == genProject.commandLines.size());
+ Q_ASSERT(genProject.projects.size() == genProduct.data.size());
+
+ // Create available configuration group factories.
+ m_factories.push_back(std::make_unique<
+ iarew::arm::v8::ArmBuildConfigurationGroupFactory>());
+ m_factories.push_back(std::make_unique<
+ iarew::avr::v7::AvrBuildConfigurationGroupFactory>());
+ m_factories.push_back(std::make_unique<
+ iarew::mcs51::v10::Mcs51BuildConfigurationGroupFactory>());
+ m_factories.push_back(std::make_unique<
+ iarew::stm8::v3::Stm8BuildConfigurationGroupFactory>());
+ m_factories.push_back(std::make_unique<
+ iarew::msp430::v7::Msp430BuildConfigurationGroupFactory>());
+
+ // Construct file version item.
+ appendChild<IarewFileVersionProperty>(versionInfo);
+
+ // Construct all build configurations items.
+ const int configsCount = std::max(genProject.projects.size(),
+ genProduct.data.size());
+ for (auto configIndex = 0; configIndex < configsCount; ++configIndex) {
+ const qbs::Project qbsProject = genProject.projects
+ .values().at(configIndex);
+ const ProductData qbsProduct = genProduct.data.values().at(configIndex);
+ const QString confName = gen::utils::buildConfigurationName(qbsProject);
+ const std::vector<ProductData> qbsProductDeps = gen::utils::dependenciesOf
+ (qbsProduct, genProject, confName);
+
+ const auto arch = gen::utils::architecture(qbsProject);
+ if (arch == gen::utils::Architecture::Unknown)
+ throw ErrorInfo(Internal::Tr::tr("Target architecture is not set,"
+ " please use the 'profile' option"));
+
+ // Construct the build configuration item, which are depend from
+ // the architecture and the version.
+ const auto factoryEnd = m_factories.cend();
+ const auto factoryIt = std::find_if(
+ m_factories.cbegin(), factoryEnd,
+ [arch, versionInfo](const auto &factory) {
+ return factory->canCreate(arch, versionInfo.version());
+ });
+ if (factoryIt == factoryEnd) {
+ throw ErrorInfo(Internal::Tr::tr("Incompatible target architecture '%1'"
+ " for IAR EW version %2xxx")
+ .arg(gen::utils::architectureName(arch))
+ .arg(versionInfo.marketingVersion()));
+ }
+ auto configGroup = (*factoryIt)->create(
+ qbsProject, qbsProduct, qbsProductDeps);
+ appendChild(std::move(configGroup));
+ }
+
+ // Construct all file groups items.
+ QMapIterator<QString, qbs::ProductData> dataIt(genProduct.data);
+ while (dataIt.hasNext()) {
+ dataIt.next();
+ const auto groups = dataIt.value().groups();
+ for (const auto &group : groups) {
+ // Ignore disabled groups (e.g. when its condition property is false).
+ if (!group.isEnabled())
+ continue;
+ auto sourceArtifacts = group.sourceArtifacts();
+ // Remove the linker script artifacts.
+ sourceArtifacts.erase(std::remove_if(sourceArtifacts.begin(),
+ sourceArtifacts.end(),
+ [](const auto &artifact){
+ const auto tags = artifact.fileTags();
+ return tags.contains(QLatin1String("linkerscript"));
+ }), sourceArtifacts.end());
+
+ if (sourceArtifacts.isEmpty())
+ continue;
+ appendChild<IarewSourceFilesPropertyGroup>(
+ genProject, group.name(), sourceArtifacts);
+ }
+ }
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewproject.h b/src/plugins/generator/iarew/iarewproject.h
new file mode 100644
index 000000000..567a58c55
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewproject.h
@@ -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.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWPROJECT_H
+#define QBS_IAREWPROJECT_H
+
+#include <generators/generatordata.h>
+#include <generators/xmlproject.h>
+#include <generators/xmlpropertygroup.h>
+
+#include <memory>
+
+namespace qbs {
+
+class IarewVersionInfo;
+
+class IarewProject final : public gen::xml::Project
+{
+public:
+ explicit IarewProject(const GeneratableProject &genProject,
+ const GeneratableProductData &genProduct,
+ const IarewVersionInfo &versionInfo);
+private:
+ std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWPROJECT_H
diff --git a/src/plugins/generator/iarew/iarewprojectwriter.cpp b/src/plugins/generator/iarew/iarewprojectwriter.cpp
new file mode 100644
index 000000000..fcb2103fe
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewprojectwriter.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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 "iarewprojectwriter.h"
+
+namespace qbs {
+
+IarewProjectWriter::IarewProjectWriter(std::ostream *device)
+ : gen::xml::ProjectWriter(device)
+{
+}
+
+void IarewProjectWriter::visitProjectStart(const gen::xml::Project *project)
+{
+ Q_UNUSED(project)
+ writer()->writeStartElement(QStringLiteral("project"));
+}
+
+void IarewProjectWriter::visitProjectEnd(const gen::xml::Project *project)
+{
+ Q_UNUSED(project)
+ writer()->writeEndElement();
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewprojectwriter.h b/src/plugins/generator/iarew/iarewprojectwriter.h
new file mode 100644
index 000000000..9356dbec4
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewprojectwriter.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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_IAREWPROJECTWRITER_H
+#define QBS_IAREWPROJECTWRITER_H
+
+#include <generators/xmlprojectwriter.h>
+
+namespace qbs {
+
+class IarewProjectWriter final : public gen::xml::ProjectWriter
+{
+ Q_DISABLE_COPY(IarewProjectWriter)
+public:
+ explicit IarewProjectWriter(std::ostream *device);
+
+private:
+ void visitProjectStart(const gen::xml::Project *project) final;
+ void visitProjectEnd(const gen::xml::Project *project) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWPROJECTWRITER_H
diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp
new file mode 100644
index 000000000..3e7b6dae7
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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 "iarewoptionpropertygroup.h"
+#include "iarewsettingspropertygroup.h"
+
+namespace qbs {
+
+constexpr int kDataWantNonLocalPropertyValue = 1;
+
+IarewSettingsPropertyGroup::IarewSettingsPropertyGroup()
+ : gen::xml::PropertyGroup(QByteArrayLiteral("settings"))
+{
+ // Append name property item.
+ m_nameProperty = appendChild<gen::xml::Property>(
+ QByteArrayLiteral("name"), QVariant{});
+
+ // Append archive version property item.
+ m_archiveVersionProperty = appendChild<gen::xml::Property>(
+ QByteArrayLiteral("archiveVersion"), QVariant{});
+
+ // Append data property group item.
+ m_dataPropertyGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("data"));
+ // Append data version property item.
+ m_dataVersionProperty = m_dataPropertyGroup->appendChild<
+ gen::xml::Property>(
+ QByteArrayLiteral("version"), QVariant{});
+ // Append data want non-local property item.
+ m_dataPropertyGroup->appendChild<gen::xml::Property>(
+ QByteArrayLiteral("wantNonLocal"),
+ kDataWantNonLocalPropertyValue);
+ // Append data debug property item.
+ m_dataDebugProperty = m_dataPropertyGroup->appendChild<
+ gen::xml::Property>(
+ QByteArrayLiteral("debug"), QVariant{});
+}
+
+void IarewSettingsPropertyGroup::setName(QByteArray name)
+{
+ m_nameProperty->setValue(std::move(name));
+}
+
+QByteArray IarewSettingsPropertyGroup::name() const
+{
+ return m_nameProperty->value().toByteArray();
+}
+
+void IarewSettingsPropertyGroup::setArchiveVersion(
+ int archiveVersion)
+{
+ m_archiveVersionProperty->setValue(archiveVersion);
+}
+
+int IarewSettingsPropertyGroup::archiveVersion() const
+{
+ return m_archiveVersionProperty->value().toInt();
+}
+
+void IarewSettingsPropertyGroup::setDataVersion(int dataVersion)
+{
+ m_dataVersionProperty->setValue(dataVersion);
+}
+
+void IarewSettingsPropertyGroup::setDataDebugInfo(int debugInfo)
+{
+ m_dataDebugProperty->setValue(debugInfo);
+}
+
+void IarewSettingsPropertyGroup::addOptionsGroup(
+ QByteArray name,
+ const QVariantList &states,
+ int version)
+{
+ m_dataPropertyGroup->appendChild<IarewOptionPropertyGroup>(
+ std::move(name), states, std::move(version));
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.h b/src/plugins/generator/iarew/iarewsettingspropertygroup.h
new file mode 100644
index 000000000..4dea76f1a
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.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_IAREWSETTINGSPROPERTYGROUP_H
+#define QBS_IAREWSETTINGSPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+class IarewSettingsPropertyGroup : public gen::xml::PropertyGroup
+{
+public:
+ explicit IarewSettingsPropertyGroup();
+
+ void setName(QByteArray name);
+ QByteArray name() const;
+
+ void setArchiveVersion(int archiveVersion);
+ int archiveVersion() const;
+
+protected:
+ void setDataVersion(int dataVersion);
+ void setDataDebugInfo(int debugInfo);
+
+ void addOptionsGroup(QByteArray name, const QVariantList &states,
+ int version = -1);
+
+private:
+ // Don't delete all this RAW pointers explicitly!
+ gen::xml::Property *m_nameProperty = nullptr;
+ gen::xml::Property *m_archiveVersionProperty = nullptr;
+
+ gen::xml::Property *m_dataPropertyGroup = nullptr;
+ gen::xml::Property *m_dataVersionProperty = nullptr;
+ gen::xml::Property *m_dataDebugProperty = nullptr;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWSETTINGSPROPERTYGROUP_H
diff --git a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.cpp b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.cpp
new file mode 100644
index 000000000..33c26e8b8
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.cpp
@@ -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.
+**
+****************************************************************************/
+
+#include "iarewsourcefilepropertygroup.h"
+#include "iarewutils.h"
+
+#include <generators/generatordata.h>
+
+#include <tools/stringconstants.h>
+
+namespace qbs {
+
+IarewSourceFilePropertyGroup::IarewSourceFilePropertyGroup(
+ const GeneratableProject &genProject,
+ const ArtifactData &sourceArtifact)
+ : gen::xml::PropertyGroup(QByteArrayLiteral("file"))
+{
+ // Create file path property item.
+ const QString fullFilePath = sourceArtifact.filePath();
+ const QString relativeFilePath = IarewUtils::projectRelativeFilePath(
+ genProject.baseBuildDirectory().absolutePath(),
+ fullFilePath);
+ appendChild<gen::xml::Property>(QByteArrayLiteral("name"),
+ relativeFilePath);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h
new file mode 100644
index 000000000..5f88cec27
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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_IAREWSOURCEFILEPROPERTYGROUP_H
+#define QBS_IAREWSOURCEFILEPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+class ArtifactData;
+class GeneratableProject;
+
+class IarewSourceFilePropertyGroup final
+ : public gen::xml::PropertyGroup
+{
+public:
+ explicit IarewSourceFilePropertyGroup(
+ const GeneratableProject &genProject,
+ const ArtifactData &sourceArtifact);
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWSOURCEFILEPROPERTYGROUP_H
diff --git a/src/plugins/generator/iarew/iarewsourcefilespropertygroup.cpp b/src/plugins/generator/iarew/iarewsourcefilespropertygroup.cpp
new file mode 100644
index 000000000..adb5925b2
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsourcefilespropertygroup.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 "iarewsourcefilepropertygroup.h"
+#include "iarewsourcefilespropertygroup.h"
+
+#include <generators/generatordata.h>
+
+#include <tools/stringconstants.h>
+
+namespace qbs {
+
+IarewSourceFilesPropertyGroup::IarewSourceFilesPropertyGroup(
+ const GeneratableProject &genProject,
+ const QString &filesGroupName,
+ const QList<ArtifactData> &sourceFiles)
+ : gen::xml::PropertyGroup(QByteArrayLiteral("group"))
+{
+ // Create group name property item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("name"),
+ filesGroupName);
+
+ // Create file paths property items.
+ for (const auto &sourceFile : sourceFiles)
+ appendChild<IarewSourceFilePropertyGroup>(genProject,
+ sourceFile);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewsourcefilespropertygroup.h b/src/plugins/generator/iarew/iarewsourcefilespropertygroup.h
new file mode 100644
index 000000000..8d8a4be0c
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewsourcefilespropertygroup.h
@@ -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.
+**
+****************************************************************************/
+
+#ifndef QBS_IAREWSOURCEFILESPROPERTYGROUP_H
+#define QBS_IAREWSOURCEFILESPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+class IarewSourceFilesPropertyGroup final
+ : public gen::xml::PropertyGroup
+{
+public:
+ explicit IarewSourceFilesPropertyGroup(
+ const GeneratableProject &genProject,
+ const QString &filesGroupName,
+ const QList<ArtifactData> &sourceFiles);
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWSOURCEFILESPROPERTYGROUP_H
diff --git a/src/plugins/generator/iarew/iarewtoolchainpropertygroup.cpp b/src/plugins/generator/iarew/iarewtoolchainpropertygroup.cpp
new file mode 100644
index 000000000..dba5015bf
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewtoolchainpropertygroup.cpp
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** 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 "iarewtoolchainpropertygroup.h"
+
+namespace qbs {
+
+IarewToolchainPropertyGroup::IarewToolchainPropertyGroup(
+ const QByteArray &toolchainName)
+ : gen::xml::PropertyGroup(QByteArrayLiteral("toolchain"))
+{
+ // Append toolchain name property item.
+ appendProperty(QByteArrayLiteral("name"), toolchainName);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewtoolchainpropertygroup.h b/src/plugins/generator/iarew/iarewtoolchainpropertygroup.h
new file mode 100644
index 000000000..e5bd6f071
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewtoolchainpropertygroup.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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_IAREWTOOLCHAINPROPERTYGROUP_H
+#define QBS_IAREWTOOLCHAINPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+class IarewToolchainPropertyGroup final
+ : public gen::xml::PropertyGroup
+{
+public:
+ explicit IarewToolchainPropertyGroup(
+ const QByteArray &toolchainName);
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWTOOLCHAINPROPERTYGROUP_H
diff --git a/src/plugins/generator/iarew/iarewutils.cpp b/src/plugins/generator/iarew/iarewutils.cpp
new file mode 100644
index 000000000..f00fce026
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewutils.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** 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 "iarewutils.h"
+
+#include <generators/generatorutils.h>
+
+namespace qbs {
+namespace IarewUtils {
+
+QString toolkitRootPath(const ProductData &qbsProduct)
+{
+ QDir dir(qbsProduct.moduleProperties()
+ .getModuleProperty(Internal::StringConstants::cppModule(),
+ QStringLiteral("toolchainInstallPath"))
+ .toString());
+ dir.cdUp();
+ return dir.absolutePath();
+}
+
+QString dlibToolkitRootPath(const ProductData &qbsProduct)
+{
+ return toolkitRootPath(qbsProduct) + QLatin1String("/lib/dlib");
+}
+
+QString clibToolkitRootPath(const ProductData &qbsProduct)
+{
+ return toolkitRootPath(qbsProduct) + QLatin1String("/lib/clib");
+}
+
+QString libToolkitRootPath(const ProductData &qbsProduct)
+{
+ return toolkitRootPath(qbsProduct) + QLatin1String("/lib");
+}
+
+QString toolkitRelativeFilePath(const QString &basePath,
+ const QString &fullFilePath)
+{
+ return QLatin1String("$TOOLKIT_DIR$/")
+ + gen::utils::relativeFilePath(basePath, fullFilePath);
+}
+
+QString projectRelativeFilePath(const QString &basePath,
+ const QString &fullFilePath)
+{
+ return QLatin1String("$PROJ_DIR$/")
+ + gen::utils::relativeFilePath(basePath, fullFilePath);
+}
+
+OutputBinaryType outputBinaryType(const ProductData &qbsProduct)
+{
+ const auto qbsProductType = qbsProduct.type();
+ if (qbsProductType.contains(QLatin1String("application")))
+ return ApplicationOutputType;
+ if (qbsProductType.contains(QLatin1String("staticlibrary")))
+ return LibraryOutputType;
+ return ApplicationOutputType;
+}
+
+QString flagValue(const QStringList &flags, const QString &flagKey)
+{
+ // Seach for full 'flagKey' option matching.
+ const auto flagBegin = flags.cbegin();
+ const auto flagEnd = flags.cend();
+ auto flagIt = std::find_if(flagBegin, flagEnd, [flagKey](const QString &flag) {
+ return flag == flagKey;
+ });
+ if (flagIt == flagEnd) {
+ // Search for start/end of 'flagKey' matching.
+ flagIt = std::find_if(flagBegin, flagEnd, [flagKey](const QString &flag) {
+ return flag.startsWith(flagKey) || flag.endsWith(flagKey);
+ });
+ if (flagIt == flagEnd)
+ return {};
+ }
+
+ QString value;
+ // Check that option is in form of 'flagKey=<flagValue>'.
+ if (flagIt->contains(QLatin1Char('='))) {
+ value = flagIt->split(QLatin1Char('=')).at(1).trimmed();
+ } else if (flagKey.count() < flagIt->count()) {
+ // In this case an option is in form of 'flagKey<flagValue>'.
+ value = flagIt->mid(flagKey.count()).trimmed();
+ } else {
+ // In this case an option is in form of 'flagKey <flagValue>'.
+ ++flagIt;
+ if (flagIt < flagEnd)
+ value = (*flagIt).trimmed();
+ else
+ return {};
+ }
+ return value;
+}
+
+QVariantList flagValues(const QStringList &flags, const QString &flagKey)
+{
+ QVariantList values;
+ for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) {
+ if (*flagIt != flagKey)
+ continue;
+ ++flagIt;
+ values.push_back(*flagIt);
+ }
+ return values;
+}
+
+QStringList cppModuleCompilerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags"), QStringLiteral("cFlags"),
+ QStringLiteral("cppFlags"), QStringLiteral("cxxFlags"),
+ QStringLiteral("commonCompilerFlags")});
+}
+
+QStringList cppModuleAssemblerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("assemblerFlags")});
+}
+
+QStringList cppModuleLinkerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags"),
+ QStringLiteral("driverLinkerFlags")});
+}
+
+} // namespace IarewUtils
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewutils.h b/src/plugins/generator/iarew/iarewutils.h
new file mode 100644
index 000000000..2d32ac188
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewutils.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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_IAREWUTILS_H
+#define QBS_IAREWUTILS_H
+
+#include <qbs.h>
+
+#include <tools/stringconstants.h>
+
+namespace qbs {
+namespace IarewUtils {
+
+enum OutputBinaryType {
+ ApplicationOutputType,
+ LibraryOutputType
+};
+
+OutputBinaryType outputBinaryType(const ProductData &qbsProduct);
+
+QString toolkitRootPath(const ProductData &qbsProduct);
+
+QString dlibToolkitRootPath(const ProductData &qbsProduct);
+
+QString clibToolkitRootPath(const ProductData &qbsProduct);
+
+QString libToolkitRootPath(const ProductData &qbsProduct);
+
+QString toolkitRelativeFilePath(const QString &basePath,
+ const QString &fullFilePath);
+
+QString projectRelativeFilePath(const QString &basePath,
+ const QString &fullFilePath);
+
+QString flagValue(const QStringList &flags, const QString &flagKey);
+
+QVariantList flagValues(const QStringList &flags, const QString &flagKey);
+
+QStringList cppModuleCompilerFlags(const PropertyMap &qbsProps);
+
+QStringList cppModuleAssemblerFlags(const PropertyMap &qbsProps);
+
+QStringList cppModuleLinkerFlags(const PropertyMap &qbsProps);
+
+} // namespace IarewUtils
+} // namespace qbs
+
+#endif // QBS_IAREWUTILS_H
diff --git a/src/plugins/generator/iarew/iarewversioninfo.cpp b/src/plugins/generator/iarew/iarewversioninfo.cpp
new file mode 100644
index 000000000..41a788e98
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewversioninfo.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 "iarewversioninfo.h"
+
+#include <QtCore/qdebug.h>
+
+namespace qbs {
+
+IarewVersionInfo::IarewVersionInfo(
+ const Version &version,
+ const std::set<gen::utils::Architecture> &archs)
+ : gen::VersionInfo(version, archs)
+{
+}
+
+std::set<IarewVersionInfo> IarewVersionInfo::knownVersions()
+{
+ static const std::set<IarewVersionInfo> known = {
+ {Version(8), {gen::utils::Architecture::Arm}},
+ {Version(7), {gen::utils::Architecture::Avr,
+ gen::utils::Architecture::Msp430}},
+ {Version(10), {gen::utils::Architecture::Mcs51}},
+ {Version(3), {gen::utils::Architecture::Stm8}},
+ };
+ return known;
+}
+
+int IarewVersionInfo::marketingVersion() const
+{
+ const auto mv = gen::VersionInfo::marketingVersion();
+ for (const IarewVersionInfo &known : knownVersions()) {
+ if (known.version().majorVersion() == mv)
+ return mv;
+ }
+ qWarning() << QStringLiteral("Unrecognized IAR EW version: ")
+ << version().toString();
+ return 0;
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewversioninfo.h b/src/plugins/generator/iarew/iarewversioninfo.h
new file mode 100644
index 000000000..4fd1b1fbc
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewversioninfo.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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 QBS_IAREWVERSIONINFO_H
+#define QBS_IAREWVERSIONINFO_H
+
+#include <generators/generatorutils.h>
+#include <generators/generatorversioninfo.h>
+
+namespace qbs {
+
+class IarewVersionInfo final : public gen::VersionInfo
+{
+public:
+ IarewVersionInfo(const Version &version,
+ const std::set<gen::utils::Architecture> &archs);
+
+ int marketingVersion() const final;
+
+ static std::set<IarewVersionInfo> knownVersions();
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWVERSIONINFO_H
diff --git a/src/plugins/generator/iarew/iarewworkspace.cpp b/src/plugins/generator/iarew/iarewworkspace.cpp
new file mode 100644
index 000000000..bfe22aea7
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewworkspace.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 "iarewworkspace.h"
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+IarewWorkspace::IarewWorkspace(const QString &workspacePath)
+ : gen::xml::Workspace(workspacePath)
+{
+ appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("batchBuild"));
+}
+
+void IarewWorkspace::addProject(const QString &projectFilePath)
+{
+ const QString relativeProjectPath = QLatin1String("$WS_DIR$/")
+ + m_baseDirectory.relativeFilePath(projectFilePath);
+
+ const auto projectGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("project"));
+ projectGroup->appendProperty("path", relativeProjectPath);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewworkspace.h b/src/plugins/generator/iarew/iarewworkspace.h
new file mode 100644
index 000000000..ea14e4174
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewworkspace.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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 QBS_IAREWWORKSPACE_H
+#define QBS_IAREWWORKSPACE_H
+
+#include <generators/xmlworkspace.h>
+
+#include <QtCore/qdir.h>
+
+namespace qbs {
+
+class IarewWorkspace final : public gen::xml::Workspace
+{
+public:
+ explicit IarewWorkspace(const QString &workspacePath);
+ void addProject(const QString &projectPath) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWWORKSPACE_H
diff --git a/src/plugins/generator/iarew/iarewworkspacewriter.cpp b/src/plugins/generator/iarew/iarewworkspacewriter.cpp
new file mode 100644
index 000000000..b06080e3a
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewworkspacewriter.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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 "iarewworkspacewriter.h"
+
+namespace qbs {
+
+IarewWorkspaceWriter::IarewWorkspaceWriter(std::ostream *device)
+ : gen::xml::WorkspaceWriter(device)
+{
+}
+
+void IarewWorkspaceWriter::visitWorkspaceStart(const gen::xml::Workspace *workspace)
+{
+ Q_UNUSED(workspace)
+ writer()->writeStartElement(QStringLiteral("workspace"));
+}
+
+void IarewWorkspaceWriter::visitWorkspaceEnd(const gen::xml::Workspace *workspace)
+{
+ Q_UNUSED(workspace)
+ writer()->writeEndElement();
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewworkspacewriter.h b/src/plugins/generator/iarew/iarewworkspacewriter.h
new file mode 100644
index 000000000..e60b102d3
--- /dev/null
+++ b/src/plugins/generator/iarew/iarewworkspacewriter.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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_IAREWWORKSPACEWRITER_H
+#define QBS_IAREWWORKSPACEWRITER_H
+
+#include <generators/xmlworkspacewriter.h>
+
+namespace qbs {
+
+class IarewWorkspaceWriter final : public gen::xml::WorkspaceWriter
+{
+ Q_DISABLE_COPY(IarewWorkspaceWriter)
+public:
+ explicit IarewWorkspaceWriter(std::ostream *device);
+
+private:
+ void visitWorkspaceStart(const gen::xml::Workspace *workspace) final;
+ void visitWorkspaceEnd(const gen::xml::Workspace *workspace) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_IAREWWORKSPACEWRITER_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.cpp
new file mode 100644
index 000000000..c5cb5f040
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 "armbuildtargetgroup_v5.h"
+#include "armcommonpropertygroup_v5.h"
+#include "armdebugoptiongroup_v5.h"
+#include "armdlloptiongroup_v5.h"
+#include "armtargetcommonoptionsgroup_v5.h"
+#include "armtargetgroup_v5.h"
+#include "armutilitiesgroup_v5.h"
+
+#include "../../keiluvconstants.h"
+#include "../../keiluvfilesgroupspropertygroup.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmBuildTargetGroup::ArmBuildTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup("Target")
+{
+ // Append target name item (it is a build configuration name).
+ const QString targetName = gen::utils::buildConfigurationName(
+ qbsProject);
+ appendProperty(QByteArrayLiteral("TargetName"), targetName);
+ // Append toolset number group item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("ToolsetNumber"),
+ QByteArrayLiteral("0x4"));
+ // Append toolset name group item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("ToolsetName"),
+ QByteArrayLiteral("ARM-ADS"));
+
+ // Append target option group item.
+ const auto targetOptionGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("TargetOption"));
+
+ targetOptionGroup->appendChild<ArmTargetCommonOptionsGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<ArmCommonPropertyGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<ArmDllOptionGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<ArmDebugOptionGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<ArmUtilitiesGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<ArmTargetGroup>(
+ qbsProject, qbsProduct);
+
+ // Append files group.
+ appendChild<KeiluvFilesGroupsPropertyGroup>(qbsProject, qbsProduct,
+ qbsProductDeps);
+}
+
+bool ArmBuildTargetGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Arm
+ && version.majorVersion() == qbs::KeiluvConstants::v5::kUVisionVersion;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+ArmBuildTargetGroupFactory::create(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps) const
+{
+ const auto group = new ArmBuildTargetGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<ArmBuildTargetGroup>(group);
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.h
new file mode 100644
index 000000000..9b8d9fe26
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armbuildtargetgroup_v5.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 QBS_KEILUVARMBUILDTARGETGROUP_V5_H
+#define QBS_KEILUVARMBUILDTARGETGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmBuildTargetGroup final : public gen::xml::PropertyGroup
+{
+private:
+ explicit ArmBuildTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps);
+
+ friend class ArmBuildTargetGroupFactory;
+};
+
+class ArmBuildTargetGroupFactory 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<qbs::ProductData> &qbsProductDeps) const final;
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMBUILDTARGETGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.cpp
new file mode 100644
index 000000000..e7a738235
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.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 "armcommonpropertygroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmCommonPropertyGroup::ArmCommonPropertyGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("CommonProperty")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.h
new file mode 100644
index 000000000..4d45decc4
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armcommonpropertygroup_v5.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 QBS_KEILUVARMCOMMONPROPERTYGROUP_V5_H
+#define QBS_KEILUVARMCOMMONPROPERTYGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmCommonPropertyGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmCommonPropertyGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_MCS51COMMONPROPERTYGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.cpp
new file mode 100644
index 000000000..553df646d
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.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 "armdebugoptiongroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmDebugOptionGroup::ArmDebugOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("DebugOption")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.h
new file mode 100644
index 000000000..22d5bb88f
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armdebugoptiongroup_v5.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 QBS_KEILUVARMDEBUGOPTIONGROUP_V5_H
+#define QBS_KEILUVARMDEBUGOPTIONGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmDebugOptionGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmDebugOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMDEBUGOPTIONGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.cpp
new file mode 100644
index 000000000..9e1bdff02
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.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 "armdlloptiongroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmDllOptionGroup::ArmDllOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("DllOption")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.h
new file mode 100644
index 000000000..948eb1568
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armdlloptiongroup_v5.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 QBS_KEILUVARMDLLOPTIONGROUP_V5_H
+#define QBS_KEILUVARMDLLOPTIONGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmDllOptionGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmDllOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMDLLOPTIONGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.cpp
new file mode 100644
index 000000000..424cb3353
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 "armtargetassemblergroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+namespace {
+
+struct AssemblerPageOptions final
+{
+ explicit AssemblerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleAssemblerFlags(qbsProps);
+
+ // Read-only position independent.
+ enableRopi = flags.contains(QLatin1String("/ropi"));
+ // Read-write position independent.
+ enableRwpi = flags.contains(QLatin1String("/rwpi"));
+ // Enable thumb mode.
+ enableThumbMode = flags.contains(QLatin1String("--16"));
+ // Split load and store multiple.
+ splitLdm = flags.contains(QLatin1String("--split_ldm"));
+ // Generation code.
+ generateExecuteOnlyCode = flags.contains(QLatin1String("--execute_only"));
+
+ // Warning levels.
+ const QString wLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ disableWarnings = wLevel == QLatin1String("none");
+
+ // Define symbols.
+ defineSymbols = qbs::KeiluvUtils::defines(qbsProps);
+ // Include paths.
+ includePaths = qbs::KeiluvUtils::includes(qbsProps);
+
+ // Interpret other compiler flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) {
+ if (flagIt->contains(QLatin1String("/ropi"))
+ || flagIt->contains(QLatin1String("/rwpi"))
+ || flagIt->contains(QLatin1String("--16"))
+ || flagIt->contains(QLatin1String("--split_ldm"))
+ || flagIt->contains(QLatin1String("--execute_only"))
+ || flagIt->contains(QLatin1String("--nowarn"))
+ ) {
+ continue;
+ }
+ if (flagIt->startsWith(QLatin1String("-I"))
+ || flagIt->startsWith(QLatin1String("--cpu"))
+ || flagIt->startsWith(QLatin1String("--fpu"))
+ || flagIt->startsWith(QLatin1String("-pd"))
+ ) {
+ ++flagIt;
+ continue;
+ }
+ miscControls.push_back(*flagIt);
+ }
+ }
+
+ int enableRopi = 0;
+ int enableRwpi = 0;
+ int enableThumbMode = 0;
+ int disableWarnings = 0;
+ int splitLdm = 0;
+ int generateExecuteOnlyCode = 0;
+
+ QStringList defineSymbols;
+ QStringList includePaths;
+ QStringList miscControls;
+};
+
+} // namespace
+
+ArmTargetAssemblerGroup::ArmTargetAssemblerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Aads")
+{
+ const AssemblerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'ROPI' item.
+ appendProperty(QByteArrayLiteral("Ropi"), opts.enableRopi);
+ // Add 'RWPI' item.
+ appendProperty(QByteArrayLiteral("Rwpi"), opts.enableRwpi);
+ // Add 'Use thumb mode' item.
+ appendProperty(QByteArrayLiteral("thumb"), opts.enableThumbMode);
+ // Add 'Slpit LDM' item.
+ appendProperty(QByteArrayLiteral("SplitLS"), opts.splitLdm);
+ // Add 'Disable warnings' item.
+ appendProperty(QByteArrayLiteral("NoWarn"), opts.disableWarnings);
+ // Add 'Generate code exedutable only' item.
+ appendProperty(QByteArrayLiteral("useXo"), opts.generateExecuteOnlyCode);
+
+ // Add other various controls.
+ // Note: A sub-items order makes sense!
+ const auto variousControlsGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("VariousControls"));
+ // Add 'Misc Controls' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("MiscControls"),
+ opts.miscControls, QLatin1Char(' '));
+ // Add 'Define' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("Define"), opts.defineSymbols);
+ // Add an empty 'Undefine' item.
+ variousControlsGroup->appendProperty(
+ QByteArrayLiteral("Undefine"), {});
+ // Add 'Include Paths' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("IncludePath"),
+ opts.includePaths, QLatin1Char(';'));
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.h
new file mode 100644
index 000000000..d61b11fe5
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetassemblergroup_v5.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 QBS_KEILUVARMTARGETASSEMBLERGROUP_V3
+#define QBS_KEILUVARMTARGETASSEMBLERGROUP_V3
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetAssemblerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetAssemblerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETASSEMBLERGROUP_V3
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.cpp
new file mode 100644
index 000000000..0ffbcaa5b
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** 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 "armtargetcommonoptionsgroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+#include <generators/generatorutils.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+namespace {
+
+static const struct DeviceEntry {
+ QByteArray cpu; // CPU option.
+ std::set<QByteArray> fpus; // FPU's options.
+ QByteArray device; // Project file entry.
+} deviceDict[] = {
+ {"8-M.Base", {}, "ARMv8MBL"},
+ {"8-M.Main", {"FPv5-SP"}, "ARMv8MML_SP"},
+ {"8-M.Main", {"FPv5_D16"}, "ARMv8MML_DP"},
+ {"8-M.Main", {"SoftVFP"},"ARMv8MML"},
+ {"8-M.Main.dsp", {"FPv5-SP"}, "ARMv8MML_DSP_SP"},
+ {"8-M.Main.dsp", {"FPv5_D16"}, "ARMv8MML_DSP_DP"},
+ {"8-M.Main.dsp", {"SoftVFP"}, "ARMv8MML_DSP"},
+ {"Cortex-M0", {}, "ARMCM0"},
+ {"Cortex-M0+", {}, "ARMCM0P"},
+ {"Cortex-M0plus", {}, "ARMCM0P"},
+ {"Cortex-M23", {}, "ARMCM23"}, // same as ARMCM23_TZ
+ {"Cortex-M3", {}, "ARMCM3"},
+ {"Cortex-M4", {}, "ARMCM4"},
+ {"Cortex-M4.fp", {}, "ARMCM4_FP"},
+ {"Cortex-M7", {"SoftVFP"}, "ARMCM7"},
+ {"Cortex-M7.fp.dp", {}, "ARMCM7_DP"},
+ {"Cortex-M7.fp.sp", {}, "ARMCM7_SP"},
+ {"SC000", {}, "ARMSC000"},
+ {"SC300", {}, "ARMSC300"},
+ {"Cortex-M33.no_dsp", {"SoftVFP"}, "ARMCM33"}, // same as ARMCM33_TZ
+ {"Cortex-M33", {"FPv5-SP", "softvfp+vfpv2"}, "ARMCM33_DSP_FP"}, // same as ARMCM33_DSP_FP_TZ
+};
+
+struct CommonPageOptions final
+{
+ explicit CommonPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Browse information.
+ // ???
+
+ // Debug information.
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+
+ // Output parameters.
+ executableName = gen::utils::targetBinary(qbsProduct);
+ // Fix output binary name if it is a library. Because
+ // the IDE appends an additional suffix (.LIB) to end
+ // of an output library name.
+ if (executableName.endsWith(QLatin1String(".lib")))
+ executableName = qbsProduct.targetName();
+
+ const QString baseDirectory = gen::utils::buildRootPath(qbsProject);
+ objectDirectory = QDir::toNativeSeparators(
+ gen::utils::objectsOutputDirectory(
+ baseDirectory, qbsProduct));
+ listingDirectory = QDir::toNativeSeparators(
+ gen::utils::listingOutputDirectory(
+ baseDirectory, qbsProduct));
+
+ // Target type.
+ targetType = KeiluvUtils::outputBinaryType(qbsProduct);
+
+ // Detect the device name from the command line options
+ // (like --cpu and --fpu).
+ const auto cpu = gen::utils::firstFlagValue(
+ flags, QStringLiteral("--cpu")).toLatin1();
+ const auto fpus = gen::utils::allFlagValues(
+ flags, QStringLiteral("--fpu"));
+
+ for (const auto &deviceEntry : deviceDict) {
+ // Since Qt 5.12 we can use QByteArray::compare(..., Qt::CaseInsensitive)
+ // instead.
+ if (cpu.toLower() != deviceEntry.cpu.toLower())
+ continue;
+
+ size_t fpuMatches = 0;
+ const auto dictFpuBegin = std::cbegin(deviceDict->fpus);
+ const auto dictFpuEnd = std::cend(deviceDict->fpus);
+ for (const auto &fpu : fpus) {
+ const auto dictFpuIt = std::find_if(
+ dictFpuBegin, dictFpuEnd,
+ [fpu](const QByteArray &dictFpu) {
+ return fpu.compare(QString::fromLatin1(dictFpu),
+ Qt::CaseInsensitive) == 0;
+ });
+ if (dictFpuIt != dictFpuEnd)
+ ++fpuMatches;
+ }
+
+ if (fpuMatches < deviceEntry.fpus.size())
+ continue;
+
+ deviceName = QString::fromLatin1(deviceEntry.device);
+ cpuType = QString::fromLatin1(deviceEntry.cpu);
+ break;
+ }
+ }
+
+ int debugInfo = false;
+ int browseInfo = false;
+ QString deviceName;
+ QString cpuType;
+ QString executableName;
+ QString objectDirectory;
+ QString listingDirectory;
+ KeiluvUtils::OutputBinaryType targetType =
+ KeiluvUtils::ApplicationOutputType;
+};
+
+} // namespace
+
+ArmTargetCommonOptionsGroup::ArmTargetCommonOptionsGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("TargetCommonOption")
+{
+ const CommonPageOptions opts(qbsProject, qbsProduct);
+
+ // Fill device items.
+ appendProperty(QByteArrayLiteral("Device"),
+ opts.deviceName);
+ appendProperty(QByteArrayLiteral("Vendor"),
+ QByteArrayLiteral("ARM"));
+ appendProperty(QByteArrayLiteral("PackID"),
+ QByteArrayLiteral("ARM.CMSIS.5.6.0"));
+ appendProperty(QByteArrayLiteral("PackURL"),
+ QByteArrayLiteral("http://www.keil.com/pack/"));
+
+ const auto cpuType = QStringLiteral("CPUTYPE(\"%1\")")
+ .arg(opts.cpuType);
+ appendProperty(QByteArrayLiteral("Cpu"), cpuType);
+
+ // Add 'Debug Information' item.
+ appendProperty(QByteArrayLiteral("DebugInformation"),
+ opts.debugInfo);
+ // Add 'Browse Information' item.
+ appendProperty(QByteArrayLiteral("BrowseInformation"),
+ opts.browseInfo);
+
+ // Add 'Name of Executable'.
+ appendProperty(QByteArrayLiteral("OutputName"),
+ opts.executableName);
+ // Add 'Output objects directory'.
+ appendProperty(QByteArrayLiteral("OutputDirectory"),
+ opts.objectDirectory);
+ // Add 'Output listing directory'.
+ appendProperty(QByteArrayLiteral("ListingPath"),
+ opts.listingDirectory);
+
+ // Add 'Create Executable/Library' item.
+ const int isExecutable = (opts.targetType
+ == KeiluvUtils::ApplicationOutputType);
+ const int isLibrary = (opts.targetType
+ == KeiluvUtils::LibraryOutputType);
+ appendProperty(QByteArrayLiteral("CreateExecutable"),
+ isExecutable);
+ appendProperty(QByteArrayLiteral("CreateLib"),
+ isLibrary);
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.h
new file mode 100644
index 000000000..b7d4ffee2
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetcommonoptionsgroup_v5.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 QBS_KEILUVARMTARGETCOMMONOPTIONSGROUP_V5_H
+#define QBS_KEILUVARMTARGETCOMMONOPTIONSGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetCommonOptionsGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetCommonOptionsGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETCOMMONOPTIONSGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.cpp
new file mode 100644
index 000000000..c923bd9b9
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** 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 "armtargetcompilergroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+namespace {
+
+struct CompilerPageOptions final
+{
+ enum WarningLevel {
+ WarningLevelUnspecified = 0,
+ WarningLevelNone,
+ WarningLevelAll
+ };
+
+ enum OptimizationLevel {
+ OptimizationLevelUnspecified = 0,
+ OptimizationLevelNone,
+ OptimizationLevelOne,
+ OptimizationLevelTwo,
+ OptimizationLevelThree,
+ };
+
+ explicit CompilerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Warning levels.
+ const QString wLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ if (wLevel == QLatin1String("none"))
+ warningLevel = WarningLevelNone;
+ else if (wLevel == QLatin1String("all"))
+ warningLevel = WarningLevelAll;
+ else
+ warningLevel = WarningLevelUnspecified;
+
+ // Generation code.
+ generateExecuteOnlyCode = flags.contains(QLatin1String("--execute_only"));
+
+ // Optimization levels.
+ const QString oLevel = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("optimization"));
+ if (oLevel == QLatin1String("fast"))
+ enableTimeOptimization = 1;
+ else if (oLevel == QLatin1String("small"))
+ optimizationLevel = OptimizationLevelThree;
+ else if (oLevel == QLatin1String("none"))
+ optimizationLevel = OptimizationLevelNone;
+
+ // Split load and store multiple.
+ splitLdm = flags.contains(QLatin1String("--split_ldm"));
+ // One ELF section per function.
+ splitSections = flags.contains(QLatin1String("--split_sections"));
+ // String ANSI C.
+ useStrictAnsiC = flags.contains(QLatin1String("--strict"));
+ // Enum container always int.
+ forceEnumAsInt = flags.contains(QLatin1String("--enum_is_int"));
+ // Plain char is signed.
+ useSignedChar = flags.contains(QLatin1String("--signed_chars"));
+ // Read-only position independent.
+ enableRopi = flags.contains(QLatin1String("/ropi"));
+ // Read-write position independent.
+ enableRwpi = flags.contains(QLatin1String("/rwpi"));
+
+ // C-language version.
+ const QString clVersion = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("cLanguageVersion"));
+ // C99 mode.
+ useC99Language = clVersion.contains(QLatin1String("c99"));
+
+ // Define symbols.
+ defineSymbols = qbs::KeiluvUtils::defines(qbsProps);
+ // Include paths.
+ includePaths = qbs::KeiluvUtils::includes(qbsProps);
+
+ // Interpret other compiler flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) {
+ if (flagIt->contains(QLatin1String("--execute_only"))
+ || flagIt->contains(QLatin1String("--split_ldm"))
+ || flagIt->contains(QLatin1String("--split_sections"))
+ || flagIt->contains(QLatin1String("--strict"))
+ || flagIt->contains(QLatin1String("--enum_is_int"))
+ || flagIt->contains(QLatin1String("--signed_chars"))
+ || flagIt->contains(QLatin1String("/ropi"))
+ || flagIt->contains(QLatin1String("/rwpi"))
+ || flagIt->contains(QLatin1String("--c99"))
+ ) {
+ continue;
+ }
+ if (flagIt->startsWith(QLatin1String("-O"))
+ || flagIt->startsWith(QLatin1String("-W"))
+ || flagIt->startsWith(QLatin1String("-D"))
+ || flagIt->startsWith(QLatin1String("-I"))
+ || flagIt->startsWith(QLatin1String("--cpu"))
+ || flagIt->startsWith(QLatin1String("--fpu"))
+ ) {
+ ++flagIt;
+ continue;
+ }
+ miscControls.push_back(*flagIt);
+ }
+ }
+
+ WarningLevel warningLevel = WarningLevelAll;
+ OptimizationLevel optimizationLevel = OptimizationLevelUnspecified;
+ int enableTimeOptimization = 0;
+ int generateExecuteOnlyCode = 0;
+ int splitLdm = 0;
+ int splitSections = 0;
+ int useStrictAnsiC = 0;
+ int forceEnumAsInt = 0;
+ int useSignedChar = 0;
+ int enableRopi = 0;
+ int enableRwpi = 0;
+ int useC99Language = 0;
+
+ QStringList defineSymbols;
+ QStringList includePaths;
+ QStringList miscControls;
+};
+
+} // namespace
+
+ArmTargetCompilerGroup::ArmTargetCompilerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Cads")
+{
+ const CompilerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Code Optimization' items.
+ appendProperty(QByteArrayLiteral("Optim"), opts.optimizationLevel);
+ appendProperty(QByteArrayLiteral("oTime"), opts.enableTimeOptimization);
+ // Add 'Slpit LDM' item.
+ appendProperty(QByteArrayLiteral("SplitLS"), opts.splitLdm);
+ // Add 'Slpit sections' item.
+ appendProperty(QByteArrayLiteral("OneElfS"), opts.splitSections);
+ // Add 'Strict ANSI C' item.
+ appendProperty(QByteArrayLiteral("Strict"), opts.useStrictAnsiC);
+ // Add 'Enums as int' item.
+ appendProperty(QByteArrayLiteral("EnumInt"), opts.forceEnumAsInt);
+ // Add 'Plain char as signed' item.
+ appendProperty(QByteArrayLiteral("PlainCh"), opts.useSignedChar);
+ // Add 'ROPI' item.
+ appendProperty(QByteArrayLiteral("Ropi"), opts.enableRopi);
+ // Add 'RWPI' item.
+ appendProperty(QByteArrayLiteral("Rwpi"), opts.enableRwpi);
+ // Add 'Warnings' item.
+ appendProperty(QByteArrayLiteral("wLevel"), opts.warningLevel);
+ // Add 'Use C99' item.
+ appendProperty(QByteArrayLiteral("uC99"), opts.useC99Language);
+ // Add 'Generate code exedutable only' item.
+ appendProperty(QByteArrayLiteral("useXo"), opts.generateExecuteOnlyCode);
+
+ // Add other various controls.
+ // Note: A sub-items order makes sense!
+ const auto variousControlsGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("VariousControls"));
+ // Add 'Misc Controls' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("MiscControls"),
+ opts.miscControls, QLatin1Char(' '));
+ // Add 'Define' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("Define"), opts.defineSymbols);
+ // Add an empty 'Undefine' item.
+ variousControlsGroup->appendProperty(
+ QByteArrayLiteral("Undefine"), {});
+ // Add 'Include Paths' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("IncludePath"),
+ opts.includePaths, QLatin1Char(';'));
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.h
new file mode 100644
index 000000000..89759ee0b
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetcompilergroup_v5.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 QBS_KEILUVARMTARGETCOMPILERGROUP_V5_H
+#define QBS_KEILUVARMTARGETCOMPILERGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetCompilerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetCompilerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETCOMPILERGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.cpp
new file mode 100644
index 000000000..61c7b5667
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.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 "armtargetassemblergroup_v5.h"
+#include "armtargetcompilergroup_v5.h"
+#include "armtargetgroup_v5.h"
+#include "armtargetlinkergroup_v5.h"
+#include "armtargetmiscgroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmTargetGroup::ArmTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("TargetArmAds")
+{
+ appendChild<ArmTargetMiscGroup>(qbsProject, qbsProduct);
+ appendChild<ArmTargetCompilerGroup>(qbsProject, qbsProduct);
+ appendChild<ArmTargetAssemblerGroup>(qbsProject, qbsProduct);
+ appendChild<ArmTargetLinkerGroup>(qbsProject, qbsProduct);
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.h
new file mode 100644
index 000000000..7472fe675
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetgroup_v5.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 QBS_KEILUVARMTARGETGROUP_V5_H
+#define QBS_KEILUVARMTARGETGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.cpp
new file mode 100644
index 000000000..930aae020
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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 "armtargetlinkergroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+#include <generators/generatorutils.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+namespace {
+
+struct LinkerPageOptions final
+{
+ explicit LinkerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleLinkerFlags(qbsProps);
+
+ // Read-only position independent.
+ enableRopi = flags.contains(QLatin1String("--ropi"));
+ // Read-write position independent.
+ enableRwpi = flags.contains(QLatin1String("--rwpi"));
+ // Don't search standard libraries.
+ dontSearchLibs = flags.contains(QLatin1String("--noscanlib"));
+ // Report 'might fail' conditions as errors.
+ enableReportMightFail = flags.contains(QLatin1String("--strict"));
+
+ QStringList scatterFiles;
+
+ // 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 scatterFile = QFileInfo(qbsArtifact.filePath())
+ .absoluteFilePath();
+ scatterFiles.push_back(scatterFile);
+ }
+ }
+
+ // Enumerate all scatter files
+ // (which are set trough '--scatter' option).
+ const QStringList scatters = gen::utils::allFlagValues(
+ flags, QStringLiteral("--scatter"));
+ for (const auto &scatter : scatters) {
+ const QString scatterFile = QFileInfo(scatter)
+ .absoluteFilePath();
+ if (!scatterFiles.contains(scatterFile))
+ scatterFiles.push_back(scatterFile);
+ }
+
+ // Transform all paths to relative.
+ const QString baseDirectory = qbs::gen::utils::buildRootPath(qbsProject);
+ std::transform(scatterFiles.begin(), scatterFiles.end(),
+ std::back_inserter(scatterFiles),
+ [baseDirectory](const QString &scatterFile) {
+ return gen::utils::relativeFilePath(baseDirectory, scatterFile);
+ });
+
+ // Make a first scatter file as a main scatter file.
+ // Other scatter files will be interpretes as a misc controls.
+ if (scatterFiles.count() > 0)
+ mainScatterFile = scatterFiles.takeFirst();
+
+ for (const auto &scatterFile : qAsConst(scatterFiles)) {
+ const auto control = QStringLiteral("--scatter %1").arg(scatterFile);
+ miscControls.push_back(control);
+ }
+
+ // Interpret other compiler flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (auto flagIt = flags.cbegin(); flagIt < flags.cend(); ++flagIt) {
+ if (flagIt->contains(QLatin1String("--ropi"))
+ || flagIt->contains(QLatin1String("--rwpi"))
+ || flagIt->contains(QLatin1String("--noscanlib"))
+ || flagIt->contains(QLatin1String("--strict"))
+ ) {
+ continue;
+ }
+ if (flagIt->startsWith(QLatin1String("--scatter"))
+ ) {
+ ++flagIt;
+ continue;
+ }
+ miscControls.push_back(*flagIt);
+ }
+ }
+
+ int enableRopi = 0;
+ int enableRwpi = 0;
+ int dontSearchLibs = 0;
+ int enableReportMightFail = 0;
+
+ QString mainScatterFile;
+ QStringList miscControls;
+};
+
+} // namespace
+
+ArmTargetLinkerGroup::ArmTargetLinkerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("LDads")
+{
+ const LinkerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'ROPI' item.
+ appendProperty(QByteArrayLiteral("Ropi"), opts.enableRopi);
+ // Add 'RWPI' item.
+ appendProperty(QByteArrayLiteral("Rwpi"), opts.enableRwpi);
+ // Add 'Don't search standard libraries' item.
+ appendProperty(QByteArrayLiteral("noStLib"), opts.dontSearchLibs);
+ // Add 'Report might fail' item.
+ appendProperty(QByteArrayLiteral("RepFail"), opts.enableReportMightFail);
+ // Add 'Scatter file' item.
+ appendProperty(QByteArrayLiteral("ScatterFile"),
+ QDir::toNativeSeparators(opts.mainScatterFile));
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.h
new file mode 100644
index 000000000..db82d4bc2
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetlinkergroup_v5.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 QBS_KEILUVARMTARGETLINKERGROUP_V5_H
+#define QBS_KEILUVARMTARGETLINKERGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetLinkerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetLinkerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETLINKERGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.cpp
new file mode 100644
index 000000000..511a16ab8
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 "armtargetmiscgroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+namespace {
+
+struct MiscPageOptions final
+{
+ explicit MiscPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ generateLinkerMap = gen::utils::cppBooleanModuleProperty(
+ qbsProps, QStringLiteral("generateMapFile"));
+ }
+
+ int generateLinkerMap = 0;
+};
+
+} // namespace
+
+ArmTargetMiscGroup::ArmTargetMiscGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("ArmAdsMisc")
+{
+ const MiscPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Generate linker map file' item.
+ appendProperty(QByteArrayLiteral("AdsLLst"), opts.generateLinkerMap);
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.h
new file mode 100644
index 000000000..025b2796d
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armtargetmiscgroup_v5.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 QBS_KEILUVARMTARGETMISCGROUP_V5_H
+#define QBS_KEILUVARMTARGETMISCGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmTargetMiscGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmTargetMiscGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMTARGETMISCGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.cpp b/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.cpp
new file mode 100644
index 000000000..eab3cc56c
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.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 "armutilitiesgroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+ArmUtilitiesGroup::ArmUtilitiesGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Utilities")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.h b/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.h
new file mode 100644
index 000000000..a34a3a395
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/arm/armutilitiesgroup_v5.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 QBS_KEILUVARMUTILITIESGROUP_V5_H
+#define QBS_KEILUVARMUTILITIESGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace arm {
+namespace v5 {
+
+class ArmUtilitiesGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit ArmUtilitiesGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace arm
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVARMUTILITIESGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.cpp
new file mode 100644
index 000000000..87b3100db
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 "mcs51buildtargetgroup_v5.h"
+#include "mcs51commonpropertygroup_v5.h"
+#include "mcs51debugoptiongroup_v5.h"
+#include "mcs51dlloptiongroup_v5.h"
+#include "mcs51targetcommonoptionsgroup_v5.h"
+#include "mcs51targetgroup_v5.h"
+#include "mcs51utilitiesgroup_v5.h"
+#include "mcs51utils.h"
+
+#include "../../keiluvconstants.h"
+#include "../../keiluvfilesgroupspropertygroup.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51BuildTargetGroup::Mcs51BuildTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup("Target")
+{
+ // Append target name item (it is a build configuration name).
+ const QString targetName = gen::utils::buildConfigurationName(
+ qbsProject);
+ appendProperty(QByteArrayLiteral("TargetName"), targetName);
+ // Append toolset number group item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("ToolsetNumber"),
+ QByteArrayLiteral("0x0"));
+ // Append toolset name group item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("ToolsetName"),
+ QByteArrayLiteral("MCS-51"));
+
+ // Append target option group item.
+ const auto targetOptionGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("TargetOption"));
+
+ targetOptionGroup->appendChild<Mcs51TargetCommonOptionsGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<Mcs51CommonPropertyGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<Mcs51DllOptionGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<Mcs51DebugOptionGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<Mcs51UtilitiesGroup>(
+ qbsProject, qbsProduct);
+ targetOptionGroup->appendChild<Mcs51TargetGroup>(
+ qbsProject, qbsProduct);
+
+ // Append files group.
+ appendChild<KeiluvFilesGroupsPropertyGroup>(qbsProject, qbsProduct,
+ qbsProductDeps);
+}
+
+bool Mcs51BuildTargetGroupFactory::canCreate(
+ gen::utils::Architecture arch,
+ const Version &version) const
+{
+ return arch == gen::utils::Architecture::Mcs51
+ && version.majorVersion() == qbs::KeiluvConstants::v5::kUVisionVersion;
+}
+
+std::unique_ptr<gen::xml::PropertyGroup>
+Mcs51BuildTargetGroupFactory::create(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps) const
+{
+ const auto group = new Mcs51BuildTargetGroup(
+ qbsProject, qbsProduct, qbsProductDeps);
+ return std::unique_ptr<Mcs51BuildTargetGroup>(group);
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.h
new file mode 100644
index 000000000..ef0c0ccba
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51buildtargetgroup_v5.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 QBS_KEILUVMCS51BUILDTARGETGROUP_V5_H
+#define QBS_KEILUVMCS51BUILDTARGETGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51BuildTargetGroup final : public gen::xml::PropertyGroup
+{
+private:
+ explicit Mcs51BuildTargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps);
+
+ friend class Mcs51BuildTargetGroupFactory;
+};
+
+class Mcs51BuildTargetGroupFactory 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<qbs::ProductData> &qbsProductDeps) const final;
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51BUILDTARGETGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.cpp
new file mode 100644
index 000000000..3d4d33046
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.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 "mcs51commonpropertygroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51CommonPropertyGroup::Mcs51CommonPropertyGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("CommonProperty")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.h
new file mode 100644
index 000000000..66dfc7a3e
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51commonpropertygroup_v5.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 QBS_KEILUVMCS51COMMONPROPERTYGROUP_V5_H
+#define QBS_KEILUVMCS51COMMONPROPERTYGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51CommonPropertyGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51CommonPropertyGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_MCS51COMMONPROPERTYGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.cpp
new file mode 100644
index 000000000..2175cc488
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.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 "mcs51debugoptiongroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51DebugOptionGroup::Mcs51DebugOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("DebugOption")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.h
new file mode 100644
index 000000000..473cf605c
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51debugoptiongroup_v5.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 QBS_KEILUVMCS51DEBUGOPTIONGROUP_V5_H
+#define QBS_KEILUVMCS51DEBUGOPTIONGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51DebugOptionGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51DebugOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51DEBUGOPTIONGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.cpp
new file mode 100644
index 000000000..59aec721d
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.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 "mcs51dlloptiongroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51DllOptionGroup::Mcs51DllOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("DllOption")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.h
new file mode 100644
index 000000000..e16833acc
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51dlloptiongroup_v5.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 QBS_KEILUVMCS51DLLOPTIONGROUP_V5_H
+#define QBS_KEILUVMCS51DLLOPTIONGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51DllOptionGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51DllOptionGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51DLLOPTIONGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.cpp
new file mode 100644
index 000000000..8d7257713
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** 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 "mcs51targetassemblergroup_v5.h"
+#include "mcs51utils.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+namespace {
+
+struct AssemblerPageOptions final
+{
+ explicit AssemblerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleAssemblerFlags(qbsProps);
+
+ // Don't use standard macro.
+ if (flags.contains(QLatin1String("NOMACRO"), Qt::CaseInsensitive))
+ useStandardMacroProcessor = false;
+
+ // Use MPL.
+ if (flags.contains(QLatin1String("MPL"), Qt::CaseInsensitive))
+ useMacroProcessingLanguage = true;
+
+ // Define 8051 SFR names.
+ if (flags.contains(QLatin1String("NOMOD51"), Qt::CaseInsensitive))
+ suppressSfrNames = true;
+
+ // Define symbols.
+ defineSymbols = qbs::KeiluvUtils::defines(qbsProps);
+ // Include paths.
+ includePaths = qbs::KeiluvUtils::includes(qbsProps);
+
+ // Interpret other assembler flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (const auto &flag : flags) {
+ if (flag.compare(QLatin1String("NOMACRO"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("MACRO"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("NOMPL"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("MPL"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("NOMOD51"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("MOD51"),
+ Qt::CaseInsensitive) == 0
+ ) {
+ continue;
+ }
+ miscControls.push_back(flag);
+ }
+ }
+
+ int useStandardMacroProcessor = true;
+ int useMacroProcessingLanguage = false;
+ int suppressSfrNames = false;
+ QStringList defineSymbols;
+ QStringList includePaths;
+ QStringList miscControls;
+};
+
+} // namespace
+
+Mcs51TargetAssemblerGroup::Mcs51TargetAssemblerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Ax51")
+{
+ const AssemblerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Macro processor (Standard)'
+ appendProperty(QByteArrayLiteral("UseStandard"),
+ opts.useStandardMacroProcessor);
+ // Add 'Macro processor (MPL)'
+ appendProperty(QByteArrayLiteral("UseMpl"),
+ opts.useMacroProcessingLanguage);
+ // Add 'Define 8051 SFR names'
+ appendProperty(QByteArrayLiteral("UseMod51"),
+ opts.suppressSfrNames);
+
+ // Add other various controls.
+ // Note: A sub-items order makes sense!
+ const auto variousControlsGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("VariousControls"));
+ // Add 'Misc Controls' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("MiscControls"),
+ opts.miscControls, QLatin1Char(' '));
+ // Add 'Define' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("Define"),
+ opts.defineSymbols);
+ // Add an empty 'Undefine' item.
+ variousControlsGroup->appendProperty(
+ QByteArrayLiteral("Undefine"), {});
+ // Add 'Include Paths' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("IncludePath"),
+ opts.includePaths, QLatin1Char(';'));
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.h
new file mode 100644
index 000000000..f9a82304d
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetassemblergroup_v5.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 QBS_KEILUVMCS51TARGETASSEMBLERGROUP_V3
+#define QBS_KEILUVMCS51TARGETASSEMBLERGROUP_V3
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetAssemblerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetAssemblerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETASSEMBLERGROUP_V3
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.cpp
new file mode 100644
index 000000000..de1be1ef6
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 "mcs51targetcommonoptionsgroup_v5.h"
+
+#include "../../keiluvutils.h"
+
+#include <generators/generatorutils.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+namespace {
+
+struct CommonPageOptions final
+{
+ explicit CommonPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Browse information.
+ if (flags.contains(QLatin1String("BROWSE"), Qt::CaseInsensitive))
+ browseInfo = true;
+
+ // Debug information.
+ debugInfo = gen::utils::debugInformation(qbsProduct);
+
+ // Output parameters.
+ executableName = gen::utils::targetBinary(qbsProduct);
+ // Fix output binary name if it is a library. Because
+ // the IDE appends an additional suffix (.LIB) to end
+ // of an output library name.
+ if (executableName.endsWith(QLatin1String(".lib")))
+ executableName = qbsProduct.targetName();
+
+ const QString baseDirectory = gen::utils::buildRootPath(qbsProject);
+ objectDirectory = QDir::toNativeSeparators(
+ gen::utils::objectsOutputDirectory(
+ baseDirectory, qbsProduct));
+ listingDirectory = QDir::toNativeSeparators(
+ gen::utils::listingOutputDirectory(
+ baseDirectory, qbsProduct));
+
+ // Target type.
+ targetType = KeiluvUtils::outputBinaryType(qbsProduct);
+ }
+
+ int browseInfo = false;
+ int debugInfo = false;
+ QString executableName;
+ QString objectDirectory;
+ QString listingDirectory;
+ KeiluvUtils::OutputBinaryType targetType =
+ KeiluvUtils::ApplicationOutputType;
+};
+
+} // namespace
+
+Mcs51TargetCommonOptionsGroup::Mcs51TargetCommonOptionsGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("TargetCommonOption")
+{
+ const CommonPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Generic 8051 device' items,
+ // because we can't detect a target device
+ // form the present command lines.
+ appendProperty(QByteArrayLiteral("Device"),
+ QByteArrayLiteral("8051 (all Variants)"));
+ appendProperty(QByteArrayLiteral("Vendor"),
+ QByteArrayLiteral("Generic"));
+ appendProperty(QByteArrayLiteral("DeviceId"),
+ QByteArrayLiteral("2994"));
+
+ // Add 'Debug Information' item.
+ appendProperty(QByteArrayLiteral("DebugInformation"),
+ opts.debugInfo);
+ // Add 'Browse Information' item.
+ appendProperty(QByteArrayLiteral("BrowseInformation"),
+ opts.browseInfo);
+
+ // Add 'Name of Executable'.
+ appendProperty(QByteArrayLiteral("OutputName"),
+ opts.executableName);
+ // Add 'Output objects directory'.
+ appendProperty(QByteArrayLiteral("OutputDirectory"),
+ opts.objectDirectory);
+ // Add 'Output listing directory'.
+ appendProperty(QByteArrayLiteral("ListingPath"),
+ opts.listingDirectory);
+
+ // Add 'Create Executable/Library' item.
+ const int isExecutable = (opts.targetType
+ == KeiluvUtils::ApplicationOutputType);
+ const int isLibrary = (opts.targetType
+ == KeiluvUtils::LibraryOutputType);
+ appendProperty(QByteArrayLiteral("CreateExecutable"),
+ isExecutable);
+ appendProperty(QByteArrayLiteral("CreateLib"),
+ isLibrary);
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.h
new file mode 100644
index 000000000..eccd9d42d
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcommonoptionsgroup_v5.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 QBS_KEILUVMCS51TARGETCOMMONOPTIONSGROUP_V5_H
+#define QBS_KEILUVMCS51TARGETCOMMONOPTIONSGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetCommonOptionsGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetCommonOptionsGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETCOMMONOPTIONSGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.cpp
new file mode 100644
index 000000000..e33c0c211
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** 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 "mcs51targetcompilergroup_v5.h"
+#include "mcs51utils.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+namespace {
+
+struct CompilerPageOptions final
+{
+ enum WarningLevel {
+ WarningLevelNone = 0,
+ WarningLevelOne,
+ WarningLevelTwo
+ };
+
+ enum OptimizationLevel {
+ ConstantFoldingOptimizationLevel = 0,
+ DeadCodeEliminationOptimizationLevel,
+ DataOverlayingOptimizationLevel,
+ PeepholeOptimizationLevel,
+ RegisterVariablesOptimizationLevel,
+ CommonSubexpressionEliminationOptimizationLevel,
+ LoopRotationOptimizationLevel,
+ ExtendedIndexAccessOptimizationLevel,
+ ReuseCommonEntryCodeOptimizationLevel,
+ CommonBlockSubroutinesOptimizationLevel,
+ RearrangeCodeOptimizationLevel,
+ ReuseCommonExitCodeOptimizationLevel
+ };
+
+ enum OptimizationEmphasis {
+ FavorSizeOptimizationEmphasis = 0,
+ FavorSpeedOptimizationEmphasis
+ };
+
+ enum FloatFuzzyBits {
+ NoFloatFuzzyBits = 0,
+ OneFloatFuzzyBit,
+ TwoFloatFuzzyBits,
+ ThreeFloatFuzzyBits,
+ FourFloatFuzzyBits,
+ FiveFloatFuzzyBits,
+ SixFloatFuzzyBits,
+ SevenFloatFuzzyBits
+ };
+
+ explicit CompilerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Warnings.
+ const QString level = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("warningLevel"));
+ if (level == QLatin1String("none")) {
+ warningLevel = WarningLevelNone;
+ } else if (level == QLatin1String("all")) {
+ warningLevel = WarningLevelTwo;
+ } else {
+ // In this case take it directly from the compiler command line,
+ // e.g. parse the line in a form: 'WARNINGLEVEL (2)'
+ const auto warnValue = KeiluvUtils::flagValue(
+ flags, QStringLiteral("WARNINGLEVEL"));
+ bool ok = false;
+ const auto level = warnValue.toInt(&ok);
+ if (ok && gen::utils::inBounds(
+ level, int(WarningLevelNone),int(WarningLevelTwo))) {
+ warningLevel = static_cast<WarningLevel>(level);
+ }
+ }
+
+ // Optimizations.
+ const QString optimization = gen::utils::cppStringModuleProperty(
+ qbsProps, QStringLiteral("optimization"));
+ if (optimization == QLatin1String("fast")) {
+ optimizationEmphasis = FavorSpeedOptimizationEmphasis;
+ } else if (level == QLatin1String("small")) {
+ optimizationEmphasis = FavorSizeOptimizationEmphasis;
+ } else if (level == QLatin1String("small")) {
+ // Don't supported by C51 compiler.
+ } else {
+ // In this case take it directly from the compiler command line,
+ // e.g. parse the line in a form: 'OPTIMIZE (8, SPEED)'
+ const auto optValue = KeiluvUtils::flagValue(
+ flags, QStringLiteral("OPTIMIZE"));
+ const auto parts = KeiluvUtils::flagValueParts(optValue);
+ for (const auto &part : parts) {
+ bool ok = false;
+ const auto level = part.toInt(&ok);
+ if (ok && (level >= ConstantFoldingOptimizationLevel)
+ && (level <= ReuseCommonExitCodeOptimizationLevel)) {
+ optimizationLevel = static_cast<OptimizationLevel>(level);
+ } else if (part.compare(QLatin1String("SIZE"),
+ Qt::CaseInsensitive) == 0) {
+ optimizationEmphasis = FavorSizeOptimizationEmphasis;
+ } else if (part.compare(QLatin1String("SPEED"),
+ Qt::CaseInsensitive) == 0) {
+ optimizationEmphasis = FavorSpeedOptimizationEmphasis;
+ }
+ }
+ }
+
+ // Don't use absolute register accesses.
+ if (flags.contains(QLatin1String("NOAREGS"), Qt::CaseInsensitive))
+ dontuseAbsoluteRegsAccess = true;
+
+ // Enable ANSI integer promotion rules.
+ if (flags.contains(QLatin1String("NOINTPROMOTE"), Qt::CaseInsensitive))
+ enableIntegerPromotionRules = false;
+
+ // Keep variables in order.
+ if (flags.contains(QLatin1String("ORDER"), Qt::CaseInsensitive))
+ keepVariablesInOrder = true;
+
+ // Don't use interrupt vector.
+ if (flags.contains(QLatin1String("NOINTVECTOR"), Qt::CaseInsensitive))
+ useInterruptVector = false;
+
+ // Interrupt vector address.
+ interruptVectorAddress = KeiluvUtils::flagValue(
+ flags, QStringLiteral("INTVECTOR"));
+
+ // Float fuzzy bits count.
+ const auto bitsValue = KeiluvUtils::flagValue(
+ flags, QStringLiteral("FLOATFUZZY"));
+ bool ok = false;
+ const auto bits = bitsValue.toInt(&ok);
+ if (ok && gen::utils::inBounds(
+ bits, int(NoFloatFuzzyBits), int(SevenFloatFuzzyBits))) {
+ floatFuzzyBits = static_cast<FloatFuzzyBits>(bits);
+ }
+
+ // Define symbols.
+ defineSymbols = qbs::KeiluvUtils::defines(qbsProps);
+ // Include paths.
+ includePaths = qbs::KeiluvUtils::includes(qbsProps);
+
+ // Interpret other compiler flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (const auto &flag : flags) {
+ if (flag.startsWith(QLatin1String("WARNINGLEVEL"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("OPTIMIZE"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("FLOATFUZZY"),
+ Qt::CaseInsensitive)
+ || flag.compare(QLatin1String("NOAREGS"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("AREGS"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("NOINTPROMOTE"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("INTPROMOTE"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("NOINTVECTOR"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("INTVECTOR"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("ORDER"),
+ Qt::CaseInsensitive) == 0
+ || flag.compare(QLatin1String("BROSWE"),
+ Qt::CaseInsensitive) == 0
+ ) {
+ continue;
+ }
+ miscControls.push_back(flag);
+ }
+ }
+
+ WarningLevel warningLevel = WarningLevelTwo;
+ OptimizationLevel optimizationLevel = ReuseCommonEntryCodeOptimizationLevel;
+ OptimizationEmphasis optimizationEmphasis = FavorSpeedOptimizationEmphasis;
+ FloatFuzzyBits floatFuzzyBits = ThreeFloatFuzzyBits;
+ int dontuseAbsoluteRegsAccess = false;
+ int enableIntegerPromotionRules = true;
+ int keepVariablesInOrder = false;
+ int useInterruptVector = true;
+ QString interruptVectorAddress;
+ QStringList defineSymbols;
+ QStringList includePaths;
+ QStringList miscControls;
+};
+
+} // namespace
+
+Mcs51TargetCompilerGroup::Mcs51TargetCompilerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("C51")
+{
+ const CompilerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Code Optimization' options.
+ appendProperty(QByteArrayLiteral("Optimize"),
+ opts.optimizationLevel);
+ appendProperty(QByteArrayLiteral("SizeSpeed"),
+ opts.optimizationEmphasis);
+ // Add 'Warnings' options.
+ appendProperty(QByteArrayLiteral("WarningLevel"),
+ opts.warningLevel);
+ // Add 'Don't use absolute register access' item.
+ appendProperty(QByteArrayLiteral("uAregs"),
+ opts.dontuseAbsoluteRegsAccess);
+ // Add 'Enable integer promotion rules' item.
+ appendProperty(QByteArrayLiteral("IntegerPromotion"),
+ opts.enableIntegerPromotionRules);
+ // Add 'Keep variables in order' item.
+ appendProperty(QByteArrayLiteral("VariablesInOrder"),
+ opts.keepVariablesInOrder);
+ // Add 'Use interrupt vector' item.
+ appendProperty(QByteArrayLiteral("UseInterruptVector"),
+ opts.useInterruptVector);
+ appendProperty(QByteArrayLiteral("InterruptVectorAddress"),
+ opts.interruptVectorAddress);
+ // Add 'Float fuzzy bits' item.
+ appendProperty(QByteArrayLiteral("Fuzzy"),
+ opts.floatFuzzyBits);
+
+ // Add other various controls.
+ // Note: A sub-items order makes sense!
+ const auto variousControlsGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("VariousControls"));
+ // Add 'Misc Controls' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("MiscControls"),
+ opts.miscControls, QLatin1Char(' '));
+ // Add 'Define' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("Define"),
+ opts.defineSymbols);
+ // Add an empty 'Undefine' item.
+ variousControlsGroup->appendProperty(
+ QByteArrayLiteral("Undefine"), {});
+ // Add 'Include Paths' item.
+ variousControlsGroup->appendMultiLineProperty(
+ QByteArrayLiteral("IncludePath"),
+ opts.includePaths, QLatin1Char(';'));
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.h
new file mode 100644
index 000000000..0f1e52ce4
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetcompilergroup_v5.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 QBS_KEILUVMCS51TARGETCOMPILERGROUP_V5_H
+#define QBS_KEILUVMCS51TARGETCOMPILERGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetCompilerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetCompilerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETCOMPILERGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.cpp
new file mode 100644
index 000000000..2a05649dd
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.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 "mcs51targetassemblergroup_v5.h"
+#include "mcs51targetcompilergroup_v5.h"
+#include "mcs51targetgroup_v5.h"
+#include "mcs51targetlinkergroup_v5.h"
+#include "mcs51targetmiscgroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51TargetGroup::Mcs51TargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Target51")
+{
+ appendChild<Mcs51TargetMiscGroup>(qbsProject, qbsProduct);
+ appendChild<Mcs51TargetCompilerGroup>(qbsProject, qbsProduct);
+ appendChild<Mcs51TargetAssemblerGroup>(qbsProject, qbsProduct);
+ appendChild<Mcs51TargetLinkerGroup>(qbsProject, qbsProduct);
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.h
new file mode 100644
index 000000000..d256dfcc7
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetgroup_v5.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 QBS_KEILUVMCS51TARGETGROUP_V5_H
+#define QBS_KEILUVMCS51TARGETGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.cpp
new file mode 100644
index 000000000..4d52b627a
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** 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 "mcs51targetlinkergroup_v5.h"
+#include "mcs51utils.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+namespace {
+
+struct LinkerPageOptions final
+{
+ explicit LinkerPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleLinkerFlags(qbsProps);
+
+ // Handle all 'BIT' memory flags.
+ parseMemory(flags, QStringLiteral("BIT"),
+ bitAddresses, bitSegments);
+ // Handle all 'CODE' memory flags.
+ parseMemory(flags, QStringLiteral("CODE"),
+ codeAddresses, codeSegments);
+ // Handle all 'DATA' memory flags.
+ parseMemory(flags, QStringLiteral("DATA"),
+ dataAddresses, dataSegments);
+ // Handle all 'IDATA' memory flags.
+ parseMemory(flags, QStringLiteral("IDATA"),
+ idataAddresses, idataSegments);
+ // Handle all 'PDATA' memory flags.
+ parseMemory(flags, QStringLiteral("PDATA"),
+ pdataAddresses, pdataSegments);
+ // Handle all 'XDATA' memory flags.
+ parseMemory(flags, QStringLiteral("XDATA"),
+ xdataAddresses, xdataSegments);
+
+ // Enumerate all flags in a form like:
+ // 'PRECEDE(foo, bar) PRECEDE(baz)'.
+ const auto precedeValues = KeiluvUtils::flagValues(
+ flags, QStringLiteral("PRECEDE"));
+ for (const auto &precedeValue : precedeValues) {
+ const auto parts = KeiluvUtils::flagValueParts(precedeValue);
+ precedeSegments.reserve(precedeSegments.size() + parts.count());
+ std::copy(parts.cbegin(), parts.cend(),
+ std::back_inserter(precedeSegments));
+ }
+
+ // Enumerate all flags in a form like:
+ // 'STACK(foo, bar) STACK(baz)'.
+ const auto stackValues = KeiluvUtils::flagValues(
+ flags, QStringLiteral("STACK"));
+ for (const auto &stackValue : stackValues) {
+ const auto parts = KeiluvUtils::flagValueParts(stackValue);
+ stackSegments.reserve(stackSegments.size() + parts.count());
+ std::copy(parts.cbegin(), parts.cend(),
+ std::back_inserter(stackSegments));
+ }
+
+ // Interpret other linker flags as a misc controls (exclude only
+ // that flags which are was already handled).
+ for (const auto &flag : flags) {
+ if (flag.startsWith(QLatin1String("BIT"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("CODE"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("DATA"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("IDATA"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("PDATA"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("XDATA"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("PRECEDE"),
+ Qt::CaseInsensitive)
+ || flag.startsWith(QLatin1String("STACK"),
+ Qt::CaseInsensitive)
+ ) {
+ continue;
+ }
+ miscControls.push_back(flag);
+ }
+ }
+
+ static void parseMemory(const QStringList &flags,
+ const QString &flagKey,
+ QStringList &destAddresses,
+ QStringList &destSegments)
+ {
+ // Handle all flags in a form like:
+ // 'FLAGKEY(0x00-0x20, 30, foo, bar(0x40)) FLAGKEY(baz)'.
+ const auto values = KeiluvUtils::flagValues(flags, flagKey);
+ for (const auto &value : values) {
+ const auto parts = KeiluvUtils::flagValueParts(value);
+ for (const auto &part : parts) {
+ if (part.contains(QLatin1Char('-'))) {
+ // Seems, it is an address range.
+ destAddresses.push_back(part);
+ } else {
+ // Check on address (specified in decimal
+ // or hexadecimal form).
+ bool ok = false;
+ part.toInt(&ok, 16);
+ if (!ok)
+ part.toInt(&ok, 10);
+ if (ok) {
+ // Seems, it is just a single address.
+ destAddresses.push_back(part);
+ } else {
+ // Seems it is a segment name.
+ destSegments.push_back(part);
+ }
+ }
+ }
+ }
+ }
+
+ QStringList bitAddresses;
+ QStringList bitSegments;
+ QStringList codeAddresses;
+ QStringList codeSegments;
+ QStringList dataAddresses;
+ QStringList dataSegments;
+ QStringList idataAddresses;
+ QStringList idataSegments;
+ QStringList pdataAddresses;
+ QStringList pdataSegments;
+ QStringList xdataAddresses;
+ QStringList xdataSegments;
+
+ QStringList precedeSegments;
+ QStringList stackSegments;
+
+ QStringList miscControls;
+};
+
+} // namespace
+
+Mcs51TargetLinkerGroup::Mcs51TargetLinkerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Lx51")
+{
+ const LinkerPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Misc Controls' item.
+ appendMultiLineProperty(QByteArrayLiteral("MiscControls"),
+ opts.miscControls, QLatin1Char(' '));
+
+ // Add 'Use Memory Layout from Target Dialog' item.
+ // Note: we always disable it, as we expect that
+ // the layout will be specified from the linker's
+ // command line.
+ appendProperty(QByteArrayLiteral("UseMemoryFromTarget"),
+ 0);
+
+ // Add 'Bit Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("BitBaseAddress"),
+ opts.bitAddresses);
+ // Add 'Code Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("CodeBaseAddress"),
+ opts.codeAddresses);
+ // Add 'Data Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("DataBaseAddress"),
+ opts.dataAddresses);
+ // Add 'IData Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("IDataBaseAddress"),
+ opts.idataAddresses);
+ // Add 'PData Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("PDataBaseAddress"),
+ opts.pdataAddresses);
+ // Add 'XData Range' item.
+ appendMultiLineProperty(QByteArrayLiteral("XDataBaseAddress"),
+ opts.xdataAddresses);
+
+ // Add 'Bit Segment' item.
+ appendMultiLineProperty(QByteArrayLiteral("BitSegmentName"),
+ opts.bitSegments);
+ // Add 'Code Segment' item.
+ appendMultiLineProperty(QByteArrayLiteral("CodeSegmentName"),
+ opts.codeSegments);
+ // Add 'Data Segment' item.
+ appendMultiLineProperty(QByteArrayLiteral("DataSegmentName"),
+ opts.dataSegments);
+ // Add 'IData Segment' item.
+ appendMultiLineProperty(QByteArrayLiteral("IDataSegmentName"),
+ opts.idataSegments);
+
+ // Note: PData has not segments!
+
+ // Add 'XData Segment' item.
+ appendMultiLineProperty(QByteArrayLiteral("XDataSegmentName"),
+ opts.xdataSegments);
+ // Add 'Precede' item.
+ appendMultiLineProperty(QByteArrayLiteral("Precede"),
+ opts.precedeSegments);
+ // Add 'Stack' item.
+ appendMultiLineProperty(QByteArrayLiteral("Stack"),
+ opts.stackSegments);
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.h
new file mode 100644
index 000000000..d701c5e0e
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetlinkergroup_v5.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 QBS_KEILUVMCS51TARGETLINKERGROUP_V5_H
+#define QBS_KEILUVMCS51TARGETLINKERGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetLinkerGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetLinkerGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETLINKERGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.cpp
new file mode 100644
index 000000000..5d95d443f
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 "mcs51targetmiscgroup_v5.h"
+#include "mcs51utils.h"
+
+#include "../../keiluvutils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+namespace {
+
+struct MiscPageOptions final
+{
+ enum MemoryModel {
+ SmallMemoryModel = 0,
+ CompactMemoryModel,
+ LargeMemoryModel
+ };
+
+ enum CodeRomSize {
+ SmallCodeRomSize = 0,
+ CompactCodeRomSize,
+ LargeCodeRomSize
+ };
+
+ explicit MiscPageOptions(const Project &qbsProject,
+ const ProductData &qbsProduct)
+ {
+ Q_UNUSED(qbsProject)
+
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto flags = qbs::KeiluvUtils::cppModuleCompilerFlags(qbsProps);
+
+ // Memory model.
+ if (flags.contains(QLatin1String("COMPACT"), Qt::CaseInsensitive))
+ memoryModel = CompactMemoryModel;
+ else if (flags.contains(QLatin1String("LARGE"), Qt::CaseInsensitive))
+ memoryModel = LargeMemoryModel;
+
+ // Code ROM size.
+ const auto sizeValue = KeiluvUtils::flagValue(
+ flags, QStringLiteral("ROM"));
+ if (sizeValue == QLatin1String("SMALL"))
+ coderomSize = SmallCodeRomSize;
+ else if (sizeValue == QLatin1String("COMPACT"))
+ coderomSize = CompactCodeRomSize;
+ }
+
+ MemoryModel memoryModel = SmallMemoryModel;
+ CodeRomSize coderomSize = LargeCodeRomSize;
+};
+
+} // namespace
+
+Mcs51TargetMiscGroup::Mcs51TargetMiscGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Target51Misc")
+{
+ const MiscPageOptions opts(qbsProject, qbsProduct);
+
+ // Add 'Memory Model' options item.
+ appendProperty(QByteArrayLiteral("MemoryModel"),
+ opts.memoryModel);
+ // Add 'ROM Size' options item.
+ appendProperty(QByteArrayLiteral("RomSize"),
+ opts.coderomSize);
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.h
new file mode 100644
index 000000000..f1680d927
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51targetmiscgroup_v5.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 QBS_KEILUVMCS51TARGETMISCGROUP_V5_H
+#define QBS_KEILUVMCS51TARGETMISCGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51TargetMiscGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51TargetMiscGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51TARGETMISCGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.cpp
new file mode 100644
index 000000000..8e8307f72
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.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 "mcs51utilitiesgroup_v5.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+Mcs51UtilitiesGroup::Mcs51UtilitiesGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct)
+ : gen::xml::PropertyGroup("Utilities")
+{
+ Q_UNUSED(qbsProject)
+ Q_UNUSED(qbsProduct)
+}
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.h
new file mode 100644
index 000000000..f95ec67c4
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51utilitiesgroup_v5.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 QBS_KEILUVMCS51UTILITIESGROUP_V5_H
+#define QBS_KEILUVMCS51UTILITIESGROUP_V5_H
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+namespace v5 {
+
+class Mcs51UtilitiesGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit Mcs51UtilitiesGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct);
+};
+
+} // namespace v5
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51UTILITIESGROUP_V5_H
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.cpp b/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.cpp
new file mode 100644
index 000000000..698f0df78
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 "mcs51utils.h"
+
+namespace qbs {
+namespace keiluv {
+namespace mcs51 {
+
+namespace KeiluvUtils {
+
+static QString extractValue(const QString &flag)
+{
+ const auto openBracketIndex = flag.indexOf(QLatin1Char('('));
+ const auto closeBracketIndex = flag.indexOf(QLatin1Char(')'));
+ const auto n = closeBracketIndex - openBracketIndex - 1;
+ return flag.mid(openBracketIndex + 1, n);
+}
+
+QStringList flagValues(const QStringList &flags, const QString &flagKey)
+{
+ QStringList values;
+ for (const auto &flag : flags) {
+ if (!flag.startsWith(flagKey, Qt::CaseInsensitive))
+ continue;
+ const auto value = extractValue(flag);
+ values.push_back(value);
+ }
+ return values;
+}
+
+QString flagValue(const QStringList &flags, const QString &flagKey)
+{
+ const auto flagEnd = flags.cend();
+ const auto flagIt = std::find_if(flags.cbegin(), flagEnd,
+ [flagKey](const auto &flag) {
+ return flag.startsWith(flagKey, Qt::CaseInsensitive);
+ });
+ if (flagIt == flagEnd)
+ return {}; // Flag key not found.
+ return extractValue(*flagIt);
+}
+
+QStringList flagValueParts(const QString &flagValue, const QLatin1Char &sep)
+{
+ auto parts = flagValue.split(sep);
+ std::transform(parts.begin(), parts.end(), parts.begin(),
+ [](const auto &part) { return part.trimmed(); });
+ return parts;
+}
+
+} // namespace KeiluvUtils
+
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.h b/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.h
new file mode 100644
index 000000000..a1a9706e4
--- /dev/null
+++ b/src/plugins/generator/keiluv/archs/mcs51/mcs51utils.h
@@ -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.
+**
+****************************************************************************/
+
+#ifndef QBS_KEILUVMCS51UTILS_H
+#define QBS_KEILUVMCS51UTILS_H
+
+#include <QtCore/qstringlist.h>
+
+namespace qbs {
+
+namespace keiluv {
+namespace mcs51 {
+
+namespace KeiluvUtils {
+
+QStringList flagValues(const QStringList &flags, const QString &flagKey);
+
+QString flagValue(const QStringList &flags, const QString &flagKey);
+
+QStringList flagValueParts(const QString &flagValue,
+ const QLatin1Char &sep = QLatin1Char(','));
+
+} // namespace KeiluvUtils
+
+} // namespace mcs51
+} // namespace keiluv
+} // namespace qbs
+
+#endif // QBS_KEILUVMCS51UTILS_H
diff --git a/src/plugins/generator/keiluv/keiluv.pro b/src/plugins/generator/keiluv/keiluv.pro
new file mode 100644
index 000000000..ba3e4d27b
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluv.pro
@@ -0,0 +1,92 @@
+include(../../plugins.pri)
+include(../../../shared/json/json.pri)
+
+TARGET = keiluvgenerator
+
+QT = core
+
+# Plugin file.
+
+SOURCES += \
+ $$PWD/keiluvgeneratorplugin.cpp \
+
+# Common files.
+
+HEADERS += \
+ $$PWD/keiluvconstants.h \
+ $$PWD/keiluvfilesgroupspropertygroup.h \
+ $$PWD/keiluvgenerator.h \
+ $$PWD/keiluvproject.h \
+ $$PWD/keiluvprojectwriter.h \
+ $$PWD/keiluvutils.h \
+ $$PWD/keiluvversioninfo.h \
+ $$PWD/keiluvworkspace.h \
+ $$PWD/keiluvworkspacewriter.h
+
+SOURCES += \
+ $$PWD/keiluvfilesgroupspropertygroup.cpp \
+ $$PWD/keiluvgenerator.cpp \
+ $$PWD/keiluvproject.cpp \
+ $$PWD/keiluvprojectwriter.cpp \
+ $$PWD/keiluvutils.cpp \
+ $$PWD/keiluvversioninfo.cpp \
+ $$PWD/keiluvworkspace.cpp \
+ $$PWD/keiluvworkspacewriter.cpp
+
+# For MCS51 architecture.
+
+HEADERS += \
+ $$PWD/archs/mcs51/mcs51buildtargetgroup_v5.h \
+ $$PWD/archs/mcs51/mcs51commonpropertygroup_v5.h \
+ $$PWD/archs/mcs51/mcs51debugoptiongroup_v5.h \
+ $$PWD/archs/mcs51/mcs51dlloptiongroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetassemblergroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetcommonoptionsgroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetcompilergroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetgroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetlinkergroup_v5.h \
+ $$PWD/archs/mcs51/mcs51targetmiscgroup_v5.h \
+ $$PWD/archs/mcs51/mcs51utilitiesgroup_v5.h \
+ $$PWD/archs/mcs51/mcs51utils.h
+
+SOURCES += \
+ $$PWD/archs/mcs51/mcs51buildtargetgroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51commonpropertygroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51debugoptiongroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51dlloptiongroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetassemblergroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetcommonoptionsgroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetcompilergroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetgroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetlinkergroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51targetmiscgroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51utilitiesgroup_v5.cpp \
+ $$PWD/archs/mcs51/mcs51utils.cpp
+
+# For ARM architecture.
+
+HEADERS += \
+ $$PWD/archs/arm/armbuildtargetgroup_v5.h \
+ $$PWD/archs/arm/armcommonpropertygroup_v5.h \
+ $$PWD/archs/arm/armdebugoptiongroup_v5.h \
+ $$PWD/archs/arm/armdlloptiongroup_v5.h \
+ $$PWD/archs/arm/armtargetassemblergroup_v5.h \
+ $$PWD/archs/arm/armtargetcommonoptionsgroup_v5.h \
+ $$PWD/archs/arm/armtargetcompilergroup_v5.h \
+ $$PWD/archs/arm/armtargetgroup_v5.h \
+ $$PWD/archs/arm/armtargetlinkergroup_v5.h \
+ $$PWD/archs/arm/armtargetmiscgroup_v5.h \
+ $$PWD/archs/arm/armutilitiesgroup_v5.h
+
+SOURCES += \
+ $$PWD/archs/arm/armbuildtargetgroup_v5.cpp \
+ $$PWD/archs/arm/armcommonpropertygroup_v5.cpp \
+ $$PWD/archs/arm/armdebugoptiongroup_v5.cpp \
+ $$PWD/archs/arm/armdlloptiongroup_v5.cpp \
+ $$PWD/archs/arm/armtargetassemblergroup_v5.cpp \
+ $$PWD/archs/arm/armtargetcommonoptionsgroup_v5.cpp \
+ $$PWD/archs/arm/armtargetcompilergroup_v5.cpp \
+ $$PWD/archs/arm/armtargetgroup_v5.cpp \
+ $$PWD/archs/arm/armtargetlinkergroup_v5.cpp \
+ $$PWD/archs/arm/armtargetmiscgroup_v5.cpp \
+ $$PWD/archs/arm/armutilitiesgroup_v5.cpp
diff --git a/src/plugins/generator/keiluv/keiluv.qbs b/src/plugins/generator/keiluv/keiluv.qbs
new file mode 100644
index 000000000..65bf6d65b
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluv.qbs
@@ -0,0 +1,90 @@
+import qbs
+import "../../qbsplugin.qbs" as QbsPlugin
+
+QbsPlugin {
+ Depends { name: "qbsjson" }
+
+ name: "keiluvgenerator"
+
+ files: ["keiluvgeneratorplugin.cpp"]
+
+ Group {
+ name: "KEIL UV generator common"
+ files: [
+ "keiluvfilesgroupspropertygroup.cpp",
+ "keiluvfilesgroupspropertygroup.h",
+ "keiluvgenerator.cpp",
+ "keiluvgenerator.h",
+ "keiluvproject.cpp",
+ "keiluvproject.h",
+ "keiluvprojectwriter.cpp",
+ "keiluvprojectwriter.h",
+ "keiluvutils.cpp",
+ "keiluvutils.h",
+ "keiluvversioninfo.cpp",
+ "keiluvversioninfo.h",
+ "keiluvworkspace.cpp",
+ "keiluvworkspace.h",
+ "keiluvworkspacewriter.cpp",
+ "keiluvworkspacewriter.h",
+ ]
+ }
+ Group {
+ name: "KEIL UV generator for MCS51"
+ prefix: "archs/mcs51/"
+ files: [
+ "mcs51buildtargetgroup_v5.cpp",
+ "mcs51buildtargetgroup_v5.h",
+ "mcs51commonpropertygroup_v5.cpp",
+ "mcs51commonpropertygroup_v5.h",
+ "mcs51debugoptiongroup_v5.cpp",
+ "mcs51debugoptiongroup_v5.h",
+ "mcs51dlloptiongroup_v5.cpp",
+ "mcs51dlloptiongroup_v5.h",
+ "mcs51targetassemblergroup_v5.cpp",
+ "mcs51targetassemblergroup_v5.h",
+ "mcs51targetcommonoptionsgroup_v5.cpp",
+ "mcs51targetcommonoptionsgroup_v5.h",
+ "mcs51targetcompilergroup_v5.cpp",
+ "mcs51targetcompilergroup_v5.h",
+ "mcs51targetgroup_v5.cpp",
+ "mcs51targetgroup_v5.h",
+ "mcs51targetlinkergroup_v5.cpp",
+ "mcs51targetlinkergroup_v5.h",
+ "mcs51targetmiscgroup_v5.cpp",
+ "mcs51targetmiscgroup_v5.h",
+ "mcs51utilitiesgroup_v5.cpp",
+ "mcs51utilitiesgroup_v5.h",
+ "mcs51utils.cpp",
+ "mcs51utils.h",
+ ]
+ }
+ Group {
+ name: "KEIL UV generator for ARM"
+ prefix: "archs/arm/"
+ files: [
+ "armbuildtargetgroup_v5.cpp",
+ "armbuildtargetgroup_v5.h",
+ "armcommonpropertygroup_v5.cpp",
+ "armcommonpropertygroup_v5.h",
+ "armdebugoptiongroup_v5.cpp",
+ "armdebugoptiongroup_v5.h",
+ "armdlloptiongroup_v5.cpp",
+ "armdlloptiongroup_v5.h",
+ "armtargetassemblergroup_v5.cpp",
+ "armtargetassemblergroup_v5.h",
+ "armtargetcommonoptionsgroup_v5.cpp",
+ "armtargetcommonoptionsgroup_v5.h",
+ "armtargetcompilergroup_v5.cpp",
+ "armtargetcompilergroup_v5.h",
+ "armtargetgroup_v5.cpp",
+ "armtargetgroup_v5.h",
+ "armtargetlinkergroup_v5.cpp",
+ "armtargetlinkergroup_v5.h",
+ "armtargetmiscgroup_v5.cpp",
+ "armtargetmiscgroup_v5.h",
+ "armutilitiesgroup_v5.cpp",
+ "armutilitiesgroup_v5.h",
+ ]
+ }
+}
diff --git a/src/plugins/generator/keiluv/keiluvconstants.h b/src/plugins/generator/keiluv/keiluvconstants.h
new file mode 100644
index 000000000..0d27ab81d
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvconstants.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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_KEILUVCONSTANTS_H
+#define QBS_KEILUVCONSTANTS_H
+
+namespace qbs {
+namespace KeiluvConstants {
+
+namespace v5 {
+constexpr int kUVisionVersion = 5;
+}
+
+} // namespace KeiluvConstants
+} // namespace qbs
+
+#endif // QBS_KEILUVCONSTANTS_H
diff --git a/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.cpp b/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.cpp
new file mode 100644
index 000000000..b9a234d6a
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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 "keiluvfilesgroupspropertygroup.h"
+#include "keiluvutils.h"
+
+#include <generators/generatordata.h>
+
+#include <tools/stringconstants.h>
+
+namespace qbs {
+
+class KeiluvFilePropertyGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit KeiluvFilePropertyGroup(
+ const QString &fullFilePath,
+ const QString &baseDirectory)
+ : gen::xml::PropertyGroup("File")
+ {
+ const QFileInfo fileInfo(fullFilePath);
+ const auto fileName = fileInfo.fileName();
+ const auto fileType = encodeFileType(fileInfo.suffix());
+ const auto filePath = QDir::toNativeSeparators(
+ gen::utils::relativeFilePath(
+ baseDirectory,
+ fileInfo.absoluteFilePath()));
+
+ appendChild<gen::xml::Property>(QByteArrayLiteral("FileName"),
+ fileName);
+ appendChild<gen::xml::Property>(QByteArrayLiteral("FileType"),
+ fileType);
+ appendChild<gen::xml::Property>(QByteArrayLiteral("FilePath"),
+ filePath);
+ }
+
+private:
+ enum FileType {
+ UnknownFileType = 0,
+ CSourceFileType = 1,
+ AssemblerFileType = 2,
+ LibraryFileType = 4,
+ TextFileType = 5,
+ CppSourceFileType = 8,
+ };
+
+ static FileType encodeFileType(const QString &fileSuffix)
+ {
+ if (fileSuffix.compare(QLatin1String("c"),
+ Qt::CaseInsensitive) == 0) {
+ return CSourceFileType;
+ } else if (fileSuffix.compare(QLatin1String("cpp"),
+ Qt::CaseInsensitive) == 0) {
+ return CppSourceFileType;
+ } else if (fileSuffix.compare(QLatin1String("s"),
+ Qt::CaseInsensitive) == 0
+ || fileSuffix.compare(QLatin1String("a51"),
+ Qt::CaseInsensitive) == 0) {
+ return AssemblerFileType;
+ } else if (fileSuffix.compare(QLatin1String("lib"),
+ Qt::CaseInsensitive) == 0) {
+ return LibraryFileType;
+ } else {
+ // All header files, text files and include files
+ // interpretes as a text file types.
+ return TextFileType;
+ }
+ }
+};
+
+class KeiluvFilesPropertyGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit KeiluvFilesPropertyGroup(
+ const QList<ArtifactData> &sourceArtifacts,
+ const QString &baseDirectory)
+ : gen::xml::PropertyGroup("Files")
+ {
+ for (const auto &artifact : sourceArtifacts)
+ appendChild<KeiluvFilePropertyGroup>(artifact.filePath(),
+ baseDirectory);
+ }
+
+ explicit KeiluvFilesPropertyGroup(
+ const QStringList &filePaths,
+ const QString &baseDirectory)
+ : gen::xml::PropertyGroup("Files")
+ {
+ for (const auto &filePath : filePaths)
+ appendChild<KeiluvFilePropertyGroup>(filePath,
+ baseDirectory);
+ }
+};
+
+class KeiluvFileGroupPropertyGroup final : public gen::xml::PropertyGroup
+{
+public:
+ explicit KeiluvFileGroupPropertyGroup(
+ const QString &groupName,
+ const QList<ArtifactData> &sourceArtifacts,
+ const QString &baseDirectory)
+ : gen::xml::PropertyGroup("Group")
+ {
+ appendChild<gen::xml::Property>(QByteArrayLiteral("GroupName"),
+ groupName);
+
+ appendChild<KeiluvFilesPropertyGroup>(sourceArtifacts,
+ baseDirectory);
+ }
+
+ explicit KeiluvFileGroupPropertyGroup(
+ const QString &groupName,
+ const QStringList &filePaths,
+ const QString &baseDirectory)
+ : gen::xml::PropertyGroup("Group")
+ {
+ appendChild<gen::xml::Property>(QByteArrayLiteral("GroupName"),
+ groupName);
+
+ appendChild<KeiluvFilesPropertyGroup>(filePaths,
+ baseDirectory);
+ }
+};
+
+KeiluvFilesGroupsPropertyGroup::KeiluvFilesGroupsPropertyGroup(
+ const Project &qbsProject,
+ const ProductData &qbsProduct,
+ const std::vector<ProductData> &qbsProductDeps)
+ : gen::xml::PropertyGroup(QByteArrayLiteral("Groups"))
+{
+ const auto baseDirectory = gen::utils::buildRootPath(qbsProject);
+
+ // Build source items.
+ const auto groups = qbsProduct.groups();
+ for (const auto &group : groups) {
+ // Ignore disabled groups (e.g. when its condition property is false).
+ if (!group.isEnabled())
+ continue;
+ auto sourceArtifacts = group.sourceArtifacts();
+ // Remove the linker script artifacts.
+ sourceArtifacts.erase(std::remove_if(sourceArtifacts.begin(),
+ sourceArtifacts.end(),
+ [](const auto &artifact){
+ const auto tags = artifact.fileTags();
+ return tags.contains(QLatin1String("linkerscript"));
+ }), sourceArtifacts.end());
+
+ if (sourceArtifacts.isEmpty())
+ continue;
+ appendChild<KeiluvFileGroupPropertyGroup>(
+ group.name(), sourceArtifacts, baseDirectory);
+ }
+
+ // Build local static library items.
+ const auto &qbsProps = qbsProduct.moduleProperties();
+ const auto staticLibs = KeiluvUtils::staticLibraries(qbsProps);
+ if (!staticLibs.isEmpty()) {
+ appendChild<KeiluvFileGroupPropertyGroup>(
+ QStringLiteral("Static Libs"), staticLibs, baseDirectory);
+ }
+
+ // Build dependency library items.
+ const auto deps = KeiluvUtils::dependencies(qbsProductDeps);
+ if (!deps.isEmpty()) {
+ appendChild<KeiluvFileGroupPropertyGroup>(
+ QStringLiteral("Dependencies"), deps, baseDirectory);
+ }
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.h b/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.h
new file mode 100644
index 000000000..bde86b89c
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvfilesgroupspropertygroup.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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_KEILUVFILESGROUPSPROPERTYGROUP_H
+#define QBS_KEILUVFILESGROUPSPROPERTYGROUP_H
+
+#include <generators/xmlpropertygroup.h>
+
+#include <generators/generatordata.h>
+
+namespace qbs {
+
+class KeiluvFilesGroupsPropertyGroup final
+ : public gen::xml::PropertyGroup
+{
+public:
+ explicit KeiluvFilesGroupsPropertyGroup(
+ const qbs::Project &qbsProject,
+ const qbs::ProductData &qbsProduct,
+ const std::vector<qbs::ProductData> &qbsProductDeps);
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVFILESGROUPSPROPERTYGROUP_H
diff --git a/src/plugins/generator/keiluv/keiluvgenerator.cpp b/src/plugins/generator/keiluv/keiluvgenerator.cpp
new file mode 100644
index 000000000..e3c959e8d
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvgenerator.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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 "keiluvgenerator.h"
+#include "keiluvproject.h"
+#include "keiluvprojectwriter.h"
+#include "keiluvworkspace.h"
+#include "keiluvworkspacewriter.h"
+
+#include <generators/generatableprojectiterator.h>
+#include <generators/generatorutils.h>
+
+#include <logging/logger.h>
+#include <logging/translator.h>
+
+#include <tools/filesaver.h>
+
+namespace qbs {
+
+static void writeProjectFiles(const std::map<QString,
+ std::shared_ptr<KeiluvProject>> &projects,
+ const Internal::Logger &logger)
+{
+ for (const auto &item : projects) {
+ const QString projectFilePath = item.first;
+ Internal::FileSaver file(projectFilePath.toStdString());
+ if (!file.open())
+ throw ErrorInfo(Internal::Tr::tr("Cannot open %s for writing")
+ .arg(projectFilePath));
+
+ std::shared_ptr<KeiluvProject> project = item.second;
+ KeiluvProjectWriter writer(file.device());
+ if (!(writer.write(project.get()) && file.commit()))
+ throw ErrorInfo(Internal::Tr::tr("Failed to generate %1")
+ .arg(projectFilePath));
+
+ logger.qbsInfo() << Internal::Tr::tr("Generated %1").arg(
+ QFileInfo(projectFilePath).fileName());
+ }
+}
+
+static void writeWorkspace(const std::shared_ptr<KeiluvWorkspace> &wokspace,
+ const QString &workspaceFilePath,
+ const Internal::Logger &logger)
+{
+ Internal::FileSaver file(workspaceFilePath.toStdString());
+ if (!file.open())
+ throw ErrorInfo(Internal::Tr::tr("Cannot open %s for writing")
+ .arg(workspaceFilePath));
+
+ KeiluvWorkspaceWriter writer(file.device());
+ if (!(writer.write(wokspace.get()) && file.commit()))
+ throw ErrorInfo(Internal::Tr::tr("Failed to generate %1")
+ .arg(workspaceFilePath));
+
+ logger.qbsInfo() << Internal::Tr::tr("Generated %1").arg(
+ QFileInfo(workspaceFilePath).fileName());
+}
+
+KeiluvGenerator::KeiluvGenerator(const KeiluvVersionInfo &versionInfo)
+ : m_versionInfo(versionInfo)
+{
+}
+
+QString KeiluvGenerator::generatorName() const
+{
+ return QStringLiteral("keiluv%1").arg(m_versionInfo.marketingVersion());
+}
+
+void KeiluvGenerator::reset()
+{
+ m_workspace.reset();
+ m_workspaceFilePath.clear();
+ m_projects.clear();
+}
+
+void KeiluvGenerator::generate()
+{
+ GeneratableProjectIterator it(project());
+ it.accept(this);
+
+ writeProjectFiles(m_projects, logger());
+ writeWorkspace(m_workspace, m_workspaceFilePath, logger());
+
+ reset();
+}
+
+void KeiluvGenerator::visitProject(const GeneratableProject &project)
+{
+ const QDir buildDir = project.baseBuildDirectory();
+
+ m_workspaceFilePath = buildDir.absoluteFilePath(
+ project.name() + QStringLiteral(".uvmpw"));
+ m_workspace = std::make_shared<KeiluvWorkspace>(m_workspaceFilePath);
+}
+
+void KeiluvGenerator::visitProjectData(
+ const GeneratableProject &project,
+ const GeneratableProjectData &projectData)
+{
+ Q_UNUSED(project)
+ Q_UNUSED(projectData)
+}
+
+void KeiluvGenerator::visitProduct(
+ const GeneratableProject &project,
+ const GeneratableProjectData &projectData,
+ const GeneratableProductData &productData)
+{
+ Q_UNUSED(projectData);
+
+ const QDir baseBuildDir(project.baseBuildDirectory().absolutePath());
+ const QString projFileName = productData.name() + QLatin1String(".uvprojx");
+ const QString projectFilePath = baseBuildDir.absoluteFilePath(projFileName);
+ const auto targetProject = std::make_shared<KeiluvProject>(
+ project, productData, m_versionInfo);
+
+ m_projects.insert({projectFilePath, targetProject});
+ m_workspace->addProject(projectFilePath);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvgenerator.h b/src/plugins/generator/keiluv/keiluvgenerator.h
new file mode 100644
index 000000000..769519562
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvgenerator.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_KEILUVGENERATOR_H
+#define QBS_KEILUVGENERATOR_H
+
+#include "keiluvversioninfo.h"
+
+#include <generators/generator.h>
+#include <generators/igeneratableprojectvisitor.h>
+
+namespace qbs {
+
+class KeiluvProject;
+class KeiluvWorkspace;
+
+class KeiluvGenerator final : public ProjectGenerator,
+ private IGeneratableProjectVisitor
+{
+public:
+ explicit KeiluvGenerator(const KeiluvVersionInfo &versionInfo);
+
+ QString generatorName() const final;
+ void generate() final;
+
+private:
+ void reset();
+
+ void visitProject(const GeneratableProject &project) final;
+ void visitProjectData(const GeneratableProject &project,
+ const GeneratableProjectData &projectData) final;
+ void visitProduct(const GeneratableProject &project,
+ const GeneratableProjectData &projectData,
+ const GeneratableProductData &productData) final;
+
+ const KeiluvVersionInfo m_versionInfo;
+ std::shared_ptr<KeiluvWorkspace> m_workspace;
+ QString m_workspaceFilePath;
+ std::map<QString, std::shared_ptr<KeiluvProject>> m_projects;
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVGENERATOR_H
diff --git a/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp
new file mode 100644
index 000000000..33e552936
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 "keiluvgenerator.h"
+#include "keiluvversioninfo.h"
+
+#include <tools/projectgeneratormanager.h>
+#include <tools/qbspluginmanager.h>
+
+static void QbsKeiluvGeneratorPluginLoad()
+{
+ for (const auto &info : qbs::KeiluvVersionInfo::knownVersions()) {
+ qbs::ProjectGeneratorManager::registerGenerator(
+ std::make_shared<qbs::KeiluvGenerator>(info));
+ }
+}
+
+static void QbsKeiluvGeneratorPluginUnload()
+{
+}
+
+#ifndef GENERATOR_EXPORT
+#if defined(WIN32) || defined(_WIN32)
+#define GENERATOR_EXPORT __declspec(dllexport)
+#else
+#define GENERATOR_EXPORT __attribute__((visibility("default")))
+#endif
+#endif
+
+QBS_REGISTER_STATIC_PLUGIN(extern "C" GENERATOR_EXPORT, QbsKeiluvGeneratorPlugin,
+ QbsKeiluvGeneratorPluginLoad, QbsKeiluvGeneratorPluginUnload)
diff --git a/src/plugins/generator/keiluv/keiluvproject.cpp b/src/plugins/generator/keiluv/keiluvproject.cpp
new file mode 100644
index 000000000..476ce8e69
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvproject.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** 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 "keiluvconstants.h"
+#include "keiluvproject.h"
+#include "keiluvutils.h"
+#include "keiluvversioninfo.h"
+
+#include "archs/mcs51/mcs51buildtargetgroup_v5.h"
+#include "archs/arm/armbuildtargetgroup_v5.h"
+
+#include <logging/translator.h>
+
+namespace qbs {
+
+static QString keilProjectSchema(const KeiluvVersionInfo &info)
+{
+ const auto v = info.marketingVersion();
+ switch (v) {
+ case KeiluvConstants::v5::kUVisionVersion:
+ return QStringLiteral("2.1");
+ default:
+ return {};
+ }
+}
+
+KeiluvProject::KeiluvProject(
+ const qbs::GeneratableProject &genProject,
+ const qbs::GeneratableProductData &genProduct,
+ const KeiluvVersionInfo &versionInfo)
+{
+ Q_ASSERT(genProject.projects.size() == genProject.commandLines.size());
+ Q_ASSERT(genProject.projects.size() == genProduct.data.size());
+
+ // Create available configuration group factories.
+ m_factories.push_back(std::make_unique<
+ keiluv::mcs51::v5::Mcs51BuildTargetGroupFactory>());
+ m_factories.push_back(std::make_unique<
+ keiluv::arm::v5::ArmBuildTargetGroupFactory>());
+
+ // Construct schema version item (is it depends on a project version?).
+ const auto schema = keilProjectSchema(versionInfo);
+ appendChild<gen::xml::Property>(QByteArrayLiteral("SchemaVersion"),
+ schema);
+
+ // Construct targets group.
+ const auto targetsGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("Targets"));
+
+ // Construct all build target items.
+ const int configsCount = std::max(genProject.projects.size(),
+ genProduct.data.size());
+ for (auto configIndex = 0; configIndex < configsCount; ++configIndex) {
+ const qbs::Project qbsProject = genProject.projects
+ .values().at(configIndex);
+ const qbs::ProductData qbsProduct = genProduct.data
+ .values().at(configIndex);
+ const QString confName = gen::utils::buildConfigurationName(qbsProject);
+ const std::vector<ProductData> qbsProductDeps = gen::utils::dependenciesOf
+ (qbsProduct, genProject, confName);
+
+ const auto arch = gen::utils::architecture(qbsProject);
+ if (arch == gen::utils::Architecture::Unknown)
+ throw ErrorInfo(Internal::Tr::tr("Target architecture is not set,"
+ " please use the 'profile' option"));
+
+ // Construct the build target item, which are depend from
+ // the architecture and the version.
+ const auto factoryEnd = m_factories.cend();
+ const auto factoryIt = std::find_if(m_factories.cbegin(), factoryEnd,
+ [arch, versionInfo](const auto &factory) {
+ return factory->canCreate(arch, versionInfo.version());
+ });
+ if (factoryIt == factoryEnd) {
+ throw ErrorInfo(Internal::Tr::tr("Incompatible target architecture '%1'"
+ " for KEIL UV version %2")
+ .arg(gen::utils::architectureName(arch))
+ .arg(versionInfo.marketingVersion()));
+ }
+
+ auto targetGroup = (*factoryIt)->create(
+ qbsProject, qbsProduct, qbsProductDeps);
+ targetsGroup->appendChild(std::move(targetGroup));
+ }
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvproject.h b/src/plugins/generator/keiluv/keiluvproject.h
new file mode 100644
index 000000000..98b2815ed
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvproject.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_KEILUVPROJECT_H
+#define QBS_KEILUVPROJECT_H
+
+#include <generators/generatordata.h>
+
+#include <generators/xmlproject.h>
+#include <generators/xmlpropertygroup.h>
+
+#include <memory>
+
+namespace qbs {
+
+class KeiluvVersionInfo;
+
+class KeiluvProject final : public gen::xml::Project
+{
+public:
+ explicit KeiluvProject(
+ const qbs::GeneratableProject &genProject,
+ const qbs::GeneratableProductData &genProduct,
+ const KeiluvVersionInfo &versionInfo);
+private:
+ std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories;
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVPROJECT_H
diff --git a/src/plugins/generator/keiluv/keiluvprojectwriter.cpp b/src/plugins/generator/keiluv/keiluvprojectwriter.cpp
new file mode 100644
index 000000000..77616335c
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvprojectwriter.cpp
@@ -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.
+**
+****************************************************************************/
+
+#include "keiluvprojectwriter.h"
+
+namespace qbs {
+
+KeiluvProjectWriter::KeiluvProjectWriter(std::ostream *device)
+ : gen::xml::ProjectWriter(device)
+{
+}
+
+void KeiluvProjectWriter::visitProjectStart(const gen::xml::Project *project)
+{
+ Q_UNUSED(project)
+ writer()->writeStartElement(QStringLiteral("Project"));
+ writer()->writeAttribute(
+ QStringLiteral("xmlns:xsi"),
+ QStringLiteral("http://www.w3.org/2001/XMLSchema-instance"));
+ writer()->writeAttribute(
+ QStringLiteral("xsi:noNamespaceSchemaLocation"),
+ QStringLiteral("project_proj.xsd"));
+}
+
+void KeiluvProjectWriter::visitProjectEnd(const gen::xml::Project *project)
+{
+ Q_UNUSED(project)
+ writer()->writeEndElement();
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvprojectwriter.h b/src/plugins/generator/keiluv/keiluvprojectwriter.h
new file mode 100644
index 000000000..6f890c8e8
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvprojectwriter.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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_KEILUVPROJECTWRITER_H
+#define QBS_KEILUVPROJECTWRITER_H
+
+#include <generators/xmlprojectwriter.h>
+
+namespace qbs {
+
+class KeiluvProjectWriter final : public gen::xml::ProjectWriter
+{
+ Q_DISABLE_COPY(KeiluvProjectWriter)
+public:
+ explicit KeiluvProjectWriter(std::ostream *device);
+
+private:
+ void visitProjectStart(const gen::xml::Project *project) final;
+ void visitProjectEnd(const gen::xml::Project *project) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVPROJECTWRITER_H
diff --git a/src/plugins/generator/keiluv/keiluvutils.cpp b/src/plugins/generator/keiluv/keiluvutils.cpp
new file mode 100644
index 000000000..8932f0f16
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvutils.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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 "keiluvutils.h"
+
+#include <generators/generatorutils.h>
+
+namespace qbs {
+namespace KeiluvUtils {
+
+OutputBinaryType outputBinaryType(const ProductData &qbsProduct)
+{
+ const auto qbsProductType = qbsProduct.type();
+ if (qbsProductType.contains(QLatin1String("application")))
+ return ApplicationOutputType;
+ if (qbsProductType.contains(QLatin1String("staticlibrary")))
+ return LibraryOutputType;
+ return ApplicationOutputType;
+}
+
+QString toolkitRootPath(const ProductData &qbsProduct)
+{
+ QDir dir(qbsProduct.moduleProperties()
+ .getModuleProperty(Internal::StringConstants::cppModule(),
+ QStringLiteral("toolchainInstallPath"))
+ .toString());
+ dir.cdUp();
+ const auto path = dir.absolutePath();
+ return QDir::toNativeSeparators(path);
+}
+
+QStringList cppModuleCompilerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverFlags"), QStringLiteral("cFlags"),
+ QStringLiteral("cppFlags"), QStringLiteral("cxxFlags"),
+ QStringLiteral("commonCompilerFlags")});
+}
+
+QStringList cppModuleAssemblerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("assemblerFlags")});
+}
+
+QStringList cppModuleLinkerFlags(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("driverLinkerFlags")});
+}
+
+QStringList includes(const PropertyMap &qbsProps)
+{
+ auto paths = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("includePaths"),
+ QStringLiteral("systemIncludePaths")});
+ // Transform include path separators to native.
+ std::transform(paths.begin(), paths.end(), paths.begin(),
+ [](const auto &path) {
+ return QDir::toNativeSeparators(path);
+ });
+ return paths;
+}
+
+QStringList defines(const PropertyMap &qbsProps)
+{
+ return gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("defines")});
+}
+
+QStringList staticLibraries(const PropertyMap &qbsProps)
+{
+ auto libs = gen::utils::cppStringModuleProperties(
+ qbsProps, {QStringLiteral("staticLibraries")});
+ // Transform library path separators to native.
+ std::transform(libs.begin(), libs.end(), libs.begin(),
+ [](const auto &path) {
+ return QDir::toNativeSeparators(path);
+ });
+ return libs;
+}
+
+QStringList dependencies(const std::vector<ProductData> &qbsProductDeps)
+{
+ QStringList deps;
+ for (const ProductData &qbsProductDep : qbsProductDeps) {
+ const auto path = qbsProductDep.buildDirectory()
+ + QLatin1String("/obj/")
+ + gen::utils::targetBinary(qbsProductDep);
+ deps.push_back(QDir::toNativeSeparators(path));
+ }
+ return deps;
+}
+
+} // namespace KeiluvUtils
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvutils.h b/src/plugins/generator/keiluv/keiluvutils.h
new file mode 100644
index 000000000..92209dc53
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvutils.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_KEILUVUTILS_H
+#define QBS_KEILUVUTILS_H
+
+#include <qbs.h>
+
+#include <tools/stringconstants.h>
+
+namespace qbs {
+namespace KeiluvUtils {
+
+enum OutputBinaryType {
+ ApplicationOutputType,
+ LibraryOutputType
+};
+
+OutputBinaryType outputBinaryType(const ProductData &qbsProduct);
+
+QString toolkitRootPath(const ProductData &qbsProduct);
+
+QStringList cppModuleCompilerFlags(const PropertyMap &qbsProps);
+
+QStringList cppModuleAssemblerFlags(const PropertyMap &qbsProps);
+
+QStringList cppModuleLinkerFlags(const PropertyMap &qbsProps);
+
+QStringList includes(const PropertyMap &qbsProps);
+QStringList defines(const PropertyMap &qbsProps);
+QStringList staticLibraries(const PropertyMap &qbsProps);
+QStringList dependencies(const std::vector<ProductData> &qbsProductDeps);
+
+} // namespace KeiluvUtils
+} // namespace qbs
+
+#endif // QBS_KEILUVUTILS_H
diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.cpp b/src/plugins/generator/keiluv/keiluvversioninfo.cpp
new file mode 100644
index 000000000..973d0a420
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvversioninfo.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 "keiluvconstants.h"
+#include "keiluvversioninfo.h"
+
+#include <QtCore/qdebug.h>
+
+namespace qbs {
+
+KeiluvVersionInfo::KeiluvVersionInfo(
+ const Version &version,
+ const std::set<gen::utils::Architecture> &archs)
+ : gen::VersionInfo(version, archs)
+{
+}
+
+std::set<KeiluvVersionInfo> KeiluvVersionInfo::knownVersions()
+{
+ static const std::set<KeiluvVersionInfo> known = {
+ {Version(KeiluvConstants::v5::kUVisionVersion),
+ {gen::utils::Architecture::Mcs51,
+ gen::utils::Architecture::Arm}},
+ };
+ return known;
+}
+
+int KeiluvVersionInfo::marketingVersion() const
+{
+ const auto mv = gen::VersionInfo::marketingVersion();
+ for (const KeiluvVersionInfo &known : knownVersions()) {
+ if (known.version().majorVersion() == mv)
+ return mv;
+ }
+ qWarning() << QStringLiteral("Unrecognized KEIL UV version: ")
+ << version().toString();
+ return 0;
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.h b/src/plugins/generator/keiluv/keiluvversioninfo.h
new file mode 100644
index 000000000..a64513492
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvversioninfo.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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 QBS_KEILUVVERSIONINFO_H
+#define QBS_KEILUVVERSIONINFO_H
+
+#include <generators/generatorutils.h>
+#include <generators/generatorversioninfo.h>
+
+namespace qbs {
+
+class KeiluvVersionInfo final : public gen::VersionInfo
+{
+public:
+ KeiluvVersionInfo(const Version &version,
+ const std::set<gen::utils::Architecture> &archs);
+
+ int marketingVersion() const final;
+
+ static std::set<KeiluvVersionInfo> knownVersions();
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVVERSIONINFO_H
diff --git a/src/plugins/generator/keiluv/keiluvworkspace.cpp b/src/plugins/generator/keiluv/keiluvworkspace.cpp
new file mode 100644
index 000000000..b4df92001
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvworkspace.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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 "keiluvworkspace.h"
+
+#include <generators/xmlpropertygroup.h>
+
+namespace qbs {
+
+KeiluvWorkspace::KeiluvWorkspace(const QString &workspacePath)
+ : gen::xml::Workspace(workspacePath)
+{
+ // Construct schema version item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("SchemaVersion"),
+ QStringLiteral("1.0"));
+
+ // Construct workspace name item.
+ appendChild<gen::xml::Property>(QByteArrayLiteral("WorkspaceName"),
+ QStringLiteral("WorkSpace"));
+}
+
+void KeiluvWorkspace::addProject(const QString &projectFilePath)
+{
+ const QString relativeProjectPath = QDir::toNativeSeparators(
+ m_baseDirectory.relativeFilePath(projectFilePath));
+
+ const auto projectGroup = appendChild<gen::xml::PropertyGroup>(
+ QByteArrayLiteral("project"));
+ projectGroup->appendProperty("PathAndName", relativeProjectPath);
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvworkspace.h b/src/plugins/generator/keiluv/keiluvworkspace.h
new file mode 100644
index 000000000..2b274c99f
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvworkspace.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 QBS_KEILUVWORKSPACE_H
+#define QBS_KEILUVWORKSPACE_H
+
+#include <generators/xmlworkspace.h>
+
+namespace qbs {
+
+class KeiluvWorkspace final : public gen::xml::Workspace
+{
+public:
+ explicit KeiluvWorkspace(const QString &workspacePath);
+ void addProject(const QString &projectPath) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVWORKSPACE_H
diff --git a/src/plugins/generator/keiluv/keiluvworkspacewriter.cpp b/src/plugins/generator/keiluv/keiluvworkspacewriter.cpp
new file mode 100644
index 000000000..c886b0e6e
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvworkspacewriter.cpp
@@ -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.
+**
+****************************************************************************/
+
+#include "keiluvworkspacewriter.h"
+
+namespace qbs {
+
+KeiluvWorkspaceWriter::KeiluvWorkspaceWriter(std::ostream *device)
+ : gen::xml::WorkspaceWriter(device)
+{
+}
+
+void KeiluvWorkspaceWriter::visitWorkspaceStart(const gen::xml::Workspace *workspace)
+{
+ Q_UNUSED(workspace)
+ writer()->writeStartElement(QStringLiteral("ProjectWorkspace"));
+ writer()->writeAttribute(
+ QStringLiteral("xmlns:xsi"),
+ QStringLiteral("http://www.w3.org/2001/XMLSchema-instance"));
+ writer()->writeAttribute(
+ QStringLiteral("xsi:noNamespaceSchemaLocation"),
+ QStringLiteral("project_mpw.xsd"));
+}
+
+void KeiluvWorkspaceWriter::visitWorkspaceEnd(const gen::xml::Workspace *workspace)
+{
+ Q_UNUSED(workspace)
+ writer()->writeEndElement();
+}
+
+} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvworkspacewriter.h b/src/plugins/generator/keiluv/keiluvworkspacewriter.h
new file mode 100644
index 000000000..2419ad761
--- /dev/null
+++ b/src/plugins/generator/keiluv/keiluvworkspacewriter.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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_KEILUVWORKSPACEWRITER_H
+#define QBS_KEILUVWORKSPACEWRITER_H
+
+#include <generators/xmlworkspacewriter.h>
+
+namespace qbs {
+
+class KeiluvWorkspaceWriter final : public gen::xml::WorkspaceWriter
+{
+ Q_DISABLE_COPY(KeiluvWorkspaceWriter)
+public:
+ explicit KeiluvWorkspaceWriter(std::ostream *device);
+
+private:
+ void visitWorkspaceStart(const gen::xml::Workspace *workspace) final;
+ void visitWorkspaceEnd(const gen::xml::Workspace *workspace) final;
+};
+
+} // namespace qbs
+
+#endif // QBS_KEILUVWORKSPACEWRITER_H
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index dcc1ded87..ee101f60e 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -6,6 +6,8 @@ Project {
"generator/clangcompilationdb/clangcompilationdb.qbs",
"generator/makefilegenerator/makefilegenerator.qbs",
"generator/visualstudio/visualstudio.qbs",
+ "generator/iarew/iarew.qbs",
+ "generator/keiluv/keiluv.qbs",
"scanner/cpp/cpp.qbs",
"scanner/qt/qt.qbs"
]
diff --git a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
index f0de12df1..f4ea8bf83 100644
--- a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
+++ b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
@@ -4,12 +4,21 @@ Project {
consoleApplication: true // suppress bundle generation
files: "main.cpp"
name: "infinite-loop"
+ cpp.cxxLanguageVersion: "c++11"
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ cpp.driverFlags: "-pthread"
+ }
}
Product {
type: "mytype"
name: "caller"
Depends { name: "infinite-loop" }
+ Depends {
+ name: "cpp" // Make sure build environment is set up properly.
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc")
+ }
Rule {
inputsFromDependencies: "application"
outputFileTags: "mytype"
diff --git a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs
index eade97126..d7ed6c862 100644
--- a/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs
+++ b/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs
@@ -11,6 +11,13 @@ Project {
files: [ "static1.cpp" ]
Depends { name: "cpp" }
Depends { name: "dynamic1" }
+
+ Probe {
+ id: osCheck
+ property bool isNormalUnix: qbs.targetOS.contains("unix")
+ && !qbs.targetOS.contains("darwin")
+ configure: { console.info("is normal unix: " + (isNormalUnix ? "yes" : "no")); }
+ }
}
DynamicLibrary {
diff --git a/tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-profile-item.qbs b/tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-profile-item.qbs
new file mode 100644
index 000000000..d7dc02cc2
--- /dev/null
+++ b/tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-profile-item.qbs
@@ -0,0 +1,19 @@
+Project {
+
+ property bool probesEvaluated: probe.found
+
+ Probe {
+ id: probe
+ configure: {
+ found = true;
+ }
+ }
+
+ Profile {
+ name: "the-profile"
+ cpp.includePaths: {
+ if (!probesEvaluated)
+ throw "project-level probes not evaluated";
+ }
+ }
+}
diff --git a/tests/auto/api/testdata/timeout-js/timeout.qbs b/tests/auto/api/testdata/timeout-js/timeout.qbs
new file mode 100644
index 000000000..26aa4ce87
--- /dev/null
+++ b/tests/auto/api/testdata/timeout-js/timeout.qbs
@@ -0,0 +1,20 @@
+Product {
+ type: "product-under-test"
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: "output.txt"
+ fileTags: "product-under-test"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Running infinite loop";
+ cmd.sourceCode = function() {
+ while (true)
+ ;
+ }
+ cmd.timeout = 3;
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/api/testdata/timeout-process/main.cpp b/tests/auto/api/testdata/timeout-process/main.cpp
new file mode 100644
index 000000000..f9b9336ba
--- /dev/null
+++ b/tests/auto/api/testdata/timeout-process/main.cpp
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <chrono>
+#include <thread>
+
+int main()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(700));
+ return 0;
+}
+
diff --git a/tests/auto/api/testdata/timeout-process/timeout.qbs b/tests/auto/api/testdata/timeout-process/timeout.qbs
new file mode 100644
index 000000000..bb8deac9b
--- /dev/null
+++ b/tests/auto/api/testdata/timeout-process/timeout.qbs
@@ -0,0 +1,34 @@
+Project {
+ CppApplication {
+ type: "application"
+ consoleApplication: true // suppress bundle generation
+ files: "main.cpp"
+ name: "infinite-loop"
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumOsxVersion: "10.8" // For <chrono>
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ cpp.driverFlags: "-pthread"
+ }
+ }
+
+ Product {
+ type: "product-under-test"
+ name: "caller"
+ Depends { name: "infinite-loop" }
+ Depends {
+ name: "cpp" // Make sure build environment is set up properly.
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc")
+ }
+ Rule {
+ inputsFromDependencies: "application"
+ outputFileTags: "product-under-test"
+ prepare: {
+ var cmd = new Command(inputs["application"][0].filePath);
+ cmd.description = "Calling application that runs forever";
+ cmd.timeout = 3;
+ return cmd;
+ }
+ }
+ }
+}
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp
index aac0f3e7e..235f2ac04 100644
--- a/tests/auto/api/tst_api.cpp
+++ b/tests/auto/api/tst_api.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.
@@ -874,7 +875,7 @@ void TestApi::changeContent()
buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
errorInfo = project.addGroup(newProjectData.products().front(), "blubb");
QVERIFY(errorInfo.hasError());
- QVERIFY2(errorInfo.toString().contains("in process"), qPrintable(errorInfo.toString()));
+ QVERIFY2(errorInfo.toString().contains("in progress"), qPrintable(errorInfo.toString()));
waitForFinished(buildJob.get());
errorInfo = project.addGroup(newProjectData.products().front(), "blubb");
VERIFY_NO_ERROR(errorInfo);
@@ -1555,9 +1556,13 @@ void TestApi::linkStaticAndDynamicLibs()
BuildDescriptionReceiver bdr;
qbs::BuildOptions options;
options.setEchoMode(qbs::CommandEchoModeCommandLine);
+ m_logSink->output.clear();
const qbs::ErrorInfo errorInfo = doBuildProject("link-staticlibs-dynamiclibs", &bdr, nullptr,
nullptr, options);
VERIFY_NO_ERROR(errorInfo);
+ const bool isNormalUnix = m_logSink->output.contains("is normal unix: yes");
+ const bool isNotNormalUnix = m_logSink->output.contains("is normal unix: no");
+ QVERIFY2(isNormalUnix != isNotNormalUnix, qPrintable(m_logSink->output));
// The dependencies libdynamic1.so and libstatic2.a must not appear in the link command for the
// executable. The -rpath-link line for libdynamic1.so must be there.
@@ -1574,12 +1579,7 @@ void TestApi::linkStaticAndDynamicLibs()
}
}
QVERIFY(!appLinkCmd.isEmpty());
- std::string targetPlatform = buildProfile.value("qbs.targetPlatform")
- .toString().toStdString();
- std::vector<std::string> targetOS = qbs::Internal::HostOsInfo::canonicalOSIdentifiers(
- targetPlatform);
- if (!qbs::Internal::contains(targetOS, "darwin")
- && !qbs::Internal::contains(targetOS, "windows")) {
+ if (isNormalUnix) {
const std::regex rpathLinkRex("-rpath-link=\\S*/"
+ relativeProductBuildDir("dynamic2").toStdString());
const auto ln = appLinkCmd.toStdString();
@@ -2374,6 +2374,12 @@ void TestApi::projectWithPropertiesItem()
VERIFY_NO_ERROR(errorInfo);
}
+void TestApi::projectWithProbeAndProfileItem()
+{
+ const qbs::ErrorInfo errorInfo = doBuildProject("project-with-probe-and-profile-item");
+ VERIFY_NO_ERROR(errorInfo);
+}
+
void TestApi::propertiesBlocks()
{
const qbs::ErrorInfo errorInfo = doBuildProject("properties-blocks");
@@ -2829,6 +2835,48 @@ void TestApi::targetArtifactStatus()
QCOMPARE(product.targetArtifacts().size(), enableTagging ? 2 : 1);
}
+void TestApi::timeout()
+{
+ QFETCH(QString, projectDirName);
+ const auto setupParams = defaultSetupParameters(projectDirName + "/timeout.qbs");
+ std::unique_ptr<qbs::SetupProjectJob> setupJob{
+ qbs::Project().setupProject(setupParams, m_logSink, nullptr)};
+ waitForFinished(setupJob.get());
+ QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString()));
+ auto project = setupJob->project();
+ const auto products = project.projectData().products();
+ QList<qbs::ProductData> helperProducts;
+ qbs::ProductData productUnderTest;
+ for (const auto &product : products) {
+ if (!product.type().contains(QLatin1String("product-under-test")))
+ helperProducts.append(product);
+ else
+ productUnderTest = product;
+ }
+ const std::unique_ptr<qbs::BuildJob> buildHelpersJob{
+ project.buildSomeProducts(helperProducts, qbs::BuildOptions())};
+ QVERIFY(waitForFinished(buildHelpersJob.get(), testTimeoutInMsecs()));
+ if (buildHelpersJob->error().hasError()) {
+ qDebug().noquote() << buildHelpersJob->error().toString();
+ QFAIL("Could not build helper products");
+ }
+
+ const std::unique_ptr<qbs::BuildJob> buildJob(project.buildOneProduct(productUnderTest,
+ qbs::BuildOptions()));
+ QVERIFY(waitForFinished(buildJob.get(), testTimeoutInMsecs()));
+ QVERIFY(buildJob->error().hasError());
+ const auto errorString = buildJob->error().toString();
+ QVERIFY2(errorString.contains("cancel"), qPrintable(errorString));
+ QVERIFY(errorString.contains("timeout"));
+}
+
+void TestApi::timeout_data()
+{
+ QTest::addColumn<QString>("projectDirName");
+ QTest::newRow("JS Command") << QString("timeout-js");
+ QTest::newRow("Process Command") << QString("timeout-process");
+}
+
void TestApi::toolInModule()
{
QVariantMap overrides({std::make_pair("qbs.installRoot", m_workingDataDir
diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h
index c04e9feb0..aa00ddc99 100644
--- a/tests/auto/api/tst_api.h
+++ b/tests/auto/api/tst_api.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.
@@ -121,6 +122,7 @@ private slots:
void projectLocking();
void projectPropertiesByName();
void projectWithPropertiesItem();
+ void projectWithProbeAndProfileItem();
void propertiesBlocks();
void rc();
void referencedFileErrors();
@@ -142,6 +144,8 @@ private slots:
void subProjects();
void targetArtifactStatus_data();
void targetArtifactStatus();
+ void timeout();
+ void timeout_data();
void toolInModule();
void trackAddQObjectHeader();
void trackRemoveQObjectHeader();
diff --git a/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs b/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs
index 1ab369c88..221105a64 100644
--- a/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs
+++ b/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs
@@ -63,7 +63,7 @@ Project {
outputFileTags: "tool_in"
outputArtifacts: {
var artifacts = [];
- for (var i = 0; i < 7; ++i)
+ for (var i = 0; i < 5; ++i)
artifacts.push({filePath: "file" + i + ".in", fileTags: "tool_in"});
return artifacts;
}
diff --git a/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp b/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp
index 0a94c6393..ec9acba80 100644
--- a/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp
+++ b/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
return 4;
}
}
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
fclose(lockFile);
std::FILE * const output = std::fopen(argv[1], "w");
if (!output) {
diff --git a/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs b/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs
new file mode 100644
index 000000000..49ee35d3a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs
@@ -0,0 +1,20 @@
+Project {
+ CppApplication {
+ name: "testApp"
+ type: ["application", "autotest"]
+ Depends { name: "autotest" }
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumOsxVersion: "10.8" // For <chrono>
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ cpp.driverFlags: "-pthread"
+ }
+ files: "test-main.cpp"
+ }
+ AutotestRunner {
+ Depends {
+ name: "cpp" // Make sure build environment is set up properly.
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc")
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/autotest-timeout/test-main.cpp b/tests/auto/blackbox/testdata/autotest-timeout/test-main.cpp
new file mode 100644
index 000000000..4bb1ca27c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/autotest-timeout/test-main.cpp
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <chrono>
+#include <thread>
+
+int main()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ return 0;
+}
+
diff --git a/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs b/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs
index 92d5ec6dd..7ae6cef73 100644
--- a/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs
+++ b/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs
@@ -21,6 +21,10 @@ Project {
}
AutotestRunner {
+ Depends {
+ name: "cpp" // Make sure build environment is set up properly.
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc")
+ }
arguments: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, "bin")
auxiliaryInputs: "test-helper"
}
diff --git a/tests/auto/blackbox/testdata/autotests/autotests.qbs b/tests/auto/blackbox/testdata/autotests/autotests.qbs
index a2c2646dc..10334156e 100644
--- a/tests/auto/blackbox/testdata/autotests/autotests.qbs
+++ b/tests/auto/blackbox/testdata/autotests/autotests.qbs
@@ -1,4 +1,9 @@
Project {
references: ["test1", "test2", "test3"]
- AutotestRunner {}
+ AutotestRunner {
+ Depends {
+ name: "cpp" // Make sure build environment is set up properly.
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("gcc")
+ }
+ }
}
diff --git a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
index 61f76f4be..6cd334247 100644
--- a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
+++ b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
@@ -8,6 +8,23 @@ CppApplication {
cpp.cxxLanguageVersion: "c++11"
cpp.minimumMacosVersion: "10.7"
consoleApplication: true
+ Probe {
+ id: pathCheck
+ property string theDir: {
+ if (qbs.targetOS.contains("windows")) {
+ if (qbs.toolchain.contains("mingw"))
+ return cpp.toolchainInstallPath;
+ if (qbs.toolchain.contains("clang") && qbs.sysroot)
+ return qbs.sysroot + "/bin";
+ }
+ }
+ configure: {
+ if (theDir)
+ console.info("add to PATH: " + theDir);
+ found = true;
+ }
+ }
+
files: [
"lexer.l",
"parser.y",
diff --git a/tests/auto/blackbox/testdata/qbs-session/file1.cpp b/tests/auto/blackbox/testdata/qbs-session/file1.cpp
new file mode 100644
index 000000000..1d6ea3b78
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/file1.cpp
@@ -0,0 +1 @@
+void f1() {}
diff --git a/tests/auto/blackbox/testdata/qbs-session/file2.cpp b/tests/auto/blackbox/testdata/qbs-session/file2.cpp
new file mode 100644
index 000000000..8ccc02b45
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/file2.cpp
@@ -0,0 +1 @@
+void f2() {}
diff --git a/tests/auto/blackbox/testdata/qbs-session/lib.cpp b/tests/auto/blackbox/testdata/qbs-session/lib.cpp
new file mode 100644
index 000000000..8101b05dc
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/lib.cpp
@@ -0,0 +1 @@
+void f() { }
diff --git a/tests/auto/blackbox/testdata/qbs-session/lib.h b/tests/auto/blackbox/testdata/qbs-session/lib.h
new file mode 100644
index 000000000..789447c02
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/lib.h
@@ -0,0 +1 @@
+void f();
diff --git a/tests/auto/blackbox/testdata/qbs-session/main.cpp b/tests/auto/blackbox/testdata/qbs-session/main.cpp
new file mode 100644
index 000000000..654a5d65b
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/main.cpp
@@ -0,0 +1,4 @@
+int main()
+{
+ int i; // Should trigger a warning and thus a process-exited message.
+}
diff --git a/tests/auto/blackbox/testdata/qbs-session/modules/mymodule/mymodule.qbs b/tests/auto/blackbox/testdata/qbs-session/modules/mymodule/mymodule.qbs
new file mode 100644
index 000000000..ecf12b5a3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/modules/mymodule/mymodule.qbs
@@ -0,0 +1,5 @@
+import qbs.Environment
+
+Module {
+ setupRunEnvironment: { Environment.putEnv("MY_MODULE", 1); }
+}
diff --git a/tests/auto/blackbox/testdata/qbs-session/qbs-session.qbs b/tests/auto/blackbox/testdata/qbs-session/qbs-session.qbs
new file mode 100644
index 000000000..8496fb38e
--- /dev/null
+++ b/tests/auto/blackbox/testdata/qbs-session/qbs-session.qbs
@@ -0,0 +1,25 @@
+Project {
+ StaticLibrary {
+ name: "theLib"
+ Depends { name: "cpp" }
+ cpp.cxxLanguageVersion: "c++11"
+ Group {
+ name: "sources"
+ files: "lib.cpp"
+ }
+ Group {
+ name: "headers"
+ files: "lib.h"
+ }
+ }
+ CppApplication {
+ name: "theApp"
+ consoleApplication: true
+ Depends { name: "mymodule" }
+ cpp.cxxLanguageVersion: "c++14"
+ cpp.warningLevel: "all"
+ files: "main.cpp"
+ install: true
+ }
+}
+
diff --git a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
index 48bdff904..0b16d1984 100644
--- a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
+++ b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
@@ -4,6 +4,15 @@ Project {
type: ["application"]
files: ["main.cpp"]
cpp.separateDebugInformation: true
+
+ Probe {
+ id: osProbe
+ property stringList targetOS: qbs.targetOS
+ configure: {
+ console.info("is windows: " + (targetOS.contains("windows") ? "yes" : "no"));
+ console.info("is darwin: " + (targetOS.contains("darwin") ? "yes" : "no"));
+ }
+ }
}
DynamicLibrary {
Depends { name: "cpp" }
diff --git a/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs b/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs
index b5ac8b289..d2d47b767 100644
--- a/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs
+++ b/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs
@@ -61,6 +61,16 @@ Project {
bundle.isBundle: false
}
+ // Testing shows that clang (8.0) does not find dynamic libraries via
+ // the -L<dir> and -l<libname> mechanism unless the name is "lib<libname>.a".
+ Properties {
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain.contains("clang")
+ cpp.dynamicLibraryPrefix: "lib"
+ cpp.dynamicLibraryImportSuffix: ".a"
+ }
+ cpp.dynamicLibraryPrefix: original
+ cpp.dynamicLibraryImportSuffix: original
+
install: true
installImportLib: true
installDir: "lib4"
@@ -91,8 +101,9 @@ Project {
property string fullInstallPrefix: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix)
property string lib3FilePath: FileInfo.joinPaths(fullInstallPrefix, "lib3",
- cpp.dynamicLibraryPrefix + "lib3" + (qbs.toolchain.contains("msvc")
- ? ".lib" : cpp.dynamicLibrarySuffix))
+ cpp.dynamicLibraryPrefix + "lib3" + (qbs.targetOS.contains("windows")
+ ? cpp.dynamicLibraryImportSuffix
+ : cpp.dynamicLibrarySuffix))
cpp.dynamicLibraries: [lib3FilePath, "lib4"]
cpp.libraryPaths: FileInfo.joinPaths(fullInstallPrefix, "lib4")
}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 19676d050..3a90d8ccb 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.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.
@@ -42,6 +43,7 @@
#include <tools/version.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
@@ -52,6 +54,7 @@
#include <QtCore/qtemporarydir.h>
#include <QtCore/qtemporaryfile.h>
+#include <algorithm>
#include <functional>
#include <regex>
#include <utility>
@@ -1805,14 +1808,17 @@ void TestBlackbox::separateDebugInfo()
{
QDir::setCurrent(testDataDir + "/separate-debug-info");
QCOMPARE(runQbs(QbsRunParameters(QStringList("qbs.debugInformation:true"))), 0);
+ const bool isWindows = m_qbsStdout.contains("is windows: yes");
+ const bool isNotWindows = m_qbsStdout.contains("is windows: no");
+ QVERIFY(isWindows != isNotWindows);
+ const bool isDarwin = m_qbsStdout.contains("is darwin: yes");
+ const bool isNotDarwin = m_qbsStdout.contains("is darwin: no");
+ QVERIFY(isDarwin != isNotDarwin);
const SettingsPtr s = settings();
Profile buildProfile(profileName(), s.get());
QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
- std::string targetPlatform = buildProfile.value("qbs.targetPlatform").toString().toStdString();
- std::vector<std::string> targetOS = HostOsInfo::canonicalOSIdentifiers(targetPlatform);
- if (qbs::Internal::contains(targetOS, "darwin")
- || (targetPlatform.empty() && HostOsInfo::isMacosHost())) {
+ if (isDarwin) {
QVERIFY(directoryExists(relativeProductBuildDir("app1") + "/app1.app.dSYM"));
QVERIFY(regularFileExists(relativeProductBuildDir("app1")
+ "/app1.app.dSYM/Contents/Info.plist"));
@@ -1877,7 +1883,6 @@ void TestBlackbox::separateDebugInfo()
.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1);
QVERIFY(regularFileExists(relativeProductBuildDir("bar5") + "/bar5.bundle.dwarf"));
} else if (toolchain.contains("gcc")) {
- const bool isWindows = qbs::Internal::contains(targetOS, "windows");
const QString exeSuffix = isWindows ? ".exe" : "";
const QString dllPrefix = isWindows ? "" : "lib";
const QString dllSuffix = isWindows ? ".dll" : ".so";
@@ -4353,6 +4358,18 @@ void TestBlackbox::lexyacc()
QCOMPARE(runQbs(), 0);
const QString parserBinary = relativeExecutableFilePath("one-grammar");
QProcess p;
+ const QByteArray magicString = "add to PATH: ";
+ const int magicStringIndex = m_qbsStdout.indexOf(magicString);
+ if (magicStringIndex != -1) {
+ const int newLineIndex = m_qbsStdout.indexOf('\n', magicStringIndex);
+ QVERIFY(newLineIndex != -1);
+ const int dirIndex = magicStringIndex + magicString.length();
+ const QString dir = QString::fromLocal8Bit(m_qbsStdout.mid(dirIndex,
+ newLineIndex - dirIndex));
+ QProcessEnvironment env;
+ env.insert("PATH", dir);
+ p.setProcessEnvironment(env);
+ }
p.start(parserBinary);
QVERIFY2(p.waitForStarted(), qPrintable(p.errorString()));
p.write("a && b || c && !d");
@@ -5293,6 +5310,648 @@ void TestBlackbox::qbsConfig()
}
}
+static QJsonObject getNextSessionPacket(QProcess &session, QByteArray &data)
+{
+ int totalSize = -1;
+ QElapsedTimer timer;
+ timer.start();
+ QByteArray msg;
+ while (totalSize == -1 || msg.size() < totalSize) {
+ if (data.isEmpty())
+ session.waitForReadyRead(1000);
+ if (timer.elapsed() >= 10000)
+ return QJsonObject();
+ data += session.readAllStandardOutput();
+ if (totalSize == -1) {
+ static const QByteArray magicString = "qbsmsg:";
+ const int magicStringOffset = data.indexOf(magicString);
+ if (magicStringOffset == -1)
+ continue;
+ const int sizeOffset = magicStringOffset + magicString.length();
+ const int newlineOffset = data.indexOf('\n', sizeOffset);
+ if (newlineOffset == -1)
+ continue;
+ const QByteArray sizeString = data.mid(sizeOffset, newlineOffset - sizeOffset);
+ bool isNumber;
+ const int size = sizeString.toInt(&isNumber);
+ if (!isNumber || size <= 0)
+ return QJsonObject();
+ data = data.mid(newlineOffset + 1);
+ totalSize = size;
+ }
+ const int bytesToTake = std::min(totalSize - msg.size(), data.size());
+ msg += data.left(bytesToTake);
+ data = data.mid(bytesToTake);
+ }
+ return QJsonDocument::fromJson(QByteArray::fromBase64(msg)).object();
+}
+
+void TestBlackbox::qbsSession()
+{
+ QDir::setCurrent(testDataDir + "/qbs-session");
+ QProcess sessionProc;
+ sessionProc.start(qbsExecutableFilePath, QStringList("session"));
+
+ // Uncomment for debugging.
+ /*
+ connect(&sessionProc, &QProcess::readyReadStandardError, [&sessionProc] {
+ qDebug() << "stderr:" << sessionProc.readAllStandardError();
+ });
+ */
+
+ QVERIFY(sessionProc.waitForStarted());
+
+ const auto sendPacket = [&sessionProc](const QJsonObject &message) {
+ const QByteArray data = QJsonDocument(message).toJson().toBase64();
+ sessionProc.write("qbsmsg:");
+ sessionProc.write(QByteArray::number(data.length()));
+ sessionProc.write("\n");
+ sessionProc.write(data);
+ };
+
+ static const auto envToJson = [](const QProcessEnvironment &env) {
+ QJsonObject envObj;
+ const QStringList keys = env.keys();
+ for (const QString &key : keys)
+ envObj.insert(key, env.value(key));
+ return envObj;
+ };
+
+ static const auto envFromJson = [](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;
+ };
+
+ QByteArray incomingData;
+
+ // Wait for and verify hello packet.
+ QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type"), "hello");
+ QCOMPARE(receivedMessage.value("api-level").toInt(), 1);
+ QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 1);
+
+ // Resolve & verify structure
+ QJsonObject resolveMessage;
+ resolveMessage.insert("type", "resolve-project");
+ resolveMessage.insert("top-level-profile", profileName());
+ resolveMessage.insert("configuration-name", "my-config");
+ resolveMessage.insert("project-file-path", QDir::currentPath() + "/qbs-session.qbs");
+ resolveMessage.insert("build-root", QDir::currentPath());
+ resolveMessage.insert("settings-directory", settings()->baseDirectory());
+ QJsonObject overriddenValues;
+ overriddenValues.insert("products.theLib.cpp.cxxLanguageVersion", "c++17");
+ resolveMessage.insert("overridden-properties", overriddenValues);
+ resolveMessage.insert("environment", envToJson(QProcessEnvironment::systemEnvironment()));
+ resolveMessage.insert("data-mode", "only-if-changed");
+ resolveMessage.insert("log-time", true);
+ resolveMessage.insert("module-properties",
+ QJsonArray::fromStringList({"cpp.cxxLanguageVersion"}));
+ sendPacket(resolveMessage);
+ bool receivedLogData = false;
+ bool receivedStartedSignal = false;
+ bool receivedProgressData = false;
+ bool receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-resolved") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("name").toString(), "qbs-session");
+ const QJsonArray products = projectData.value("products").toArray();
+ QCOMPARE(products.size(), 2);
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("name").toString();
+ QVERIFY(!productName.isEmpty());
+ QVERIFY2(product.value("is-enabled").toBool(), qPrintable(productName));
+ bool theLib = false;
+ bool theApp = false;
+ if (productName == "theLib")
+ theLib = true;
+ else if (productName == "theApp")
+ theApp = true;
+ QVERIFY2(theLib || theApp, qPrintable(productName));
+ const QJsonArray groups = product.value("groups").toArray();
+ if (theLib)
+ QVERIFY(groups.size() >= 3);
+ else
+ QVERIFY(!groups.isEmpty());
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QJsonArray sourceArtifacts
+ = group.value("source-artifacts").toArray();
+ const auto findArtifact = [&sourceArtifacts](const QString fileName) {
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QJsonObject artifact = v.toObject();
+ if (QFileInfo(artifact.value("file-path").toString()).fileName()
+ == fileName) {
+ return artifact;
+ }
+ }
+ return QJsonObject();
+ };
+ const QString groupName = group.value("name").toString();
+ const auto getCxxLanguageVersion = [&group, &product] {
+ QJsonObject moduleProperties = group.value("module-properties").toObject();
+ if (moduleProperties.isEmpty())
+ moduleProperties = product.value("module-properties").toObject();
+ return moduleProperties.toVariantMap().value("cpp.cxxLanguageVersion")
+ .toStringList();
+ };
+ if (groupName == "sources") {
+ const QJsonObject artifact = findArtifact("lib.cpp");
+ QVERIFY2(!artifact.isEmpty(), "lib.cpp");
+ QCOMPARE(getCxxLanguageVersion(), {"c++17"});
+ } else if (groupName == "headers") {
+ const QJsonObject artifact = findArtifact("lib.h");
+ QVERIFY2(!artifact.isEmpty(), "lib.h");
+ } else if (groupName == "theApp") {
+ const QJsonObject artifact = findArtifact("main.cpp");
+ QVERIFY2(!artifact.isEmpty(), "main.cpp");
+ QCOMPARE(getCxxLanguageVersion(), {"c++14"});
+ }
+ }
+ }
+ break;
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+
+ // First build: No install, log time, default command description.
+ QJsonObject buildRequest;
+ buildRequest.insert("type", "build-project");
+ buildRequest.insert("log-time", true);
+ buildRequest.insert("install", false);
+ buildRequest.insert("data-mode", "only-if-changed");
+ sendPacket(buildRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ bool receivedCommandDescription = false;
+ bool receivedProcessResult = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("name").toString(), "qbs-session");
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType == "command-description") {
+ if (receivedMessage.value("message").toString().contains("compiling main.cpp"))
+ receivedCommandDescription = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY(receivedCommandDescription);
+ QVERIFY(receivedProcessResult);
+ const QString &exeFilePath = QDir::currentPath() + '/'
+ + relativeExecutableFilePath("theApp", "my-config");
+ QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath));
+ const QString defaultInstallRoot = QDir::currentPath() + '/'
+ + relativeBuildDir("my-config") + "/install-root";
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+
+ // Clean.
+ QJsonObject cleanRequest;
+ cleanRequest.insert("type", "clean-project");
+ cleanRequest.insert("settings-dir", settings()->baseDirectory());
+ cleanRequest.insert("log-time", true);
+ sendPacket(cleanRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-cleaned") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY2(!regularFileExists(exeFilePath), qPrintable(exeFilePath));
+
+ // Second build: Do not log the time, show command lines.
+ buildRequest.insert("log-time", false);
+ buildRequest.insert("command-echo-mode", "command-line");
+ sendPacket(buildRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ receivedCommandDescription = false;
+ receivedProcessResult = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QVERIFY(projectData.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType == "command-description") {
+ if (receivedMessage.value("message").toString().contains(
+ QDir::separator() + QString("main.cpp"))) {
+ receivedCommandDescription = true;
+ }
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(!receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY(receivedCommandDescription);
+ QVERIFY(receivedProcessResult);
+ QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath));
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+
+ // Install.
+ QJsonObject installRequest;
+ installRequest.insert("type", "install-project");
+ installRequest.insert("log-time", true);
+ const QString customInstallRoot = QDir::currentPath() + "/my-install-root";
+ QVERIFY2(!QFile::exists(customInstallRoot), qPrintable(customInstallRoot));
+ installRequest.insert("install-root", customInstallRoot);
+ sendPacket(installRequest);
+ receivedReply = false;
+ receivedLogData = false;
+ receivedStartedSignal = false;
+ receivedProgressData = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "install-done") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "log-data") {
+ if (receivedMessage.value("message").toString().contains("activity"))
+ receivedLogData = true;
+ } else if (msgType == "task-started") {
+ receivedStartedSignal = true;
+ } else if (msgType == "task-progress") {
+ receivedProgressData = true;
+ } else if (msgType != "new-max-progress") {
+ QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType)));
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedLogData);
+ QVERIFY(receivedStartedSignal);
+ QVERIFY(receivedProgressData);
+ QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot));
+ QVERIFY2(directoryExists(customInstallRoot), qPrintable(customInstallRoot));
+
+ // Retrieve modified environment.
+ QJsonObject getRunEnvRequest;
+ getRunEnvRequest.insert("type", "get-run-environment");
+ getRunEnvRequest.insert("product", "theApp");
+ const QProcessEnvironment inEnv = QProcessEnvironment::systemEnvironment();
+ QVERIFY(!inEnv.contains("MY_MODULE"));
+ getRunEnvRequest.insert("base-environment", envToJson(inEnv));
+ sendPacket(getRunEnvRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("run-environment"));
+ QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QProcessEnvironment outEnv = envFromJson(receivedMessage.value("full-environment"));
+ QVERIFY(outEnv.keys().size() > inEnv.keys().size());
+ QCOMPARE(outEnv.value("MY_MODULE"), QString("1"));
+
+ // Add two files to library and re-build.
+ QJsonObject addFilesRequest;
+ addFilesRequest.insert("type", "add-files");
+ addFilesRequest.insert("product", "theLib");
+ addFilesRequest.insert("group", "sources");
+ addFilesRequest.insert("files",
+ QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp",
+ QDir::currentPath() + "/file2.cpp"}));
+ sendPacket(addFilesRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("files-added"));
+ error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QJsonArray products = projectData.value("products").toArray();
+ bool file1 = false;
+ bool file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
+ }
+ }
+ QVERIFY(file1);
+ QVERIFY(file2);
+ receivedReply = false;
+ receivedProcessResult = false;
+ bool compiledFile1 = false;
+ bool compiledFile2 = false;
+ bool compiledMain = false;
+ bool compiledLib = false;
+ buildRequest.remove("command-echo-mode");
+ sendPacket(buildRequest);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "command-description") {
+ const QString msg = receivedMessage.value("message").toString();
+ if (msg.contains("compiling file1.cpp"))
+ compiledFile1 = true;
+ else if (msg.contains("compiling file2.cpp"))
+ compiledFile2 = true;
+ else if (msg.contains("compiling main.cpp"))
+ compiledMain = true;
+ else if (msg.contains("compiling lib.cpp"))
+ compiledLib = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(!receivedProcessResult);
+ QVERIFY(compiledFile1);
+ QVERIFY(compiledFile2);
+ QVERIFY(!compiledLib);
+ QVERIFY(!compiledMain);
+
+ // Remove one of the newly added files again and re-build.
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("file1.cpp");
+ touch("file2.cpp");
+ touch("main.cpp");
+ QJsonObject removeFilesRequest;
+ removeFilesRequest.insert("type", "remove-files");
+ removeFilesRequest.insert("product", "theLib");
+ removeFilesRequest.insert("group", "sources");
+ removeFilesRequest.insert("files",
+ QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp"}));
+ sendPacket(removeFilesRequest);
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("files-removed"));
+ error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ projectData = receivedMessage.value("project-data").toObject();
+ products = projectData.value("products").toArray();
+ file1 = false;
+ file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
+ }
+ }
+ QVERIFY(!file1);
+ QVERIFY(file2);
+ receivedReply = false;
+ receivedProcessResult = false;
+ compiledFile1 = false;
+ compiledFile2 = false;
+ compiledMain = false;
+ compiledLib = false;
+ sendPacket(buildRequest);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-built") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ } else if (msgType == "command-description") {
+ const QString msg = receivedMessage.value("message").toString();
+ if (msg.contains("compiling file1.cpp"))
+ compiledFile1 = true;
+ else if (msg.contains("compiling file2.cpp"))
+ compiledFile2 = true;
+ else if (msg.contains("compiling main.cpp"))
+ compiledMain = true;
+ else if (msg.contains("compiling lib.cpp"))
+ compiledLib = true;
+ } else if (msgType == "process-result") {
+ QCOMPARE(receivedMessage.value("exit-code").toInt(), 0);
+ receivedProcessResult = true;
+ }
+ }
+ QVERIFY(receivedReply);
+ QVERIFY(receivedProcessResult);
+ QVERIFY(!compiledFile1);
+ QVERIFY(compiledFile2);
+ QVERIFY(!compiledLib);
+ QVERIFY(compiledMain);
+
+ // Get generated files.
+ QJsonObject genFilesRequestPerFile;
+ genFilesRequestPerFile.insert("source-file", QDir::currentPath() + "/main.cpp");
+ genFilesRequestPerFile.insert("tags", QJsonArray{QJsonValue("obj")});
+ QJsonObject genFilesRequestPerProduct;
+ genFilesRequestPerProduct.insert("full-display-name", "theApp");
+ genFilesRequestPerProduct.insert("requests", QJsonArray({genFilesRequestPerFile}));
+ QJsonObject genFilesRequest;
+ genFilesRequest.insert("type", "get-generated-files-for-sources");
+ genFilesRequest.insert("products", QJsonArray({genFilesRequestPerProduct}));
+ sendPacket(genFilesRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("generated-files-for-sources"));
+ const QJsonArray products = receivedMessage.value("products").toArray();
+ QCOMPARE(products.size(), 1);
+ const QJsonArray results = products.first().toObject().value("results").toArray();
+ QCOMPARE(results.size(), 1);
+ const QJsonObject result = results.first().toObject();
+ QCOMPARE(result.value("source-file"), QDir::currentPath() + "/main.cpp");
+ const QJsonArray generatedFiles = result.value("generated-files").toArray();
+ QCOMPARE(generatedFiles.count(), 1);
+ QCOMPARE(QFileInfo(generatedFiles.first().toString()).fileName(),
+ objectFileName("main.cpp", profileName()));
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ // Release project.
+ const QJsonObject releaseRequest{qMakePair(QString("type"), QJsonValue("release-project"))};
+ sendPacket(releaseRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("project-released"));
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ // Get build graph info.
+ QJsonObject loadProjectMessage;
+ loadProjectMessage.insert("type", "resolve-project");
+ loadProjectMessage.insert("configuration-name", "my-config");
+ loadProjectMessage.insert("build-root", QDir::currentPath());
+ loadProjectMessage.insert("settings-dir", settings()->baseDirectory());
+ loadProjectMessage.insert("restore-behavior", "restore-only");
+ loadProjectMessage.insert("data-mode", "only-if-changed");
+ sendPacket(loadProjectMessage);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ if (receivedMessage.value("type") != "project-resolved")
+ continue;
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QString bgFilePath = QDir::currentPath() + '/'
+ + relativeBuildGraphFilePath("my-config");
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QCOMPARE(projectData.value("build-graph-file-path").toString(), bgFilePath);
+ QCOMPARE(projectData.value("overridden-properties"), overriddenValues);
+ }
+ QVERIFY(receivedReply);
+
+ // Send unknown request.
+ const QJsonObject unknownRequest({qMakePair(QString("type"), QJsonValue("blubb"))});
+ sendPacket(unknownRequest);
+ receivedReply = false;
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QCOMPARE(receivedMessage.value("type").toString(), QString("protocol-error"));
+ receivedReply = true;
+ }
+ QVERIFY(receivedReply);
+
+ QJsonObject quitRequest;
+ quitRequest.insert("type", "quit");
+ sendPacket(quitRequest);
+ QVERIFY(sessionProc.waitForFinished(3000));
+}
+
void TestBlackbox::radAfterIncompleteBuild_data()
{
QTest::addColumn<QString>("projectFileName");
@@ -5624,6 +6283,34 @@ void TestBlackbox::autotestWithDependencies()
&& m_qbsStdout.contains("i am the helper"), m_qbsStdout.constData());
}
+void TestBlackbox::autotestTimeout()
+{
+ QFETCH(QStringList, resolveParams);
+ QFETCH(bool, expectFailure);
+ QDir::setCurrent(testDataDir + "/autotest-timeout");
+ QbsRunParameters resolveParameters("resolve", resolveParams);
+ QCOMPARE(runQbs(resolveParameters), 0);
+ QbsRunParameters buildParameters(QStringList({"-p", "autotest-runner"}));
+ buildParameters.expectFailure = expectFailure;
+ if (expectFailure) {
+ QVERIFY(runQbs(buildParameters) != 0);
+ QVERIFY(m_qbsStderr.contains("cancelled") && m_qbsStderr.contains("timeout"));
+ }
+ else
+ QVERIFY(runQbs(buildParameters) == 0);
+}
+
+void TestBlackbox::autotestTimeout_data()
+{
+ QTest::addColumn<QStringList>("resolveParams");
+ QTest::addColumn<bool>("expectFailure");
+ QTest::newRow("no timeout") << QStringList() << false;
+ QTest::newRow("timeout on test") << QStringList({"products.testApp.autotest.timeout:2"})
+ << true;
+ QTest::newRow("timeout on runner") << QStringList({"products.autotest-runner.timeout:2"})
+ << true;
+}
+
void TestBlackbox::autotests_data()
{
QTest::addColumn<QString>("evilPropertySpec");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 959858321..382c65389 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.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.
@@ -48,6 +49,8 @@ private slots:
void artifactScanning();
void assembly();
void autotestWithDependencies();
+ void autotestTimeout();
+ void autotestTimeout_data();
void autotests_data();
void autotests();
void auxiliaryInputsFromDependencies();
@@ -237,6 +240,7 @@ private slots:
void protobuf();
void pseudoMultiplexing();
void qbsConfig();
+ void qbsSession();
void qbsVersion();
void qtBug51237();
void radAfterIncompleteBuild();
diff --git a/tests/auto/blackbox/tst_blackboxjoblimits.cpp b/tests/auto/blackbox/tst_blackboxjoblimits.cpp
index 0c366759d..89b5f638e 100644
--- a/tests/auto/blackbox/tst_blackboxjoblimits.cpp
+++ b/tests/auto/blackbox/tst_blackboxjoblimits.cpp
@@ -165,7 +165,7 @@ void TestBlackboxJobLimits::jobLimits()
else
QVERIFY2(m_qbsStderr.contains("exclusive"), m_qbsStderr.constData());
if (exitCode == 0)
- QCOMPARE(m_qbsStdout.count("Running tool"), 7);
+ QCOMPARE(m_qbsStdout.count("Running tool"), 5);
}
QTEST_MAIN(TestBlackboxJobLimits)
diff --git a/tests/auto/shared.h b/tests/auto/shared.h
index f40a7dbfb..8f85f5d6c 100644
--- a/tests/auto/shared.h
+++ b/tests/auto/shared.h
@@ -101,8 +101,9 @@ inline QString relativeBuildDir(const QString &configurationName = QString())
return !configurationName.isEmpty() ? configurationName : QLatin1String("default");
}
-inline QString relativeBuildGraphFilePath() {
- return relativeBuildDir() + QLatin1Char('/') + relativeBuildDir() + QLatin1String(".bg");
+inline QString relativeBuildGraphFilePath(const QString &configName = QString()) {
+ return relativeBuildDir(configName) + QLatin1Char('/') + relativeBuildDir(configName)
+ + QLatin1String(".bg");
}
inline bool regularFileExists(const QString &filePath)
@@ -215,9 +216,10 @@ inline QString relativeProductBuildDir(const QString &productName,
return relativeBuildDir(configurationName) + '/' + dirName;
}
-inline QString relativeExecutableFilePath(const QString &productName)
+inline QString relativeExecutableFilePath(const QString &productName,
+ const QString &configName = QString())
{
- return relativeProductBuildDir(productName) + '/'
+ return relativeProductBuildDir(productName, configName) + '/'
+ qbs::Internal::HostOsInfo::appendExecutableSuffix(productName);
}