Patchwork [U-Boot] buildman: Allow make flags to be specified for each board

login
register
mail settings
Submitter Simon Glass
Date May 25, 2013, 2:36 p.m.
Message ID <1369492596-25066-1-git-send-email-sjg@chromium.org>
Download mbox | patch
Permalink /patch/246344/
State Superseded
Delegated to: Simon Glass
Headers show

Comments

Simon Glass - May 25, 2013, 2:36 p.m.
There are a few make options such as BUILD_TAG which can be provided when
building U-Boot. Provide a way for buildman to pass these flags to make
also.

The flags should be in a [make-flags] section and arranged by target name
(the 'target' column in boards.cfg. See the README for more details.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/buildman/README       | 22 +++++++++++++
 tools/buildman/bsettings.py |  3 --
 tools/buildman/builder.py   |  1 +
 tools/buildman/buildman.py  | 13 ++++++++
 tools/buildman/toolchain.py | 79 +++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 113 insertions(+), 5 deletions(-)
Simon Glass - June 4, 2013, 1:19 a.m.
Hi,

On Sat, May 25, 2013 at 7:36 AM, Simon Glass <sjg@chromium.org> wrote:

> There are a few make options such as BUILD_TAG which can be provided when
> building U-Boot. Provide a way for buildman to pass these flags to make
> also.
>
> The flags should be in a [make-flags] section and arranged by target name
> (the 'target' column in boards.cfg. See the README for more details.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
>

This is a new feature - I think it should wait until next time, so I did
not put it in the recent pull request. If no objections it can sit there
until the next merge window.

Regards,
Simon

Patch

diff --git a/tools/buildman/README b/tools/buildman/README
index 7221007..281bdbe 100644
--- a/tools/buildman/README
+++ b/tools/buildman/README
@@ -645,6 +645,28 @@  It is common when refactoring code for the rodata to decrease as the text size
 increases, and vice versa.
 
 
+Providing 'make' flags
+======================
+
+U-Boot's build system supports a few flags (such as BUILD_TAG) which affect
+the build product. These flags can be specified in the buildman settings
+file. They can also be useful when building U-Boot against other open source
+software.
+
+[make-flags]
+at91-boards=ENABLE_AT91_TEST=1
+snapper9260=${at91-boards} BUILD_TAG=442
+snapper9g45=${at91-boards} BUILD_TAG=443
+
+This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
+and 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9g45. A special
+variable ${target} is available to access the target name (snapper9260 and
+snapper9g20 in this case). Variables are resolved recursively.
+
+It is expected that any variables added are dealt with in U-Boot's
+config.mk file and documented in the README.
+
+
 Other options
 =============
 
diff --git a/tools/buildman/bsettings.py b/tools/buildman/bsettings.py
index 7e66c63..6ca7b1e 100644
--- a/tools/buildman/bsettings.py
+++ b/tools/buildman/bsettings.py
@@ -52,9 +52,6 @@  def GetItems(section):
         return settings.items(section)
     except ConfigParser.NoSectionError as e:
         print e
-        print ("Warning: No tool chains - please add a [toolchain] section "
-                "to your buildman config file %s. See README for details" %
-                config_fname)
         return []
     except:
         raise
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index e426442..b1a4d5a 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -269,6 +269,7 @@  class BuilderThread(threading.Thread):
                     args.extend(['-j', str(self.builder.num_jobs)])
                 config_args = ['%s_config' % brd.target]
                 config_out = ''
+                args.extend(self.builder.toolchains.GetMakeArguments(brd))
 
                 # If we need to reconfigure, do that now
                 if do_config:
diff --git a/tools/buildman/buildman.py b/tools/buildman/buildman.py
index 7b05d0f..1e80c8a 100755
--- a/tools/buildman/buildman.py
+++ b/tools/buildman/buildman.py
@@ -48,6 +48,19 @@  import toolchain
 
 def RunTests():
     import test
+    import doctest
+
+    result = unittest.TestResult()
+    for module in ['toolchain']:
+        suite = doctest.DocTestSuite(module)
+        suite.run(result)
+
+    # TODO: Surely we can just 'print' result?
+    print result
+    for test, err in result.errors:
+        print err
+    for test, err in result.failures:
+        print err
 
     sys.argv = [sys.argv[0]]
     suite = unittest.TestLoader().loadTestsFromTestCase(test.TestBuild)
diff --git a/tools/buildman/toolchain.py b/tools/buildman/toolchain.py
index e0a6970..9804dfc 100644
--- a/tools/buildman/toolchain.py
+++ b/tools/buildman/toolchain.py
@@ -19,6 +19,7 @@ 
 # MA 02111-1307 USA
 #
 
+import re
 import glob
 import os
 
@@ -113,12 +114,18 @@  class Toolchains:
     def __init__(self):
         self.toolchains = {}
         self.paths = []
-        for name, value in bsettings.GetItems('toolchain'):
+        toolchains = bsettings.GetItems('toolchain')
+        if not toolchains:
+            print ("Warning: No tool chains - please add a [toolchain] section"
+                 " to your buildman config file %s. See README for details" %
+                 config_fname)
+
+        for name, value in toolchains:
             if '*' in value:
                 self.paths += glob.glob(value)
             else:
                 self.paths.append(value)
-
+        self._make_flags = dict(bsettings.GetItems('make-flags'))
 
     def Add(self, fname, test=True, verbose=False):
         """Add a toolchain to our list
@@ -183,3 +190,71 @@  class Toolchains:
         if not arch in self.toolchains:
             raise ValueError, ("No tool chain found for arch '%s'" % arch)
         return self.toolchains[arch]
+
+    def ResolveReferences(self, var_dict, args):
+        """Resolve variable references in a string
+
+        This converts ${blah} within the string to the value of blah.
+        This function works recursively.
+
+        Args:
+            var_dict: Dictionary containing variables and their values
+            args: String containing make arguments
+        Returns:
+            Resolved string
+
+        >>> tc = Toolchain('fred', False)
+        >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
+                        'second' : '2nd'}
+        >>> tc.ResolveReferences(var_dict, 'this=${oblique}_set')
+        'this=OBLIQUE_set'
+        >>> tc.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
+        'this=OBLIQUE_setfi2ndrstnd'
+        """
+        re_var = re.compile('(\$\{[a-z0-9A-Z]{1,}\})')
+
+        while True:
+            m = re_var.search(args)
+            if not m:
+                break
+            lookup = m.group(0)[2:-1]
+            value = var_dict.get(lookup, '')
+            args = args[:m.start(0)] + value + args[m.end(0):]
+        return args
+
+    def GetMakeArguments(self, board):
+        """Returns 'make' arguments for a given board
+
+        The flags are in a section called 'make-flags'. Flags are named
+        after the target they represent, for example snapper9260=TESTING=1
+        will pass TESTING=1 to make when building the snapper9260 board.
+
+        References to other boards can be added in the string also. For
+        example:
+
+        [make-flags]
+        at91-boards=ENABLE_AT91_TEST=1
+        snapper9260=${at91-boards} BUILD_TAG=442
+        snapper9g45=${at91-boards} BUILD_TAG=443
+
+        This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
+        and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
+
+        A special 'target' variable is set to the board target.
+
+        Args:
+            board: Board object for the board to check.
+        Returns:
+            'make' flags for that board, or '' if none
+        """
+        self._make_flags['target'] = board.target
+        arg_str = self.ResolveReferences(self._make_flags,
+                           self._make_flags.get(board.target, ''))
+        args = arg_str.split(' ')
+        i = 0
+        while i < len(args):
+            if not args[i]:
+                del args[i]
+            else:
+                i += 1
+        return args