summaryrefslogtreecommitdiff
path: root/src/plugins/autotoolsprojectmanager/makefileparser.h
blob: 894201bef558da3c3500ed429c2d9ee891dc94c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/**************************************************************************
**
** Copyright (C) 2013 Openismus GmbH.
** Authors: Peter Penz (ppenz@openismus.com)
**          Patricia Santana Cruz (patriciasantanacruz@gmail.com)
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#ifndef MAKEFILEPARSER_H
#define MAKEFILEPARSER_H

#include <QMutex>
#include <QStringList>
#include <QTextStream>
#include <QObject>

QT_FORWARD_DECLARE_CLASS(QDir)

namespace AutotoolsProjectManager {
namespace Internal {

/**
 * @brief Parses the autotools makefile Makefile.am.
 *
 * The parser returns the sources, makefiles and executable.
 * Variables like $(test) are not evaluated. If such a variable
 * is part of a SOURCES target, a fallback will be done and all
 * sub directories get parsed for C- and C++ files.
 */
class MakefileParser : public QObject
{
    Q_OBJECT

public:
    /**
     * @param makefile  Filename including path of the autotools
     *                  makefile that should be parsed.
     */
    MakefileParser(const QString &makefile);

    ~MakefileParser();

    /**
     * Parses the makefile. Must be invoked at least once, otherwise
     * the getter functions of MakefileParser will return empty values.
     * @return True, if the parsing was successful. If false is returned,
     *         the makefile could not be opened.
     */
    bool parse();

    /**
     * @return List of sources that are set for the _SOURCES target.
     *         Sources in sub directorties contain the sub directory as
     *         prefix.
     */
    QStringList sources() const;

    /**
     * @return List of Makefile.am files from the current directory and
     *         all sub directories. The values for sub directories contain
     *         the sub directory as prefix.
     */
    QStringList makefiles() const;

    /**
     * @return File name of the executable.
     */
    QString executable() const;

    /**
     * @return List of include paths. Should be invoked, after the signal
     *         finished() has been emitted.
     */
    QStringList includePaths() const;

    /**
     * @return Concatenated normalized defines, just like in code:
     * @code
     * #define X12_DEPRECATED __attribute__((deprecated))
     * #define X12_HAS_DEPRECATED
     * @endcode
     */
    QByteArray defines() const;

    /**
     * @return List of compiler flags for C.
     */
    QStringList cflags() const;

    /**
     * @return List of compiler flags for C++.
     */
    QStringList cxxflags() const;

    /**
     * Cancels the parsing. Calling this function only makes sense, if the
     * parser runs in a different thread than the caller of this function.
     * The function is thread-safe.
     */
    void cancel();

    /**
     * @return True, if the parser has been cancelled by MakefileParser::cancel().
     *         The function is thread-safe.
     */
    bool isCanceled() const;

signals:
    /**
     * Is emitted periodically during parsing the Makefile.am files
     * and the sub directories. \p status provides a translated
     * string, that can be shown to indicate the current state
     * of the parsing.
     */
    void status(const QString &status);

private:
    enum TopTarget {
        Undefined,
        AmDefaultSourceExt,
        BinPrograms,
        BuiltSources,
        Sources,
        SubDirs
    };

    TopTarget topTarget() const;

    /**
     * Parses the bin_PROGRAM target and stores it in m_executable.
     */
    void parseBinPrograms();

    /**
     * Parses all values from a _SOURCE target and appends them to
     * the m_sources list.
     */
    void parseSources();

    /**
     * Parses all sub directories for files having the extension
     * specified by 'AM_DEFAULT_SOURCE_EXT ='. The result will be
     * append to the m_sources list. Corresponding header files
     * will automatically be attached too.
     */
    void parseDefaultSourceExtensions();

    /**
     * Parses all sub directories specified by the SUBDIRS target and
     * adds the found sources to the m_sources list. The found makefiles
     * get added to the m_makefiles list.
     */
    void parseSubDirs();

    /**
     * Helper function for parseDefaultExtensions(). Returns recursively all sources
     * inside the directory \p directory that match with the extension \p extension.
     */
    QStringList directorySources(const QString &directory,
                                 const QStringList &extensions);

    /**
     * Helper function for all parse-functions. Returns each value of a target as string in
     * the stringlist. The current line m_line is used as starting point and increased
     * if the current line ends with a \.
     *
     * Example: For the text
     * \code
     * my_SOURCES = a.cpp\
     *              b.cpp c.cpp\
     *              d.cpp
     * \endcode
     * the string list contains all 4 *.cpp files. m_line is positioned to d.cpp afterwards.
     * Variables like $(test) are skipped and not part of the return value.
     *
     * @param hasVariables Optional output parameter. Is set to true, if the target values
     *                     contained a variable like $(test). Note that all variables are not
     *                     part of the return value, as they cannot get interpreted currently.
     */
    QStringList targetValues(bool *hasVariables = 0);

    /**
     * Adds recursively all sources of the current folder to m_sources and removes
     * all duplicates. The Makefile.am is not parsed, only the folders and files are
     * handled. This function should only be called, if the sources parsing in the Makefile.am
     * failed because variables (e.g. $(test)) have been used.
     */
    void addAllSources();

    /**
     * Adds all include paths to m_includePaths. TODO: Currently this is done
     * by parsing the generated Makefile. It might be more efficient and reliable
     * to parse the Makefile.am instead.
     */
    void parseIncludePaths();

    /**
     * Helper function for MakefileParser::directorySources(). Appends the name of the headerfile
     * to \p list, if the header could be found in the directory specified by \p dir.
     * The headerfile base name is defined by \p fileName.
     */
    static void appendHeader(QStringList &list, const QDir &dir, const QString &fileName);

    /**
     * If line starts with identifier and = goes next, return identifier.
     * Identifier is valid target name and it matches regexp [a-zA-Z1-9_]+
     */
    static QString parseIdentifierBeforeAssign(const QString &line);

    /**
     * Parses list of space-separated terms after "="
     */
    static QStringList parseTermsAfterAssign(const QString &line);

    /**
     * If term is compiler flag -D<macro>, adds macro to defines and returns true.
     */
    bool maybeParseDefine(const QString &term);

    /**
     * If term is compiler flag -I<path>, adds path to includes and returns true.
     * @param term Term itself
     * @param dirName Directory where Makefile placed
     */
    bool maybeParseInclude(const QString &term, const QString &dirName);

    /**
     * If term is compiler flag -<flag>, adds it to cflags and returns true.
     */
    bool maybeParseCFlag(const QString &term);

    /**
     * If term is compiler flag -<flag>, adds it to cxxflags and returns true.
     */
    bool maybeParseCXXFlag(const QString &term);

private:
    bool m_success;             ///< Return value for MakefileParser::parse().

    bool m_cancel;              ///< True, if the parsing should be cancelled.
    mutable QMutex m_mutex;     ///< Mutex to protect m_cancel.

    QString m_makefile;         ///< Filename of the makefile
    QString m_executable;       ///< Return value for MakefileParser::executable()
    QStringList m_sources;      ///< Return value for MakefileParser::sources()
    QStringList m_makefiles;    ///< Return value for MakefileParser::makefiles()
    QStringList m_includePaths; ///< Return value for MakefileParser::includePaths()
    QByteArray m_defines;       ///< Return value for MakefileParser::defines()
    QStringList m_cflags;       ///< Return value for MakefileParser::cflags()
    QStringList m_cxxflags;       ///< Return value for MakefileParser::cxxflags()

    QString m_line;             ///< Current line of the makefile
    QTextStream m_textStream;   ///< Textstream that represents the makefile
};

} // namespace Internal
} // namespace AutotoolsProjectManager

#endif // MAKEFILEPARSER_H