--- /dev/null
+#!/usr/bin/env python3
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU simulators.
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""Helper to generate nltvals.def.
+
+nltvals.def is a file that describes various newlib/libgloss target values used
+by the host/target interface. This needs to be rerun whenever the newlib source
+changes. Developers manually run it.
+
+If the path to newlib is not specified, it will be searched for in:
+- the root of this source tree
+- alongside this source tree
+"""
+
+import argparse
+from pathlib import Path
+import re
+import subprocess
+import sys
+from typing import Iterable, List, TextIO
+
+
+PROG = Path(__file__).name
+
+# Unfortunately, each newlib/libgloss port has seen fit to define their own
+# syscall.h file. This means that system call numbers can vary for each port.
+# Support for all this crud is kept here, rather than trying to get too fancy.
+# If you want to try to improve this, please do, but don't break anything.
+# Note that there is a standard syscall.h file (libgloss/syscall.h) now which
+# hopefully more targets can use.
+#
+# NB: New ports should use libgloss, not newlib.
+TARGET_DIRS = {
+ 'cr16': 'libgloss/cr16/sys',
+ 'd10v': 'newlib/libc/sys/d10v/sys',
+ 'i960': 'libgloss/i960',
+ 'mcore': 'libgloss/mcore',
+ 'v850': 'libgloss/v850/sys',
+}
+TARGETS = {
+ 'bfin',
+ 'cr16',
+ 'd10v',
+ 'fr30',
+ 'frv',
+ 'i960',
+ 'lm32',
+ 'm32r',
+ 'mcore',
+ 'mn10200',
+ 'mn10300',
+ 'msp430',
+ 'pru',
+ 'sparc',
+ 'v850',
+}
+
+# Make sure TARGET_DIRS doesn't gain any typos.
+assert not set(TARGET_DIRS) - TARGETS
+
+# The header for the generated def file.
+FILE_HEADER = f"""\
+/* Newlib/libgloss macro values needed by remote target support. */
+/* This file is machine generated by {PROG}. */\
+"""
+
+
+def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
+ headers: Iterable[str],
+ pattern: str,
+ target: str = None):
+ """Extract constants from the specified files using a regular expression.
+
+ We'll run things through the preprocessor.
+ """
+ headers = tuple(headers)
+
+ # Require all files exist in order to regenerate properly.
+ for header in headers:
+ fullpath = srcdir / header
+ assert fullpath.exists(), f'{fullpath} does not exist'
+
+ if target is None:
+ print(f'#ifdef {srctype}_defs', file=output)
+ else:
+ print(f'#ifdef NL_TARGET_{target}', file=output)
+ print(f'#ifdef {srctype}_defs', file=output)
+
+ print('\n'.join(f'/* from {x} */' for x in headers), file=output)
+
+ if target is None:
+ print(f'/* begin {srctype} target macros */', file=output)
+ else:
+ print(f'/* begin {target} {srctype} target macros */', file=output)
+
+ # Extract all the symbols.
+ srcfile = ''.join(f'#include <{x}>\n' for x in headers)
+ syms = set()
+ define_pattern = re.compile(r'^#\s*define\s+(' + pattern + ')')
+ for header in headers:
+ with open(srcdir / header, 'r', encoding='utf-8') as fp:
+ data = fp.read()
+ for line in data.splitlines():
+ m = define_pattern.match(line)
+ if m:
+ syms.add(m.group(1))
+ for sym in sorted(syms):
+ srcfile += f'#ifdef {sym}\nDEFVAL {{ "{sym}", {sym} }},\n#endif\n'
+
+ result = subprocess.run(
+ f'{cpp} -E -I"{srcdir}" -', shell=True, check=True, encoding='utf-8',
+ input=srcfile, capture_output=True)
+ for line in result.stdout.splitlines():
+ if line.startswith('DEFVAL '):
+ print(line[6:].rstrip(), file=output)
+
+ if target is None:
+ print(f'/* end {srctype} target macros */', file=output)
+ print('#endif', file=output)
+ else:
+ print(f'/* end {target} {srctype} target macros */', file=output)
+ print('#endif', file=output)
+ print('#endif', file=output)
+
+
+def gen_common(output: TextIO, newlib: Path, cpp: str):
+ """Generate the common C library constants.
+
+ No arch should override these.
+ """
+ gentvals(output, cpp, 'errno', newlib / 'newlib/libc/include',
+ ('errno.h', 'sys/errno.h'), 'E[A-Z0-9]*')
+
+ gentvals(output, cpp, 'signal', newlib / 'newlib/libc/include',
+ ('signal.h', 'sys/signal.h'), r'SIG[A-Z0-9]*')
+
+ gentvals(output, cpp, 'open', newlib / 'newlib/libc/include',
+ ('fcntl.h', 'sys/fcntl.h', 'sys/_default_fcntl.h'), r'O_[A-Z0-9]*')
+
+
+def gen_targets(output: TextIO, newlib: Path, cpp: str):
+ """Generate the target-specific lists."""
+ for target in sorted(TARGETS):
+ subdir = TARGET_DIRS.get(target, 'libgloss')
+ gentvals(output, cpp, 'sys', newlib / subdir, ('syscall.h',),
+ r'SYS_[_a-zA-Z0-9]*', target=target)
+
+
+def gen(output: TextIO, newlib: Path, cpp: str):
+ """Generate all the things!"""
+ print(FILE_HEADER, file=output)
+ gen_common(output, newlib, cpp)
+ gen_targets(output, newlib, cpp)
+
+
+def get_parser() -> argparse.ArgumentParser:
+ """Get CLI parser."""
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument(
+ '-o', '--output', type=Path,
+ help='write to the specified file instead of stdout')
+ parser.add_argument(
+ '--cpp', type=str, default='cpp',
+ help='the preprocessor to use')
+ parser.add_argument(
+ '--srcroot', type=Path,
+ help='the root of this source tree')
+ parser.add_argument(
+ 'newlib', nargs='?', type=Path,
+ help='path to the newlib+libgloss source tree')
+ return parser
+
+
+def parse_args(argv: List[str]) -> argparse.Namespace:
+ """Process the command line & default options."""
+ parser = get_parser()
+ opts = parser.parse_args(argv)
+
+ if opts.srcroot is None:
+ opts.srcroot = Path(__file__).resolve().parent.parent.parent
+
+ if opts.newlib is None:
+ # Try to find newlib relative to our source tree.
+ if (opts.srcroot / 'newlib').is_dir():
+ # If newlib is manually in the same source tree, use it.
+ if (opts.srcroot / 'libgloss').is_dir():
+ opts.newlib = opts.srcroot
+ else:
+ opts.newlib = opts.srcroot / 'newlib'
+ elif (opts.srcroot.parent / 'newlib').is_dir():
+ # Or see if it's alongside the gdb/binutils repo.
+ opts.newlib = opts.srcroot.parent / 'newlib'
+ if opts.newlib is None or not opts.newlib.is_dir():
+ parser.error('unable to find newlib')
+
+ return opts
+
+
+def main(argv: List[str]) -> int:
+ """The main entry point for scripts."""
+ opts = parse_args(argv)
+
+ if opts.output is not None:
+ output = open(opts.output, 'w', encoding='utf-8')
+ else:
+ output = sys.stdout
+
+ gen(output, opts.newlib, opts.cpp)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
+++ /dev/null
-#! /bin/sh
-# Copyright (C) 1996-2021 Free Software Foundation, Inc.
-#
-# This file is part of the GNU simulators.
-#
-# This program 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 of the License, or
-# (at your option) any later version.
-#
-# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Display the tool usage and exit.
-usage() {
- cat <<EOF
-Usage: $0 [path to newlib source tree]
-
-Generate nltvals.def, a file that describes various newlib/libgloss target
-values used by the host/target interface. This needs to be rerun whenever
-the newlib source changes. Developers manually run it.
-
-If the path to newlib is not specified, it will be searched for in:
-- the root of this source tree
-- alongside this source tree
-
-Options:
- -o, --output <file> Write to the specified file instead of stdout.
- --cpp <cpp> The preprocessor to use.
- --srcroot <dir> The root of this source tree.
- -h, --help This text you're reading!
-EOF
- if [ $# -gt 0 ]; then
- error "$*"
- fi
- exit 0
-}
-
-# Show an error message and exit.
-error() {
- echo "$0: error: $*" >&2
- exit 1
-}
-
-ARG_CPP="cpp"
-ARG_SRCROOT=""
-ARG_NEWLIB=""
-ARG_OUTPUT=""
-
-# Emit the header for this generated def file.
-gen_header() {
- cat <<EOF
-/* Newlib/libgloss macro values needed by remote target support. */
-/* This file is machine generated by gennltvals.sh. */
-EOF
-}
-
-# Extract constants from the specified files using a regular expression and the
-# preprocessor.
-gentvals() {
- target=$1
- type=$2
- dir=$3
- # FIXME: Would be nice to process #include's in these files.
- files=$4
- pattern=$5
-
- # Require all files exist in order to regenerate properly.
- for f in ${files}; do
- if [ ! -f "${dir}/${f}" ]; then
- error "file does not exist: ${dir}/${f}"
- fi
- done
-
- if [ -z "${target}" ]; then
- echo "#ifdef ${type}_defs"
- else
- echo "#ifdef NL_TARGET_${target}"
- echo "#ifdef ${type}_defs"
- fi
-
- printf "/* from %s */\n" ${files}
-
- if [ -z "${target}" ]; then
- echo "/* begin ${type} target macros */"
- else
- echo "/* begin ${target} ${type} target macros */"
- fi
-
- # Extract all the symbols.
- (
- printf '#include <%s>\n' ${files}
- for f in ${files}; do
- sed -E -n -e "/^# *define[[:space:]]${pattern}/{\
- s|# *define[[:space:]](${pattern})[[:space:]]*([^[:space:]][^[:space:]]*).*$|\1|; \
- p}" \
- "${dir}/${f}"
- done |
- sort -u |
- while read -r sym; do
- echo "#ifdef ${sym}"
- echo "DEFVAL { \"${sym}\", ${sym} },"
- echo "#endif"
- done
- ) |
- ${ARG_CPP} -E -I"${dir}" - |
- sed -E -n -e '/^DEFVAL/{s/DEFVAL//; s/[[:space:]]+/ /; p}'
-
- if [ -z "${target}" ]; then
- echo "/* end ${type} target macros */"
- echo "#endif"
- else
- echo "/* end ${target} ${type} target macros */"
- echo "#endif"
- echo "#endif"
- fi
-}
-
-# Generate the common C library constants. No arch should override these.
-gen_common() {
- gentvals "" errno ${ARG_NEWLIB}/newlib/libc/include \
- "errno.h sys/errno.h" 'E[[:upper:][:digit:]]*'
-
- gentvals "" signal ${ARG_NEWLIB}/newlib/libc/include \
- "signal.h sys/signal.h" 'SIG[[:upper:][:digit:]]*'
-
- gentvals "" open ${ARG_NEWLIB}/newlib/libc/include \
- "fcntl.h sys/fcntl.h sys/_default_fcntl.h" 'O_[[:upper:][:digit:]]*'
-}
-
-# Unfortunately, each newlib/libgloss port has seen fit to define their own
-# syscall.h file. This means that system call numbers can vary for each port.
-# Support for all this crud is kept here, rather than trying to get too fancy.
-# If you want to try to improve this, please do, but don't break anything.
-# Note that there is a standard syscall.h file (libgloss/syscall.h) now which
-# hopefully more targets can use.
-#
-# NB: New ports should use libgloss, not newlib.
-gen_arch() {
- target="$1"
- dir="${2:-libgloss}"
- gentvals "${target}" sys "${ARG_NEWLIB}/${dir}" "syscall.h" 'SYS_[_[:alnum:]]*'
-}
-
-gen_arches() {
- gen_arch bfin
- gen_arch cr16 libgloss/cr16/sys
- gen_arch d10v newlib/libc/sys/d10v/sys
- gen_arch fr30
- gen_arch frv
- gen_arch i960 libgloss/i960
- gen_arch lm32
- gen_arch m32r
- gen_arch mcore libgloss/mcore
- gen_arch mn10200
- gen_arch mn10300
- gen_arch msp430
- gen_arch pru
- gen_arch sparc
- gen_arch v850 libgloss/v850/sys
-}
-
-# Process the script command line options.
-parse_opts() {
- while [ $# -gt 0 ]; do
- case $1 in
- --cpp)
- ARG_CPP="$2"
- shift
- ;;
- -o|--output)
- ARG_OUTPUT="$2"
- shift
- ;;
- --srcroot)
- ARG_SRCROOT="$2"
- shift
- ;;
- -h|--help)
- usage
- ;;
- --)
- shift
- break
- ;;
- -*)
- usage "unknown option: $1"
- ;;
- *)
- break
- ;;
- esac
- shift
- done
-
- if [ $# -gt 2 ]; then
- error "too many arguments: $*"
- elif [ $# -eq 1 ]; then
- ARG_NEWLIB="$1"
- fi
-
- # Try to find newlib relative to our source tree.
- if [ -z "${ARG_NEWLIB}" ]; then
- if [ -z "${ARG_SRCROOT}" ]; then
- ARG_SRCROOT="$(dirname "$0")/../.."
- fi
- if [ -d "${ARG_SRCROOT}/newlib" ]; then
- # If newlib is manually in the same source tree, use it.
- ARG_NEWLIB="${ARG_SRCROOT}/newlib"
- elif [ -d "${ARG_SRCROOT}/../newlib" ]; then
- # Or see if it's alongside the gdb/binutils repo.
- ARG_NEWLIB="${ARG_SRCROOT}/../newlib"
- else
- error "unable to find newlib"
- fi
- fi
-}
-
-main() {
- # The error checking isn't perfect, but should be good enough for this script.
- set -e
-
- parse_opts "$@"
-
- if [ -n "${ARG_OUTPUT}" ]; then
- exec >"${ARG_OUTPUT}" || exit 1
- fi
-
- gen_header
- gen_common
- gen_arches
-}
-main "$@"