summaryrefslogtreecommitdiffstats
path: root/bin/metabuild
blob: 4f1f509cd426ee8a586a7289978d443c250f49e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/python

# metabuild: Generic build system wrapper
# Copyright 2010 Colin Walters <walters@verbum.org>
# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)

# metabuild currently just wraps autotools (configure+make).
# To use it, you must first use the "inroot" tool to enter an alternative
# buildroot.
#
# $ inroot /path/to/buildroot bash
#
# Next, just type:
# $ metabuild
# This will:
#  1) Run ./configure if necessary
#  2) Run make
#
# The build output is automatically logged to $TMPDIR/build-$(PWD).log.
# For example, invoking metabuild in a directory named "foo" will log
# to /tmp/build-foo.log
#
# You can pass arguments to metabuild; if they start with '--', they're
# given to configure.  Otherwise, they're passed to make.
#
# $ metabuild --enable-libfoo  # passed to configure
# $ metabuild -j 1             # passed to make

import os,sys,subprocess,tempfile
from multiprocessing import cpu_count
import glib,gio

if 'INROOT_DIR' not in os.environ:
    print "INROOT_DIR not set; run under inroot"
    sys.exit(1)
root = os.environ['INROOT_DIR']
if os.path.isdir('/lib64'):
    libdir=os.path.join(root, 'lib64')
else:
    libdir=os.path.join(root, 'lib')

configargs = ['--prefix=' + root, '--libdir=' + libdir]
makeargs = ['make', '-j', '%d' % (cpu_count() * 2, )]
for arg in sys.argv[1:]:
    if arg.startswith('--'):
        configargs.append(arg)
    else:
        makeargs.append(arg)

have_configure=(os.path.exists('configure.ac') or os.path.exists('configure.in'))
if have_configure and not os.path.exists('configure'):
    if os.path.exists('autogen.sh'):
        args = ['./autogen.sh']
        args.extend(configargs)
        subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr)
    else:
        subprocess.check_call(['autoreconf', '-f', '-i'], stdout=sys.stdout, stderr=sys.stderr)
        args = ['./configure']
        args.extend(configargs)
        subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr)
prefix_matches=True
if have_configure and os.path.exists('config.log'):
    previous_prefix = None
    f = open('config.log')
    for line in f:
        if line.startswith('prefix=\''):
            previous_prefix = line[8:-2]
            break
    f.close()
    if previous_prefix != root:
        print "Reruning configure due to prefix change (%r -> %r)" % (root, previous_prefix)
        prefix_matches=False

if have_configure and (not os.path.exists('Makefile') or not prefix_matches):
    args = ['./configure']
    args.extend(configargs)
    subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr)

class Tail(object):
    def __init__(self, filename, output):
        self.filename = filename
        self.output = output
        self._gfile = gio.File(path=filename)
        self._mon = self._gfile.monitor(gio.FILE_MONITOR_NONE)
        self._fd = os.open(self.filename, os.O_RDONLY)
        self._position = 0
        self._mon.connect('changed', self._on_changed)
        self._do_read()

    def _do_read(self):
        buf = os.read(self._fd, 8192)
        while buf != '':
            self._position += len(buf)
            self.output.write(buf)
            buf = os.read(self._fd, 8192)

    def _on_changed(self, mon, gfile, other, event):
        self._do_read()

    def finish(self):
        self._do_read()

loop = glib.MainLoop()
build_condition = None

tempdir = os.environ.get('TMPDIR', '/tmp')
logfile_path = os.path.join(tempdir, 'build-%s.log' % (os.path.basename(os.getcwd()), ))
try:
    os.unlink(logfile_path)
except OSError, e:
    pass
logfile_write_fd = os.open(logfile_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
sys.stdout.write('metabuild: logging to %r\n' % (logfile_path, ))
sys.stdout.flush()
def child_setup(*args):
    os.dup2(logfile_write_fd, 1)
    os.dup2(logfile_write_fd, 2)
(make_pid, stdin_fd, stdout_fd, stderr_fd) = \
    glib.spawn_async(makeargs,
                     flags=(glib.SPAWN_DO_NOT_REAP_CHILD | glib.SPAWN_SEARCH_PATH),
                     child_setup=child_setup)
os.close(logfile_write_fd)
tail = Tail(logfile_path, sys.stdout)
def on_child(pid, condition):
    global loop
    global build_condition
    build_condition = condition
    loop.quit()
glib.child_watch_add(make_pid, on_child)
loop.run()
tail.finish()
print "metabuild: make exited with status %r, logfile=%r" % (build_condition, logfile_path)
sys.exit(0 if build_condition == 0 else 1)