summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-04-18 12:43:15 +1000
committerAndrew Tridgell <tridge@samba.org>2010-04-18 15:00:37 +1000
commitd3dea9b1248edf9a3e96e88bea8de3e098fbc2fe (patch)
tree65d6715821f50f237668f8793f1805a3f9a7a36e
parent877439e26422568bd5ca6ffc019c3ae1d6c2499c (diff)
downloadsamba-d3dea9b1248edf9a3e96e88bea8de3e098fbc2fe.tar.gz
samba-d3dea9b1248edf9a3e96e88bea8de3e098fbc2fe.tar.bz2
samba-d3dea9b1248edf9a3e96e88bea8de3e098fbc2fe.zip
build: added ABI checking to the WAF build
See http://wiki.samba.org/index.php/Waf#ABI_Checking for details
-rw-r--r--buildtools/wafsamba/samba_abi.py112
-rw-r--r--buildtools/wafsamba/samba_autoconf.py4
-rw-r--r--buildtools/wafsamba/samba_bundled.py1
-rw-r--r--buildtools/wafsamba/samba_utils.py36
-rw-r--r--buildtools/wafsamba/wafsamba.py17
-rw-r--r--buildtools/wafsamba/wscript71
6 files changed, 214 insertions, 27 deletions
diff --git a/buildtools/wafsamba/samba_abi.py b/buildtools/wafsamba/samba_abi.py
new file mode 100644
index 0000000000..6e4d8d81e0
--- /dev/null
+++ b/buildtools/wafsamba/samba_abi.py
@@ -0,0 +1,112 @@
+# functions for handling ABI checking of libraries
+
+import Options, Utils, os, Logs, samba_utils, sys, Task, fnmatch, re
+from TaskGen import feature, before, after
+
+def normalise_signature(sig):
+ '''normalise a signature from gdb'''
+ sig = sig.strip()
+ sig = re.sub('^\$[0-9]+\s=\s\{*', '', sig)
+ sig = re.sub('\}(\s0x[0-9a-f]+\s<\w+>)?$', '', sig)
+ sig = re.sub('0x[0-9a-f]+', '0xXXXX', sig)
+ return sig
+
+def normalise_varargs(sig):
+ '''cope with older versions of gdb'''
+ sig = re.sub(',\s\.\.\.', '', sig)
+ return sig
+
+def parse_sigs(sigs, abi_match):
+ '''parse ABI signatures file'''
+ abi_match = samba_utils.TO_LIST(abi_match)
+ ret = {}
+ a = sigs.split('\n')
+ for s in a:
+ if s.find(':') == -1:
+ continue
+ sa = s.split(':')
+ if abi_match:
+ matched = False
+ for p in abi_match:
+ if fnmatch.fnmatch(sa[0], p):
+ matched = True
+ break
+ if not matched:
+ continue
+ ret[sa[0]] = normalise_signature(sa[1])
+ return ret
+
+def save_sigs(sig_file, parsed_sigs):
+ '''save ABI signatures to a file'''
+ sigs = ''
+ for s in sorted(parsed_sigs.keys()):
+ sigs += '%s: %s\n' % (s, parsed_sigs[s])
+ return samba_utils.save_file(sig_file, sigs, create_dir=True)
+
+
+def abi_check_task(self):
+ '''check if the ABI has changed'''
+ abi_gen = self.ABI_GEN
+
+ libpath = self.inputs[0].abspath(self.env)
+ libname = os.path.basename(libpath)
+
+ sigs = Utils.cmd_output([abi_gen, libpath])
+ parsed_sigs = parse_sigs(sigs, self.ABI_MATCH)
+
+ sig_file = self.ABI_FILE
+
+ old_sigs = samba_utils.load_file(sig_file)
+ if old_sigs is None or Options.options.ABI_UPDATE:
+ if not save_sigs(sig_file, parsed_sigs):
+ raise Utils.WafError('Failed to save ABI file "%s"' % sig_file)
+ Logs.warn('Generated ABI signatures %s' % sig_file)
+ return
+
+ parsed_old_sigs = parse_sigs(old_sigs, self.ABI_MATCH)
+
+ # check all old sigs
+ got_error = False
+ for s in parsed_old_sigs:
+ if not s in parsed_sigs:
+ Logs.error('%s: symbol %s has been removed - please update major version\n\tsignature: %s' % (
+ libname, s, parsed_old_sigs[s]))
+ got_error = True
+ elif normalise_varargs(parsed_old_sigs[s]) != normalise_varargs(parsed_sigs[s]):
+ Logs.error('%s: symbol %s has changed - please update major version\n\told_signature: %s\n\tnew_signature: %s' % (
+ libname, s, parsed_old_sigs[s], parsed_sigs[s]))
+ got_error = True
+
+ for s in parsed_sigs:
+ if not s in parsed_old_sigs:
+ Logs.error('%s: symbol %s has been added - please mark it _PRIVATE_ or update minor version\n\tsignature: %s' % (
+ libname, s, parsed_sigs[s]))
+ got_error = True
+
+ if got_error:
+ raise Utils.WafError('ABI for %s has changed - please fix library version then build with --abi-update\nSee http://wiki.samba.org/index.php/Waf#ABI_Checking for more information' % libname)
+
+
+t = Task.task_type_from_func('abi_check', abi_check_task, color='BLUE', ext_in='.bin')
+t.quiet = True
+
+@after('apply_link')
+@feature('abi_check')
+def abi_check(self):
+ '''check that ABI matches saved signatures'''
+ env = self.bld.env
+ if not env.ABI_CHECK or self.abi_file is None:
+ return
+
+ # if the platform doesn't support -fvisibility=hidden then the ABI
+ # checks become fairly meaningless
+ if not env.HAVE_VISIBILITY_ATTR:
+ return
+
+ topsrc = self.bld.srcnode.abspath()
+ abi_gen = os.path.join(topsrc, 'buildtools/scripts/abi_gen.sh')
+
+ tsk = self.create_task('abi_check', self.link_task.outputs[0])
+ tsk.ABI_FILE = self.abi_file
+ tsk.ABI_MATCH = self.abi_match
+ tsk.ABI_GEN = abi_gen
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
index dca6595964..dd7abe2864 100644
--- a/buildtools/wafsamba/samba_autoconf.py
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -604,7 +604,7 @@ def ADD_EXTRA_INCLUDES(conf, includes):
-def CURRENT_CFLAGS(bld, target, cflags):
+def CURRENT_CFLAGS(bld, target, cflags, hide_symbols=False):
'''work out the current flags. local flags are added first'''
if not 'EXTRA_CFLAGS' in bld.env:
list = []
@@ -612,6 +612,8 @@ def CURRENT_CFLAGS(bld, target, cflags):
list = bld.env['EXTRA_CFLAGS'];
ret = TO_LIST(cflags)
ret.extend(list)
+ if hide_symbols and bld.env.HAVE_VISIBILITY_ATTR:
+ ret.append('-fvisibility=hidden')
return ret
diff --git a/buildtools/wafsamba/samba_bundled.py b/buildtools/wafsamba/samba_bundled.py
index 6a393ebf2c..f668d56cb6 100644
--- a/buildtools/wafsamba/samba_bundled.py
+++ b/buildtools/wafsamba/samba_bundled.py
@@ -35,6 +35,7 @@ def BUILTIN_LIBRARY(bld, name):
if bld.env.DISABLE_SHARED:
return True
return target_in_list(name, bld.env.BUILTIN_LIBRARIES, False)
+Build.BuildContext.BUILTIN_LIBRARY = BUILTIN_LIBRARY
def BUILTIN_DEFAULT(opt, builtins):
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index 94975c6519..a3448b702a 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -464,3 +464,39 @@ def CHECK_MAKEFLAGS(bld):
Options.options.jobs = 1
Build.BuildContext.CHECK_MAKEFLAGS = CHECK_MAKEFLAGS
+
+option_groups = {}
+
+def option_group(opt, name):
+ '''find or create an option group'''
+ global option_groups
+ if name in option_groups:
+ return option_groups[name]
+ gr = opt.add_option_group(name)
+ option_groups[name] = gr
+ return gr
+Options.Handler.option_group = option_group
+
+
+def save_file(filename, contents, create_dir=False):
+ '''save data to a file'''
+ if create_dir:
+ mkdir_p(os.path.dirname(filename))
+ try:
+ f = open(filename, 'w')
+ f.write(contents)
+ f.close()
+ except:
+ return False
+ return True
+
+
+def load_file(filename):
+ '''return contents of a file'''
+ try:
+ f = open(filename, 'r')
+ r = f.read()
+ f.close()
+ except:
+ return None
+ return r
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 633484bd68..1714718c36 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -20,6 +20,7 @@ from samba_deps import *
from samba_bundled import *
import samba_install
import samba_conftests
+import samba_abi
import tru64cc
import irixcc
import generic_cc
@@ -108,6 +109,9 @@ def SAMBA_LIBRARY(bld, libname, source,
target_type='LIBRARY',
bundled_extension=True,
link_name=None,
+ abi_file=None,
+ abi_match=None,
+ hide_symbols=False,
enabled=True):
'''define a Samba library'''
@@ -142,6 +146,7 @@ def SAMBA_LIBRARY(bld, libname, source,
autoproto = autoproto,
depends_on = depends_on,
needs_python = needs_python,
+ hide_symbols = hide_symbols,
local_include = local_include)
if libname == obj_target:
@@ -165,6 +170,11 @@ def SAMBA_LIBRARY(bld, libname, source,
features += ' pyext'
elif needs_python:
features += ' pyembed'
+ if abi_file:
+ features += ' abi_check'
+
+ if abi_file:
+ abi_file = os.path.join(bld.curdir, abi_file)
bld.SET_BUILD_GROUP(group)
t = bld(
@@ -181,7 +191,9 @@ def SAMBA_LIBRARY(bld, libname, source,
samba_inst_path = install_path,
name = libname,
samba_realname = realname,
- samba_install = install
+ samba_install = install,
+ abi_file = abi_file,
+ abi_match = abi_match
)
if link_name:
@@ -366,6 +378,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
use_hostcc=False,
use_global_deps=True,
vars=None,
+ hide_symbols=False,
needs_python=False):
'''define a Samba subsystem'''
@@ -395,7 +408,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
features = features,
source = source,
target = modname,
- samba_cflags = CURRENT_CFLAGS(bld, modname, cflags),
+ samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
depends_on = depends_on,
samba_deps = TO_LIST(deps),
samba_includes = includes,
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index b4fcb99684..a611797b47 100644
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -12,70 +12,88 @@ def set_options(opt):
opt.tool_options('gnu_dirs')
- opt.add_option('--bundled-libraries',
+ gr = opt.add_option_group('library handling options')
+
+ gr.add_option('--bundled-libraries',
help=("comma separated list of bundled libraries. May include !LIBNAME to disable bundling a library. Can be 'NONE' or 'ALL' [auto]"),
action="store", dest='BUNDLED_LIBS', default='')
extension_default = Options.options['BUNDLED_EXTENSION_DEFAULT']
- opt.add_option('--bundled-library-extension',
+ gr.add_option('--bundled-library-extension',
help=("name extension for bundled libraries [%s]" % extension_default),
action="store", dest='BUNDLED_EXTENSION', default=extension_default)
extension_exception = Options.options['BUNDLED_EXTENSION_EXCEPTION']
- opt.add_option('--bundled-extension-exception',
+ gr.add_option('--bundled-extension-exception',
help=("comman separated list of libraries to not apply extension to [%s]" % extension_exception),
action="store", dest='BUNDLED_EXTENSION_EXCEPTION', default=extension_exception)
builtin_defauilt = Options.options['BUILTIN_LIBRARIES_DEFAULT']
- opt.add_option('--builtin-libraries',
+ gr.add_option('--builtin-libraries',
help=("command separated list of libraries to build directly into binaries [%s]" % builtin_defauilt),
action="store", dest='BUILTIN_LIBRARIES', default=builtin_defauilt)
- opt.add_option('--minimum-library-version',
+ gr.add_option('--minimum-library-version',
help=("list of minimum system library versions (LIBNAME1:version,LIBNAME2:version)"),
action="store", dest='MINIMUM_LIBRARY_VERSION', default='')
- opt.add_option('--with-modulesdir',
- help=("modules directory [PREFIX/modules]"),
- action="store", dest='MODULESDIR', default='${PREFIX}/modules')
- opt.add_option('--disable-shared',
+ gr.add_option('--disable-shared',
help=("Disable all use of shared libraries"),
action="store_true", dest='disable_shared', default=False)
- opt.add_option('--disable-rpath',
+ gr.add_option('--disable-rpath',
help=("Disable use of rpath for build binaries"),
action="store_true", dest='disable_rpath_build', default=False)
- opt.add_option('--disable-rpath-install',
+ gr.add_option('--disable-rpath-install',
help=("Disable use of rpath for installed binaries"),
action="store_true", dest='disable_rpath_install', default=False)
- opt.add_option('--enable-developer',
+
+ opt.add_option('--with-modulesdir',
+ help=("modules directory [PREFIX/modules]"),
+ action="store", dest='MODULESDIR', default='${PREFIX}/modules')
+
+ gr = opt.option_group('developer options')
+
+ gr.add_option('-C',
+ help='enable configure cacheing',
+ action='store_true', dest='enable_configure_cache')
+ gr.add_option('--enable-developer',
help=("Turn on developer warnings and debugging"),
action="store_true", dest='developer', default=False)
- opt.add_option('--picky-developer',
+ gr.add_option('--picky-developer',
help=("Treat all warnings as errors (enable -Werror)"),
action="store_true", dest='picky_developer', default=False)
- opt.add_option('--fatal-errors',
+ gr.add_option('--fatal-errors',
help=("Stop compilation on first error (enable -Wfatal-errors)"),
action="store_true", dest='fatal_errors', default=False)
- opt.add_option('--enable-gccdeps',
- help=("Enable use gcc -MD dependency module"),
+ gr.add_option('--enable-gccdeps',
+ help=("Enable use of gcc -MD dependency module"),
action="store_true", dest='enable_gccdeps', default=False)
- opt.add_option('--timestamp-dependencies',
+ gr.add_option('--timestamp-dependencies',
help=("use file timestamps instead of content for build dependencies (BROKEN)"),
action="store_true", dest='timestamp_dependencies', default=False)
- opt.add_option('-C',
- help='enable configure cacheing',
- action='store_true', dest='enable_configure_cache')
- opt.add_option('--pedantic',
+ gr.add_option('--pedantic',
help=("Enable even more compiler warnings"),
action='store_true', dest='pedantic', default=False)
- opt.add_option('--cross-compile',
+ gr.add_option('--abi-check',
+ help=("Check ABI signatures for libraries"),
+ action='store_true', dest='ABI_CHECK', default=False)
+ gr.add_option('--abi-check-disable',
+ help=("Disable ABI checking (used with --enable-developer)"),
+ action='store_true', dest='ABI_CHECK_DISABLE', default=False)
+ gr.add_option('--abi-update',
+ help=("Update ABI signature files for libraries"),
+ action='store_true', dest='ABI_UPDATE', default=False)
+
+ gr = opt.add_option_group('cross compilation options')
+
+ gr.add_option('--cross-compile',
help=("configure for cross-compilation"),
action='store_true', dest='CROSS_COMPILE', default=False)
- opt.add_option('--cross-execute',
+ gr.add_option('--cross-execute',
help=("command prefix to use for cross-execution in configure"),
action='store', dest='CROSS_EXECUTE', default='')
- opt.add_option('--hostcc',
+ gr.add_option('--hostcc',
help=("set host compiler when cross compiling"),
action='store', dest='HOSTCC', default=False)
@@ -147,6 +165,11 @@ def configure(conf):
Logs.error('ERROR: --program-prefix not supported')
sys.exit(1)
+ # enable ABI checking for developers
+ conf.env.ABI_CHECK = Options.options.ABI_CHECK or Options.options.developer
+ if Options.options.ABI_CHECK_DISABLE:
+ conf.env.ABI_CHECK = False
+
# see if we can compile and run a simple C program
conf.CHECK_CODE('printf("hello world\\n")',
define='HAVE_SIMPLE_C_PROG',