]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/gennltvals.py
sim: ppc: fallback when ln is not available [PR sim/18864]
[thirdparty/binutils-gdb.git] / sim / common / gennltvals.py
CommitLineData
9a7ba4aa
MF
1#!/usr/bin/env python3
2# Copyright (C) 1996-2021 Free Software Foundation, Inc.
3#
4# This file is part of the GNU simulators.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Helper to generate nltvals.def.
20
21nltvals.def is a file that describes various newlib/libgloss target values used
22by the host/target interface. This needs to be rerun whenever the newlib source
23changes. Developers manually run it.
24
25If the path to newlib is not specified, it will be searched for in:
26- the root of this source tree
27- alongside this source tree
28"""
29
30import argparse
31from pathlib import Path
32import re
33import subprocess
34import sys
35from typing import Iterable, List, TextIO
36
37
38PROG = Path(__file__).name
39
bd0918c9 40# Unfortunately, many newlib/libgloss ports have seen fit to define their own
9a7ba4aa
MF
41# syscall.h file. This means that system call numbers can vary for each port.
42# Support for all this crud is kept here, rather than trying to get too fancy.
43# If you want to try to improve this, please do, but don't break anything.
bd0918c9
MF
44#
45# If a target isn't listed here, it gets the standard syscall.h file (see
46# libgloss/syscall.h) which hopefully new targets will use.
9a7ba4aa
MF
47#
48# NB: New ports should use libgloss, not newlib.
49TARGET_DIRS = {
50 'cr16': 'libgloss/cr16/sys',
51 'd10v': 'newlib/libc/sys/d10v/sys',
52 'i960': 'libgloss/i960',
53 'mcore': 'libgloss/mcore',
b9249c46 54 'riscv': 'libgloss/riscv/machine',
b7c5246b 55 'sh': 'newlib/libc/sys/sh/sys',
9a7ba4aa
MF
56 'v850': 'libgloss/v850/sys',
57}
9a7ba4aa 58
9a7ba4aa
MF
59
60# The header for the generated def file.
61FILE_HEADER = f"""\
62/* Newlib/libgloss macro values needed by remote target support. */
63/* This file is machine generated by {PROG}. */\
64"""
65
66
67def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
68 headers: Iterable[str],
69 pattern: str,
70 target: str = None):
71 """Extract constants from the specified files using a regular expression.
72
73 We'll run things through the preprocessor.
74 """
75 headers = tuple(headers)
76
77 # Require all files exist in order to regenerate properly.
78 for header in headers:
79 fullpath = srcdir / header
80 assert fullpath.exists(), f'{fullpath} does not exist'
81
bd0918c9 82 if target is not None:
9a7ba4aa 83 print(f'#ifdef NL_TARGET_{target}', file=output)
bd0918c9 84 print(f'#ifdef {srctype}_defs', file=output)
9a7ba4aa
MF
85
86 print('\n'.join(f'/* from {x} */' for x in headers), file=output)
87
88 if target is None:
89 print(f'/* begin {srctype} target macros */', file=output)
90 else:
91 print(f'/* begin {target} {srctype} target macros */', file=output)
92
93 # Extract all the symbols.
94 srcfile = ''.join(f'#include <{x}>\n' for x in headers)
95 syms = set()
96 define_pattern = re.compile(r'^#\s*define\s+(' + pattern + ')')
97 for header in headers:
98 with open(srcdir / header, 'r', encoding='utf-8') as fp:
99 data = fp.read()
100 for line in data.splitlines():
101 m = define_pattern.match(line)
102 if m:
103 syms.add(m.group(1))
104 for sym in sorted(syms):
105 srcfile += f'#ifdef {sym}\nDEFVAL {{ "{sym}", {sym} }},\n#endif\n'
106
107 result = subprocess.run(
108 f'{cpp} -E -I"{srcdir}" -', shell=True, check=True, encoding='utf-8',
109 input=srcfile, capture_output=True)
110 for line in result.stdout.splitlines():
111 if line.startswith('DEFVAL '):
112 print(line[6:].rstrip(), file=output)
113
bd0918c9 114 print(f'#undef {srctype}_defs', file=output)
9a7ba4aa
MF
115 if target is None:
116 print(f'/* end {srctype} target macros */', file=output)
9a7ba4aa
MF
117 else:
118 print(f'/* end {target} {srctype} target macros */', file=output)
119 print('#endif', file=output)
bd0918c9 120 print('#endif', file=output)
9a7ba4aa
MF
121
122
123def gen_common(output: TextIO, newlib: Path, cpp: str):
124 """Generate the common C library constants.
125
126 No arch should override these.
127 """
128 gentvals(output, cpp, 'errno', newlib / 'newlib/libc/include',
129 ('errno.h', 'sys/errno.h'), 'E[A-Z0-9]*')
130
131 gentvals(output, cpp, 'signal', newlib / 'newlib/libc/include',
132 ('signal.h', 'sys/signal.h'), r'SIG[A-Z0-9]*')
133
134 gentvals(output, cpp, 'open', newlib / 'newlib/libc/include',
135 ('fcntl.h', 'sys/fcntl.h', 'sys/_default_fcntl.h'), r'O_[A-Z0-9]*')
136
137
138def gen_targets(output: TextIO, newlib: Path, cpp: str):
139 """Generate the target-specific lists."""
bd0918c9 140 for target, subdir in sorted(TARGET_DIRS.items()):
9a7ba4aa
MF
141 gentvals(output, cpp, 'sys', newlib / subdir, ('syscall.h',),
142 r'SYS_[_a-zA-Z0-9]*', target=target)
143
bd0918c9
MF
144 # Then output the common syscall targets.
145 gentvals(output, cpp, 'sys', newlib / 'libgloss', ('syscall.h',),
146 r'SYS_[_a-zA-Z0-9]*')
147
9a7ba4aa
MF
148
149def gen(output: TextIO, newlib: Path, cpp: str):
150 """Generate all the things!"""
151 print(FILE_HEADER, file=output)
152 gen_common(output, newlib, cpp)
153 gen_targets(output, newlib, cpp)
154
155
156def get_parser() -> argparse.ArgumentParser:
157 """Get CLI parser."""
158 parser = argparse.ArgumentParser(
159 description=__doc__,
160 formatter_class=argparse.RawDescriptionHelpFormatter)
161 parser.add_argument(
162 '-o', '--output', type=Path,
082cf694 163 help='write to the specified directory')
9a7ba4aa
MF
164 parser.add_argument(
165 '--cpp', type=str, default='cpp',
166 help='the preprocessor to use')
167 parser.add_argument(
168 '--srcroot', type=Path,
169 help='the root of this source tree')
170 parser.add_argument(
171 'newlib', nargs='?', type=Path,
172 help='path to the newlib+libgloss source tree')
173 return parser
174
175
176def parse_args(argv: List[str]) -> argparse.Namespace:
177 """Process the command line & default options."""
178 parser = get_parser()
179 opts = parser.parse_args(argv)
180
082cf694
MF
181 if opts.output is None:
182 # Default to where the script lives.
183 opts.output = Path(__file__).resolve().parent
184
9a7ba4aa
MF
185 if opts.srcroot is None:
186 opts.srcroot = Path(__file__).resolve().parent.parent.parent
082cf694
MF
187 else:
188 opts.srcroot = opts.srcroot.resolve()
9a7ba4aa
MF
189
190 if opts.newlib is None:
191 # Try to find newlib relative to our source tree.
192 if (opts.srcroot / 'newlib').is_dir():
193 # If newlib is manually in the same source tree, use it.
194 if (opts.srcroot / 'libgloss').is_dir():
195 opts.newlib = opts.srcroot
196 else:
197 opts.newlib = opts.srcroot / 'newlib'
198 elif (opts.srcroot.parent / 'newlib').is_dir():
199 # Or see if it's alongside the gdb/binutils repo.
200 opts.newlib = opts.srcroot.parent / 'newlib'
201 if opts.newlib is None or not opts.newlib.is_dir():
202 parser.error('unable to find newlib')
203
204 return opts
205
206
207def main(argv: List[str]) -> int:
208 """The main entry point for scripts."""
209 opts = parse_args(argv)
210
082cf694 211 output = (opts.output / 'nltvals.def').open('w', encoding='utf-8')
9a7ba4aa
MF
212
213 gen(output, opts.newlib, opts.cpp)
214 return 0
215
216
217if __name__ == '__main__':
218 sys.exit(main(sys.argv[1:]))