From 7e2edad8efea55e8df1faa695d1389ef4e326d7c Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 16 Jul 2013 13:28:28 +0200 Subject: switch the build system to waf This commit adds a new build system based on waf. configure and Makefile are deprecated effective immediately and someday in the future they will be removed (they are still available by running ./old-configure). You can find how the choice for waf came to be in `DOCS/waf-buildsystem.rst`. TL;DR: we couldn't get the same level of abstraction and customization with other build systems we tried (CMake and autotools). For guidance on how to build the software now, take a look at README.md and the cross compilation guide. CREDITS: This is a squash of ~250 commits. Some of them are not by me, so here is the deserved attribution: - @wm4 contributed some Windows fixes, renamed configure to old-configure and contributed to the bootstrap script. Also, GNU/Linux testing. - @lachs0r contributed some Windows fixes and the bootstrap script. - @Nikoli contributed a lot of testing and discovered many bugs. - @CrimsonVoid contributed changes to the bootstrap script. --- waftools/checks/__init__.py | 0 waftools/checks/custom.py | 119 +++++++++++++++++++++++++++++++++++++++ waftools/checks/generic.py | 134 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 waftools/checks/__init__.py create mode 100644 waftools/checks/custom.py create mode 100644 waftools/checks/generic.py (limited to 'waftools/checks') diff --git a/waftools/checks/__init__.py b/waftools/checks/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/waftools/checks/custom.py b/waftools/checks/custom.py new file mode 100644 index 0000000000..d2da024037 --- /dev/null +++ b/waftools/checks/custom.py @@ -0,0 +1,119 @@ +from waftools.checks.generic import * + +__all__ = ["check_pthreads", "check_iconv", "check_lua", "check_oss"] + +pthreads_program = load_fragment('pthreads.c') + +def check_pthreads(ctx, dependency_identifier): + platform_cflags = { + 'linux': '-D_REENTRANT', + 'freebsd': '-D_THREAD_SAFE', + 'netbsd': '-D_THREAD_SAFE', + 'openbsd': '-D_THREAD_SAFE', + 'win32': '-DPTW32_STATIC_LIB', + }.get(ctx.env.DEST_OS, '') + libs = ['pthreadGC2', 'pthread'] + checkfn = check_cc(fragment=pthreads_program, cflags=platform_cflags) + return check_libs(libs, checkfn)(ctx, dependency_identifier) + +def check_iconv(ctx, dependency_identifier): + iconv_program = load_fragment('iconv.c') + libdliconv = " ".join(ctx.env.LIB_LIBDL + ['iconv']) + libs = ['iconv', libdliconv] + checkfn = check_cc(fragment=iconv_program) + return check_libs(libs, checkfn)(ctx, dependency_identifier) + +def check_lua(ctx, dependency_identifier): + if 'libquvi4' in ctx.env.satisfied_deps: + additional_lua_test_header = '#include ' + additional_lua_test_code = load_fragment('lua_libquvi4.c') + elif 'libquvi9' in ctx.env.satisfied_deps: + additional_lua_test_header = '#include ' + additional_lua_test_code = load_fragment('lua_libquvi9.c') + else: + additional_lua_test_header = '' + additional_lua_test_code = '' + + fragment = load_fragment('lua.c').format( + additional_lua_test_header='', + additional_lua_test_code='') + + lua_versions = [ + ( '51', 'lua >= 5.1.0 lua < 5.2.0'), + ( '51deb', 'lua5.1 >= 5.1.0'), # debian + ( 'luajit', 'luajit >= 2.0.0' ), + # assume all our dependencies (libquvi in particular) link with 5.1 + ( '52', 'lua >= 5.2.0' ), + ( '52deb', 'lua5.2 >= 5.2.0'), # debian + ] + + if ctx.options.LUA_VER: + lua_versions = \ + [lv for lv in lua_versions if lv[0] == ctx.options.LUA_VER] + + for lua_version, pkgconfig_query in lua_versions: + if compose_checks( + check_pkg_config(pkgconfig_query, uselib_store=lua_version), + check_cc(fragment=fragment, use=lua_version))\ + (ctx, dependency_identifier): + # XXX: this is a bit of a hack, ask waf developers if I can copy + # the uselib_store to 'lua' + ctx.mark_satisfied(lua_version) + ctx.add_optional_message(dependency_identifier, + 'version found: ' + lua_version) + return True + return False + +# from here on there is the OSS check.. just stop reading here unless you want +# to die inside a little +def __fail_oss_check__(ctx): + ctx.define('PATH_DEV_DSP', '') + ctx.define('PATH_DEV_MIXER', '') + return False + +def __get_osslibdir__(): + try: + cmd = ['sh', '-c', "'source /etc/oss.conf && echo $OSSLIBDIR'"] + p = Utils.subprocess.Popen(cmd, stdin=Utils.subprocess.PIPE, + stdout=Utils.subprocess.PIPE, + stderr=Utils.subprocess.PIPE) + return p.communicate()[0] + except Exception: + return "" + +def __check_oss_headers__(ctx, dependency_identifier): + import os + + real_oss = ctx.check_cc(fragment=load_fragment('oss_audio_header.c'), + use='soundcard') + + if real_oss: + if os.path.exists('/etc/oss.conf'): + osslibdir = __get_osslibdir__() + ossincdir = os.path.join(osslibdir, 'include') + soundcard_h = os.path.join(ossincdir, 'sys', 'soundcard.h') + if os.path.exists(soundcard_h): + ctx.env.CFLAGS.append('-I{0}'.format(ossincdir)) + + return True + +def __check_oss_bsd__(ctxdependency_identifier): + # add the oss audio library through a check + ctx.define('PATH_DEV_DSP', '/dev/sound') + if check_cc(lib='ossaudio')(ctx, dependency_identifier): + return True + else: + return __fail_oss_check__(ctx) + +def check_oss(ctx, dependency_identifier): + func = check_cc(fragment=load_fragment('oss_audio.c'), use='soundcard') + if func(ctx, dependency_identifier): + ctx.define('PATH_DEV_DSP', '/dev/dsp') + ctx.define('PATH_DEV_MIXER', '/dev/mixer') + + if ctx.env.DEST_OS in ['openbsd', 'netbsd']: + return __check_oss_bsd_library__(ctx, dependency_identifier) + else: + return __check_oss_headers__(ctx, dependency_identifier) + + return __fail_oss_check__(ctx) diff --git a/waftools/checks/generic.py b/waftools/checks/generic.py new file mode 100644 index 0000000000..46813aed01 --- /dev/null +++ b/waftools/checks/generic.py @@ -0,0 +1,134 @@ +import os +from inflectors import DependencyInflector + +__all__ = [ + "check_pkg_config", "check_cc", "check_statement", "check_libs", + "check_headers", "compose_checks", "check_true", "any_version", + "load_fragment", "check_stub", "check_ctx_vars"] + +any_version = None + +def even(n): + return n % 2 == 0 + +def __define_options__(dependency_identifier): + return DependencyInflector(dependency_identifier).define_dict() + +def __merge_options__(dependency_identifier, *args): + options_accu = DependencyInflector(dependency_identifier).storage_dict() + options_accu['mandatory'] = False + [options_accu.update(arg) for arg in args if arg] + return options_accu + + +def check_libs(libs, function): + libs = [None] + libs + def fn(ctx, dependency_identifier): + for lib in libs: + kwargs = lib and {'lib': lib} or {} + if function(ctx, dependency_identifier, **kwargs): + return True + return False + return fn + +def check_statement(header, statement, **kw_ext): + def fn(ctx, dependency_identifier, **kw): + fragment = """ + #include <{0}> + int main(int argc, char **argv) + {{ {1}; return 0; }} """.format(header, statement) + opts = __merge_options__(dependency_identifier, + {'fragment':fragment}, + __define_options__(dependency_identifier), + kw_ext, kw) + return ctx.check_cc(**opts) + return fn + +def check_cc(**kw_ext): + def fn(ctx, dependency_identifier, **kw): + options = __merge_options__(dependency_identifier, + __define_options__(dependency_identifier), + kw_ext, kw) + return ctx.check_cc(**options) + return fn + +def check_pkg_config(*args, **kw_ext): + def fn(ctx, dependency_identifier, **kw): + argsl = list(args) + packages = [el for (i, el) in enumerate(args) if even(i)] + sargs = [i for i in args if i] # remove None + pkgc_args = ["--libs", "--cflags"] + if ctx.dependency_satisfied('static-build'): + pkgc_args += ["--static"] + + defaults = { + 'path': ctx.env.PKG_CONFIG, + 'package': " ".join(packages), + 'args': sargs + pkgc_args } + opts = __merge_options__(dependency_identifier, defaults, kw_ext, kw) + if ctx.check_cfg(**opts): + return True + else: + defkey = DependencyInflector(dependency_identifier).define_key() + ctx.undefine(defkey) + return False + return fn + +def check_headers(*headers): + def undef_others(ctx, headers, found): + not_found_hs = set(headers) - set([found]) + for not_found_h in not_found_hs: + defkey = DependencyInflector(not_found_h).define_key() + ctx.undefine(defkey) + + def fn(ctx, dependency_identifier): + for header in headers: + defaults = {'header_name': header, 'features': 'c cprogram'} + options = __merge_options__(dependency_identifier, defaults) + if ctx.check(**options): + undef_others(ctx, headers, header) + defkey = DependencyInflector(dependency_identifier).define_key() + ctx.define(defkey, 1) + return True + undef_others(ctx, headers, None) + return False + return fn + +def check_true(ctx, dependency_identifier): + defkey = DependencyInflector(dependency_identifier).define_key() + ctx.define(defkey, 1) + return True + +def check_ctx_vars(*variables): + def fn(ctx, dependency_identifier): + missing = [] + for variable in variables: + if variable not in ctx.env: + missing.append(variable) + + if any(missing): + ctx.add_optional_message(dependency_identifier, + 'missing {0}'.format(', '.join(missing))) + return False + else: + return True + + return fn + +def check_stub(ctx, dependency_identifier): + defkey = DependencyInflector(dependency_identifier).define_key() + ctx.undefine(defkey) + return False + +def compose_checks(*checks): + def fn(ctx, dependency_identifier): + return all([check(ctx, dependency_identifier) for check in checks]) + return fn + +def load_fragment(fragment): + file_path = os.path.join(os.path.dirname(__file__), '..', 'fragments', + fragment) + fp = open(file_path,"r") + fragment_code = fp.read() + fp.close() + return fragment_code -- cgit v1.2.3