mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
build: added ABI checking to the WAF build
See http://wiki.samba.org/index.php/Waf#ABI_Checking for details
This commit is contained in:
parent
877439e264
commit
d3dea9b124
112
buildtools/wafsamba/samba_abi.py
Normal file
112
buildtools/wafsamba/samba_abi.py
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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='')
|
||||
|
||||
gr.add_option('--disable-shared',
|
||||
help=("Disable all use of shared libraries"),
|
||||
action="store_true", dest='disable_shared', default=False)
|
||||
gr.add_option('--disable-rpath',
|
||||
help=("Disable use of rpath for build binaries"),
|
||||
action="store_true", dest='disable_rpath_build', default=False)
|
||||
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('--with-modulesdir',
|
||||
help=("modules directory [PREFIX/modules]"),
|
||||
action="store", dest='MODULESDIR', default='${PREFIX}/modules')
|
||||
opt.add_option('--disable-shared',
|
||||
help=("Disable all use of shared libraries"),
|
||||
action="store_true", dest='disable_shared', default=False)
|
||||
opt.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',
|
||||
help=("Disable use of rpath for installed binaries"),
|
||||
action="store_true", dest='disable_rpath_install', default=False)
|
||||
opt.add_option('--enable-developer',
|
||||
help=("Turn on developer warnings and debugging"),
|
||||
action="store_true", dest='developer', default=False)
|
||||
opt.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',
|
||||
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"),
|
||||
action="store_true", dest='enable_gccdeps', default=False)
|
||||
opt.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',
|
||||
|
||||
gr = opt.option_group('developer options')
|
||||
|
||||
gr.add_option('-C',
|
||||
help='enable configure cacheing',
|
||||
action='store_true', dest='enable_configure_cache')
|
||||
opt.add_option('--pedantic',
|
||||
gr.add_option('--enable-developer',
|
||||
help=("Turn on developer warnings and debugging"),
|
||||
action="store_true", dest='developer', default=False)
|
||||
gr.add_option('--picky-developer',
|
||||
help=("Treat all warnings as errors (enable -Werror)"),
|
||||
action="store_true", dest='picky_developer', default=False)
|
||||
gr.add_option('--fatal-errors',
|
||||
help=("Stop compilation on first error (enable -Wfatal-errors)"),
|
||||
action="store_true", dest='fatal_errors', default=False)
|
||||
gr.add_option('--enable-gccdeps',
|
||||
help=("Enable use of gcc -MD dependency module"),
|
||||
action="store_true", dest='enable_gccdeps', default=False)
|
||||
gr.add_option('--timestamp-dependencies',
|
||||
help=("use file timestamps instead of content for build dependencies (BROKEN)"),
|
||||
action="store_true", dest='timestamp_dependencies', default=False)
|
||||
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',
|
||||
|
Loading…
Reference in New Issue
Block a user