blob: bb1f8edf3916e323c8ff68f98c1269c280d9bd38 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (C) 2022 Free Software Foundation, Inc.
# This file is part of GCC.
# GCC is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# GCC 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
# Generate gcc source files:
# - the export description of the standard C++ library module
# - the gperf tables used to hint at actions to fix problems
# related to missing symbols in the std:: namespace
import csv
import os
import time
# The CSV file contains the following columns:
# column value
# 1 header file, including angle brackets
# 2 symbol name without std:: prefix
# 3 nonzero if to be exported
# 4 "no" if not to be added to the hint table else the appropriate enum cxx_dialect value
# 5 optional, a string used after #if in a line inserted first to enable conditional definitions
def print_condition(prev, e):
if len(e) > 4 and e[4] != '':
if not prev or prev != e[4]:
if prev:
print('#endif')
print(f'#if {e[4]}')
return e[4]
if prev:
print('#endif')
return None
def export(script, content):
print("""// This file is auto-generated by {:s}.
#if __cplusplus <= 202002L
# if __cplusplus == 202002L
# ifdef __STRICT_ANSI__
# error "module `std' is only available before C++23 if using -std=gnu++20"
# endif
# else
# error "module `std' is not available before C++23"
# endif
#endif
export module std;
import <bits/stdc++.h>;
// new/delete operators in global namespace from <new>
export using ::operator new;
export using ::operator delete;
export using ::operator new[];
export using ::operator delete[];""".format(script))
header = ''
printed_header = False
cond = None
for e in content:
if e[0] != header:
header = e[0]
printed_header = False
if e[2] != 0:
if not printed_header:
if cond:
print('#endif')
cond = None
print(f'\n// {header}')
printed_header = True
cond = print_condition(cond, e)
print(f'export using std::{e[1]};')
if cond:
print('#endif')
def hints(script, content):
print("""%language=C++
%define class-name std_name_hint_lookup
%struct-type
%{{
/* This file is auto-generated by {:s}. */
/* Copyright (C) {:s} Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
%}}
struct std_name_hint
{{
/* A name within "std::". */
const char *name;
/* The header name defining it within the C++ Standard Library
(with '<' and '>'). */
const char* header;
/* The dialect of C++ in which this was added. */
enum cxx_dialect min_dialect;
}};
%%
# The standard-defined types, functions, and options in the std:: namespace
# as defined in the C++ language specification. The result is used in the
# get_std_name_hint functions.
# throws an exception.
#""".format(script, time.strftime('%Y')))
header = ''
printed_header = False
for e in content:
if e[0] != header:
header = e[0]
printed_header = False
if e[3] != 'no':
if not printed_header:
print(f'# {header}')
printed_header = True
print(f'{e[1]}, "{e[0]}", {e[3]}')
def remove_comment(f):
for row in f:
row = row.strip()
if row[0] != '#':
yield row
modes = {
'export': export,
'hints': hints
}
def usage(script):
print(f'Usage: {script} [{"|".join(modes.keys())}] CSVFILE')
exit(1)
def main(argv):
if len(argv) < 3:
usage(argv[0] if len(argv) > 0 else '???')
script = argv[0]
mode = argv[1]
filename = argv[2]
if mode not in modes:
print(f"{script}: unrecognized mode '{mode}'")
usage(script)
try:
with open(filename, 'r') as csvfile:
modes[mode](os.path.basename(script), sorted(csv.reader(remove_comment(csvfile), delimiter=',')))
except FileNotFoundError:
print(f"{script}: cannot find CSV file '{filename}'")
exit(1)
except PermissionError:
print(f"{script}: insufficient permission to read CSV file '{filename}'")
exit(1)
if __name__ == '__main__':
import sys
main(sys.argv)