bison: add command line option to map file prefixes

Teaches bison about a new command line option, --file-prefix-map OLD=NEW
(based on the -ffile-prefix-map option from GCC) which causes it to
replace and file path of OLD in the text of the output file with NEW,
mainly for header guards and comments. The primary use of this is to
make builds reproducible with different input paths, and in particular
the debugging information produced when the source code is compiled. For
example, a distro may know that the bison source code will be located at
"/usr/src/bison" and thus can generate bison files that are reproducible
with the following command:

    bison --output=/build/bison/parse.c -d --file-prefix-map=/build/bison/=/usr/src/bison/ parse.y

Importantly, this will change the header guards and #line directives
from:

    #ifndef YY_BUILD_BISON_PARSE_H
    #line 100 "/build/bison/parse.h"

to

    #ifndef YY_USR_SRC_BISON_PARSE_H
    #line 100 "/usr/src/bison/parse.h"

which is reproducible.

See https://lists.gnu.org/r/bison-patches/2020-05/msg00016.html
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>

* src/files.h, src/files.c (spec_mapped_header_file)
(mapped_dir_prefix, map_file_name, add_prefix_map): New.
* src/getargs.c (-M, --file-prefix-map): New option.
* src/output.c (prepare): Define b4_mapped_dir_prefix and
b4_spec_header_file.
* src/scan-skel.l (@ofile@): Output the mapped file name.
* data/skeletons/glr.c, data/skeletons/glr.cc,
* data/skeletons/lalr1.cc, data/skeletons/location.cc,
* data/skeletons/yacc.c:
Adjust.
* doc/bison.texi: Document.
* tests/input.at, tests/output.at: Check.
This commit is contained in:
Joshua Watt
2020-05-23 20:26:17 -05:00
committed by Akim Demaille
parent 6ed813c122
commit dd878d1851
14 changed files with 294 additions and 28 deletions

View File

@@ -3006,3 +3006,31 @@ AT_TEST([%define parse.error detailed %token-table],[[input.y:1.1-28]])
m4_popdef([AT_TEST])
AT_CLEANUP
## --------------------------------------- ##
## Invalid file prefix mapping arguments. ##
## --------------------------------------- ##
AT_SETUP([[Invalid file prefix mapping arguments]])
# AT_TEST(DIRECTIVES, OPTIONS, ERROR-LOCATION)
# --------------------------------------------
m4_pushdef([AT_TEST],
[AT_DATA([[input.y]],
[[
%%
exp: %empty;
]])
AT_BISON_CHECK([[$1 input.y]], [[1]], [[]],
[[$3: error: invalid argument for '--file-prefix-map': $2
]])
])
AT_TEST([-M foo], [foo], [<command line>:4])
AT_TEST([--file-prefix-map foo], [foo], [<command line>:4])
AT_TEST([-M foo=bar -M baz], [baz], [<command line>:6])
AT_TEST([-M foo= -M baz], [baz], [<command line>:6])
m4_popdef([AT_TEST])
AT_CLEANUP

View File

@@ -674,3 +674,103 @@ imm: '0';
]])
m4_popdef([AT_TEST])
## -------------------------------- ##
## C++ Output File Prefix Mapping. ##
## -------------------------------- ##
AT_SETUP([C++ Output File Prefix Mapping])
# AT_TEST([PREFIX], [DIRECTIVES])
m4_pushdef([AT_TEST],
[AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc" %define api.namespace {$1} $2])
AT_LOC_PUSHDEF([begin.line], [begin.column], [end.line], [end.column])
AT_DATA_GRAMMAR([$1.yy],
[[%skeleton "lalr1.cc"
%define api.namespace {$1}
$2
%code {
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[
}
%%
exp: '0';
%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE(["0"])[
]])
AT_BISON_CHECK([-fcaret -o out/$1.cc -M out/=bar/ $1.yy])
AT_LANG_COMPILE([out/$1.o], [], [-Iout/include])
AT_LOC_POPDEF
AT_BISON_OPTION_POPDEFS
])
mkdir -p out/include/ast
AT_TEST([x1],
[%defines
%locations
%define api.location.file "include/ast/loc.hh"
])
# Check the CPP guard and Doxyen comments.
AT_CHECK([sed -ne 's/#line [0-9]\+ "/#line "/p;/INCLUDED/p;/\\file/{p;n;p;}' out/include/ast/loc.hh], [],
[[ ** \file bar/include/ast/loc.hh
** Define the x1::location class.
#ifndef YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
# define YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
#line "x1.yy"
#line "bar/include/ast/loc.hh"
#line "x1.yy"
#line "bar/include/ast/loc.hh"
#endif // !YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
]])
AT_CHECK([sed -ne 's/^#line [0-9]\+ "/#line "/p;/INCLUDED/p;/\\file/{p;n;p;}' out/x1.hh], [],
[[ ** \file bar/x1.hh
** Define the x1::parser class.
#ifndef YY_YY_BAR_X1_HH_INCLUDED
# define YY_YY_BAR_X1_HH_INCLUDED
#line "x1.yy"
#line "bar/x1.hh"
#line "x1.yy"
#line "bar/x1.hh"
#endif // !YY_YY_BAR_X1_HH_INCLUDED
]])
AT_TEST([x2],
[%defines
%locations
%code requires {#include "include/ast/loc.hh"}
%define api.location.type {x1::location}])
m4_popdef([AT_TEST])
AT_DATA([main.cc],
[AT_DATA_SOURCE_PROLOGUE
[#include "x1.hh"
#include "x2.hh"
#define RUN(S) \
do { \
S::parser parser; \
int res = parser.parse(); \
if (res) \
std::cerr << #S": " << res << '\n'; \
} while (false)
int
main (void)
{
RUN(x1);
RUN(x2);
}
]])# main.cc
AT_COMPILE_CXX([parser], [[out/x[12].o main.cc]], [-Iout/])
AT_PARSER_CHECK([parser], [0])
AT_CLEANUP