1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
4 ** Contact: http://www.qt.io/licensing
5 **
6 ** This file is part of Qbs.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms and
13 ** conditions see http://www.qt.io/terms-conditions. For further information
14 ** use the contact form at http://www.qt.io/contact-us.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 or version 3 as published by the Free
19 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
20 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
21 ** following information to ensure the GNU Lesser General Public License
22 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
23 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, The Qt Company gives you certain additional
26 ** rights. These rights are described in The Qt Company LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ****************************************************************************/
30
31 #include "mcs51linkersettingsgroup_v10.h"
32
33 #include "../../iarewutils.h"
34
35 #include <QtCore/qdir.h>
36
37 namespace qbs {
38 namespace iarew {
39 namespace mcs51 {
40 namespace v10 {
41
42 constexpr int kLinkerArchiveVersion = 4;
43 constexpr int kLinkerDataVersion = 21;
44
45 namespace {
46
47 // Config page options.
48
49 struct ConfigPageOptions final
50 {
ConfigPageOptionsqbs::iarew::mcs51::v10::__anon7906a0450111::ConfigPageOptions51 explicit ConfigPageOptions(const QString &baseDirectory,
52 const ProductData &qbsProduct)
53 {
54 const auto &qbsProps = qbsProduct.moduleProperties();
55 const QString toolkitPath = IarewUtils::toolkitRootPath(qbsProduct);
56
57 entryPoint = gen::utils::cppStringModuleProperty(
58 qbsProps, QStringLiteral("entryPoint"));
59
60 // Enumerate all product linker config files
61 // (which are set trough 'linkerscript' tag).
62 for (const auto &qbsGroup : qbsProduct.groups()) {
63 const auto qbsArtifacts = qbsGroup.sourceArtifacts();
64 for (const auto &qbsArtifact : qbsArtifacts) {
65 const auto qbsTags = qbsArtifact.fileTags();
66 if (!qbsTags.contains(QLatin1String("linkerscript")))
67 continue;
68 const QString fullConfigPath = qbsArtifact.filePath();
69 if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
70 const QString path = IarewUtils::toolkitRelativeFilePath(
71 toolkitPath, fullConfigPath);
72 configFilePaths.push_back(path);
73 } else {
74 const QString path = IarewUtils::projectRelativeFilePath(
75 baseDirectory, fullConfigPath);
76 configFilePaths.push_back(path);
77 }
78 }
79 }
80
81 // Enumerate all product linker config files
82 // (which are set trough '-f' option).
83 const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
84 const QVariantList configPathValues = IarewUtils::flagValues(
85 flags, QStringLiteral("-f"));
86 for (const QVariant &configPathValue : configPathValues) {
87 const QString fullConfigPath = configPathValue.toString();
88 if (fullConfigPath.startsWith(toolkitPath, Qt::CaseInsensitive)) {
89 const QString path = IarewUtils::toolkitRelativeFilePath(
90 toolkitPath, fullConfigPath);
91 if (!configFilePaths.contains(path))
92 configFilePaths.push_back(path);
93 } else {
94 const QString path =IarewUtils::projectRelativeFilePath(
95 baseDirectory, fullConfigPath);
96 if (!configFilePaths.contains(path))
97 configFilePaths.push_back(path);
98 }
99 }
100
101 // Add libraries search paths.
102 const QStringList libraryPaths = gen::utils::cppStringModuleProperties(
103 qbsProps, {QStringLiteral("libraryPaths")});
104 for (const QString &libraryPath : libraryPaths) {
105 const QFileInfo libraryPathInfo(libraryPath);
106 const QString fullLibrarySearchPath = libraryPathInfo.absoluteFilePath();
107 if (fullLibrarySearchPath.startsWith(toolkitPath,
108 Qt::CaseInsensitive)) {
109 const QString path = IarewUtils::toolkitRelativeFilePath(
110 toolkitPath, fullLibrarySearchPath);
111 librarySearchPaths.push_back(path);
112 } else {
113 const QString path = IarewUtils::projectRelativeFilePath(
114 baseDirectory, fullLibrarySearchPath);
115 librarySearchPaths.push_back(path);
116 }
117 }
118 }
119
120 QVariantList configFilePaths;
121 QVariantList librarySearchPaths;
122 QString entryPoint;
123 };
124
125 // Output page options.
126
127 struct OutputPageOptions final
128 {
OutputPageOptionsqbs::iarew::mcs51::v10::__anon7906a0450111::OutputPageOptions129 explicit OutputPageOptions(const ProductData &qbsProduct)
130 {
131 outputFile = gen::utils::targetBinary(qbsProduct);
132 }
133
134 QString outputFile;
135 };
136
137 // List page options.
138
139 struct ListPageOptions final
140 {
141 enum ListingAction {
142 NoListing,
143 GenerateListing
144 };
145
ListPageOptionsqbs::iarew::mcs51::v10::__anon7906a0450111::ListPageOptions146 explicit ListPageOptions(const ProductData &qbsProduct)
147 {
148 const auto &qbsProps = qbsProduct.moduleProperties();
149 generateMap = gen::utils::cppBooleanModuleProperty(
150 qbsProps, QStringLiteral("generateLinkerMapFile"))
151 ? ListPageOptions::GenerateListing
152 : ListPageOptions::NoListing;
153 }
154
155 ListingAction generateMap = NoListing;
156 };
157
158 // Define page options.
159
160 struct DefinePageOptions final
161 {
DefinePageOptionsqbs::iarew::mcs51::v10::__anon7906a0450111::DefinePageOptions162 explicit DefinePageOptions(const ProductData &qbsProduct)
163 {
164 const auto &qbsProps = qbsProduct.moduleProperties();
165 const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
166 // Enumerate all linker defines.
167 for (const QString &flag : flags) {
168 if (!flag.startsWith(QLatin1String("-D")))
169 continue;
170 const QString symbol = flag.mid(2);
171 // Ignore system-defined macroses, because its already
172 // handled in "General Options" page.
173 if (symbol.startsWith(QLatin1Char('?'))
174 || symbol.startsWith(QLatin1Char('_'))
175 ) {
176 continue;
177 }
178 defineSymbols.push_back(symbol);
179 }
180 }
181
182 QVariantList defineSymbols;
183 };
184
185 // Diagnostics page options.
186
187 struct DiagnosticsPageOptions final
188 {
DiagnosticsPageOptionsqbs::iarew::mcs51::v10::__anon7906a0450111::DiagnosticsPageOptions189 explicit DiagnosticsPageOptions(const ProductData &qbsProduct)
190 {
191 const auto &qbsProps = qbsProduct.moduleProperties();
192 const QString warningLevel = gen::utils::cppStringModuleProperty(
193 qbsProps, QStringLiteral("warningLevel"));
194 suppressAllWarnings = (warningLevel == QLatin1String("none"));
195 }
196
197 int suppressAllWarnings = 0;
198 };
199
200 } // namespace
201
202 // Mcs51LinkerSettingsGroup
203
Mcs51LinkerSettingsGroup(const Project & qbsProject,const ProductData & qbsProduct,const std::vector<ProductData> & qbsProductDeps)204 Mcs51LinkerSettingsGroup::Mcs51LinkerSettingsGroup(
205 const Project &qbsProject,
206 const ProductData &qbsProduct,
207 const std::vector<ProductData> &qbsProductDeps)
208 {
209 Q_UNUSED(qbsProject)
210 Q_UNUSED(qbsProductDeps)
211
212 setName(QByteArrayLiteral("XLINK"));
213 setArchiveVersion(kLinkerArchiveVersion);
214 setDataVersion(kLinkerDataVersion);
215 setDataDebugInfo(gen::utils::debugInformation(qbsProduct));
216
217 const QString buildRootDirectory = gen::utils::buildRootPath(qbsProject);
218
219 buildConfigPage(buildRootDirectory, qbsProduct);
220 buildOutputPage(qbsProduct);
221 buildListPage(qbsProduct);
222 buildDefinePage(qbsProduct);
223 buildDiagnosticsPage(qbsProduct);
224
225 // Should be called as latest stage!
226 buildExtraOptionsPage(qbsProduct);
227 }
228
buildConfigPage(const QString & baseDirectory,const ProductData & qbsProduct)229 void Mcs51LinkerSettingsGroup::buildConfigPage(
230 const QString &baseDirectory,
231 const ProductData &qbsProduct)
232 {
233 ConfigPageOptions opts(baseDirectory, qbsProduct);
234
235 if (opts.configFilePaths.count() > 0) {
236 // Note: IAR IDE does not allow to specify a multiple config files,
237 // although the IAR linker support it. So, we use followig 'trick':
238 // we take a first config file and to add it as usual to required items;
239 // and then an other remainders we forward to the "Extra options page".
240 const QVariant configPath = opts.configFilePaths.takeFirst();
241 // Add 'XclOverride' item (Override default).
242 addOptionsGroup(QByteArrayLiteral("XclOverride"),
243 {1});
244 // Add 'XclFile' item (Linke configuration file).
245 addOptionsGroup(QByteArrayLiteral("XclFile"),
246 {configPath});
247
248 // Add remainder configuration files to the "Extra options page".
249 if (!opts.configFilePaths.isEmpty()) {
250 for (QVariant &configPath : opts.configFilePaths)
251 configPath = QLatin1String("-f ") + configPath.toString();
252
253 m_extraOptions << opts.configFilePaths;
254 }
255 }
256
257 // Add 'xcProgramEntryLabel' item (Entry symbol).
258 addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabel"),
259 {opts.entryPoint});
260 // Add 'xcOverrideProgramEntryLabel' item
261 // (Override default program entry).
262 addOptionsGroup(QByteArrayLiteral("xcOverrideProgramEntryLabel"),
263 {1});
264 // Add 'xcProgramEntryLabelSelect' item.
265 addOptionsGroup(QByteArrayLiteral("xcProgramEntryLabelSelect"),
266 {0});
267
268 // Add 'XIncludes' item (Libraries search paths).
269 addOptionsGroup(QByteArrayLiteral("XIncludes"),
270 opts.librarySearchPaths);
271 }
272
buildOutputPage(const ProductData & qbsProduct)273 void Mcs51LinkerSettingsGroup::buildOutputPage(
274 const ProductData &qbsProduct)
275 {
276 const OutputPageOptions opts(qbsProduct);
277 // Add 'XOutOverride' item (Override default output file).
278 addOptionsGroup(QByteArrayLiteral("XOutOverride"),
279 {1});
280 // Add 'OutputFile' item (Output file name).
281 addOptionsGroup(QByteArrayLiteral("OutputFile"),
282 {opts.outputFile});
283 }
284
buildListPage(const ProductData & qbsProduct)285 void Mcs51LinkerSettingsGroup::buildListPage(
286 const ProductData &qbsProduct)
287 {
288 const ListPageOptions opts(qbsProduct);
289 // Add 'XList' item (Generate linker listing).
290 addOptionsGroup(QByteArrayLiteral("XList"),
291 {opts.generateMap});
292 }
293
buildDefinePage(const ProductData & qbsProduct)294 void Mcs51LinkerSettingsGroup::buildDefinePage(
295 const ProductData &qbsProduct)
296 {
297 const DefinePageOptions opts(qbsProduct);
298 // Add 'XDefines' item (Defined symbols).
299 addOptionsGroup(QByteArrayLiteral("XDefines"),
300 opts.defineSymbols);
301 }
302
buildDiagnosticsPage(const ProductData & qbsProduct)303 void Mcs51LinkerSettingsGroup::buildDiagnosticsPage(
304 const ProductData &qbsProduct)
305 {
306 const DiagnosticsPageOptions opts(qbsProduct);
307 // Add 'SuppressAllWarn' item (Suppress all warnings).
308 addOptionsGroup(QByteArrayLiteral("SuppressAllWarn"),
309 {opts.suppressAllWarnings});
310 }
311
buildExtraOptionsPage(const ProductData & qbsProduct)312 void Mcs51LinkerSettingsGroup::buildExtraOptionsPage(
313 const ProductData &qbsProduct)
314 {
315 const auto &qbsProps = qbsProduct.moduleProperties();
316 const QStringList flags = IarewUtils::cppModuleLinkerFlags(qbsProps);
317 for (const QString &flag : flags) {
318 if (flag.startsWith(QLatin1String("-Z")))
319 m_extraOptions.push_back(flag);
320 }
321
322 if (!m_extraOptions.isEmpty()) {
323 // Add 'Linker Extra Options Check' (Use command line options).
324 addOptionsGroup(QByteArrayLiteral("Linker Extra Options Check"),
325 {1});
326 // Add 'Linker Extra Options Edit' item (Command line options).
327 addOptionsGroup(QByteArrayLiteral("Linker Extra Options Edit"),
328 m_extraOptions);
329 }
330 }
331
332 } // namespace v10
333 } // namespace mcs51
334 } // namespace iarew
335 } // namespace qbs
336