1
0
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:
Andrew Tridgell 2010-04-18 12:43:15 +10:00
parent 877439e264
commit d3dea9b124
6 changed files with 224 additions and 37 deletions

View 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

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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,

View File

@ -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',