buildman: A few more features and improvements (Christmas edition)
cover buildman: A few more features and improvements (Christmas edition)
Various people (on CC) have suggested improvements and reported bugs in buildman. I've done a pass through these and this series is the result. In summary the main changes are:
- Flatten the output tree for 'current source builds'
- Improve docs to talk about Python environment and ~/.buildman file
- Toolchain path improvements and changes
- Download and install a new toolchain automatically
- Guess the upstream commit instead of requiring it to be set
- Access to the full build output
- Support for building an arbitrary range of commits
Simon Glass (17):
buildman: Add tests that check the correct output directory is used
buildman: Put build in 'current', not 'current/current'
buildman: Don't prune output space for 'current source' build
buildman: Try to guess the upstream commit
buildman: Add an option to flatten output directory trees
buildman: Don't remove entire output directory when testing
buildman: Allow specifying a range of commits to build
buildman: Try to avoid hard-coded string parsing
buildman: Put the toolchain path first instead of last in PATH
buildman: Add an option to use the full tool chain path
buildman: Add a note about Python pre-requisites
buildman: Add documentation about the .buildman file
buildman: Don't complain about missing sections in ~/.buildman
buildman: Don't use the local settings when running tests
buildman: Allow architecture to alias to multiple toolchains
buildman: Add the option to download toolchains from kernel.org
buildman: Add an option to write the full build output
tools/buildman/README | 142 +++++++++++++++++---- tools/buildman/bsettings.py | 11 +- tools/buildman/builder.py | 21 +++- tools/buildman/builderthread.py | 7 +- tools/buildman/cmdline.py | 10 ++ tools/buildman/control.py | 58 +++++++-- tools/buildman/test.py | 75 ++++++++++- tools/buildman/toolchain.py | 270 +++++++++++++++++++++++++++++++++++++--- tools/patman/gitutil.py | 90 ++++++++++++-- 9 files changed, 606 insertions(+), 78 deletions(-)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 1/17 buildman: Add tests that check the correct output directory is used
Add a few tests of the output directory logic.
---
tools/buildman/test.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
tools/buildman/test.py +31 -0
@@ -83,6 +83,8 @@ boards = [ ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], ] +BASE_DIR = 'base' + class Options: """Class that holds build options""" pass
@@ -341,6 +343,35 @@ class TestBuild(unittest.TestCase): self.assertEqual(self.boards.SelectBoards(['sandbox sandbox', 'sandbox']), {'all': 1, 'sandbox': 1}) + def CheckDirs(self, build, dirname): + self.assertEqual('base%s' % dirname, build._GetOutputDir(1)) + self.assertEqual('base%s/fred' % dirname, + build.GetBuildDir(1, 'fred')) + self.assertEqual('base%s/fred/done' % dirname, + build.GetDoneFile(1, 'fred')) + self.assertEqual('base%s/fred/u-boot.sizes' % dirname, + build.GetFuncSizesFile(1, 'fred', 'u-boot')) + self.assertEqual('base%s/fred/u-boot.objdump' % dirname, + build.GetObjdumpFile(1, 'fred', 'u-boot')) + self.assertEqual('base%s/fred/err' % dirname, + build.GetErrFile(1, 'fred')) + + def testOutputDir(self): + build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, + checkout=False, show_unknown=False) + build.commits = self.commits + build.commit_count = len(self.commits) + subject = self.commits[1].subject.translate(builder.trans_valid_chars) + dirname ='/%02d_of_%02d_g%s_%s' % (2, build.commit_count, commits[1][0], + subject[:20]) + self.CheckDirs(build, dirname) + + def testOutputDirCurrent(self): + build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, + checkout=False, show_unknown=False) + build.commits = None + build.commit_count = 0 + self.CheckDirs(build, '/current') if __name__ == "__main__": unittest.main()
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 1/17 buildman: Add tests that check the correct output directory is used
Hi Tom.
Quoted 8 lines · Simon Glass
Add a few tests of the output directory logic.
Signed-off-by Simon Glass <[email protected]>---
tools/buildman/test.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
Do you think we should pull these in for the release? This series is a mixture of fixes but also new features. Maybe wait until we get a few more replies?
[snip]
Regards,
Simon
PATCH 2/17 buildman: Put build in 'current', not 'current/current'
In reply to Simon GlassBuildman currently puts current-source builds in a current/current subdirectory, but there is no need for the extra depth.
---
tools/buildman/control.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
tools/buildman/control.py +3 -4
@@ -205,12 +205,11 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, if not gnu_make: sys.exit('GNU Make not found') - # Create a new builder with the selected options + # Create a new builder with the selected options. + output_dir = options.output_dir if options.branch: dirname = options.branch.replace('/', '_') - else: - dirname = 'current' - output_dir = os.path.join(options.output_dir, dirname) + output_dir = os.path.join(options.output_dir, dirname) if clean_dir and os.path.exists(output_dir): shutil.rmtree(output_dir) builder = Builder(toolchains, output_dir, options.git_dir,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 3/17 buildman: Don't prune output space for 'current source' build
In reply to Simon GlassThis is not needed since we always do a full (non-incremental) build. Also it might be dangerous since it will try to delete everything below the base directory.
Fix this potentially nasty bug.
---
tools/buildman/builder.py | 2 ++ 1 file changed, 2 insertions(+)
tools/buildman/builder.py +2 -0
@@ -1115,6 +1115,8 @@ class Builder: create. Having left over directories is confusing when the user wants to check the output manually. """ + if not self.commits: + return dir_list = [] for commit_upto in range(self.commit_count): dir_list.append(self._GetOutputDir(commit_upto))
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 4/17 buildman: Try to guess the upstream commit
In reply to Simon GlassBuildman normally obtains the upstream commit by asking git. Provided that the branch was created with 'git checkout -b <branch> <some_upstream>' then this normally works.
When there is no upstream, we can try to guess one, by looking up through the commits until we find a branch. Add a function to try this and print a warning if buildman ends up relying on it.
Also update the documentation to match.
---
tools/buildman/README | 5 ++-- tools/buildman/control.py | 10 +++---- tools/patman/gitutil.py | 68 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 67 insertions(+), 16 deletions(-)
tools/buildman/README +3 -2
@@ -310,8 +310,9 @@ branch with a valid upstream) $ ./tools/buildman/buildman -b <branch> -n If it can't detect the upstream branch, try checking out the branch, and -doing something like 'git branch --set-upstream <branch> upstream/master' -or something similar. +doing something like 'git branch --set-upstream-to upstream/master' +or something similar. Buildman will try to guess a suitable upstream branch +if it can't find one (you will see a message like" Guessing upstream as ...). As an example:
tools/buildman/control.py +5 -5
@@ -127,12 +127,12 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, if not options.branch: count = 1 else: - count = gitutil.CountCommitsInBranch(options.git_dir, - options.branch) + count, msg = gitutil.CountCommitsInBranch(options.git_dir, + options.branch) if count is None: - str = ("Branch '%s' not found or has no upstream" % - options.branch) - sys.exit(col.Color(col.RED, str)) + sys.exit(col.Color(col.RED, msg)) + if msg: + print col.Color(col.YELLOW, msg) count += 1 # Build upstream commit also if not count:
tools/patman/gitutil.py +59 -9
109 lines not on this page · raw message
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 5/17 buildman: Add an option to flatten output directory trees
In reply to Simon GlassWhen building current source for a single board, buildman puts the output in <output_dir>/current/current/<board>. Add an option to make it use <output_dir>/<board> instead. This removes the unnecessary directories in that case, controlled by the --no-subdirs/-N option.
---
tools/buildman/builder.py | 12 ++++++++---- tools/buildman/cmdline.py | 2 ++ tools/buildman/control.py | 8 ++++++-- tools/buildman/test.py | 8 ++++++++ 4 files changed, 24 insertions(+), 6 deletions(-)
tools/buildman/builder.py +8 -4
@@ -174,7 +174,8 @@ class Builder: self.func_sizes = func_sizes def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs, - gnu_make='make', checkout=True, show_unknown=True, step=1): + gnu_make='make', checkout=True, show_unknown=True, step=1, + no_subdirs=False): """Create a new Builder object Args:
@@ -213,6 +214,7 @@ class Builder: self._step = step self.in_tree = False self._error_lines = 0 + self.no_subdirs = no_subdirs self.col = terminal.Color()
@@ -392,15 +394,17 @@ class Builder: Args: commit_upto: Commit number to use (0..self.count-1) """ + commit_dir = None if self.commits: commit = self.commits[commit_upto] subject = commit.subject.translate(trans_valid_chars) commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1, self.commit_count, commit.hash, subject[:20])) - else: + elif not self.no_subdirs: commit_dir = 'current' - output_dir = os.path.join(self.base_dir, commit_dir) - return output_dir + if not commit_dir: + return self.base_dir + return os.path.join(self.base_dir, commit_dir) def GetBuildDir(self, commit_upto, target): """Get the name of the build directory for a commit number
tools/buildman/cmdline.py +2 -0
@@ -55,6 +55,8 @@ def ParseArgs(): help='List available tool chains') parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', default=False, help="Do a dry run (describe actions, but do nothing)") + parser.add_option('-N', '--no-subdirs', action='store_true', dest='no_subdirs', + default=False, help="Don't create subdirectories when building current source for a single board") parser.add_option('-o', '--output-dir', type='string', dest='output_dir', default='..', help='Directory where all builds happen and buildman has its workspace (default is ../)')
tools/buildman/control.py +6 -2
@@ -209,12 +209,16 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, output_dir = options.output_dir if options.branch: dirname = options.branch.replace('/', '_') - output_dir = os.path.join(options.output_dir, dirname) + # As a special case allow the board directory to be placed in the + # output directory itself rather than any subdirectory. + if not options.no_subdirs: + output_dir = os.path.join(options.output_dir, dirname) if clean_dir and os.path.exists(output_dir): shutil.rmtree(output_dir) builder = Builder(toolchains, output_dir, options.git_dir, options.threads, options.jobs, gnu_make=gnu_make, checkout=True, - show_unknown=options.show_unknown, step=options.step) + show_unknown=options.show_unknown, step=options.step, + no_subdirs=options.no_subdirs) builder.force_config_on_failure = not options.quick if make_func: builder.do_make = make_func
tools/buildman/test.py +8 -0
@@ -373,5 +373,13 @@ class TestBuild(unittest.TestCase): build.commit_count = 0 self.CheckDirs(build, '/current') + def testOutputDirNoSubdirs(self): + build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, + checkout=False, show_unknown=False, + no_subdirs=True) + build.commits = None + build.commit_count = 0 + self.CheckDirs(build, '') + if __name__ == "__main__": unittest.main()
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 6/17 buildman: Don't remove entire output directory when testing
In reply to Simon GlassWhen running tests the output directory is often wiped. This is only safe if a branch is being built. The output directory may contain other things besides the buildman test output.
---
tools/buildman/control.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/buildman/control.py +2 -1
@@ -213,7 +213,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, # output directory itself rather than any subdirectory. if not options.no_subdirs: output_dir = os.path.join(options.output_dir, dirname) - if clean_dir and os.path.exists(output_dir): + if (clean_dir and output_dir != options.output_dir and + os.path.exists(output_dir)): shutil.rmtree(output_dir) builder = Builder(toolchains, output_dir, options.git_dir, options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 7/17 buildman: Allow specifying a range of commits to build
In reply to Simon GlassAdjust the -b flag to permit a range expression as well as a branch.
---
tools/buildman/README | 11 +++++++++++ tools/buildman/control.py | 19 +++++++++++++++---- tools/patman/gitutil.py | 24 +++++++++++++++++++----- 3 files changed, 45 insertions(+), 9 deletions(-)
tools/buildman/README +11 -0
@@ -699,6 +699,17 @@ build the selected boards and display build status as it runs (i.e. -v is enabled automatically). Use -e to see errors/warnings as well. +Building Ranges +=============== + +You can build a range of commits by specifying a range instead of a branch +when using the -b flag. For example: + + upstream/master..us-buildman + +will build commits in us-buildman that are not in upstream/master. + + Other options =============
tools/buildman/control.py +15 -4
@@ -123,14 +123,22 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, # problems introduced by the first commit on the branch. col = terminal.Color() count = options.count + has_range = options.branch and '..' in options.branch if count == -1: if not options.branch: count = 1 else: - count, msg = gitutil.CountCommitsInBranch(options.git_dir, - options.branch) + if has_range: + count, msg = gitutil.CountCommitsInRange(options.git_dir, + options.branch) + else: + count, msg = gitutil.CountCommitsInBranch(options.git_dir, + options.branch) if count is None: sys.exit(col.Color(col.RED, msg)) + elif count == 0: + sys.exit(col.Color(col.RED, "Range '%s' has no commits" % + options.branch)) if msg: print col.Color(col.YELLOW, msg) count += 1 # Build upstream commit also
@@ -172,8 +180,11 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, # to overwrite earlier ones by setting allow_overwrite=True if options.branch: if count == -1: - range_expr = gitutil.GetRangeInBranch(options.git_dir, - options.branch) + if has_range: + range_expr = options.branch + else: + range_expr = gitutil.GetRangeInBranch(options.git_dir, + options.branch) upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch) series = patchstream.GetMetaDataForList(upstream_commit,
tools/patman/gitutil.py +19 -5
@@ -154,6 +154,24 @@ def GetRangeInBranch(git_dir, branch, include_upstream=False): rstr = '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) return rstr, msg +def CountCommitsInRange(git_dir, range_expr): + """Returns the number of commits in the given range. + + Args: + git_dir: Directory containing git repo + range_expr: Range to check + Return: + Number of patches that exist in the supplied rangem or None if none + were found + """ + pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True)] + result = command.RunPipe(pipe, capture=True, capture_stderr=True, + raise_on_error=False) + if result.return_code: + return None, "Range '%s' not found or is invalid" % range_expr + patch_count = len(result.stdout.splitlines()) + return patch_count, None + def CountCommitsInBranch(git_dir, branch, include_upstream=False): """Returns the number of commits in the given branch.
@@ -167,11 +185,7 @@ def CountCommitsInBranch(git_dir, branch, include_upstream=False): range_expr, msg = GetRangeInBranch(git_dir, branch, include_upstream) if not range_expr: return None, msg - pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True), - ['wc', '-l']] - result = command.RunPipe(pipe, capture=True, oneline=True) - patch_count = int(result.stdout) - return patch_count, msg + return CountCommitsInRange(git_dir, range_expr) def CountCommits(commit_range): """Returns the number of commits in the given range.
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 7/17 buildman: Allow specifying a range of commits to build
Hi Simon,
Quoted 4 lines · Simon Glass
Adjust the -b flag to permit a range expression as well as a branch.
Signed-off-by Simon Glass <[email protected]>Suggested-by Daniel Schwierzeck <[email protected]>
works great, thanks.
Quoted 115 lines
---
tools/buildman/README | 11 +++++++++++ tools/buildman/control.py | 19 +++++++++++++++---- tools/patman/gitutil.py | 24 +++++++++++++++++++----- 3 files changed, 45 insertions(+), 9 deletions(-)tools/buildman/README +11
-0@@ -699,6 +699,17 @@ build the selected boards and display build status as it runs (i.e. -v is enabled automatically). Use -e to see errors/warnings as well. +Building Ranges +=============== + +You can build a range of commits by specifying a range instead of a branch +when using the -b flag. For example: + + upstream/master..us-buildman + +will build commits in us-buildman that are not in upstream/master. + + Other options =============tools/buildman/control.py +15
-4@@ -123,14 +123,22 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, # problems introduced by the first commit on the branch. col = terminal.Color() count = options.count + has_range = options.branch and '..' in options.branch if count == -1: if not options.branch: count = 1 else: - count, msg = gitutil.CountCommitsInBranch(options.git_dir, - options.branch) + if has_range: + count, msg = gitutil.CountCommitsInRange(options.git_dir, + options.branch) + else: + count, msg = gitutil.CountCommitsInBranch(options.git_dir, + options.branch) if count is None: sys.exit(col.Color(col.RED, msg)) + elif count == 0: + sys.exit(col.Color(col.RED, "Range '%s' has no commits" % + options.branch)) if msg: print col.Color(col.YELLOW, msg) count += 1 # Build upstream commit also@@ -172,8 +180,11 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, # to overwrite earlier ones by setting allow_overwrite=True if options.branch: if count == -1: - range_expr = gitutil.GetRangeInBranch(options.git_dir, - options.branch) + if has_range: + range_expr = options.branch + else: + range_expr = gitutil.GetRangeInBranch(options.git_dir, + options.branch) upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch) series = patchstream.GetMetaDataForList(upstream_commit,tools/patman/gitutil.py +19
-5@@ -154,6 +154,24 @@ def GetRangeInBranch(git_dir, branch, include_upstream=False): rstr = '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) return rstr, msg +def CountCommitsInRange(git_dir, range_expr): + """Returns the number of commits in the given range. + + Args: + git_dir: Directory containing git repo + range_expr: Range to check + Return: + Number of patches that exist in the supplied rangem or None if none + were found + """ + pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True)] + result = command.RunPipe(pipe, capture=True, capture_stderr=True, + raise_on_error=False) + if result.return_code: + return None, "Range '%s' not found or is invalid" % range_expr + patch_count = len(result.stdout.splitlines()) + return patch_count, None + def CountCommitsInBranch(git_dir, branch, include_upstream=False): """Returns the number of commits in the given branch.@@ -167,11 +185,7 @@ def CountCommitsInBranch(git_dir, branch, include_upstream=False): range_expr, msg = GetRangeInBranch(git_dir, branch, include_upstream) if not range_expr: return None, msg - pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True), - ['wc', '-l']] - result = command.RunPipe(pipe, capture=True, oneline=True) - patch_count = int(result.stdout) - return patch_count, msg + return CountCommitsInRange(git_dir, range_expr) def CountCommits(commit_range): """Returns the number of commits in the given range.
Signature · 1 line
- Daniel
PATCH 8/17 buildman: Try to avoid hard-coded string parsing
In reply to Simon GlassThe assumption that the compiler name will always end in gcc is incorrect for clang and apparently on BSD.
---
tools/buildman/toolchain.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/buildman/toolchain.py +8 -1
@@ -30,7 +30,14 @@ class Toolchain: """ self.gcc = fname self.path = os.path.dirname(fname) - self.cross = os.path.basename(fname)[:-3] + + # Find the CROSS_COMPILE prefix to use for U-Boot. For example, + # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'. + basename = os.path.basename(fname) + pos = basename.rfind('-') + self.cross = basename[:pos + 1] if pos != -1 else '' + + # The architecture is the first part of the name pos = self.cross.find('-') self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 9/17 buildman: Put the toolchain path first instead of last in PATH
In reply to Simon GlassIf:
1. Toolchains A and B have the same filename
2. Toolchain A is in the PATH
3. Toolchain B is given in ~/.buildman and buildman uses it to build
then buildman will add toolchain B to the end of its path but will not necessarily use it since U-Boot will find toolchain A first in the PATH.
Try to fix this by putting the toolchain first in the path instead of last.
---
tools/buildman/toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/buildman/toolchain.py +1 -1
@@ -89,7 +89,7 @@ class Toolchain: """ env = dict(os.environ) env['CROSS_COMPILE'] = self.cross - env['PATH'] += (':' + self.path) + env['PATH'] = self.path + ':' + env['PATH'] return env
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 10/17 buildman: Add an option to use the full tool chain path
In reply to Simon GlassIn some cases there may be multiple toolchains with the same name in the path. Provide an option to use the full path in the CROSS_COMPILE environment variable.
Note: Wolfgang mentioned that this is dangerous since in some cases there may be other tools on the path that are needed. So this is set up as an option, not the default. I will need test confirmation (i.e. that this commit fixes a real problem) before merging it.
---
tools/buildman/builder.py | 7 ++++++- tools/buildman/builderthread.py | 4 ++-- tools/buildman/cmdline.py | 2 ++ tools/buildman/control.py | 2 +- tools/buildman/toolchain.py | 20 ++++++++++++++------ 5 files changed, 25 insertions(+), 10 deletions(-)
tools/buildman/builder.py +6 -1
@@ -175,7 +175,7 @@ class Builder: def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs, gnu_make='make', checkout=True, show_unknown=True, step=1, - no_subdirs=False): + no_subdirs=False, full_path=False): """Create a new Builder object Args:
@@ -189,6 +189,10 @@ class Builder: This is used for testing. show_unknown: Show unknown boards (those not built) in summary step: 1 to process every commit, n to process every nth commit + no_subdirs: Don't create subdirectories when building current + source for a single board + full_path: Return the full path in CROSS_COMPILE and don't set + PATH """ self.toolchains = toolchains self.base_dir = base_dir
@@ -215,6 +219,7 @@ class Builder: self.in_tree = False self._error_lines = 0 self.no_subdirs = no_subdirs + self.full_path = full_path self.col = terminal.Color()
tools/buildman/builderthread.py +2 -2
@@ -177,7 +177,7 @@ class BuilderThread(threading.Thread): commit = 'current' # Set up the environment and command line - env = self.toolchain.MakeEnvironment() + env = self.toolchain.MakeEnvironment(self.builder.full_path) Mkdir(out_dir) args = [] cwd = work_dir
@@ -284,7 +284,7 @@ class BuilderThread(threading.Thread): print >>fd, 'path', result.toolchain.path # Write out the image and function size information and an objdump - env = result.toolchain.MakeEnvironment() + env = result.toolchain.MakeEnvironment(self.builder.full_path) lines = [] for fname in ['u-boot', 'spl/u-boot-spl']: cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
tools/buildman/cmdline.py +2 -0
@@ -62,6 +62,8 @@ def ParseArgs(): help='Directory where all builds happen and buildman has its workspace (default is ../)') parser.add_option('-Q', '--quick', action='store_true', default=False, help='Do a rough build, with limited warning resolution') + parser.add_option('-p', '--full-path', action='store_true', + default=False, help="Use full toolchain path in CROSS_COMPILE") parser.add_option('-s', '--summary', action='store_true', default=False, help='Show a build summary') parser.add_option('-S', '--show-sizes', action='store_true',
tools/buildman/control.py +1 -1
@@ -230,7 +230,7 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, builder = Builder(toolchains, output_dir, options.git_dir, options.threads, options.jobs, gnu_make=gnu_make, checkout=True, show_unknown=options.show_unknown, step=options.step, - no_subdirs=options.no_subdirs) + no_subdirs=options.no_subdirs, full_path=options.full_path) builder.force_config_on_failure = not options.quick if make_func: builder.do_make = make_func
tools/buildman/toolchain.py +14 -6
@@ -41,7 +41,7 @@ class Toolchain: pos = self.cross.find('-') self.arch = self.cross[:pos] if pos != -1 else 'sandbox' - env = self.MakeEnvironment() + env = self.MakeEnvironment(False) # As a basic sanity check, run the C compiler with --version cmd = [fname, '--version']
@@ -81,15 +81,23 @@ class Toolchain: return prio return prio - def MakeEnvironment(self): + def MakeEnvironment(self, full_path): """Returns an environment for using the toolchain. - Thie takes the current environment, adds CROSS_COMPILE and - augments PATH so that the toolchain will operate correctly. + Thie takes the current environment and adds CROSS_COMPILE so that + the tool chain will operate correctly. + + Args: + full_path: Return the full path in CROSS_COMPILE and don't set + PATH """ env = dict(os.environ) - env['CROSS_COMPILE'] = self.cross - env['PATH'] = self.path + ':' + env['PATH'] + if full_path: + env['CROSS_COMPILE'] = os.path.join(self.path, self.cross) + else: + env['CROSS_COMPILE'] = self.cross + env['PATH'] = self.path + ':' + env['PATH'] + return env
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 11/17 buildman: Add a note about Python pre-requisites
In reply to Simon GlassSince we need a few modules which might not be available in a bare-bones distribution, add a note about that to the README.
---
tools/buildman/README | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
tools/buildman/README +10 -1
@@ -171,7 +171,16 @@ The toolchain-alias section indicates that the i386 toolchain should be used to build x86 commits. -2. Check the available toolchains +3. Make sure you have the require Python pre-requisites + +Buildman uses multiprocessing, Queue, shutil, StringIO and ConfigParser. +These should normally be available, but if you get an error like this then +you will need to obtain those modules: + + ImportError: No module named multiprocessing + + +4. Check the available toolchains Run this check to make sure that you have a toolchain for every architecture.
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 12/17 buildman: Add documentation about the .buildman file
In reply to Simon GlassThis file is only partially documented. Add some more details.
---
tools/buildman/README | 73 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 20 deletions(-)
tools/buildman/README +53 -20
@@ -141,8 +141,8 @@ $ git clone git://git.denx.de/u-boot.git . $ git checkout -b my-branch origin/master $ # Add some commits to the branch, reading for testing -2. Create ~/.buildman to tell buildman where to find tool chains. As an -example: +2. Create ~/.buildman to tell buildman where to find tool chains (see 'The +.buildman file' later for details). As an example: # Buildman settings file
@@ -675,28 +675,61 @@ It is common when refactoring code for the rodata to decrease as the text size increases, and vice versa. -Providing 'make' flags -====================== +The .buildman file +================== + +The .buildman file provides information about the available toolchains and +also allows build flags to be passed to 'make'. It consists of several +sections, with the section name in square brackets. Within each section are +a set of (tag, value) pairs. + +'[toolchain]' section + + This lists the available toolchains. The tag here doesn't matter, but + make sure it is unique. The value is the path to the toolchain. Buildman + will look in that path for a file ending in 'gcc'. It will then execute + it to check that it is a C compiler, passing only the --version flag to + it. If the return code is 0, buildman assumes that it is a valid C + compiler. It uses the first part of the name as the architecture and + strips off the last part when setting the CROSS_COMPILE environment + variable (parts are delimited with a hyphen). + + For example powerpc-linux-gcc will be noted as a toolchain for 'powerpc' + and CROSS_COMPILE will be set to powerpc-linux- when using it. + +'[toolchain-alias]' section + + This converts toolchain architecture names to U-Boot names. For example, + if an x86 toolchains is called i386-linux-gcc it will not normally be + used for architecture 'x86'. Adding 'x86: i386' to this section will + tell buildman that the i386 toolchain can be used for x86. + +'[make-flags]' section + + 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 -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. + This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 + and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special + variable ${target} is available to access the target name (snapper9260 + and snapper9g20 in this case). Variables are resolved recursively. Note + that variables can only contain the characters A-Z, a-z, 0-9, hyphen (-) + and underscore (_). -[make-flags] -at91-boards=ENABLE_AT91_TEST=1 -snapper9260=${at91-boards} BUILD_TAG=442 -snapper9g45=${at91-boards} BUILD_TAG=443 + It is expected that any variables added are dealt with in U-Boot's + config.mk file and documented in the README. -This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 -and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special -variable ${target} is available to access the target name (snapper9260 and -snapper9g20 in this case). Variables are resolved recursively. Note that -variables can only contain the characters A-Z, a-z, 0-9, hyphen (-) and -underscore (_). + Note that you can pass ad-hoc options to the build using environment + variables, for example: -It is expected that any variables added are dealt with in U-Boot's -config.mk file and documented in the README. + SOME_OPTION=1234 ./tools/buildman/buildman my_board Quick Sanity Check
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 13/17 buildman: Don't complain about missing sections in ~/.buildman
In reply to Simon GlassSilently ignore this since it is valid to have missing sections.
---
tools/buildman/bsettings.py | 1 - 1 file changed, 1 deletion(-)
tools/buildman/bsettings.py +0 -1
@@ -40,7 +40,6 @@ def GetItems(section): try: return settings.items(section) except ConfigParser.NoSectionError as e: - print e return [] except: raise
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 14/17 buildman: Don't use the local settings when running tests
In reply to Simon GlassWe should create a test setting file when running testes, not use whatever happens to be on the local machine.
---
tools/buildman/test.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
tools/buildman/test.py +14 -1
@@ -24,6 +24,16 @@ import commit import terminal import toolchain +settings_data = ''' +# Buildman settings file + +[toolchain] +main: /usr/sbin + +[toolchain-alias] +x86: i386 x86_64 +''' + errors = [ '''main.c: In function 'main_loop': main.c:260:6: warning: unused variable 'joe' [-Wunused-variable]
@@ -113,8 +123,11 @@ class TestBuild(unittest.TestCase): self.boards.AddBoard(board.Board(*brd)) self.boards.SelectBoards([]) + # Add some test settings + bsettings.Setup(None) + bsettings.AddFile(settings_data) + # Set up the toolchains - bsettings.Setup() self.toolchains = toolchain.Toolchains() self.toolchains.Add('arm-linux-gcc', test=False) self.toolchains.Add('sparc-linux-gcc', test=False)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 15/17 buildman: Allow architecture to alias to multiple toolchains
In reply to Simon GlassSome archs have need than one alias, so support a list of alises in the ..buildman file.
---
tools/buildman/README | 5 +++-- tools/buildman/test.py | 15 +++++++++++++++ tools/buildman/toolchain.py | 8 +++++--- 3 files changed, 23 insertions(+), 5 deletions(-)
tools/buildman/README +3 -2
@@ -701,8 +701,9 @@ a set of (tag, value) pairs. This converts toolchain architecture names to U-Boot names. For example, if an x86 toolchains is called i386-linux-gcc it will not normally be - used for architecture 'x86'. Adding 'x86: i386' to this section will - tell buildman that the i386 toolchain can be used for x86. + used for architecture 'x86'. Adding 'x86: i386 x86_64' to this section + will tell buildman that the i386 and x86_64 toolchains can be used for + the x86 architecture. '[make-flags]' section
tools/buildman/test.py +15 -0
@@ -394,5 +394,20 @@ class TestBuild(unittest.TestCase): build.commit_count = 0 self.CheckDirs(build, '') + def testToolchainAliases(self): + self.assertTrue(self.toolchains.Select('arm') != None) + with self.assertRaises(ValueError): + self.toolchains.Select('no-arch') + with self.assertRaises(ValueError): + self.toolchains.Select('x86') + + self.toolchains = toolchain.Toolchains() + self.toolchains.Add('x86_64-linux-gcc', test=False) + self.assertTrue(self.toolchains.Select('x86') != None) + + self.toolchains = toolchain.Toolchains() + self.toolchains.Add('i386-linux-gcc', test=False) + self.assertTrue(self.toolchains.Select('x86') != None) + if __name__ == "__main__": unittest.main()
tools/buildman/toolchain.py +5 -3
@@ -185,9 +185,11 @@ class Toolchains: returns: toolchain object, or None if none found """ - for name, value in bsettings.GetItems('toolchain-alias'): - if arch == name: - arch = value + for tag, value in bsettings.GetItems('toolchain-alias'): + if arch == tag: + for alias in value.split(): + if alias in self.toolchains: + return self.toolchains[alias] if not arch in self.toolchains: raise ValueError, ("No tool chain found for arch '%s'" % arch)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 16/17 buildman: Add the option to download toolchains from kernel.org
In reply to Simon GlassThe site at https://www.kernel.org/pub/tools/crosstool/ is a convenient repository of toolchains which can be used for U-Boot. Add a feature to download and install a toolchain for a selected architecture automatically.
It isn't clear how long this site will stay in the current place and format, but we should be able to rely on bug reports if it changes.
---
tools/buildman/README | 47 ++++++++- tools/buildman/bsettings.py | 10 ++ tools/buildman/cmdline.py | 4 + tools/buildman/control.py | 16 +++ tools/buildman/test.py | 6 ++ tools/buildman/toolchain.py | 233 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 303 insertions(+), 13 deletions(-)
tools/buildman/README +44 -3
@@ -173,9 +173,9 @@ to build x86 commits. 3. Make sure you have the require Python pre-requisites -Buildman uses multiprocessing, Queue, shutil, StringIO and ConfigParser. -These should normally be available, but if you get an error like this then -you will need to obtain those modules: +Buildman uses multiprocessing, Queue, shutil, StringIO, ConfigParser and +urllib2. These should normally be available, but if you get an error like +this then you will need to obtain those modules: ImportError: No module named multiprocessing
@@ -310,6 +310,47 @@ You can see that everything is covered, even some strange ones that won't be used (c88 and c99). This is a feature. +5. Install new toolchains if needed + +You can download toolchains and update the [toolchain] section of the +settings file to find them. + +To make this easier, buildman can automatically download and install +toolchains from kernel.org. First list the available architectures: + +$ ./tools/buildman/buildman sandbox --fetch-arch list +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/ +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.2/ +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1/ +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.2.4/ +Available architectures: alpha am33_2.0 arm avr32 bfin cris crisv32 frv h8300 +hppa hppa64 i386 ia64 m32r m68k mips mips64 or32 powerpc powerpc64 s390x sh4 +sparc sparc64 tilegx x86_64 xtensa + +Then pick one and download it: + +$ ./tools/buildman/buildman sandbox --fetch-arch or32 +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/ +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.2/ +Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1/ +Downloading: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1//x86_64-gcc-4.5.1-nolibc_or32-linux.tar.xz +Unpacking to: /home/sjg/.buildman-toolchains +Testing + - looking in '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/.' + - looking in '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/bin' + - found '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/bin/or32-linux-gcc' +Tool chain test: OK + +Buildman should now be set up to use your new toolchain. + +At the time of writing, U-Boot has these architectures: + + arc, arm, avr32, blackfin, m68k, microblaze, mips, nds32, nios2, openrisc + powerpc, sandbox, sh, sparc, x86 + +Of these, only arc, microblaze and nds32 are not available at kernel.org.. + + How to run it =============
tools/buildman/bsettings.py +10 -0
@@ -43,3 +43,13 @@ def GetItems(section): return [] except: raise + +def SetItem(section, tag, value): + """Set an item and write it back to the settings file""" + global settings + global config_fname + + settings.set(section, tag, value) + if config_fname is not None: + with open(config_fname, 'w') as fd: + settings.write(fd)
tools/buildman/cmdline.py +4 -0
@@ -36,6 +36,10 @@ def ParseArgs(): parser.add_option('-F', '--force-build-failures', dest='force_build_failures', action='store_true', default=False, help='Force build of previously-failed build') + parser.add_option('--fetch-arch', type='string', + help="Fetch a toolchain for architecture FETCH_ARCH ('list' to list)." + ' You can also fetch several toolchains separate by comma, or' + " 'all' to download all") parser.add_option('-g', '--git', type='string', help='Git repo containing branch to build', default='.') parser.add_option('-G', '--config-file', type='string',
tools/buildman/control.py +16 -0
@@ -118,6 +118,22 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, print return 0 + if options.fetch_arch: + if options.fetch_arch == 'list': + sorted_list = toolchains.ListArchs() + print 'Available architectures: %s\n' % ' '.join(sorted_list) + return 0 + else: + fetch_arch = options.fetch_arch + if fetch_arch == 'all': + fetch_arch = ','.join(toolchains.ListArchs()) + print 'Downloading toolchains: %s\n' % fetch_arch + for arch in fetch_arch.split(','): + ret = toolchains.FetchAndInstall(arch) + if ret: + return ret + return 0 + # Work out how many commits to build. We want to build everything on the # branch. We also build the upstream commit as a control so we can see # problems introduced by the first commit on the branch.
tools/buildman/test.py +6 -0
@@ -409,5 +409,11 @@ class TestBuild(unittest.TestCase): self.toolchains.Add('i386-linux-gcc', test=False) self.assertTrue(self.toolchains.Select('x86') != None) + def testToolchainDownload(self): + """Test that we can download toolchains""" + self.assertEqual('https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/x86_64-gcc-4.6.3-nolibc_arm-unknown-linux-gnueabi.tar..xz', + self.toolchains.LocateArchUrl('arm')) + + if __name__ == "__main__": unittest.main()
tools/buildman/toolchain.py +223 -10
280 lines not on this page · raw message
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH 17/17 buildman: Add an option to write the full build output
In reply to Simon GlassNormally buildman runs with 'make -s' meaning that only errors and warnings appear in the log file. Add a -V option to run make in verbose mode, and with V=1, causing a full build log to be created.
---
tools/buildman/builder.py | 4 +++- tools/buildman/builderthread.py | 3 ++- tools/buildman/cmdline.py | 2 ++ tools/buildman/control.py | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-)
tools/buildman/builder.py +3 -1
@@ -175,7 +175,7 @@ class Builder: def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs, gnu_make='make', checkout=True, show_unknown=True, step=1, - no_subdirs=False, full_path=False): + no_subdirs=False, full_path=False, verbose_build=False): """Create a new Builder object Args:
@@ -193,6 +193,7 @@ class Builder: source for a single board full_path: Return the full path in CROSS_COMPILE and don't set PATH + verbose_build: Run build with V=1 and don't use 'make -s' """ self.toolchains = toolchains self.base_dir = base_dir
@@ -220,6 +221,7 @@ class Builder: self._error_lines = 0 self.no_subdirs = no_subdirs self.full_path = full_path + self.verbose_build = verbose_build self.col = terminal.Color()
tools/buildman/builderthread.py +2 -1
@@ -197,7 +197,8 @@ class BuilderThread(threading.Thread): src_dir = os.getcwd() else: args.append('O=build') - args.append('-s') + if not self.builder.verbose_build: + args.append('-s') if self.builder.num_jobs is not None: args.extend(['-j', str(self.builder.num_jobs)]) config_args = ['%s_defconfig' % brd.target]
tools/buildman/cmdline.py +2 -0
@@ -82,6 +82,8 @@ def ParseArgs(): default=False, help='Show boards with unknown build result') parser.add_option('-v', '--verbose', action='store_true', default=False, help='Show build results while the build progresses') + parser.add_option('-V', '--verbose-build', action='store_true', + default=False, help='Run make with V=1, showing all output') parser.add_option('-x', '--exclude', dest='exclude', type='string', action='append', help='Specify a list of boards to exclude, separated by comma')
tools/buildman/control.py +2 -1
@@ -246,7 +246,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, builder = Builder(toolchains, output_dir, options.git_dir, options.threads, options.jobs, gnu_make=gnu_make, checkout=True, show_unknown=options.show_unknown, step=options.step, - no_subdirs=options.no_subdirs, full_path=options.full_path) + no_subdirs=options.no_subdirs, full_path=options.full_path, + verbose_build=options.verbose_build) builder.force_config_on_failure = not options.quick if make_func: builder.do_make = make_func
Signature · 1 line
2.2.0.rc0.207.ga3a616c
cover buildman: A few more features and improvements (Christmas edition)
In reply to Simon GlassHi,
Quoted 11 lines · Simon Glass
Various people (on CC) have suggested improvements and reported bugs in buildman. I've done a pass through these and this series is the result. In summary the main changes are:
- Flatten the output tree for 'current source builds'
- Improve docs to talk about Python environment and ~/.buildman file
- Toolchain path improvements and changes
- Download and install a new toolchain automatically
- Guess the upstream commit instead of requiring it to be set
- Access to the full build output
- Support for building an arbitrary range of commits
This series is available at u-boot-x86/buildman-working.
Regards,
Simon
cover buildman: A few more features and improvements (Christmas edition)
Hi,
Quoted 15 lines · Simon Glass
Hi,
Quoted 11 lines · Simon Glass
Various people (on CC) have suggested improvements and reported bugs in buildman. I've done a pass through these and this series is the result. In summary the main changes are:
- Flatten the output tree for 'current source builds'
- Improve docs to talk about Python environment and ~/.buildman file
- Toolchain path improvements and changes
- Download and install a new toolchain automatically
- Guess the upstream commit instead of requiring it to be set
- Access to the full build output
- Support for building an arbitrary range of commits
Quoted 4 lines
This series is available at u-boot-x86/buildman-working.
Regards,
Simon
Any testing on this? We could perhaps apply some of the doc updates and fixes for this release.
Regards,
Simon
cover buildman: A few more features and improvements (Christmas edition)
good improvements -- and it fixes my issues....
Thanks!
(tested buildman-working 6c7f1b6)
Quoted 29 lines · Simon Glass
Hi,
Quoted 15 lines · Simon Glass
Hi,
Quoted 11 lines · Simon Glass
Various people (on CC) have suggested improvements and reported bugs in buildman. I've done a pass through these and this series is the result. In summary the main changes are:
- Flatten the output tree for 'current source builds'
- Improve docs to talk about Python environment and ~/.buildman file
- Toolchain path improvements and changes
- Download and install a new toolchain automatically
- Guess the upstream commit instead of requiring it to be set
- Access to the full build output
- Support for building an arbitrary range of commitsQuoted 4 lines
This series is available at u-boot-x86/buildman-working.
Regards,
SimonAny testing on this? We could perhaps apply some of the doc updates and fixes for this release.
Regards,
Simon