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