1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Linguist of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "profileevaluator.h"
30 
31 #include "qmakeglobals.h"
32 #include "ioutils.h"
33 #include "qmakevfs.h"
34 
35 #include <QDir>
36 
37 using namespace QMakeInternal;
38 
39 QT_BEGIN_NAMESPACE
40 
initialize()41 void ProFileEvaluator::initialize()
42 {
43     QMakeEvaluator::initStatics();
44 }
45 
ProFileEvaluator(ProFileGlobals * option,QMakeParser * parser,QMakeVfs * vfs,QMakeHandler * handler)46 ProFileEvaluator::ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
47                                    QMakeHandler *handler)
48   : d(new QMakeEvaluator(option, parser, vfs, handler))
49 {
50 }
51 
~ProFileEvaluator()52 ProFileEvaluator::~ProFileEvaluator()
53 {
54     delete d;
55 }
56 
contains(const QString & variableName) const57 bool ProFileEvaluator::contains(const QString &variableName) const
58 {
59     return d->m_valuemapStack.top().contains(ProKey(variableName));
60 }
61 
value(const QString & variable) const62 QString ProFileEvaluator::value(const QString &variable) const
63 {
64     const QStringList &vals = values(variable);
65     if (!vals.isEmpty())
66         return vals.first();
67 
68     return QString();
69 }
70 
values(const QString & variableName) const71 QStringList ProFileEvaluator::values(const QString &variableName) const
72 {
73     const ProStringList &values = d->values(ProKey(variableName));
74     QStringList ret;
75     ret.reserve(values.size());
76     foreach (const ProString &str, values)
77         ret << d->m_option->expandEnvVars(str.toQString());
78     return ret;
79 }
80 
values(const QString & variableName,const ProFile * pro) const81 QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
82 {
83     // It makes no sense to put any kind of magic into expanding these
84     const ProStringList &values = d->m_valuemapStack.front().value(ProKey(variableName));
85     QStringList ret;
86     ret.reserve(values.size());
87     foreach (const ProString &str, values)
88         if (str.sourceFile() == pro->id())
89             ret << d->m_option->expandEnvVars(str.toQString());
90     return ret;
91 }
92 
sysrootify(const QString & path,const QString & baseDir) const93 QString ProFileEvaluator::sysrootify(const QString &path, const QString &baseDir) const
94 {
95     ProFileGlobals *option = static_cast<ProFileGlobals *>(d->m_option);
96 #ifdef Q_OS_WIN
97     Qt::CaseSensitivity cs = Qt::CaseInsensitive;
98 #else
99     Qt::CaseSensitivity cs = Qt::CaseSensitive;
100 #endif
101     const bool isHostSystemPath =
102         option->sysroot.isEmpty() || path.startsWith(option->sysroot, cs)
103         || path.startsWith(baseDir, cs) || path.startsWith(d->m_outputDir, cs);
104 
105     return isHostSystemPath ? path : option->sysroot + path;
106 }
107 
absolutePathValues(const QString & variable,const QString & baseDirectory) const108 QStringList ProFileEvaluator::absolutePathValues(
109         const QString &variable, const QString &baseDirectory) const
110 {
111     QStringList result;
112     foreach (const QString &el, values(variable)) {
113         QString absEl = IoUtils::isAbsolutePath(el)
114             ? sysrootify(el, baseDirectory) : IoUtils::resolvePath(baseDirectory, el);
115         if (IoUtils::fileType(absEl) == IoUtils::FileIsDir)
116             result << QDir::cleanPath(absEl);
117     }
118     return result;
119 }
120 
absoluteFileValues(const QString & variable,const QString & baseDirectory,const QStringList & searchDirs,const ProFile * pro) const121 QStringList ProFileEvaluator::absoluteFileValues(
122         const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
123         const ProFile *pro) const
124 {
125     QStringList result;
126     foreach (const QString &el, pro ? values(variable, pro) : values(variable)) {
127         QString absEl;
128         if (IoUtils::isAbsolutePath(el)) {
129             const QString elWithSysroot = QDir::cleanPath(sysrootify(el, baseDirectory));
130             if (d->m_vfs->exists(elWithSysroot, QMakeVfs::VfsCumulative)) {
131                 result << elWithSysroot;
132                 goto next;
133             }
134             absEl = elWithSysroot;
135         } else {
136             foreach (const QString &dir, searchDirs) {
137                 QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el);
138                 if (d->m_vfs->exists(fn, QMakeVfs::VfsCumulative)) {
139                     result << fn;
140                     goto next;
141                 }
142             }
143             if (baseDirectory.isEmpty())
144                 goto next;
145             absEl = QDir::cleanPath(baseDirectory + QLatin1Char('/') + el);
146         }
147         {
148             int nameOff = absEl.lastIndexOf(QLatin1Char('/'));
149             QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff);
150             // NOTE: This does not support virtual files. That shouldn't be a problem,
151             // because no sane project would add generated files by wildcard.
152             if (IoUtils::fileType(absDir) == IoUtils::FileIsDir) {
153                 QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1,
154                                                         absEl.length() - nameOff - 1);
155                 if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
156                     wildcard.detach(); // Keep m_tmp out of QRegExp's cache
157                     QDir theDir(absDir);
158                     foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
159                         if (fn != QLatin1String(".") && fn != QLatin1String(".."))
160                             result << absDir + QLatin1Char('/') + fn;
161                 } // else if (acceptMissing)
162             }
163         }
164       next: ;
165     }
166     return result;
167 }
168 
templateType() const169 ProFileEvaluator::TemplateType ProFileEvaluator::templateType() const
170 {
171     const ProStringList &templ = d->values(ProKey("TEMPLATE"));
172     if (templ.count() >= 1) {
173         const QString &t = templ.at(0).toQString();
174         if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive))
175             return TT_Application;
176         if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive))
177             return TT_Library;
178         if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive))
179             return TT_Script;
180         if (!t.compare(QLatin1String("aux"), Qt::CaseInsensitive))
181             return TT_Aux;
182         if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive))
183             return TT_Subdirs;
184     }
185     return TT_Unknown;
186 }
187 
loadNamedSpec(const QString & specDir,bool hostSpec)188 bool ProFileEvaluator::loadNamedSpec(const QString &specDir, bool hostSpec)
189 {
190     d->m_qmakespec = specDir;
191     d->m_hostBuild = hostSpec;
192 
193     d->updateMkspecPaths();
194     return d->loadSpecInternal();
195 }
196 
accept(ProFile * pro,QMakeEvaluator::LoadFlags flags)197 bool ProFileEvaluator::accept(ProFile *pro, QMakeEvaluator::LoadFlags flags)
198 {
199     return d->visitProFile(pro, QMakeHandler::EvalProjectFile, flags) == QMakeEvaluator::ReturnTrue;
200 }
201 
propertyValue(const QString & name) const202 QString ProFileEvaluator::propertyValue(const QString &name) const
203 {
204     return d->m_option->propertyValue(ProKey(name)).toQString();
205 }
206 
resolvedMkSpec() const207 QString ProFileEvaluator::resolvedMkSpec() const
208 {
209     return d->m_qmakespec;
210 }
211 
212 #ifdef PROEVALUATOR_CUMULATIVE
setCumulative(bool on)213 void ProFileEvaluator::setCumulative(bool on)
214 {
215     d->m_cumulative = on;
216 }
217 #endif
218 
setExtraVars(const QHash<QString,QStringList> & extraVars)219 void ProFileEvaluator::setExtraVars(const QHash<QString, QStringList> &extraVars)
220 {
221     ProValueMap map;
222     QHash<QString, QStringList>::const_iterator it = extraVars.constBegin();
223     QHash<QString, QStringList>::const_iterator end = extraVars.constEnd();
224     for ( ; it != end; ++it)
225         map.insert(ProKey(it.key()), ProStringList(it.value()));
226     d->setExtraVars(map);
227 }
228 
setExtraConfigs(const QStringList & extraConfigs)229 void ProFileEvaluator::setExtraConfigs(const QStringList &extraConfigs)
230 {
231      d->setExtraConfigs(ProStringList(extraConfigs));
232 }
233 
setOutputDir(const QString & dir)234 void ProFileEvaluator::setOutputDir(const QString &dir)
235 {
236     d->m_outputDir = dir;
237 }
238 
239 QT_END_NAMESPACE
240