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 "generatorutils.h"
32 
33 namespace qbs {
34 namespace gen {
35 namespace utils {
36 
architectureName(Architecture arch)37 QString architectureName(Architecture arch)
38 {
39     switch (arch) {
40     case Architecture::Arm:
41         return QStringLiteral("arm");
42     case Architecture::Avr:
43         return QStringLiteral("avr");
44     case Architecture::Mcs51:
45         return QStringLiteral("mcs51");
46     default:
47         return QStringLiteral("unknown");
48     }
49 }
50 
architecture(const Project & qbsProject)51 Architecture architecture(const Project &qbsProject)
52 {
53     const auto qbsArch = qbsProject.projectConfiguration()
54             .value(Internal::StringConstants::qbsModule()).toMap()
55             .value(QStringLiteral("architecture")).toString();
56 
57     if (qbsArch == QLatin1String("arm"))
58         return Architecture::Arm;
59     if (qbsArch == QLatin1String("avr"))
60         return Architecture::Avr;
61     if (qbsArch == QLatin1String("mcs51"))
62         return Architecture::Mcs51;
63     if (qbsArch == QLatin1String("stm8"))
64         return Architecture::Stm8;
65     if (qbsArch == QLatin1String("msp430"))
66         return Architecture::Msp430;
67     return Architecture::Unknown;
68 }
69 
buildConfigurationName(const Project & qbsProject)70 QString buildConfigurationName(const Project &qbsProject)
71 {
72     return qbsProject.projectConfiguration()
73             .value(Internal::StringConstants::qbsModule()).toMap()
74             .value(QStringLiteral("configurationName")).toString();
75 }
76 
debugInformation(const ProductData & qbsProduct)77 int debugInformation(const ProductData &qbsProduct)
78 {
79     return qbsProduct.moduleProperties().getModuleProperty(
80                 Internal::StringConstants::qbsModule(),
81                 QStringLiteral("debugInformation"))
82             .toInt();
83 }
84 
buildRootPath(const Project & qbsProject)85 QString buildRootPath(const Project &qbsProject)
86 {
87     QDir dir(qbsProject.projectData().buildDirectory());
88     dir.cdUp();
89     return dir.absolutePath();
90 }
91 
relativeFilePath(const QString & baseDirectory,const QString & fullFilePath)92 QString relativeFilePath(const QString &baseDirectory,
93                          const QString &fullFilePath)
94 {
95     return QDir(baseDirectory).relativeFilePath(fullFilePath);
96 }
97 
binaryOutputDirectory(const QString & baseDirectory,const ProductData & qbsProduct)98 QString binaryOutputDirectory(const QString &baseDirectory,
99                               const ProductData &qbsProduct)
100 {
101     return QDir(baseDirectory).relativeFilePath(
102                 qbsProduct.buildDirectory())
103             + QLatin1String("/bin");
104 }
105 
objectsOutputDirectory(const QString & baseDirectory,const ProductData & qbsProduct)106 QString objectsOutputDirectory(const QString &baseDirectory,
107                                const ProductData &qbsProduct)
108 {
109     return QDir(baseDirectory).relativeFilePath(
110                 qbsProduct.buildDirectory())
111             + QLatin1String("/obj");
112 }
113 
listingOutputDirectory(const QString & baseDirectory,const ProductData & qbsProduct)114 QString listingOutputDirectory(const QString &baseDirectory,
115                                const ProductData &qbsProduct)
116 {
117     return QDir(baseDirectory).relativeFilePath(
118                 qbsProduct.buildDirectory())
119             + QLatin1String("/lst");
120 }
121 
dependenciesOf(const ProductData & qbsProduct,const GeneratableProject & genProject,const QString & configurationName)122 std::vector<ProductData> dependenciesOf(const ProductData &qbsProduct,
123                                         const GeneratableProject &genProject,
124                                         const QString &configurationName)
125 {
126     std::vector<ProductData> result;
127     const auto &depsNames = qbsProduct.dependencies();
128     for (const auto &product : qAsConst(genProject.products)) {
129         const auto pt = product.type();
130         if (!pt.contains(QLatin1String("staticlibrary")))
131             continue;
132         const auto pn = product.name();
133         if (!depsNames.contains(pn))
134             continue;
135         result.push_back(product.data.value(configurationName));
136     }
137     return result;
138 }
139 
targetBinary(const ProductData & qbsProduct)140 QString targetBinary(const ProductData &qbsProduct)
141 {
142     const auto &type = qbsProduct.type();
143     if (type.contains(QLatin1String("application"))) {
144         return QFileInfo(qbsProduct.targetExecutable()).fileName();
145     } else if (type.contains(QLatin1String("staticlibrary"))) {
146         for (const auto &artifact : qbsProduct.targetArtifacts()) {
147             if (artifact.fileTags().contains(QLatin1String("staticlibrary")))
148                 return QFileInfo(artifact.filePath()).fileName();
149         }
150     }
151 
152     return {};
153 }
154 
targetBinaryPath(const QString & baseDirectory,const ProductData & qbsProduct)155 QString targetBinaryPath(const QString &baseDirectory,
156                          const ProductData &qbsProduct)
157 {
158     return binaryOutputDirectory(baseDirectory, qbsProduct)
159             + QLatin1Char('/') + targetBinary(qbsProduct);
160 }
161 
cppStringModuleProperty(const PropertyMap & qbsProps,const QString & propertyName)162 QString cppStringModuleProperty(const PropertyMap &qbsProps,
163                                 const QString &propertyName)
164 {
165     return qbsProps.getModuleProperty(
166                 Internal::StringConstants::cppModule(),
167                 propertyName).toString().trimmed();
168 }
169 
cppBooleanModuleProperty(const PropertyMap & qbsProps,const QString & propertyName)170 bool cppBooleanModuleProperty(const PropertyMap &qbsProps,
171                               const QString &propertyName)
172 {
173     return qbsProps.getModuleProperty(
174                 Internal::StringConstants::cppModule(),
175                 propertyName).toBool();
176 }
177 
cppIntegerModuleProperty(const PropertyMap & qbsProps,const QString & propertyName)178 int cppIntegerModuleProperty(const PropertyMap &qbsProps,
179                              const QString &propertyName)
180 {
181     return qbsProps.getModuleProperty(
182                 Internal::StringConstants::cppModule(),
183                 propertyName).toInt();
184 }
185 
cppStringModuleProperties(const PropertyMap & qbsProps,const QStringList & propertyNames)186 QStringList cppStringModuleProperties(const PropertyMap &qbsProps,
187                                       const QStringList &propertyNames)
188 {
189     QStringList properties;
190     for (const auto &propertyName : propertyNames) {
191         const auto entries = qbsProps.getModuleProperty(
192                     Internal::StringConstants::cppModule(),
193                     propertyName).toStringList();
194         for (const auto &entry : entries)
195             properties.push_back(entry.trimmed());
196     }
197     return properties;
198 }
199 
cppVariantModuleProperties(const PropertyMap & qbsProps,const QStringList & propertyNames)200 QVariantList cppVariantModuleProperties(const PropertyMap &qbsProps,
201                                         const QStringList &propertyNames)
202 {
203     QVariantList properties;
204     for (const auto &propertyName : propertyNames) {
205         properties << qbsProps.getModuleProperty(
206                           Internal::StringConstants::cppModule(),
207                           propertyName).toList();
208     }
209     return properties;
210 }
211 
parseFlagValue(const QString & flagKey,QStringList::const_iterator & flagIt,const QStringList::const_iterator & flagEnd)212 static QString parseFlagValue(const QString &flagKey,
213                               QStringList::const_iterator &flagIt,
214                               const QStringList::const_iterator &flagEnd)
215 {
216     if (flagIt->contains(QLatin1Char('='))) {
217         // In this case an option is in form of 'flagKey=<flagValue>'.
218         const auto parts = flagIt->split(QLatin1Char('='));
219         if (parts.count() == 2)
220             return parts.at(1).trimmed();
221     } else if (flagKey < *flagIt) {
222         // In this case an option is in form of 'flagKey<flagValue>'.
223         return flagIt->mid(flagKey.count()).trimmed();
224     } else {
225         // In this case an option is in form of 'flagKey <flagValue>'.
226         ++flagIt;
227         if (flagIt < flagEnd && !flagIt->startsWith(QLatin1Char('-')))
228             return (*flagIt).trimmed();
229     }
230     return {};
231 }
232 
firstFlagValue(const QStringList & flags,const QString & flagKey)233 QString firstFlagValue(const QStringList &flags, const QString &flagKey)
234 {
235     const auto flagBegin = flags.cbegin();
236     const auto flagEnd = flags.cend();
237     auto flagIt = std::find_if(flagBegin, flagEnd, [flagKey](const QString &flag) {
238         return flag == flagKey || flag.startsWith(flagKey);
239     });
240     if (flagIt == flagEnd)
241         return {};
242     return parseFlagValue(flagKey, flagIt, flagEnd);
243 }
244 
allFlagValues(const QStringList & flags,const QString & flagKey)245 QStringList allFlagValues(const QStringList &flags, const QString &flagKey)
246 {
247     QStringList values;
248     const auto flagEnd = flags.cend();
249     for (auto flagIt = flags.cbegin(); flagIt < flagEnd; ++flagIt) {
250         if (*flagIt == flagKey || flagIt->startsWith(flagKey)) {
251             const QString value = parseFlagValue(flagKey, flagIt, flagEnd);
252             if (!value.isEmpty())
253                 values.push_back(value);
254         }
255     }
256     return values;
257 }
258 
259 } // namespace utils
260 } // namespace gen
261 } // namespace qbs
262