From 2bbd06bcee5fe62896d71f78c6c2b6d0f3a23467 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 31 Aug 2018 21:19:51 +0000 Subject: [PATCH] Replace conform/list-header-symbols.pl with a Python script. Continuing the move of test code from Perl to Python (which seems uncontroversial, unlike dependencies on Python in the actual build of glibc), this patch replaces conform/list-header-symbols.pl with a Python script, as a first step in converting the conform/ tests. (conform/glibcconform.py is an equivalent to GlibcConform.pm, containing code that will be relevant to move than one of the conform/ scripts.) Tested for x86_64, including verifying that the symbol lists generated are identical to those generated by the Perl version. * conform/glibcconform.py: New file. * conform/list-header-symbols.py: Likewise. * conform/list-header-symbols.pl: Remove. * conform/Makefile (tests-special): Only add linknamespace tests if [PYTHON]. ($(linknamespace-symlists-tests)): Use list-header-symbols.py. --- ChangeLog | 9 ++++ conform/Makefile | 15 ++++-- conform/glibcconform.py | 77 +++++++++++++++++++++++++++++++ conform/list-header-symbols.pl | 83 ---------------------------------- conform/list-header-symbols.py | 76 +++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 88 deletions(-) create mode 100644 conform/glibcconform.py delete mode 100644 conform/list-header-symbols.pl create mode 100644 conform/list-header-symbols.py diff --git a/ChangeLog b/ChangeLog index 5288a7e519..e4a1b51d2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2018-08-31 Joseph Myers + + * conform/glibcconform.py: New file. + * conform/list-header-symbols.py: Likewise. + * conform/list-header-symbols.pl: Remove. + * conform/Makefile (tests-special): Only add linknamespace tests + if [PYTHON]. + ($(linknamespace-symlists-tests)): Use list-header-symbols.py. + 2018-08-31 H.J. Lu [BZ #23597] diff --git a/conform/Makefile b/conform/Makefile index d43093171b..71e58a46c8 100644 --- a/conform/Makefile +++ b/conform/Makefile @@ -120,7 +120,9 @@ linknamespace-symlists-base := $(foreach std,$(conformtest-standards),\ symlist-$(std)) linknamespace-symlists-tests := $(addprefix $(objpfx),\ $(linknamespace-symlists-base)) +ifdef PYTHON tests-special += $(linknamespace-symlists-tests) +endif linknamespace-symlist-stdlibs-base := $(foreach std,$(conformtest-standards),\ symlist-stdlibs-$(std)) @@ -128,7 +130,9 @@ linknamespace-symlist-stdlibs-tests := \ $(addprefix $(objpfx),\ $(linknamespace-symlist-stdlibs-base)) +ifdef PYTHON tests-special += $(linknamespace-symlist-stdlibs-tests) +endif linknamespace-header-base := $(foreach std,\ $(conformtest-standards),\ @@ -137,7 +141,9 @@ linknamespace-header-base := $(foreach std,\ $(std)/$(h)/linknamespace.out)) linknamespace-header-tests := $(addprefix $(objpfx),\ $(linknamespace-header-base)) +ifdef PYTHON tests-special += $(linknamespace-header-tests) +endif include ../Rules @@ -181,11 +187,10 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \ > $@); \ $(evaluate-test) -$(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl - $(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ - --flags='$(conformtest-cc-flags)' --standard=$* \ - --headers="$(strip $(conformtest-headers-$*))" \ - > $@ 2> $@.err; \ +$(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.py + $(PYTHON) $< --cc='$(CC)' --flags='$(conformtest-cc-flags)' \ + --standard=$* --headers="$(strip $(conformtest-headers-$*))" \ + > $@ 2> $@.err; \ $(evaluate-test) linknamespace-libs-isoc = $(common-objpfx)libc.a $(common-objpfx)math/libm.a diff --git a/conform/glibcconform.py b/conform/glibcconform.py new file mode 100644 index 0000000000..31ad4a9f9f --- /dev/null +++ b/conform/glibcconform.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +# Shared code for glibc conformance tests. +# Copyright (C) 2018 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +import os.path +import re +import shutil +import subprocess +import tempfile + + +# Compiler options for each standard. +CFLAGS = {'ISO': '-ansi', + 'ISO99': '-std=c99', + 'ISO11': '-std=c11', + 'POSIX': '-D_POSIX_C_SOURCE=199506L -ansi', + 'XPG4': '-ansi -D_XOPEN_SOURCE', + 'XPG42': '-ansi -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED', + 'UNIX98': '-ansi -D_XOPEN_SOURCE=500', + 'XOPEN2K': '-std=c99 -D_XOPEN_SOURCE=600', + 'XOPEN2K8': '-std=c99 -D_XOPEN_SOURCE=700', + 'POSIX2008': '-std=c99 -D_POSIX_C_SOURCE=200809L'} + + +def list_exported_functions(cc, standard, header): + """Return the set of functions exported by a header, empty if an + include of the header does not compile. + + """ + cc_all = '%s -D_ISOMAC %s' % (cc, CFLAGS[standard]) + # tempfile.TemporaryDirectory requires Python 3.2, so use mkdtemp. + temp_dir = tempfile.mkdtemp() + c_file_name = os.path.join(temp_dir, 'test.c') + aux_file_name = os.path.join(temp_dir, 'test.c.aux') + try: + with open(c_file_name, 'w') as c_file: + c_file.write('#include <%s>\n' % header) + fns = set() + cmd = ('%s -c %s -o /dev/null -aux-info %s' + % (cc_all, c_file_name, aux_file_name)) + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError: + return fns + with open(aux_file_name, 'r') as aux_file: + for line in aux_file: + line = re.sub(r'/\*.*?\*/', '', line) + line = line.strip() + if line: + # The word before a '(' that isn't '(*' is the + # function name before the argument list (not + # fully general, but sufficient for -aux-info + # output on standard headers). + m = re.search(r'([A-Za-z0-9_]+) *\([^*]', line) + if m: + fns.add(m.group(1)) + else: + raise ValueError("couldn't parse -aux-info output: %s" + % line) + finally: + shutil.rmtree(temp_dir) + return fns diff --git a/conform/list-header-symbols.pl b/conform/list-header-symbols.pl deleted file mode 100644 index 0db61bfe86..0000000000 --- a/conform/list-header-symbols.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl - -# Print a list of symbols exported by some headers that would -# otherwise be in the user's namespace. - -# Copyright (C) 2014-2018 Free Software Foundation, Inc. -# This file is part of the GNU C Library. - -# The GNU C Library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. - -# The GNU C Library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with the GNU C Library; if not, see -# . - -use GlibcConform; -use Getopt::Long; - -GetOptions ('headers=s' => \$headers, 'standard=s' => \$standard, - 'flags=s' => \$flags, 'cc=s' => \$CC, 'tmpdir=s' => \$tmpdir); -@headers = split (/\s+/, $headers); - -# Extra symbols possibly not found through -aux-info but still -# reserved by the standard: either data symbols, or symbols where the -# standard leaves unspecified whether the identifier is a macro or -# defined with external linkage. -$extra_syms{"ISO"} = ["errno", "setjmp", "va_end"]; -$extra_syms{"ISO99"} = ["errno", "math_errhandling", "setjmp", "va_end"]; -# stdatomic.h not yet covered by conformance tests; as per DR#419, all -# the generic functions there or may not be defined with external -# linkage (but are reserved in any case). -$extra_syms{"ISO11"} = ["errno", "math_errhandling", "setjmp", "va_end"]; -# The following lists may not be exhaustive. -$extra_syms{"POSIX"} = ["errno", "setjmp", "va_end", "environ", "sigsetjmp", - "optarg", "optind", "opterr", "optopt", "tzname"]; -$extra_syms{"XPG4"} = ["errno", "setjmp", "va_end", "environ", "signgam", - "loc1", "loc2", "locs", "sigsetjmp", "optarg", - "optind", "opterr", "optopt", "daylight", "timezone", - "tzname"]; -$extra_syms{"XPG42"} = ["errno", "setjmp", "va_end", "environ", "signgam", - "loc1", "loc2", "locs", "sigsetjmp", "optarg", - "optind", "opterr", "optopt", "daylight", "timezone", - "tzname", "getdate_err", "h_errno"]; -$extra_syms{"UNIX98"} = ["errno", "setjmp", "va_end", "environ", "signgam", - "loc1", "loc2", "locs", "sigsetjmp", "optarg", - "optind", "opterr", "optopt", "daylight", "timezone", - "tzname", "getdate_err", "h_errno"]; -$extra_syms{"XOPEN2K"} = ["errno", "setjmp", "va_end", "environ", "signgam", - "sigsetjmp", "optarg", "optind", "opterr", "optopt", - "daylight", "timezone", "tzname", "getdate_err", - "h_errno", "in6addr_any", "in6addr_loopback"]; -$extra_syms{"XOPEN2K8"} = ["errno", "setjmp", "va_end", "environ", "signgam", - "sigsetjmp", "optarg", "optind", "opterr", "optopt", - "daylight", "timezone", "tzname", "getdate_err", - "in6addr_any", "in6addr_loopback"]; -$extra_syms{"POSIX2008"} = ["errno", "setjmp", "va_end", "environ", - "sigsetjmp", "optarg", "optind", "opterr", "optopt", - "tzname", "in6addr_any", "in6addr_loopback"]; - -%user_syms = (); - -foreach my $header (@headers) { - @syms = list_exported_functions ("$CC $flags", $standard, $header, $tmpdir); - foreach my $sym (@syms) { - if ($sym !~ /^_/) { - $user_syms{$sym} = 1; - } - } -} -foreach my $sym (@{$extra_syms{$standard}}) { - $user_syms{$sym} = 1; -} - -foreach my $sym (sort keys %user_syms) { - print "$sym\n"; -} diff --git a/conform/list-header-symbols.py b/conform/list-header-symbols.py new file mode 100644 index 0000000000..5dd0a51605 --- /dev/null +++ b/conform/list-header-symbols.py @@ -0,0 +1,76 @@ +#!/usr/bin/python +# Print a list of symbols exported by some headers that would +# otherwise be in the user's namespace. +# Copyright (C) 2018 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +import argparse + +import glibcconform + +# Extra symbols possibly not found through -aux-info but still +# reserved by the standard: either data symbols, or symbols where the +# standard leaves unspecified whether the identifier is a macro or +# defined with external linkage. +EXTRA_SYMS = {} +EXTRA_SYMS['ISO'] = {'errno', 'setjmp', 'va_end'} +EXTRA_SYMS['ISO99'] = EXTRA_SYMS['ISO'] | {'math_errhandling'} +# stdatomic.h not yet covered by conformance tests; as per DR#419, all +# the generic functions there or may not be defined with external +# linkage (but are reserved in any case). +EXTRA_SYMS['ISO11'] = EXTRA_SYMS['ISO99'] +# The following lists may not be exhaustive. +EXTRA_SYMS['POSIX'] = (EXTRA_SYMS['ISO'] + | {'environ', 'sigsetjmp', 'optarg', 'optind', 'opterr', + 'optopt', 'tzname'}) +EXTRA_SYMS['XPG4'] = (EXTRA_SYMS['POSIX'] + | {'signgam', 'loc1', 'loc2', 'locs', 'daylight', + 'timezone'}) +EXTRA_SYMS['XPG42'] = EXTRA_SYMS['XPG4'] | {'getdate_err', 'h_errno'} +EXTRA_SYMS['UNIX98'] = EXTRA_SYMS['XPG42'] +EXTRA_SYMS['XOPEN2K'] = (EXTRA_SYMS['POSIX'] + | {'signgam', 'daylight', 'timezone', 'getdate_err', + 'h_errno', 'in6addr_any', 'in6addr_loopback'}) +EXTRA_SYMS['POSIX2008'] = (EXTRA_SYMS['POSIX'] + | {'in6addr_any', 'in6addr_loopback'}) +EXTRA_SYMS['XOPEN2K8'] = (EXTRA_SYMS['POSIX2008'] + | {'signgam', 'daylight', 'timezone', 'getdate_err'}) + + +def main(): + """The main entry point.""" + parser = argparse.ArgumentParser(description='List exported symbols.') + parser.add_argument('--headers', metavar='HEADERS', + help='list of headers') + parser.add_argument('--standard', metavar='STD', + help='standard to use when processing headers') + parser.add_argument('--cc', metavar='CC', + help='C compiler to use') + parser.add_argument('--flags', metavar='CFLAGS', + help='Compiler flags to use with CC') + args = parser.parse_args() + fns = set() + compiler = '%s %s' % (args.cc, args.flags) + for header in args.headers.split(): + fns |= glibcconform.list_exported_functions(compiler, args.standard, + header) + fns |= EXTRA_SYMS[args.standard] + print('\n'.join(sorted(fn for fn in fns if not fn.startswith('_')))) + + +if __name__ == '__main__': + main() -- 2.43.5