From f7a4107c6f2e6c8231b606e38af5adb31178a342 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 28 Nov 2016 14:23:15 +1100 Subject: Add a RTEMS Debugger TCP remote transport. The patch also adds support to libbsd's build system making source conditional on a configure check. The debugger support is not available on all architectures and this feature lets us test if is avaliable. --- libbsd.py | 8 + libbsd_waf.py | 27 +- rtemsbsd/debugger/rtems-debugger-remote-tcp.c | 342 +++++++++++++++++++++ rtemsbsd/include/rtems/rtems-debugger-remote-tcp.h | 47 +++ testsuite/debugger01/test_main.c | 71 +++++ waf_generator.py | 261 +++++++++++----- 6 files changed, 670 insertions(+), 86 deletions(-) create mode 100644 rtemsbsd/debugger/rtems-debugger-remote-tcp.c create mode 100644 rtemsbsd/include/rtems/rtems-debugger-remote-tcp.h create mode 100644 testsuite/debugger01/test_main.c diff --git a/libbsd.py b/libbsd.py index a8cbd339..36851919 100755 --- a/libbsd.py +++ b/libbsd.py @@ -163,6 +163,12 @@ def rtems(mm): ], mm.generator['source']() ) + mod.addRTEMSSourceFiles( + [ + 'debugger/rtems-debugger-remote-tcp.c', + ], + mm.generator['source-if-header']('rtems/rtems-debugger.h') + ) mod.addFile(mm.generator['file']('rtems/rtems-kernel-kvm-symbols.c', mm.generator['rtems-path'](), mm.generator['no-convert'](), @@ -2559,6 +2565,8 @@ def tests(mm): mod.addTest(mm.generator['test']('cdev01', ['test_main', 'test_cdev'])) mod.addTest(mm.generator['test']('pf01', ['test_main'])) mod.addTest(mm.generator['test']('pf02', ['test_main'], runTest = False)) + mod.addTest(mm.generator['test-if-header']('debugger01', 'rtems/rtems-debugger.h', + ['test_main'], runTest = False, netTest = True)) return mod # diff --git a/libbsd_waf.py b/libbsd_waf.py index 32b8b132..7ea6a369 100644 --- a/libbsd_waf.py +++ b/libbsd_waf.py @@ -26,10 +26,10 @@ def options(opt): pass def bsp_configure(conf, arch_bsp): - pass + conf.check(header_name = "rtems/rtems-debugger.h", features = "c", includes = conf.env.IFLAGS, mandatory = False) def configure(conf): - pass + rtems.configure(conf, bsp_configure) def build(bld): # C/C++ flags @@ -455,7 +455,7 @@ def build(bld): features = "c", cflags = cflags, includes = [] + includes, - defines = defines + ['NO_SSL', 'NO_POPEN', 'NO_CGI', 'USE_WEBSOCKET'], + defines = defines + ['NO_CGI', 'NO_POPEN', 'NO_SSL', 'USE_WEBSOCKET'], source = objs02_source) libbsd_use += ["objs02"] @@ -487,7 +487,7 @@ def build(bld): features = "c", cflags = cflags, includes = [] + includes, - defines = defines + ['__DBINTERFACE_PRIVATE', 'INET6'], + defines = defines + ['INET6', '__DBINTERFACE_PRIVATE'], source = objs03_source) libbsd_use += ["objs03"] @@ -517,7 +517,7 @@ def build(bld): features = "c", cflags = cflags, includes = [] + includes, - defines = defines + ['__FreeBSD__', 'THERE_IS_NO_FORK', 'MASTER_ONLY', 'INET', 'INET6'], + defines = defines + ['INET', 'INET6', 'MASTER_ONLY', 'THERE_IS_NO_FORK', '__FreeBSD__'], source = objs04_source) libbsd_use += ["objs04"] @@ -538,7 +538,7 @@ def build(bld): features = "c", cflags = cflags, includes = [] + includes, - defines = defines + ['__FreeBSD__=1', 'BSD=1', 'INET6', '_U_=__attribute__((unused))', 'HAVE_LIMITS_H=1', 'HAVE_INTTYPES=1', 'HAVE_STDINT=1', 'HAVE_STRERROR=1', 'HAVE_STRLCPY=1', 'HAVE_SNPRINTF=1', 'HAVE_VSNPRINTF=1', 'HAVE_SOCKADDR_SA_LEN=1', 'HAVE_NET_IF_MEDIA_H=1', 'HAVE_SYS_IOCCOM_H=1'], + defines = defines + ['BSD=1', 'HAVE_INTTYPES=1', 'HAVE_LIMITS_H=1', 'HAVE_NET_IF_MEDIA_H=1', 'HAVE_SNPRINTF=1', 'HAVE_SOCKADDR_SA_LEN=1', 'HAVE_STDINT=1', 'HAVE_STRERROR=1', 'HAVE_STRLCPY=1', 'HAVE_SYS_IOCCOM_H=1', 'HAVE_VSNPRINTF=1', 'INET6', '_U_=__attribute__((unused))', '__FreeBSD__=1'], source = objs05_source) libbsd_use += ["objs05"] @@ -689,7 +689,7 @@ def build(bld): features = "c", cflags = cflags, includes = ['freebsd/contrib/tcpdump', 'freebsd/usr.sbin/tcpdump/tcpdump'] + includes, - defines = defines + ['__FreeBSD__=1', 'INET6', '_U_=__attribute__((unused))', 'HAVE_CONFIG_H=1', 'HAVE_NET_PFVAR_H=1'], + defines = defines + ['HAVE_CONFIG_H=1', 'HAVE_NET_PFVAR_H=1', 'INET6', '_U_=__attribute__((unused))', '__FreeBSD__=1'], source = objs06_source) libbsd_use += ["objs06"] @@ -1140,6 +1140,8 @@ def build(bld): 'rtemsbsd/telnetd/telnetd-init.c', 'rtemsbsd/telnetd/telnetd-service.c', 'rtemsbsd/telnetd/telnetd.c'] + if bld.env["HAVE_RTEMS_RTEMS_DEBUGGER_H"]: + source += ['rtemsbsd/debugger/rtems-debugger-remote-tcp.c'] if bld.get_env()["RTEMS_ARCH"] == "arm": source += ['freebsd/sys/mips/mips/in_cksum.c'] if bld.get_env()["RTEMS_ARCH"] == "avr": @@ -1256,6 +1258,17 @@ def build(bld): lib = ["m", "z"], install_path = None) + if bld.env["HAVE_RTEMS_RTEMS_DEBUGGER_H"]: + test_debugger01 = ['testsuite/debugger01/test_main.c'] + bld.program(target = "debugger01.exe", + features = "cprogram", + cflags = cflags, + includes = includes, + source = test_debugger01, + use = ["bsd"], + lib = ["m", "z"], + install_path = None) + test_dhcpcd01 = ['testsuite/dhcpcd01/test_main.c'] bld.program(target = "dhcpcd01.exe", features = "cprogram", diff --git a/rtemsbsd/debugger/rtems-debugger-remote-tcp.c b/rtemsbsd/debugger/rtems-debugger-remote-tcp.c new file mode 100644 index 00000000..af222e00 --- /dev/null +++ b/rtemsbsd/debugger/rtems-debugger-remote-tcp.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2016 Chris Johns . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/** + * Debugger default server port. 'RT' as ASCII. + */ +#define RTEMS_DB_PORT_DEFAULT (8284) + +/** + * TCP Remote data. + */ +typedef struct +{ + int fd; + int port; +} rtems_debugger_remote_tcp; + +static rtems_debugger_remote_tcp* +tcp_remote(rtems_debugger_remote* remote) +{ + rtems_debugger_remote_tcp* tcp = NULL; + rtems_debugger_lock(); + if (remote != NULL && remote->data != NULL) + tcp = (rtems_debugger_remote_tcp*) remote->data; + rtems_debugger_unlock(); + return tcp; +} + +static int +tcp_remote_begin(rtems_debugger_remote* remote, const char* device) +{ + rtems_debugger_remote_tcp* tcp; + int port; + char* end; + + rtems_debugger_lock(); + + /* + * Parse the port number. + */ + port = strtoul(device, &end, 10); + if (port == 0 || *end != '\0') { + rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device); + return -1; + } + + tcp = malloc(sizeof(rtems_debugger_remote_tcp)); + if (tcp == NULL) { + errno = ENOMEM; + return -1; + } + + remote->data = tcp; + + tcp->fd = -1; + tcp->port = port; + + rtems_debugger_unlock(); + + return 0; +} + +static int +tcp_remote_end(rtems_debugger_remote* remote) +{ + rtems_debugger_lock(); + + if (remote != NULL && remote->data != NULL) { + rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data; + if (tcp != NULL) { + if (tcp->fd >= 0) + close(tcp->fd); + free(tcp); + remote->data = NULL; + } + } + + rtems_debugger_unlock(); + + return 0; +} + +static int +tcp_remote_connect(rtems_debugger_remote* remote) +{ + int ld; + struct sockaddr_in addr; + socklen_t opt; + socklen_t len; + bool running; + struct timeval timeout; + rtems_debugger_remote_tcp* tcp = tcp_remote(remote); + int r; + + if (rtems_debugger_verbose()) + rtems_debugger_printf("error: rtems-db: tcp remote: connect\n"); + + ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (ld < 0) { + rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + + opt = 1; + r = setsockopt(ld, + SOL_SOCKET, + SO_REUSEADDR, + (char *) &opt, + sizeof(opt)); + if (r < 0) { + close(ld); + rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + + addr.sin_family = PF_INET; + addr.sin_port = htons(tcp->port); + addr.sin_addr.s_addr = INADDR_ANY; + + r = bind(ld, (struct sockaddr *) &addr, sizeof(addr)); + if (r < 0) { + close(ld); + rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + + /* + * Backlog of 1 connection. + */ + r = listen(ld, 1); + if (r < 0) { + close(ld); + rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + + /* + * Use a random port if the port is 0. + */ + if (tcp->port == 0) { + len = sizeof(addr); + r = getsockname(ld, (struct sockaddr *) &addr, &len); + if (r < 0 || len < sizeof(addr)) { + close(ld); + rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + tcp->port = ntohs(addr.sin_port); + } + + rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n", + tcp->port); + + len = sizeof(addr); + tcp->fd = accept(ld, (struct sockaddr *) &addr, &len); + + running = rtems_debugger_server_running(); + + close(ld); + + if (tcp->fd < 0) { + /* + * EBADF means the socket has been closed, ignore it. + */ + if (errno != EBADF) + rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n", + errno, strerror(errno)); + return -1; + } + + if (!running) { + close(tcp->fd); + errno = EIO; + return -1; + } + + opt = 1; + r = setsockopt(tcp->fd, + SOL_SOCKET, SO_KEEPALIVE, + (char*) &opt, + sizeof(opt)); + if (r < 0) { + int errno_ = errno; + close(tcp->fd); + rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n", + errno, strerror(errno)); + errno = errno_; + return -1; + } + + opt = 1; + r = setsockopt(tcp->fd, + IPPROTO_TCP, TCP_NODELAY, + (char*) &opt, sizeof(opt)); + if (r < 0) { + int errno_ = errno; + close(tcp->fd); + rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n", + errno, strerror(errno)); + errno = errno_; + return -1; + } + + timeout.tv_sec = rtems_debugger->timeout; + timeout.tv_usec = 0; + + r = setsockopt(tcp->fd, + SOL_SOCKET, SO_RCVTIMEO, + (char*) &timeout, sizeof(timeout)); + if (r < 0) { + int errno_ = errno; + close(tcp->fd); + rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n", + errno, strerror(errno)); + errno = errno_; + return -1; + } + + rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n", + inet_ntoa(addr.sin_addr)); + + return 0; +} + +static int +tcp_remote_disconnect(rtems_debugger_remote* remote) +{ + rtems_debugger_remote_tcp* tcp; + + rtems_debugger_lock(); + + rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n"); + + tcp = (rtems_debugger_remote_tcp*) remote->data; + close(tcp->fd); + + rtems_debugger_unlock(); + + return 0; +} + +static bool +tcp_remote_isconnected(rtems_debugger_remote* remote) +{ + rtems_debugger_remote_tcp* tcp = tcp_remote(remote); + return tcp != NULL && tcp->fd >= 0; +} + +static ssize_t +tcp_remote_receive(rtems_debugger_remote* remote, + void* buf, + size_t nbytes) +{ + rtems_debugger_remote_tcp* tcp = tcp_remote(remote); + ssize_t len; + if (tcp != NULL) { + len = read(tcp->fd, buf, nbytes); + } + else { + errno = EIO; + len = -1; + } + return len; +} + +static ssize_t +tcp_remote_send(rtems_debugger_remote* remote, + const void* buf, + size_t nbytes) +{ + rtems_debugger_remote_tcp* tcp = tcp_remote(remote); + ssize_t len; + if (tcp != NULL) { + len = write(tcp->fd, buf, nbytes); + } + else { + errno = EIO; + len = -1; + } + return len; +} + +static rtems_debugger_remote remote_tcp = +{ + .name = "tcp", + .begin = tcp_remote_begin, + .end = tcp_remote_end, + .connect = tcp_remote_connect, + .disconnect = tcp_remote_disconnect, + .isconnected = tcp_remote_isconnected, + .read = tcp_remote_receive, + .write = tcp_remote_send +}; + +int +rtems_debugger_register_tcp_remote(void) +{ + return rtems_debugger_remote_register(&remote_tcp); +} diff --git a/rtemsbsd/include/rtems/rtems-debugger-remote-tcp.h b/rtemsbsd/include/rtems/rtems-debugger-remote-tcp.h new file mode 100644 index 00000000..d9d7feeb --- /dev/null +++ b/rtemsbsd/include/rtems/rtems-debugger-remote-tcp.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Chris Johns . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Debugger for RTEMS. + */ + +#ifndef _RTEMS_DEBUGGER_REMOTE_TCP_h +#define _RTEMS_DEBUGGER_REMOTE_TCP_h + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Register a remote with the server. + */ +int rtems_debugger_register_tcp_remote(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif diff --git a/testsuite/debugger01/test_main.c b/testsuite/debugger01/test_main.c new file mode 100644 index 00000000..6a4095c8 --- /dev/null +++ b/testsuite/debugger01/test_main.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Chris Johns + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#define TEST_NAME "LIBBSD DEBUGGER 1" + +extern rtems_shell_cmd_t rtems_shell_DEBUGGER_Command; + +static void +test_main(void) +{ + rtems_printer printer; + int r; + + rtems_print_printer_fprintf(&printer, stdout); + + rtems_shell_add_cmd_struct(&rtems_shell_DEBUGGER_Command); + + r = rtems_debugger_register_tcp_remote(); + if (r < 0) { + printf("error: TCP remote register: %s\n", strerror(errno)); + return; + } + + r = rtems_debugger_start("tcp", "1122", 3, 1, &printer); + if (r < 0) { + printf("error: debugger start: %s\n", strerror(errno)); + return; + } + + while (true) + sleep(60); +} + +#define DEFAULT_NETWORK_SHELL + +#define CONFIGURE_MAXIMUM_DRIVERS 32 + +#include diff --git a/waf_generator.py b/waf_generator.py index 27b8ce88..35fe35f4 100755 --- a/waf_generator.py +++ b/waf_generator.py @@ -40,6 +40,9 @@ import tempfile import builder +# +# Dump the data created from the fragments returned from the builder composers. +# trace = False data = { } @@ -72,8 +75,29 @@ class SourceFileFragmentComposer(builder.BuildSystemFragmentComposer): def compose(self, path): if None in self.includes: - return ['sources', self.cflags], [path], self.cflags, self.includes - return ['sources', self.cflags + self.includes], [path], self.cflags, self.includes + flags = self.cflags + else: + flags = self.cflags + self.includes + return ['sources', flags, ('default', None)], [path], self.cflags, self.includes + +class SourceFileIfHeaderComposer(SourceFileFragmentComposer): + + def __init__(self, headers, cflags = "default", includes = None): + if headers is not list: + headers = [headers] + self.headers = headers + super(SourceFileIfHeaderComposer, self).__init__(cflags = cflags, includes = includes) + + def compose(self, path): + r = SourceFileFragmentComposer.compose(self, path) + define_keys = '' + for h in self.headers: + h = h.upper() + for c in '\/-.': + h = h.replace(c, '_') + define_keys += ' ' + h + r[0][2] = (define_keys.strip(), self.headers) + return r class TestFragementComposer(builder.BuildSystemFragmentComposer): @@ -84,24 +108,44 @@ class TestFragementComposer(builder.BuildSystemFragmentComposer): self.netTest = netTest def compose(self, path): - return ['tests', self.testName], { 'files': self.fileFragments, - 'run': self.runTest, - 'net': self.netTest } + return ['tests', self.testName, ('default', None)], { 'files': self.fileFragments, + 'run': self.runTest, + 'net': self.netTest } + +class TestIfHeaderComposer(TestFragementComposer): + + def __init__(self, testName, headers, fileFragments, runTest = True, netTest = False): + if headers is not list: + headers = [headers] + self.headers = headers + super(TestIfHeaderComposer, self).__init__(testName, fileFragments, + runTest = runTest, netTest = netTest) + + def compose(self, path): + r = TestFragementComposer.compose(self, path) + define_keys = '' + for h in self.headers: + h = h.upper() + for c in '\/-.': + h = h.replace(c, '_') + define_keys += ' ' + h + r[0][2] = (define_keys.strip(), self.headers) + return r class KVMSymbolsFragmentComposer(builder.BuildSystemFragmentComposer): def compose(self, path): - return ['KVMSymbols', 'files'], [path], self.includes + return ['KVMSymbols', 'files', ('default', None)], [path], self.includes class RPCGENFragmentComposer(builder.BuildSystemFragmentComposer): def compose(self, path): - return ['RPCGen', 'files'], [path] + return ['RPCGen', 'files', ('default', None)], [path] class RouteKeywordsFragmentComposer(builder.BuildSystemFragmentComposer): def compose(self, path): - return ['RouteKeywords', 'files'], [path] + return ['RouteKeywords', 'files', ('default', None)], [path] class LexFragmentComposer(builder.BuildSystemFragmentComposer): @@ -118,7 +162,7 @@ class LexFragmentComposer(builder.BuildSystemFragmentComposer): d['cflags'] = self.cflags if None not in self.includes: d['includes'] = self.includes - return ['lex', path], d + return ['lex', path, ('default', None)], d class YaccFragmentComposer(builder.BuildSystemFragmentComposer): @@ -135,7 +179,7 @@ class YaccFragmentComposer(builder.BuildSystemFragmentComposer): d['cflags'] = self.cflags if None not in self.includes: d['includes'] = self.includes - return ['yacc', path], d + return ['yacc', path, ('default', None)], d # Module Manager - Collection of Modules class ModuleManager(builder.ModuleManager): @@ -171,9 +215,13 @@ class ModuleManager(builder.ModuleManager): self.generator['lex'] = LexFragmentComposer self.generator['yacc'] = YaccFragmentComposer + self.generator['source-if-header'] = SourceFileIfHeaderComposer + self.generator['test-if-header'] = TestIfHeaderComposer + def generate(self, rtems_version): - def _sourceList(lhs, files, append = False): + def _sourceListSources(lhs, sources, append = False, block = 0): + indent = block * 4 if append: adder = '+' adderSpace = ' ' @@ -181,16 +229,36 @@ class ModuleManager(builder.ModuleManager): adder = '' adderSpace = '' ll = len(lhs) - if len(files) == 1: - self.add('%s %s= [%r]' % (lhs, adder, files[0])) - elif len(files) == 2: - self.add('%s %s= [%r,' % (lhs, adder, files[0])) - self.add('%s %s %r]' % (' ' * ll, adderSpace, files[-1])) - elif len(files) > 0: - self.add('%s %s= [%r,' % (lhs, adder, files[0])) - for f in files[1:-1]: - self.add('%s %s %r,' % (' ' * ll, adderSpace, f)) - self.add('%s %s %r]' % (' ' * ll, adderSpace, files[-1])) + if len(sources) == 1: + self.add('%s%s %s= [%r]' % (' ' * indent, lhs, adder, sources[0])) + elif len(sources) == 2: + self.add('%s%s %s= [%r,' % (' ' * indent, lhs, adder, sources[0])) + self.add('%s%s %s %r]' % (' ' * indent, ' ' * ll, adderSpace, sources[-1])) + elif len(sources) > 0: + self.add('%s%s %s= [%r,' % (' ' * indent, lhs, adder, sources[0])) + for f in sources[1:-1]: + self.add('%s%s %s %r,' % (' ' * indent, ' ' * ll, adderSpace, f)) + self.add('%s%s %s %r]' % (' ' * indent, ' ' * ll, adderSpace, sources[-1])) + + def _sourceList(lhs, files, append = False): + if type(files) is dict: + appending = False + for cfg in files: + if cfg in ['cflags', 'includes']: + continue + if cfg != 'default': + cs = '' + ors = '' + for c in cfg.split(' '): + cs += '%s bld.env["HAVE_%s"]' % (ors, c) + ors = ' and' + self.add(' if%s:' % (cs)) + _sourceListSources(lhs, sorted(files[cfg]), append = appending, block = 1) + else: + _sourceListSources(lhs, sorted(files[cfg]), append) + appending = True + else: + _sourceListSources(lhs, sorted(files), append) def _dataInsert(data, cpu, frag): # @@ -213,19 +281,31 @@ class ModuleManager(builder.ModuleManager): d[p] = {} d = d[p] if cpu not in d: - d[cpu] = [] + d[cpu] = { } + config = frag[0][2][0] + if config != 'default': + if 'configure' not in data: + data['configure'] = { } + data['configure'][config] = frag[0][2][1] if type(frag[1]) is list: - d[cpu] += frag[1] + if config not in d[cpu]: + d[cpu][config] = [] + d[cpu][config] += frag[1] else: - d[cpu] = frag[1] + d[cpu][config] = frag[1] + # + # The CPU is for files and the flags and includes are common. + # if len(frag) > 3: - if 'cflags' not in d[cpu]: + if 'cflags' not in d: d['cflags'] = [] d['cflags'] += frag[2] + d['cflags'] = list(set(d['cflags'])) if len(frag) >= 3 and None not in frag[-1]: - if 'includes' not in d[cpu]: + if 'includes' not in d: d['includes'] = [] d['includes'] += frag[-1] + d['includes'] = list(set(d['includes'])) data = { } @@ -273,10 +353,17 @@ class ModuleManager(builder.ModuleManager): self.add(' pass') self.add('') self.add('def bsp_configure(conf, arch_bsp):') - self.add(' pass') + + if 'configure' in data: + for cfg in data['configure']: + for h in data['configure'][cfg]: + self.add(' conf.check(header_name = "%s", features = "c", includes = conf.env.IFLAGS, mandatory = False)' % h) + else: + self.add(' pass') + self.add('') self.add('def configure(conf):') - self.add(' pass') + self.add(' rtems.configure(conf, bsp_configure)') self.add('') self.add('def build(bld):') self.add(' # C/C++ flags') @@ -367,7 +454,7 @@ class ModuleManager(builder.ModuleManager): else: includes = [] self.add(' # KVM Symbols') - self.add(' bld(target = "%s",' % (kvmsymbols['files']['all'][0])) + self.add(' bld(target = "%s",' % (kvmsymbols['files']['all']['default'][0])) self.add(' source = "rtemsbsd/rtems/generate_kvm_symbols",') self.add(' rule = host_shell + "./${SRC} > ${TGT}",') self.add(' update_outputs = True)') @@ -375,7 +462,7 @@ class ModuleManager(builder.ModuleManager): self.add(' features = "c",') self.add(' cflags = cflags,') self.add(' includes = %r + includes,' % (includes)) - self.add(' source = "%s")' % (kvmsymbols['files']['all'][0])) + self.add(' source = "%s")' % (kvmsymbols['files']['all']['default'][0])) self.add(' libbsd_use += ["kvmsymbols"]') self.add('') @@ -383,7 +470,7 @@ class ModuleManager(builder.ModuleManager): if 'RPCGen' in data: rpcgen = data['RPCGen'] - rpcname = rpcgen['files']['all'][0][:-2] + rpcname = rpcgen['files']['all']['default'][0][:-2] self.add(' # RPC Generation') self.add(' if bld.env.AUTO_REGEN:') self.add(' bld(target = "%s.h",' % (rpcname)) @@ -393,7 +480,7 @@ class ModuleManager(builder.ModuleManager): if 'RouteKeywords' in data: routekw = data['RouteKeywords'] - rkwname = routekw['files']['all'][0] + rkwname = routekw['files']['all']['default'][0] self.add(' # Route keywords') self.add(' if bld.env.AUTO_REGEN:') self.add(' rkw_rule = host_shell + "cat ${SRC} | ' + \ @@ -409,7 +496,7 @@ class ModuleManager(builder.ModuleManager): lexes = data['lex'] self.add(' # Lex') for l in sorted(lexes.keys()): - lex = lexes[l]['all'] + lex = lexes[l]['all']['default'] if 'cflags' in lex: lexDefines = [d[2:] for d in lex['cflags']] else: @@ -436,7 +523,7 @@ class ModuleManager(builder.ModuleManager): yaccs = data['yacc'] self.add(' # Yacc') for y in sorted(yaccs.keys()): - yacc = yaccs[y]['all'] + yacc = yaccs[y]['all']['default'] yaccFile = yacc['file'] if yacc['sym'] is not None: yaccSym = yacc['sym'] @@ -473,46 +560,48 @@ class ModuleManager(builder.ModuleManager): # objs = 0 self.add(' # Objects built with different CFLAGS') - for flags in sorted(data['sources']): - if flags is not 'default': - objs += 1 - _sourceList(' objs%02d_source' % objs, sorted(data['sources'][flags]['all'])) - archs = sorted(data['sources'][flags]) - for arch in archs: - if arch not in ['all', 'cflags', 'includes']: - self.add(' if bld.get_env()["RTEMS_ARCH"] == "%s":' % arch) - _sourceList(' objs%02d_source' % objs, - sorted(data['sources'][flags][arch]), - append = True) - if 'cflags' in data['sources'][flags]: - defines = [d[2:] for d in data['sources'][flags]['cflags']] - else: - defines = [] - if 'includes' in data['sources'][flags]: - includes = data['sources'][flags]['includes'] - else: - includes = [] - self.add(' bld.objects(target = "objs%02d",' % (objs)) - self.add(' features = "c",') - self.add(' cflags = cflags,') - self.add(' includes = %r + includes,' % (includes)) - self.add(' defines = defines + %r,' % (defines)) - self.add(' source = objs%02d_source)' % objs) - self.add(' libbsd_use += ["objs%02d"]' % (objs)) - self.add('') + sources = sorted(data['sources']) + if 'default' in sources: + sources.remove('default') + for flags in sources: + objs += 1 + build = data['sources'][flags] + _sourceList(' objs%02d_source' % objs, build['all']) + archs = sorted(build) + for i in ['all', 'cflags', 'includes']: + if i in archs: + archs.remove(i) + for arch in archs: + self.add(' if bld.get_env()["RTEMS_ARCH"] == "%s":' % arch) + _sourceList(' objs%02d_source' % objs, build[arch], append = True) + if 'cflags' in build: + defines = [d[2:] for d in build['cflags']] + else: + defines = [] + if 'includes' in build: + includes = build['includes'] + else: + includes = [] + self.add(' bld.objects(target = "objs%02d",' % (objs)) + self.add(' features = "c",') + self.add(' cflags = cflags,') + self.add(' includes = %r + includes,' % (sorted(includes))) + self.add(' defines = defines + %r,' % (sorted(defines))) + self.add(' source = objs%02d_source)' % objs) + self.add(' libbsd_use += ["objs%02d"]' % (objs)) + self.add('') # # We hold the 'default' cflags set of files to the end to create the # static library with. # - _sourceList(' source', sorted(data['sources']['default']['all'])) - archs = sorted(data['sources']['default']) + build = data['sources']['default'] + _sourceList(' source', build['all']) + archs = sorted(build) + archs.remove('all') for arch in archs: - if arch is not 'all': - self.add(' if bld.get_env()["RTEMS_ARCH"] == "%s":' % arch) - _sourceList(' source', - sorted(data['sources']['default'][arch]), - append = True) + self.add(' if bld.get_env()["RTEMS_ARCH"] == "%s":' % arch) + _sourceList(' source', build[arch], append = True) self.add(' bld.stlib(target = "bsd",') self.add(' features = "c cxx",') self.add(' cflags = cflags,') @@ -524,7 +613,7 @@ class ModuleManager(builder.ModuleManager): self.add('') # - # Head file collector. + # Header file collector. # self.add(' # Installs. ') self.add(' bld.install_files("${PREFIX}/" + rtems.arch_bsp_lib_path(bld.env.RTEMS_VERSION, bld.env.RTEMS_ARCH_BSP), ["libbsd.a"])') @@ -545,16 +634,30 @@ class ModuleManager(builder.ModuleManager): self.add(' # Tests') tests = data['tests'] for testName in sorted(tests): - files = ['testsuite/%s/%s.c' % (testName, f) for f in data['tests'][testName]['all']['files']] - _sourceList(' test_%s' % (testName), sorted(files)) - self.add(' bld.program(target = "%s.exe",' % (testName)) - self.add(' features = "cprogram",') - self.add(' cflags = cflags,') - self.add(' includes = includes,') - self.add(' source = test_%s,' % (testName)) - self.add(' use = ["bsd"],') - self.add(' lib = ["m", "z"],') - self.add(' install_path = None)') + test = data['tests'][testName]['all'] + block = 0 + files = [] + for cfg in test: + if cfg != 'default': + cs = '' + ors = '' + for c in cfg.split(' '): + cs += '%s bld.env["HAVE_%s"]' % (ors, c) + ors = ' and' + self.add(' if%s:' % (cs)) + block = 1 + files = ['testsuite/%s/%s.c' % (testName, f) \ + for f in test[cfg]['files']] + indent = ' ' * block * 4 + _sourceList('%s test_%s' % (indent, testName), files) + self.add('%s bld.program(target = "%s.exe",' % (indent, testName)) + self.add('%s features = "cprogram",' % (indent)) + self.add('%s cflags = cflags,' % (indent)) + self.add('%s includes = includes,' % (indent)) + self.add('%s source = test_%s,' % (indent, testName)) + self.add('%s use = ["bsd"],' % (indent)) + self.add('%s lib = ["m", "z"],' % (indent)) + self.add('%s install_path = None)' % (indent)) self.add('') self.write() -- cgit v1.2.3