aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2020-12-28 20:34:51 -0700
committerSimon Glass <sjg@chromium.org>2021-01-05 12:26:35 -0700
commitbe44f27156bf46807049a0e1c303626d05f781f8 (patch)
tree867c4db9c187d9a5a66941aa30c57fa378eb97bc
parent192c111cfce0684fa1cbbd4a4bd3df03720ef7a6 (diff)
downloadu-boot-be44f27156bf46807049a0e1c303626d05f781f8.zip
u-boot-be44f27156bf46807049a0e1c303626d05f781f8.tar.gz
u-boot-be44f27156bf46807049a0e1c303626d05f781f8.tar.bz2
dtoc: Allow outputing to multiple files
Implement the 'output directory' feature, allowing dtoc to write the output files separately to the supplied directories. This allows us to handle the struct and platdata output in one run of dtoc. Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r--tools/dtoc/dtb_platdata.py96
-rwxr-xr-xtools/dtoc/test_dtoc.py8
2 files changed, 94 insertions, 10 deletions
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 62a65d6..e2fddfd 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -15,6 +15,7 @@ See doc/driver-model/of-plat.rst for more informaiton
import collections
import copy
+from enum import IntEnum
import os
import re
import sys
@@ -49,6 +50,15 @@ TYPE_NAMES = {
STRUCT_PREFIX = 'dtd_'
VAL_PREFIX = 'dtv_'
+class Ftype(IntEnum):
+ SOURCE, HEADER = range(2)
+
+
+# This holds information about each type of output file dtoc can create
+# type: Type of file (Ftype)
+# fname: Filename excluding directory, e.g. 'dt-platdata.c'
+OutputFile = collections.namedtuple('OutputFile', ['ftype', 'fname'])
+
# This holds information about a property which includes phandles.
#
# max_args: integer: Maximum number or arguments that any phandle uses (int).
@@ -180,6 +190,8 @@ class DtbPlatdata():
U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
value: Driver name declared with U_BOOT_DRIVER(driver_name)
_drivers_additional: List of additional drivers to use during scanning
+ _dirname: Directory to hold output files, or None for none (all files
+ go to stdout)
"""
def __init__(self, dtb_fname, include_disabled, warning_disabled,
drivers_additional=None):
@@ -193,6 +205,7 @@ class DtbPlatdata():
self._drivers = {}
self._driver_aliases = {}
self._drivers_additional = drivers_additional or []
+ self._dirnames = [None] * len(Ftype)
def get_normalized_compat_name(self, node):
"""Get a node's normalized compat name
@@ -230,20 +243,68 @@ class DtbPlatdata():
return compat_list_c[0], compat_list_c[1:]
- def setup_output(self, fname):
+ def setup_output_dirs(self, output_dirs):
+ """Set up the output directories
+
+ This should be done before setup_output() is called
+
+ Args:
+ output_dirs (tuple of str):
+ Directory to use for C output files.
+ Use None to write files relative current directory
+ Directory to use for H output files.
+ Defaults to the C output dir
+ """
+ def process_dir(ftype, dirname):
+ if dirname:
+ os.makedirs(dirname, exist_ok=True)
+ self._dirnames[ftype] = dirname
+
+ if output_dirs:
+ c_dirname = output_dirs[0]
+ h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
+ process_dir(Ftype.SOURCE, c_dirname)
+ process_dir(Ftype.HEADER, h_dirname)
+
+ def setup_output(self, ftype, fname):
"""Set up the output destination
Once this is done, future calls to self.out() will output to this
- file.
+ file. The file used is as follows:
+
+ self._dirnames[ftype] is None: output to fname, or stdout if None
+ self._dirnames[ftype] is not None: output to fname in that directory
+
+ Calling this function multiple times will close the old file and open
+ the new one. If they are the same file, nothing happens and output will
+ continue to the same file.
Args:
- fname (str): Filename to send output to, or None for stdout
+ ftype (str): Type of file to create ('c' or 'h')
+ fname (str): Filename to send output to. If there is a directory in
+ self._dirnames for this file type, it will be put in that
+ directory
"""
- if fname:
- self._outfile = open(fname, 'w')
+ dirname = self._dirnames[ftype]
+ if dirname:
+ pathname = os.path.join(dirname, fname)
+ if self._outfile:
+ self._outfile.close()
+ self._outfile = open(pathname, 'w')
+ elif fname:
+ if not self._outfile:
+ self._outfile = open(fname, 'w')
else:
self._outfile = sys.stdout
+ def finish_output(self):
+ """Finish outputing to a file
+
+ This closes the output file, if one is in use
+ """
+ if self._outfile != sys.stdout:
+ self._outfile.close()
+
def out(self, line):
"""Output a string to the output file
@@ -758,6 +819,15 @@ class DtbPlatdata():
self.out(''.join(self.get_buf()))
+# Types of output file we understand
+# key: Command used to generate this file
+# value: OutputFile for this command
+OUTPUT_FILES = {
+ 'struct': OutputFile(Ftype.HEADER, 'dt-structs-gen.h'),
+ 'platdata': OutputFile(Ftype.SOURCE, 'dt-platdata.c'),
+ }
+
+
def run_steps(args, dtb_file, include_disabled, output, output_dirs,
warning_disabled=False, drivers_additional=None):
"""Run all the steps of the dtoc tool
@@ -778,7 +848,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
ValueError: if args has no command, or an unknown command
"""
if not args:
- raise ValueError('Please specify a command: struct, platdata')
+ raise ValueError('Please specify a command: struct, platdata, all')
+ if output and output_dirs and any(output_dirs):
+ raise ValueError('Must specify either output or output_dirs, not both')
plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
drivers_additional)
@@ -786,15 +858,19 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
plat.scan_dtb()
plat.scan_tree()
plat.scan_reg_sizes()
- plat.setup_output(output)
+ plat.setup_output_dirs(output_dirs)
structs = plat.scan_structs()
plat.scan_phandles()
for cmd in args[0].split(','):
+ outfile = OUTPUT_FILES.get(cmd)
+ if not outfile:
+ raise ValueError("Unknown command '%s': (use: %s)" %
+ (cmd, ', '.join(OUTPUT_FILES.keys())))
+ plat.setup_output(outfile.ftype,
+ outfile.fname if output_dirs else output)
if cmd == 'struct':
plat.generate_structs(structs)
elif cmd == 'platdata':
plat.generate_tables()
- else:
- raise ValueError("Unknown command '%s': (use: struct, platdata)" %
- cmd)
+ plat.finish_output()
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index b023a1e..6f9af90 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -884,6 +884,14 @@ U_BOOT_DEVICE(spl_test2) = {
self.run_test(['struct'], dtb_file, None)
self._check_strings(self.struct_text, stdout.getvalue())
+ def test_multi_to_file(self):
+ """Test output of multiple pieces to a single file"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct,platdata'], dtb_file, output)
+ data = tools.ReadFile(output, binary=False)
+ self._check_strings(self.struct_text + self.platdata_text, data)
+
def test_no_command(self):
"""Test running dtoc without a command"""
with self.assertRaises(ValueError) as exc: