source: rtems-source-builder/source-builder/sb/bootstrap.py @ d897e93

4.104.9
Last change on this file since d897e93 was d897e93, checked in by Chris Johns <chrisj@…>, on Feb 24, 2016 at 3:18:42 AM

Fix sb-bootrap to run on Windows using MSYS2.

Prepend 'sh' to the command so the autoreconf runs in a shell.

Is the first item in the path is a reference to MSYS2 remove it.

Closes #2613.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19#
20
21import datetime
22import operator
23import os
24import re
25import sys
26import threading
27import time
28
29import error
30import log
31import options
32import path
33import version
34
35def _collect(path_, file):
36    confs = []
37    for root, dirs, files in os.walk(path.host(path_), topdown = True):
38        for f in files:
39            if f == file:
40                confs += [path.shell(path.join(root, f))]
41    return confs
42
43def _grep(file, pattern):
44    rege = re.compile(pattern)
45    try:
46        f = open(path.host(file), 'r')
47        matches = [rege.match(l) != None for l in f.readlines()]
48        f.close()
49    except IOError, err:
50        raise error.general('reading: %s' % (file))
51    return True in matches
52
53class command:
54
55    def __init__(self, cmd, cwd):
56        self.exit_code = 0
57        self.thread = None
58        self.output = None
59        self.cmd = cmd
60        self.cwd = cwd
61        self.result = None
62
63    def runner(self):
64
65        import subprocess
66
67        #
68        # Support Python 2.6
69        #
70        if "check_output" not in dir(subprocess):
71            def f(*popenargs, **kwargs):
72                if 'stdout' in kwargs:
73                    raise ValueError('stdout argument not allowed, it will be overridden.')
74                process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
75                output, unused_err = process.communicate()
76                retcode = process.poll()
77                if retcode:
78                    cmd = kwargs.get("args")
79                    if cmd is None:
80                        cmd = popenargs[0]
81                    raise subprocess.CalledProcessError(retcode, cmd)
82                return output
83            subprocess.check_output = f
84
85        self.start_time = datetime.datetime.now()
86        self.exit_code = 0
87        try:
88            try:
89                if os.name == 'nt':
90                    cmd = ['sh', '-c'] + self.cmd
91                else:
92                    cmd = self.cmd
93                self.output = subprocess.check_output(cmd, cwd = path.host(self.cwd))
94            except subprocess.CalledProcessError, cpe:
95                self.exit_code = cpe.returncode
96                self.output = cpe.output
97            except OSError, ose:
98                raise error.general('bootstrap failed: %s in %s: %s' % \
99                                        (' '.join(cmd), path.host(self.cwd), (str(ose))))
100            except KeyboardInterrupt:
101                pass
102            except:
103                raise
104        except:
105            self.result = sys.exc_info()
106        self.end_time = datetime.datetime.now()
107
108    def run(self):
109        self.thread = threading.Thread(target = self.runner)
110        self.thread.start()
111
112    def is_alive(self):
113        return self.thread and self.thread.is_alive()
114
115    def reraise(self):
116        if self.result is not None:
117            raise self.result[0], self.result[1], self.result[2]
118
119class autoreconf:
120
121    def __init__(self, topdir, configure):
122        self.topdir = topdir
123        self.configure = configure
124        self.cwd = path.dirname(self.configure)
125        self.bspopts()
126        self.command = command(['autoreconf', '-i', '--no-recursive'], self.cwd)
127        self.command.run()
128
129    def bspopts(self):
130        if _grep(self.configure, 'RTEMS_CHECK_BSPDIR'):
131            bsp_specs = _collect(self.cwd, 'bsp_specs')
132            try:
133                acinclude = path.join(self.cwd, 'acinclude.m4')
134                b = open(path.host(acinclude), 'w')
135                b.write('# RTEMS_CHECK_BSPDIR(RTEMS_BSP_FAMILY)' + os.linesep)
136                b.write('AC_DEFUN([RTEMS_CHECK_BSPDIR],' + os.linesep)
137                b.write('[' + os.linesep)
138                b.write('  case "$1" in' + os.linesep)
139                for bs in sorted(bsp_specs):
140                    dir = path.dirname(bs)[len(self.cwd) + 1:]
141                    b.write(%s )%s' % (dir, os.linesep))
142                    b.write('    AC_CONFIG_SUBDIRS([%s]);;%s' % (dir, os.linesep))
143                b.write('  *)' + os.linesep)
144                b.write('    AC_MSG_ERROR([Invalid BSP]);;' + os.linesep)
145                b.write('  esac' + os.linesep)
146                b.write('])' + os.linesep)
147                b.close()
148            except IOError, err:
149                raise error.general('writing: %s' % (acinclude))
150
151    def is_alive(self):
152        return self.command.is_alive()
153
154    def post_process(self):
155        if self.command is not None:
156            self.command.reraise()
157            if self.command.exit_code != 0:
158                raise error.general('error: autoreconf: %s' % (' '.join(self.command.cmd)))
159            makefile = path.join(self.cwd, 'Makefile.am')
160            if path.exists(makefile):
161                if _grep(makefile, 'stamp-h\.in'):
162                    stamp_h = path.join(self.cwd, 'stamp-h.in')
163                    try:
164                        t = open(path.host(stamp_h), 'w')
165                        t.write('timestamp')
166                        t.close()
167                    except IOError, err:
168                        raise error.general('writing: %s' % (stamp_h))
169
170def generate(topdir, jobs):
171    if type(jobs) is str:
172        jobs = int(jobs)
173    start_time = datetime.datetime.now()
174    confs = _collect(topdir, 'configure.ac')
175    next = 0
176    autoreconfs = []
177    while next < len(confs) or len(autoreconfs) > 0:
178        if next < len(confs) and len(autoreconfs) < jobs:
179            log.notice('%3d/%3d: autoreconf: %s' % \
180                           (next + 1, len(confs), confs[next][len(topdir) + 1:]))
181            autoreconfs += [autoreconf(topdir, confs[next])]
182            next += 1
183        else:
184            for ac in autoreconfs:
185                if not ac.is_alive():
186                    ac.post_process()
187                    autoreconfs.remove(ac)
188                    del ac
189            if len(autoreconfs) >= jobs:
190                time.sleep(1)
191    end_time = datetime.datetime.now()
192    log.notice('Bootstrap time: %s' % (str(end_time - start_time)))
193
194class ampolish3:
195
196    def __init__(self, topdir, makefile):
197        self.topdir = topdir
198        self.makefile = makefile
199        self.preinstall = path.join(path.dirname(makefile), 'preinstall.am')
200        self.command = command([path.join(topdir, 'ampolish3'), makefile], self.topdir)
201        self.command.run()
202
203    def is_alive(self):
204        return self.command.is_alive()
205
206    def post_process(self):
207        if self.command is not None:
208            if self.command.exit_code != 0:
209                raise error.general('error: ampolish3: %s' % (' '.join(self.command.cmd)))
210            try:
211                p = open(path.host(self.preinstall), 'w')
212                for l in self.command.output:
213                    p.write(l)
214                p.close()
215            except IOError, err:
216                raise error.general('writing: %s' % (self.preinstall))
217
218def preinstall(topdir, jobs):
219    if type(jobs) is str:
220        jobs = int(jobs)
221    start_time = datetime.datetime.now()
222    makes = []
223    for am in _collect(topdir, 'Makefile.am'):
224        if _grep(am, 'include .*/preinstall\.am'):
225            makes += [am]
226    next = 0
227    ampolish3s = []
228    while next < len(makes) or len(ampolish3s) > 0:
229        if next < len(makes) and len(ampolish3s) < jobs:
230            log.notice('%3d/%3d: ampolish3: %s' % \
231                           (next + 1, len(makes), makes[next][len(topdir) + 1:]))
232            ampolish3s += [ampolish3(topdir, makes[next])]
233            next += 1
234        else:
235            for ap in ampolish3s:
236                if not ap.is_alive():
237                    ap.post_process()
238                    ampolish3s.remove(ap)
239                    del ap
240            if len(ampolish3s) >= jobs:
241                time.sleep(1)
242    end_time = datetime.datetime.now()
243    log.notice('Preinstall time: %s' % (str(end_time - start_time)))
244
245def run(args):
246    try:
247        #
248        # On Windows MSYS2 prepends a path to itself to the environment
249        # path. This means the RTEMS specific automake is not found and which
250        # breaks the bootstrap. We need to remove the prepended path. Also
251        # remove any ACLOCAL paths from the environment.
252        #
253        if os.name == 'nt':
254            cspath = os.environ['PATH'].split(os.pathsep)
255            if 'msys' in cspath[0] and cspath[0].endswith('bin'):
256                os.environ['PATH'] = os.pathsep.join(cspath[1:])
257            if 'ACLOCAL_PATH' in os.environ:
258                os.environ['ACLOCAL_PATH'].clear()
259        optargs = { '--rtems':       'The RTEMS source directory',
260                    '--preinstall':  'Preinstall AM generation' }
261        log.notice('RTEMS Source Builder - RTEMS Bootstrap, %s' % (version.str()))
262        opts = options.load(sys.argv, optargs)
263        if opts.get_arg('--rtems'):
264            topdir = opts.get_arg('--rtems')
265        else:
266            topdir = os.getcwd()
267        if opts.get_arg('--preinstall'):
268            preinstall(topdir, opts.jobs(opts.defaults['_ncpus']))
269        else:
270            generate(topdir, opts.jobs(opts.defaults['_ncpus']))
271    except error.general, gerr:
272        print gerr
273        print >> sys.stderr, 'Bootstrap FAILED'
274        sys.exit(1)
275    except error.internal, ierr:
276        print ierr
277        print >> sys.stderr, 'Bootstrap FAILED'
278        sys.exit(1)
279    except error.exit, eerr:
280        pass
281    except KeyboardInterrupt:
282        log.notice('abort: user terminated')
283        sys.exit(1)
284    sys.exit(0)
285
286if __name__ == "__main__":
287    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.