Add a parser for GCC-style depfiles

Introduce the function cmReadGccDepfile that parses a GCC-style depfile
and returns its content. The implementation uses a lexer that is
modeled after the re2c implementation in Ninja.

The sample files of the autotest have been created with gcc 8.3.0.

This depfile reader is to be used by the Autogen facility to make use
of the depfiles that are generated by Qt's meta object compiler.
This commit is contained in:
Joerg Bornemann 2020-01-21 10:26:42 +01:00 committed by Brad King
parent 306328ace8
commit f8c505d4b3
20 changed files with 3390 additions and 1 deletions

View File

@ -99,6 +99,7 @@ The following individuals and institutions are among the Contributors:
* Sebastian Holtermann <sebholt@xwmw.org>
* Stephen Kelly <steveire@gmail.com>
* Sylvain Joubert <joubert.sy@gmail.com>
* The Qt Company Ltd.
* Thomas Sondergaard <ts@medical-insight.com>
* Tobias Hunger <tobias.hunger@qt.io>
* Todd Gamblin <tgamblin@llnl.gov>

View File

@ -134,6 +134,9 @@ set(SRCS
LexerParser/cmFortranParser.cxx
LexerParser/cmFortranParserTokens.h
LexerParser/cmFortranParser.y
LexerParser/cmGccDepfileLexer.cxx
LexerParser/cmGccDepfileLexer.h
LexerParser/cmGccDepfileLexer.in.l
LexerParser/cmListFileLexer.c
LexerParser/cmListFileLexer.in.l
@ -270,6 +273,10 @@ set(SRCS
cmFortranParserImpl.cxx
cmFSPermissions.cxx
cmFSPermissions.h
cmGccDepfileLexerHelper.cxx
cmGccDepfileLexerHelper.h
cmGccDepfileReader.cxx
cmGccDepfileReader.h
cmGeneratedFileStream.cxx
cmGeneratorExpressionContext.cxx
cmGeneratorExpressionContext.h

View File

@ -16,4 +16,6 @@
/cmFortranLexer.h generated
/cmFortranParser.cxx generated
/cmFortranParserTokens.h generated
/cmGccDepfileLexer.cxx generated
/cmGccDepfileLexer.h generated
/cmListFileLexer.c generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,687 @@
#ifndef cmGccDepfile_yyHEADER_H
#define cmGccDepfile_yyHEADER_H 1
#define cmGccDepfile_yyIN_HEADER 1
#define FLEXINT_H 1
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 4
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
#ifdef yy_create_buffer
#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
#else
#define yy_create_buffer cmGccDepfile_yy_create_buffer
#endif
#ifdef yy_delete_buffer
#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
#else
#define yy_delete_buffer cmGccDepfile_yy_delete_buffer
#endif
#ifdef yy_scan_buffer
#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
#else
#define yy_scan_buffer cmGccDepfile_yy_scan_buffer
#endif
#ifdef yy_scan_string
#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED
#else
#define yy_scan_string cmGccDepfile_yy_scan_string
#endif
#ifdef yy_scan_bytes
#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
#else
#define yy_scan_bytes cmGccDepfile_yy_scan_bytes
#endif
#ifdef yy_init_buffer
#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
#else
#define yy_init_buffer cmGccDepfile_yy_init_buffer
#endif
#ifdef yy_flush_buffer
#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
#else
#define yy_flush_buffer cmGccDepfile_yy_flush_buffer
#endif
#ifdef yy_load_buffer_state
#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
#else
#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state
#endif
#ifdef yy_switch_to_buffer
#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
#else
#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer
#endif
#ifdef yypush_buffer_state
#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
#else
#define yypush_buffer_state cmGccDepfile_yypush_buffer_state
#endif
#ifdef yypop_buffer_state
#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
#else
#define yypop_buffer_state cmGccDepfile_yypop_buffer_state
#endif
#ifdef yyensure_buffer_stack
#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
#else
#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack
#endif
#ifdef yylex
#define cmGccDepfile_yylex_ALREADY_DEFINED
#else
#define yylex cmGccDepfile_yylex
#endif
#ifdef yyrestart
#define cmGccDepfile_yyrestart_ALREADY_DEFINED
#else
#define yyrestart cmGccDepfile_yyrestart
#endif
#ifdef yylex_init
#define cmGccDepfile_yylex_init_ALREADY_DEFINED
#else
#define yylex_init cmGccDepfile_yylex_init
#endif
#ifdef yylex_init_extra
#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
#else
#define yylex_init_extra cmGccDepfile_yylex_init_extra
#endif
#ifdef yylex_destroy
#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED
#else
#define yylex_destroy cmGccDepfile_yylex_destroy
#endif
#ifdef yyget_debug
#define cmGccDepfile_yyget_debug_ALREADY_DEFINED
#else
#define yyget_debug cmGccDepfile_yyget_debug
#endif
#ifdef yyset_debug
#define cmGccDepfile_yyset_debug_ALREADY_DEFINED
#else
#define yyset_debug cmGccDepfile_yyset_debug
#endif
#ifdef yyget_extra
#define cmGccDepfile_yyget_extra_ALREADY_DEFINED
#else
#define yyget_extra cmGccDepfile_yyget_extra
#endif
#ifdef yyset_extra
#define cmGccDepfile_yyset_extra_ALREADY_DEFINED
#else
#define yyset_extra cmGccDepfile_yyset_extra
#endif
#ifdef yyget_in
#define cmGccDepfile_yyget_in_ALREADY_DEFINED
#else
#define yyget_in cmGccDepfile_yyget_in
#endif
#ifdef yyset_in
#define cmGccDepfile_yyset_in_ALREADY_DEFINED
#else
#define yyset_in cmGccDepfile_yyset_in
#endif
#ifdef yyget_out
#define cmGccDepfile_yyget_out_ALREADY_DEFINED
#else
#define yyget_out cmGccDepfile_yyget_out
#endif
#ifdef yyset_out
#define cmGccDepfile_yyset_out_ALREADY_DEFINED
#else
#define yyset_out cmGccDepfile_yyset_out
#endif
#ifdef yyget_leng
#define cmGccDepfile_yyget_leng_ALREADY_DEFINED
#else
#define yyget_leng cmGccDepfile_yyget_leng
#endif
#ifdef yyget_text
#define cmGccDepfile_yyget_text_ALREADY_DEFINED
#else
#define yyget_text cmGccDepfile_yyget_text
#endif
#ifdef yyget_lineno
#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED
#else
#define yyget_lineno cmGccDepfile_yyget_lineno
#endif
#ifdef yyset_lineno
#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED
#else
#define yyset_lineno cmGccDepfile_yyset_lineno
#endif
#ifdef yyget_column
#define cmGccDepfile_yyget_column_ALREADY_DEFINED
#else
#define yyget_column cmGccDepfile_yyget_column
#endif
#ifdef yyset_column
#define cmGccDepfile_yyset_column_ALREADY_DEFINED
#else
#define yyset_column cmGccDepfile_yyset_column
#endif
#ifdef yywrap
#define cmGccDepfile_yywrap_ALREADY_DEFINED
#else
#define yywrap cmGccDepfile_yywrap
#endif
#ifdef yyalloc
#define cmGccDepfile_yyalloc_ALREADY_DEFINED
#else
#define yyalloc cmGccDepfile_yyalloc
#endif
#ifdef yyrealloc
#define cmGccDepfile_yyrealloc_ALREADY_DEFINED
#else
#define yyrealloc cmGccDepfile_yyrealloc
#endif
#ifdef yyfree
#define cmGccDepfile_yyfree_ALREADY_DEFINED
#else
#define yyfree cmGccDepfile_yyfree
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#ifndef SIZE_MAX
#define SIZE_MAX (~(size_t)0)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
/* begin standard C++ headers. */
/* TODO: this is always defined, so inline it */
#define yyconst const
#if defined(__GNUC__) && __GNUC__ >= 3
#define yynoreturn __attribute__((__noreturn__))
#else
#define yynoreturn
#endif
/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
/* For convenience, these vars (plus the bison vars far below)
are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
#define yyout yyg->yyout_r
#define yyextra yyg->yyextra_r
#define yyleng yyg->yyleng_r
#define yytext yyg->yytext_r
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
#define yy_flex_debug yyg->yy_flex_debug_r
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k.
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
* Ditto for the __ia64__ case accordingly.
*/
#define YY_BUF_SIZE 32768
#else
#define YY_BUF_SIZE 16384
#endif /* __ia64__ */
#endif
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
int yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
void yypop_buffer_state ( yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
void yyfree ( void * , yyscan_t yyscanner );
/* Begin user sect3 */
#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1)
#define YY_SKIP_YYWRAP
#define yytext_ptr yytext_r
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
#define INITIAL 0
#endif
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
int yylex_init (yyscan_t* scanner);
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy ( yyscan_t yyscanner );
int yyget_debug ( yyscan_t yyscanner );
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
FILE *yyget_in ( yyscan_t yyscanner );
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
FILE *yyget_out ( yyscan_t yyscanner );
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
int yyget_leng ( yyscan_t yyscanner );
char *yyget_text ( yyscan_t yyscanner );
int yyget_lineno ( yyscan_t yyscanner );
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
int yyget_column ( yyscan_t yyscanner );
void yyset_column ( int _column_no , yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap ( yyscan_t yyscanner );
#else
extern int yywrap ( yyscan_t yyscanner );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k */
#define YY_READ_BUF_SIZE 16384
#else
#define YY_READ_BUF_SIZE 8192
#endif /* __ia64__ */
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex (yyscan_t yyscanner);
#define YY_DECL int yylex (yyscan_t yyscanner)
#endif /* !YY_DECL */
/* yy_get_previous_state - get the state just before the EOB char was reached */
#undef YY_NEW_FILE
#undef YY_FLUSH_BUFFER
#undef yy_set_bol
#undef yy_new_buffer
#undef yy_set_interactive
#undef YY_DO_BEFORE_ACTION
#ifdef YY_DECL_IS_OURS
#undef YY_DECL_IS_OURS
#undef YY_DECL
#endif
#ifndef cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
#undef yy_create_buffer
#endif
#ifndef cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
#undef yy_delete_buffer
#endif
#ifndef cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
#undef yy_scan_buffer
#endif
#ifndef cmGccDepfile_yy_scan_string_ALREADY_DEFINED
#undef yy_scan_string
#endif
#ifndef cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
#undef yy_scan_bytes
#endif
#ifndef cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
#undef yy_init_buffer
#endif
#ifndef cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
#undef yy_flush_buffer
#endif
#ifndef cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
#undef yy_load_buffer_state
#endif
#ifndef cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
#undef yy_switch_to_buffer
#endif
#ifndef cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
#undef yypush_buffer_state
#endif
#ifndef cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
#undef yypop_buffer_state
#endif
#ifndef cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
#undef yyensure_buffer_stack
#endif
#ifndef cmGccDepfile_yylex_ALREADY_DEFINED
#undef yylex
#endif
#ifndef cmGccDepfile_yyrestart_ALREADY_DEFINED
#undef yyrestart
#endif
#ifndef cmGccDepfile_yylex_init_ALREADY_DEFINED
#undef yylex_init
#endif
#ifndef cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
#undef yylex_init_extra
#endif
#ifndef cmGccDepfile_yylex_destroy_ALREADY_DEFINED
#undef yylex_destroy
#endif
#ifndef cmGccDepfile_yyget_debug_ALREADY_DEFINED
#undef yyget_debug
#endif
#ifndef cmGccDepfile_yyset_debug_ALREADY_DEFINED
#undef yyset_debug
#endif
#ifndef cmGccDepfile_yyget_extra_ALREADY_DEFINED
#undef yyget_extra
#endif
#ifndef cmGccDepfile_yyset_extra_ALREADY_DEFINED
#undef yyset_extra
#endif
#ifndef cmGccDepfile_yyget_in_ALREADY_DEFINED
#undef yyget_in
#endif
#ifndef cmGccDepfile_yyset_in_ALREADY_DEFINED
#undef yyset_in
#endif
#ifndef cmGccDepfile_yyget_out_ALREADY_DEFINED
#undef yyget_out
#endif
#ifndef cmGccDepfile_yyset_out_ALREADY_DEFINED
#undef yyset_out
#endif
#ifndef cmGccDepfile_yyget_leng_ALREADY_DEFINED
#undef yyget_leng
#endif
#ifndef cmGccDepfile_yyget_text_ALREADY_DEFINED
#undef yyget_text
#endif
#ifndef cmGccDepfile_yyget_lineno_ALREADY_DEFINED
#undef yyget_lineno
#endif
#ifndef cmGccDepfile_yyset_lineno_ALREADY_DEFINED
#undef yyset_lineno
#endif
#ifndef cmGccDepfile_yyget_column_ALREADY_DEFINED
#undef yyget_column
#endif
#ifndef cmGccDepfile_yyset_column_ALREADY_DEFINED
#undef yyset_column
#endif
#ifndef cmGccDepfile_yywrap_ALREADY_DEFINED
#undef yywrap
#endif
#ifndef cmGccDepfile_yyget_lval_ALREADY_DEFINED
#undef yyget_lval
#endif
#ifndef cmGccDepfile_yyset_lval_ALREADY_DEFINED
#undef yyset_lval
#endif
#ifndef cmGccDepfile_yyget_lloc_ALREADY_DEFINED
#undef yyget_lloc
#endif
#ifndef cmGccDepfile_yyset_lloc_ALREADY_DEFINED
#undef yyset_lloc
#endif
#ifndef cmGccDepfile_yyalloc_ALREADY_DEFINED
#undef yyalloc
#endif
#ifndef cmGccDepfile_yyrealloc_ALREADY_DEFINED
#undef yyrealloc
#endif
#ifndef cmGccDepfile_yyfree_ALREADY_DEFINED
#undef yyfree
#endif
#ifndef cmGccDepfile_yytext_ALREADY_DEFINED
#undef yytext
#endif
#ifndef cmGccDepfile_yyleng_ALREADY_DEFINED
#undef yyleng
#endif
#ifndef cmGccDepfile_yyin_ALREADY_DEFINED
#undef yyin
#endif
#ifndef cmGccDepfile_yyout_ALREADY_DEFINED
#undef yyout
#endif
#ifndef cmGccDepfile_yy_flex_debug_ALREADY_DEFINED
#undef yy_flex_debug
#endif
#ifndef cmGccDepfile_yylineno_ALREADY_DEFINED
#undef yylineno
#endif
#ifndef cmGccDepfile_yytables_fload_ALREADY_DEFINED
#undef yytables_fload
#endif
#ifndef cmGccDepfile_yytables_destroy_ALREADY_DEFINED
#undef yytables_destroy
#endif
#ifndef cmGccDepfile_yyTABLES_NAME_ALREADY_DEFINED
#undef yyTABLES_NAME
#endif
#undef cmGccDepfile_yyIN_HEADER
#endif /* cmGccDepfile_yyHEADER_H */

View File

@ -0,0 +1,72 @@
%{
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
/* IWYU pragma: no_forward_declare yyguts_t */
#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
#include <cmGccDepfileLexerHelper.h>
#include <string>
%}
%option prefix="cmGccDepfile_yy"
%option noyywrap
%option reentrant
%pointer
WSPACE [ \t]
NEWLINE \r?\n
%%
\${2} {
// Unescape the dollar sign.
yyextra->addToCurrentPath("$");
}
\\# {
// Unescape the hash.
yyextra->addToCurrentPath("#");
}
(\\\\)*\\[ ] {
// 2N+1 backslashes plus space -> N backslashes plus space.
size_t c = (strlen(yytext) - 1) / 2;
std::string s(c, '\\');
s.push_back(' ');
yyextra->addToCurrentPath(s.c_str());
}
(\\\\)+[ ] {
// 2N backslashes plus space -> 2N backslashes, end of filename.
yytext[strlen(yytext) - 1] = 0;
yyextra->addToCurrentPath(yytext);
yyextra->newDependency();
}
{WSPACE}*\\{NEWLINE} {
// A line continuation ends the current file name.
yyextra->newDependency();
}
{NEWLINE} {
// A newline ends the current file name and the current rule.
yyextra->newEntry();
}
:{WSPACE}+ {
// A colon followed by space ends the rules and starts a new dependency.
yyextra->newDependency();
}
{WSPACE}+ {
// Rules and dependencies are separated by blocks of whitespace.
yyextra->newRuleOrDependency();
}
[a-zA-Z0-9+,/_.~()}{%=@\x5B\x5D!\x80-\xFF-]+ {
// Got a span of plain text.
yyextra->addToCurrentPath(yytext);
}
. {
// Got an otherwise unmatched character.
yyextra->addToCurrentPath(yytext);
}
%%
/*--------------------------------------------------------------------------*/
#endif /* __clang_analyzer__ */

View File

@ -0,0 +1,126 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGccDepfileLexerHelper.h"
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include "cmGccDepfileReaderTypes.h"
#include "LexerParser/cmGccDepfileLexer.h"
#ifdef _WIN32
# include "cmsys/Encoding.h"
#endif
bool cmGccDepfileLexerHelper::readFile(const char* filePath)
{
#ifdef _WIN32
wchar_t* wpath = cmsysEncoding_DupToWide(filePath);
FILE* file = _wfopen(wpath, L"rb");
free(wpath);
#else
FILE* file = fopen(filePath, "r");
#endif
if (!file) {
return false;
}
newEntry();
yyscan_t scanner;
cmGccDepfile_yylex_init(&scanner);
cmGccDepfile_yyset_extra(this, scanner);
cmGccDepfile_yyrestart(file, scanner);
cmGccDepfile_yylex(scanner);
cmGccDepfile_yylex_destroy(scanner);
sanitizeContent();
fclose(file);
return true;
}
void cmGccDepfileLexerHelper::newEntry()
{
this->HelperState = State::Rule;
this->Content.emplace_back();
newRule();
}
void cmGccDepfileLexerHelper::newRule()
{
auto& entry = this->Content.back();
if (entry.rules.empty() || !entry.rules.back().empty()) {
entry.rules.emplace_back();
}
}
void cmGccDepfileLexerHelper::newDependency()
{
// printf("NEW DEP\n");
this->HelperState = State::Dependency;
if (this->Content.back().paths.empty() ||
!this->Content.back().paths.back().empty()) {
this->Content.back().paths.emplace_back();
}
}
void cmGccDepfileLexerHelper::newRuleOrDependency()
{
if (this->HelperState == State::Rule) {
newRule();
} else {
newDependency();
}
}
void cmGccDepfileLexerHelper::addToCurrentPath(const char* s)
{
if (this->Content.empty()) {
return;
}
cmGccStyleDependency* dep = &this->Content.back();
std::string* dst = nullptr;
switch (this->HelperState) {
case State::Rule: {
if (dep->rules.empty()) {
return;
}
dst = &dep->rules.back();
} break;
case State::Dependency: {
if (dep->paths.empty()) {
return;
}
dst = &dep->paths.back();
} break;
}
dst->append(s);
}
void cmGccDepfileLexerHelper::sanitizeContent()
{
for (auto it = this->Content.begin(); it != this->Content.end();) {
// Remove empty rules
for (auto rit = it->rules.begin(); rit != it->rules.end();) {
if (rit->empty()) {
rit = it->rules.erase(rit);
} else {
++rit;
}
}
// Remove the entry if rules are empty
if (it->rules.empty()) {
it = this->Content.erase(it);
} else {
// Remove empty paths
for (auto pit = it->paths.begin(); pit != it->paths.end();) {
if (pit->empty()) {
pit = it->paths.erase(pit);
} else {
++pit;
}
}
++it;
}
}
}

View File

@ -0,0 +1,40 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmGccDepfileLexerHelper_h
#define cmGccDepfileLexerHelper_h
#include <utility>
#include <cmGccDepfileReaderTypes.h>
class cmGccDepfileLexerHelper
{
public:
cmGccDepfileLexerHelper() = default;
bool readFile(const char* filePath);
cmGccDepfileContent extractContent() && { return std::move(this->Content); }
// Functions called by the lexer
void newEntry();
void newRule();
void newDependency();
void newRuleOrDependency();
void addToCurrentPath(const char* s);
private:
void sanitizeContent();
cmGccDepfileContent Content;
enum class State
{
Rule,
Dependency
};
State HelperState = State::Rule;
};
#define YY_EXTRA_TYPE cmGccDepfileLexerHelper*
#endif

View File

@ -0,0 +1,18 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGccDepfileReader.h"
#include <type_traits>
#include <utility>
#include "cmGccDepfileLexerHelper.h"
cmGccDepfileContent cmReadGccDepfile(const char* filePath)
{
cmGccDepfileContent result;
cmGccDepfileLexerHelper helper;
if (helper.readFile(filePath)) {
result = std::move(helper).extractContent();
}
return result;
}

View File

@ -0,0 +1,10 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmGccDepfileReader_h
#define cmGccDepfileReader_h
#include "cmGccDepfileReaderTypes.h"
cmGccDepfileContent cmReadGccDepfile(const char* filePath);
#endif

View File

@ -0,0 +1,17 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmGccDepfileReaderTypes_h
#define cmGccDepfileReaderTypes_h
#include <string>
#include <vector>
struct cmGccStyleDependency
{
std::vector<std::string> rules;
std::vector<std::string> paths;
};
using cmGccDepfileContent = std::vector<cmGccStyleDependency>;
#endif

View File

@ -11,6 +11,7 @@ set(CMakeLib_TESTS
testCTestResourceAllocator.cxx
testCTestResourceSpec.cxx
testCTestResourceGroups.cxx
testGccDepfileReader.cxx
testGeneratedFileStream.cxx
testRST.cxx
testRange.cxx
@ -35,6 +36,7 @@ set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>)
set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>)
set(testCTestResourceSpec_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
set(testGccDepfileReader_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
if(WIN32)
list(APPEND CMakeLib_TESTS

View File

@ -0,0 +1,131 @@
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "cmsys/FStream.hxx"
#include "cmGccDepfileReader.h"
#include "cmGccDepfileReaderTypes.h" // for cmGccDepfileContent, cmGccStyle...
#include "cmSystemTools.h"
namespace {
cmGccDepfileContent readPlainDepfile(const char* filePath)
{
cmGccDepfileContent result;
cmsys::ifstream is(filePath);
if (!is.is_open())
return result;
std::string line;
cmGccStyleDependency dep;
bool readingRules = true;
while (cmSystemTools::GetLineFromStream(is, line)) {
if (line == "--RULES--") {
if (!dep.rules.empty()) {
result.push_back(std::move(dep));
dep = cmGccStyleDependency();
}
readingRules = true;
} else if (line == "--DEPENDENCIES--") {
readingRules = false;
} else {
std::vector<std::string>& dst = readingRules ? dep.rules : dep.paths;
dst.push_back(std::move(line));
line = std::string();
}
}
if (!dep.rules.empty()) {
result.push_back(std::move(dep));
}
return result;
}
bool compare(const std::vector<std::string>& actual,
const std::vector<std::string>& expected, const char* msg)
{
if (actual.size() != expected.size()) {
std::cerr << msg << "expected " << expected.size() << " entries."
<< std::endl
<< "Actual number of entries: " << actual.size() << std::endl;
return false;
}
for (std::size_t i = 0; i < actual.size(); ++i) {
if (actual[i] != expected[i]) {
std::cerr << msg << std::endl
<< "expected: " << expected[i] << std::endl
<< "actual: " << actual[i] << std::endl;
return false;
}
}
return true;
}
bool compare(const cmGccDepfileContent& actual,
const cmGccDepfileContent& expected)
{
if (actual.size() != expected.size()) {
std::cerr << "Expected " << expected.size() << " entries." << std::endl
<< "Actual number of entries: " << actual.size() << std::endl;
return false;
}
for (std::size_t i = 0; i < actual.size(); ++i) {
if (!compare(actual[i].rules, expected[i].rules, "Rules differ: ") ||
!compare(actual[i].paths, expected[i].paths, "Paths differ: ")) {
return false;
}
}
return true;
}
void dump(const char* label, const cmGccDepfileContent& dfc)
{
std::cerr << label << std::endl;
for (const auto& entry : dfc) {
auto rit = entry.rules.cbegin();
if (rit != entry.rules.cend()) {
std::cerr << *rit;
for (++rit; rit != entry.rules.cend(); ++rit) {
std::cerr << " " << *rit;
}
std::cerr << ": " << std::endl;
}
for (const auto& path : entry.paths) {
std::cerr << " " << path << std::endl;
}
}
}
} // anonymous namespace
int testGccDepfileReader(int argc, char* argv[])
{
if (argc < 2) {
std::cout << "Invalid arguments.\n";
return -1;
}
std::string dataDirPath = argv[1];
dataDirPath += "/testGccDepfileReader_data";
const int numberOfTestFiles = 3;
for (int i = 1; i <= numberOfTestFiles; ++i) {
const std::string base = dataDirPath + "/deps" + std::to_string(i);
const std::string depfile = base + ".d";
const std::string plainDepfile = base + ".txt";
std::cout << "Comparing " << base << " with " << plainDepfile << std::endl;
const auto actual = cmReadGccDepfile(depfile.c_str());
const auto expected = readPlainDepfile(plainDepfile.c_str());
if (!compare(actual, expected)) {
dump("actual", actual);
dump("expected", expected);
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,20 @@
main.o: main.cpp /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
/usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
/usr/include/x86_64-linux-gnu/bits/long-double.h \
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h \
/usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h \
/usr/include/x86_64-linux-gnu/bits/types.h \
/usr/include/x86_64-linux-gnu/bits/typesizes.h \
/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h \
/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h \
/usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
/usr/include/x86_64-linux-gnu/bits/types/FILE.h \
/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h \
/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h \
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h

View File

@ -0,0 +1,26 @@
--RULES--
main.o
--DEPENDENCIES--
main.cpp
/usr/include/stdc-predef.h
/usr/include/stdio.h
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h
/usr/include/features.h
/usr/include/x86_64-linux-gnu/sys/cdefs.h
/usr/include/x86_64-linux-gnu/bits/wordsize.h
/usr/include/x86_64-linux-gnu/bits/long-double.h
/usr/include/x86_64-linux-gnu/gnu/stubs.h
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h
/usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h
/usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h
/usr/include/x86_64-linux-gnu/bits/types.h
/usr/include/x86_64-linux-gnu/bits/typesizes.h
/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h
/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h
/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h
/usr/include/x86_64-linux-gnu/bits/types/__FILE.h
/usr/include/x86_64-linux-gnu/bits/types/FILE.h
/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h
/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h

View File

@ -0,0 +1 @@
foo.o bar.o: foobar.c

View File

@ -0,0 +1,5 @@
--RULES--
foo.o
bar.o
--DEPENDENCIES--
foobar.c

View File

@ -0,0 +1,2 @@
main.o: main.cpp foo\#bar.h foo\\#bar.h foo\ bar.h \
foo\\\ bar.h foo\\\\\ bar.h foo\\\\ foo$$bar.h

View File

@ -0,0 +1,11 @@
--RULES--
main.o
--DEPENDENCIES--
main.cpp
foo#bar.h
foo\#bar.h
foo bar.h
foo\ bar.h
foo\\ bar.h
foo\\\\
foo$bar.h

View File

@ -14,7 +14,8 @@ for lexer in \
CTestResourceGroups \
DependsJava \
Expr \
Fortran
Fortran \
GccDepfile
do
cxx_file=cm${lexer}Lexer.cxx
h_file=cm${lexer}Lexer.h