binman: Convert print statements to Python 3
[oweals/u-boot.git] / tools / binman / control.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4 #
5 # Creates binary images from input files controlled by a description
6 #
7
8 from __future__ import print_function
9
10 from collections import OrderedDict
11 import os
12 import sys
13 import tools
14
15 import command
16 import elf
17 from image import Image
18 import state
19 import tout
20
21 # List of images we plan to create
22 # Make this global so that it can be referenced from tests
23 images = OrderedDict()
24
25 def _ReadImageDesc(binman_node):
26     """Read the image descriptions from the /binman node
27
28     This normally produces a single Image object called 'image'. But if
29     multiple images are present, they will all be returned.
30
31     Args:
32         binman_node: Node object of the /binman node
33     Returns:
34         OrderedDict of Image objects, each of which describes an image
35     """
36     images = OrderedDict()
37     if 'multiple-images' in binman_node.props:
38         for node in binman_node.subnodes:
39             images[node.name] = Image(node.name, node)
40     else:
41         images['image'] = Image('image', binman_node)
42     return images
43
44 def _FindBinmanNode(dtb):
45     """Find the 'binman' node in the device tree
46
47     Args:
48         dtb: Fdt object to scan
49     Returns:
50         Node object of /binman node, or None if not found
51     """
52     for node in dtb.GetRoot().subnodes:
53         if node.name == 'binman':
54             return node
55     return None
56
57 def WriteEntryDocs(modules, test_missing=None):
58     """Write out documentation for all entries
59
60     Args:
61         modules: List of Module objects to get docs for
62         test_missing: Used for testing only, to force an entry's documeentation
63             to show as missing even if it is present. Should be set to None in
64             normal use.
65     """
66     from entry import Entry
67     Entry.WriteDocs(modules, test_missing)
68
69 def Binman(options, args):
70     """The main control code for binman
71
72     This assumes that help and test options have already been dealt with. It
73     deals with the core task of building images.
74
75     Args:
76         options: Command line options object
77         args: Command line arguments (list of strings)
78     """
79     global images
80
81     if options.full_help:
82         pager = os.getenv('PAGER')
83         if not pager:
84             pager = 'more'
85         fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
86                             'README')
87         command.Run(pager, fname)
88         return 0
89
90     # Try to figure out which device tree contains our image description
91     if options.dt:
92         dtb_fname = options.dt
93     else:
94         board = options.board
95         if not board:
96             raise ValueError('Must provide a board to process (use -b <board>)')
97         board_pathname = os.path.join(options.build_dir, board)
98         dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
99         if not options.indir:
100             options.indir = ['.']
101         options.indir.append(board_pathname)
102
103     try:
104         # Import these here in case libfdt.py is not available, in which case
105         # the above help option still works.
106         import fdt
107         import fdt_util
108
109         tout.Init(options.verbosity)
110         elf.debug = options.debug
111         state.use_fake_dtb = options.fake_dtb
112         try:
113             tools.SetInputDirs(options.indir)
114             tools.PrepareOutputDir(options.outdir, options.preserve)
115             state.SetEntryArgs(options.entry_arg)
116
117             # Get the device tree ready by compiling it and copying the compiled
118             # output into a file in our output directly. Then scan it for use
119             # in binman.
120             dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
121             fname = tools.GetOutputFilename('u-boot.dtb.out')
122             tools.WriteFile(fname, tools.ReadFile(dtb_fname))
123             dtb = fdt.FdtScan(fname)
124
125             node = _FindBinmanNode(dtb)
126             if not node:
127                 raise ValueError("Device tree '%s' does not have a 'binman' "
128                                  "node" % dtb_fname)
129
130             images = _ReadImageDesc(node)
131
132             if options.image:
133                 skip = []
134                 for name, image in images.iteritems():
135                     if name not in options.image:
136                         del images[name]
137                         skip.append(name)
138                 if skip and options.verbosity >= 2:
139                     print('Skipping images: %s' % ', '.join(skip))
140
141             state.Prepare(images, dtb)
142
143             # Prepare the device tree by making sure that any missing
144             # properties are added (e.g. 'pos' and 'size'). The values of these
145             # may not be correct yet, but we add placeholders so that the
146             # size of the device tree is correct. Later, in
147             # SetCalculatedProperties() we will insert the correct values
148             # without changing the device-tree size, thus ensuring that our
149             # entry offsets remain the same.
150             for image in images.values():
151                 image.ExpandEntries()
152                 if options.update_fdt:
153                     image.AddMissingProperties()
154                 image.ProcessFdt(dtb)
155
156             for dtb_item in state.GetFdts():
157                 dtb_item.Sync(auto_resize=True)
158                 dtb_item.Pack()
159                 dtb_item.Flush()
160
161             for image in images.values():
162                 # Perform all steps for this image, including checking and
163                 # writing it. This means that errors found with a later
164                 # image will be reported after earlier images are already
165                 # completed and written, but that does not seem important.
166                 image.GetEntryContents()
167                 image.GetEntryOffsets()
168                 try:
169                     image.PackEntries()
170                     image.CheckSize()
171                     image.CheckEntries()
172                 except Exception as e:
173                     if options.map:
174                         fname = image.WriteMap()
175                         print("Wrote map file '%s' to show errors"  % fname)
176                     raise
177                 image.SetImagePos()
178                 if options.update_fdt:
179                     image.SetCalculatedProperties()
180                     for dtb_item in state.GetFdts():
181                         dtb_item.Sync()
182                 image.ProcessEntryContents()
183                 image.WriteSymbols()
184                 image.BuildImage()
185                 if options.map:
186                     image.WriteMap()
187
188             # Write the updated FDTs to our output files
189             for dtb_item in state.GetFdts():
190                 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
191
192         finally:
193             tools.FinaliseOutputDir()
194     finally:
195         tout.Uninit()
196
197     return 0