2010-03-17 12:12:16 +03:00
# Samba automatic dependency handling and project rules
2010-03-17 14:07:11 +03:00
2019-06-12 13:27:04 +03:00
import os , sys , re
2015-10-27 22:46:46 +03:00
2022-01-21 19:06:15 +03:00
from waflib import Build , Options , Logs , Utils , Errors , Task
2018-01-31 12:48:43 +03:00
from waflib . Logs import debug
from waflib . Configure import conf
from waflib import ConfigSet
2015-10-27 22:46:46 +03:00
2019-11-04 07:07:44 +03:00
from samba_utils import LOCAL_CACHE , TO_LIST , get_tgt_list , unique_list
2015-10-27 22:46:46 +03:00
from samba_autoconf import library_flags
2010-03-17 14:07:11 +03:00
@conf
def ADD_GLOBAL_DEPENDENCY ( ctx , dep ) :
''' add a dependency for all binaries and libraries '''
if not ' GLOBAL_DEPENDENCIES ' in ctx . env :
ctx . env . GLOBAL_DEPENDENCIES = [ ]
ctx . env . GLOBAL_DEPENDENCIES . append ( dep )
2010-10-13 15:58:25 +04:00
@conf
def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES ( ctx ) :
''' indicate that circular dependencies between libraries should be broken. '''
ctx . env . ALLOW_CIRCULAR_LIB_DEPENDENCIES = True
2010-03-29 15:27:17 +04:00
@conf
def SET_SYSLIB_DEPS ( conf , target , deps ) :
''' setup some implied dependencies for a SYSLIB '''
cache = LOCAL_CACHE ( conf , ' SYSLIB_DEPS ' )
cache [ target ] = deps
2010-03-17 12:12:16 +03:00
def expand_subsystem_deps ( bld ) :
''' expand the reverse dependencies resulting from subsystem
2010-10-20 11:11:31 +04:00
attributes of modules . This is walking over the complete list
of declared subsystems , and expands the samba_deps_extended list for any
module < - > subsystem dependencies '''
subsystem_list = LOCAL_CACHE ( bld , ' INIT_FUNCTIONS ' )
2010-03-17 12:12:16 +03:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-10-20 11:11:31 +04:00
for subsystem_name in subsystem_list :
bld . ASSERT ( subsystem_name in targets , " Subsystem target %s not declared " % subsystem_name )
type = targets [ subsystem_name ]
2010-03-17 12:12:16 +03:00
if type == ' DISABLED ' or type == ' EMPTY ' :
continue
2010-03-17 14:07:11 +03:00
2010-10-20 11:11:31 +04:00
# for example,
# subsystem_name = dcerpc_server (a subsystem)
# subsystem = dcerpc_server (a subsystem object)
# module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
# module = rpc_epmapper (a module object within the dcerpc_server subsystem)
2015-06-26 23:32:43 +03:00
subsystem = bld . get_tgen_by_name ( subsystem_name )
2010-10-27 04:47:54 +04:00
bld . ASSERT ( subsystem is not None , " Unable to find subsystem %s " % subsystem_name )
2010-10-20 11:11:31 +04:00
for d in subsystem_list [ subsystem_name ] :
module_name = d [ ' TARGET ' ]
module_type = targets [ module_name ]
if module_type in [ ' DISABLED ' , ' EMPTY ' ] :
continue
bld . ASSERT ( subsystem is not None ,
" Subsystem target %s for %s ( %s ) not found " % ( subsystem_name , module_name , module_type ) )
if module_type in [ ' SUBSYSTEM ' ] :
# if a module is a plain object type (not a library) then the
# subsystem it is part of needs to have it as a dependency, so targets
# that depend on this subsystem get the modules of that subsystem
subsystem . samba_deps_extended . append ( module_name )
subsystem . samba_deps_extended = unique_list ( subsystem . samba_deps_extended )
2010-03-17 14:07:11 +03:00
def build_dependencies ( self ) :
''' This builds the dependency list for a target. It runs after all the targets are declared
The reason this is not just done in the SAMBA_ * ( ) rules is that we have no way of knowing
2010-03-17 12:12:16 +03:00
the full dependency list for a target until we have all of the targets declared .
2010-03-17 14:07:11 +03:00
'''
2021-08-21 00:05:57 +03:00
if self . samba_type in [ ' LIBRARY ' , ' PLUGIN ' , ' BINARY ' , ' PYTHON ' ] :
2010-03-23 23:44:48 +03:00
self . uselib = list ( self . final_syslibs )
self . uselib_local = list ( self . final_libs )
self . add_objects = list ( self . final_objects )
# extra link flags from pkg_config
2023-12-17 19:37:33 +03:00
( cflags , ldflags , cpppath , libs ) = library_flags (
self , list ( self . final_syslibs . copy ( ) ) )
2010-12-15 06:59:47 +03:00
new_ldflags = getattr ( self , ' samba_ldflags ' , [ ] ) [ : ]
2010-03-23 23:44:48 +03:00
new_ldflags . extend ( ldflags )
self . ldflags = new_ldflags
2011-02-15 08:15:15 +03:00
if getattr ( self , ' allow_undefined_symbols ' , False ) and self . env . undefined_ldflags :
for f in self . env . undefined_ldflags :
self . ldflags . remove ( f )
2011-04-16 01:15:51 +04:00
if getattr ( self , ' allow_undefined_symbols ' , False ) and self . env . undefined_ignore_ldflags :
for f in self . env . undefined_ignore_ldflags :
self . ldflags . append ( f )
2010-03-23 23:44:48 +03:00
debug ( ' deps: computed dependencies for target %s : uselib= %s uselib_local= %s add_objects= %s ' ,
self . sname , self . uselib , self . uselib_local , self . add_objects )
2021-08-19 18:31:24 +03:00
if self . samba_type in [ ' SUBSYSTEM ' , ' BUILTIN ' ] :
2016-03-26 15:18:07 +03:00
# this is needed for the cflags of libs that come from pkg_config
2010-11-03 04:23:43 +03:00
self . uselib = list ( self . final_syslibs )
self . uselib . extend ( list ( self . direct_syslibs ) )
for lib in self . final_libs :
2015-06-26 23:32:43 +03:00
t = self . bld . get_tgen_by_name ( lib )
2010-11-03 04:23:43 +03:00
self . uselib . extend ( list ( t . final_syslibs ) )
self . uselib = unique_list ( self . uselib )
2010-03-17 14:07:11 +03:00
2010-03-24 01:29:20 +03:00
if getattr ( self , ' uselib ' , None ) :
up_list = [ ]
2010-04-08 01:45:46 +04:00
for l in self . uselib :
up_list . append ( l . upper ( ) )
self . uselib = up_list
2010-03-17 14:07:11 +03:00
2010-10-27 04:47:54 +04:00
2010-03-17 14:07:11 +03:00
def build_includes ( self ) :
''' This builds the right set of includes for a target.
One tricky part of this is that the includes = attribute for a
target needs to use paths which are relative to that targets
declaration directory ( which we can get at via t . path ) .
The way this works is the includes list gets added as
samba_includes in the main build task declaration . Then this
function runs after all of the tasks are declared , and it
processes the samba_includes attribute to produce a includes =
attribute
'''
if getattr ( self , ' samba_includes ' , None ) is None :
return
bld = self . bld
2010-03-22 08:57:44 +03:00
inc_deps = includes_objects ( bld , self , set ( ) , { } )
2010-03-17 14:07:11 +03:00
includes = [ ]
2010-03-17 12:12:16 +03:00
# maybe add local includes
2012-09-27 20:30:47 +04:00
if getattr ( self , ' local_include ' , True ) and getattr ( self , ' local_include_first ' , True ) :
2010-03-17 14:07:11 +03:00
includes . append ( ' . ' )
2010-03-17 12:12:16 +03:00
includes . extend ( self . samba_includes_extended )
2010-03-17 14:07:11 +03:00
2011-02-28 10:52:36 +03:00
if ' EXTRA_INCLUDES ' in bld . env and getattr ( self , ' global_include ' , True ) :
2010-03-17 14:07:11 +03:00
includes . extend ( bld . env [ ' EXTRA_INCLUDES ' ] )
includes . append ( ' # ' )
2010-03-17 12:12:16 +03:00
inc_set = set ( )
inc_abs = [ ]
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
for d in inc_deps :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( d )
2010-03-17 12:12:16 +03:00
bld . ASSERT ( t is not None , " Unable to find dependency %s for %s " % ( d , self . sname ) )
2010-10-27 04:47:54 +04:00
inclist = getattr ( t , ' samba_includes_extended ' , [ ] ) [ : ]
2012-09-27 20:30:47 +04:00
if getattr ( t , ' local_include ' , True ) :
2010-03-17 14:07:11 +03:00
inclist . append ( ' . ' )
if inclist == [ ] :
continue
2010-03-17 12:12:16 +03:00
tpath = t . samba_abspath
2010-03-17 14:07:11 +03:00
for inc in inclist :
2010-03-17 12:12:16 +03:00
npath = tpath + ' / ' + inc
if not npath in inc_set :
inc_abs . append ( npath )
inc_set . add ( npath )
mypath = self . path . abspath ( bld . env )
for inc in inc_abs :
2019-11-04 07:07:44 +03:00
relpath = os . path . relpath ( inc , mypath )
2010-03-17 12:12:16 +03:00
includes . append ( relpath )
2010-03-17 14:07:11 +03:00
2012-09-27 20:30:47 +04:00
if getattr ( self , ' local_include ' , True ) and not getattr ( self , ' local_include_first ' , True ) :
2010-03-17 14:07:11 +03:00
includes . append ( ' . ' )
2010-03-17 03:46:14 +03:00
# now transform the includes list to be relative to the top directory
# which is represented by '#' in waf. This allows waf to cache the
# includes lists more efficiently
includes_top = [ ]
for i in includes :
if i [ 0 ] == ' # ' :
# some are already top based
includes_top . append ( i )
continue
absinc = os . path . join ( self . path . abspath ( ) , i )
2019-11-04 07:07:44 +03:00
relinc = os . path . relpath ( absinc , self . bld . srcnode . abspath ( ) )
2010-03-17 03:46:14 +03:00
includes_top . append ( ' # ' + relinc )
self . includes = unique_list ( includes_top )
debug ( ' deps: includes for target %s : includes= %s ' ,
self . sname , self . includes )
2010-03-17 12:12:16 +03:00
2010-03-17 14:07:11 +03:00
def add_init_functions ( self ) :
''' This builds the right set of init functions '''
bld = self . bld
subsystems = LOCAL_CACHE ( bld , ' INIT_FUNCTIONS ' )
2010-03-18 15:47:48 +03:00
# cope with the separated object lists from BINARY and LIBRARY targets
sname = self . sname
if sname . endswith ( ' .objlist ' ) :
sname = sname [ 0 : - 8 ]
2010-03-17 14:07:11 +03:00
modules = [ ]
2010-03-18 15:47:48 +03:00
if sname in subsystems :
modules . append ( sname )
2010-03-17 14:07:11 +03:00
m = getattr ( self , ' samba_modules ' , None )
if m is not None :
modules . extend ( TO_LIST ( m ) )
m = getattr ( self , ' samba_subsystem ' , None )
if m is not None :
modules . append ( m )
2015-08-03 12:39:01 +03:00
if ' pyembed ' in self . features :
return
2012-04-09 16:33:37 +04:00
sentinel = getattr ( self , ' init_function_sentinel ' , ' NULL ' )
2010-03-17 12:12:16 +03:00
2010-03-20 14:55:04 +03:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-17 12:12:16 +03:00
cflags = getattr ( self , ' samba_cflags ' , [ ] ) [ : ]
2010-10-30 04:21:35 +04:00
if modules == [ ] :
2011-02-11 14:05:10 +03:00
sname = sname . replace ( ' - ' , ' _ ' )
2017-02-09 05:07:39 +03:00
sname = sname . replace ( ' . ' , ' _ ' )
2011-02-11 14:05:10 +03:00
sname = sname . replace ( ' / ' , ' _ ' )
2012-04-09 16:33:37 +04:00
cflags . append ( ' -DSTATIC_ %s _MODULES= %s ' % ( sname , sentinel ) )
if sentinel == ' NULL ' :
2014-03-27 12:37:26 +04:00
proto = " extern void __ %s _dummy_module_proto(void) " % ( sname )
cflags . append ( ' -DSTATIC_ %s _MODULES_PROTO= %s ' % ( sname , proto ) )
2016-03-26 15:18:07 +03:00
self . cflags = cflags
2010-10-30 04:21:35 +04:00
return
2010-03-17 14:07:11 +03:00
for m in modules :
bld . ASSERT ( m in subsystems ,
2010-03-17 12:12:16 +03:00
" No init_function defined for module ' %s ' in target ' %s ' " % ( m , self . sname ) )
init_fn_list = [ ]
for d in subsystems [ m ] :
2010-03-20 14:55:04 +03:00
if targets [ d [ ' TARGET ' ] ] != ' DISABLED ' :
init_fn_list . append ( d [ ' INIT_FUNCTION ' ] )
if init_fn_list == [ ] :
2012-04-09 16:33:37 +04:00
cflags . append ( ' -DSTATIC_ %s _MODULES= %s ' % ( m , sentinel ) )
if sentinel == ' NULL ' :
2014-03-27 12:37:26 +04:00
proto = " extern void __ %s _dummy_module_proto(void) " % ( m )
cflags . append ( ' -DSTATIC_ %s _MODULES_PROTO= %s ' % ( m , proto ) )
2010-03-20 14:55:04 +03:00
else :
2012-04-09 16:33:37 +04:00
cflags . append ( ' -DSTATIC_ %s _MODULES= %s ' % ( m , ' , ' . join ( init_fn_list ) + ' , ' + sentinel ) )
2019-08-26 00:02:37 +03:00
proto = " " . join ( ' _MODULE_PROTO( %s ) ' % f for f in init_fn_list ) + \
" extern void __ %s _dummy_module_proto(void) " % ( m )
2010-11-01 06:57:57 +03:00
cflags . append ( ' -DSTATIC_ %s _MODULES_PROTO= %s ' % ( m , proto ) )
2016-03-26 15:18:07 +03:00
self . cflags = cflags
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
def check_duplicate_sources ( bld , tgt_list ) :
2015-11-05 02:34:03 +03:00
''' see if we are compiling the same source file more than once '''
2010-03-17 12:12:16 +03:00
debug ( ' deps: checking for duplicate sources ' )
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-21 03:04:26 +03:00
for t in tgt_list :
2010-10-27 04:47:54 +04:00
source_list = TO_LIST ( getattr ( t , ' source ' , ' ' ) )
2019-11-04 07:07:44 +03:00
tpath = os . path . normpath ( os . path . relpath ( t . path . abspath ( bld . env ) , t . env . BUILD_DIRECTORY + ' /default ' ) )
2010-11-08 03:11:32 +03:00
obj_sources = set ( )
2010-10-27 04:47:54 +04:00
for s in source_list :
2016-03-26 15:18:07 +03:00
if not isinstance ( s , str ) :
print ( ' strange path in check_duplicate_sources %r ' % s )
s = s . abspath ( )
2010-10-27 04:47:54 +04:00
p = os . path . normpath ( os . path . join ( tpath , s ) )
if p in obj_sources :
Logs . error ( " ERROR: source %s appears twice in target ' %s ' " % ( p , t . sname ) )
sys . exit ( 1 )
obj_sources . add ( p )
t . samba_source_set = obj_sources
subsystems = { }
2010-03-17 12:12:16 +03:00
2010-10-27 04:47:54 +04:00
# build a list of targets that each source file is part of
2010-03-17 12:12:16 +03:00
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if not targets [ t . sname ] in [ ' LIBRARY ' , ' PLUGIN ' , ' BINARY ' , ' PYTHON ' ] :
2010-03-17 12:12:16 +03:00
continue
for obj in t . add_objects :
2015-06-26 23:32:43 +03:00
t2 = t . bld . get_tgen_by_name ( obj )
2010-03-21 03:04:26 +03:00
source_set = getattr ( t2 , ' samba_source_set ' , set ( ) )
2010-10-27 04:47:54 +04:00
for s in source_set :
if not s in subsystems :
subsystems [ s ] = { }
if not t . sname in subsystems [ s ] :
subsystems [ s ] [ t . sname ] = [ ]
subsystems [ s ] [ t . sname ] . append ( t2 . sname )
for s in subsystems :
if len ( subsystems [ s ] ) > 1 and Options . options . SHOW_DUPLICATES :
Logs . warn ( " WARNING: source %s is in more than one target: %s " % ( s , subsystems [ s ] . keys ( ) ) )
for tname in subsystems [ s ] :
if len ( subsystems [ s ] [ tname ] ) > 1 :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( " ERROR: source %s is in more than one subsystem of target ' %s ' : %s " % ( s , tname , subsystems [ s ] [ tname ] ) )
2012-02-19 02:17:59 +04:00
2015-11-05 02:34:03 +03:00
return True
2010-03-21 03:04:26 +03:00
2010-05-03 18:04:56 +04:00
def check_group_ordering ( bld , tgt_list ) :
''' see if we have any dependencies that violate the group ordering
It is an error for a target to depend on a target from a later
build group
'''
def group_name ( g ) :
tm = bld . task_manager
return [ x for x in tm . groups_names if id ( tm . groups_names [ x ] ) == id ( g ) ] [ 0 ]
for g in bld . task_manager . groups :
gname = group_name ( g )
for t in g . tasks_gen :
t . samba_group = gname
grp_map = { }
idx = 0
for g in bld . task_manager . groups :
name = group_name ( g )
grp_map [ name ] = idx
idx + = 1
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
ret = True
for t in tgt_list :
tdeps = getattr ( t , ' add_objects ' , [ ] ) + getattr ( t , ' uselib_local ' , [ ] )
for d in tdeps :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( d )
2010-05-03 18:04:56 +04:00
if t2 is None :
continue
map1 = grp_map [ t . samba_group ]
map2 = grp_map [ t2 . samba_group ]
if map2 > map1 :
Logs . error ( " Target %r in build group %r depends on target %r from later build group %r " % (
t . sname , t . samba_group , t2 . sname , t2 . samba_group ) )
ret = False
return ret
2015-11-19 03:55:43 +03:00
Build . BuildContext . check_group_ordering = check_group_ordering
2010-05-03 18:04:56 +04:00
2010-03-17 12:12:16 +03:00
def show_final_deps ( bld , tgt_list ) :
''' show the final dependencies for all targets '''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if not targets [ t . sname ] in [ ' LIBRARY ' , ' PLUGIN ' , ' BINARY ' , ' PYTHON ' , ' SUBSYSTEM ' , ' BUILTIN ' ] :
2010-03-17 14:07:11 +03:00
continue
2010-03-17 12:12:16 +03:00
debug ( ' deps: final dependencies for target %s : uselib= %s uselib_local= %s add_objects= %s ' ,
2010-11-03 04:23:43 +03:00
t . sname , t . uselib , getattr ( t , ' uselib_local ' , [ ] ) , getattr ( t , ' add_objects ' , [ ] ) )
2010-03-17 12:12:16 +03:00
def add_samba_attributes ( bld , tgt_list ) :
2023-08-29 05:22:58 +03:00
''' ensure a target has the required samba attributes '''
2010-03-17 12:12:16 +03:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
for t in tgt_list :
if t . name != ' ' :
t . sname = t . name
else :
t . sname = t . target
t . samba_type = targets [ t . sname ]
t . samba_abspath = t . path . abspath ( bld . env )
t . samba_deps_extended = t . samba_deps [ : ]
t . samba_includes_extended = TO_LIST ( t . samba_includes ) [ : ]
2016-03-26 15:18:07 +03:00
t . cflags = getattr ( t , ' samba_cflags ' , ' ' )
2010-03-17 12:12:16 +03:00
2021-08-19 18:31:24 +03:00
def replace_builtin_subsystem_deps ( bld , tgt_list ) :
''' replace dependencies based on builtin subsystems/libraries
'''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
# If either the target or the dependency require builtin linking
# we should replace the dependency
for t in tgt_list :
t_require_builtin_deps = getattr ( t , ' samba_require_builtin_deps ' , False )
if t_require_builtin_deps :
debug ( " deps: target %s : requires builtin dependencies... " % ( t . sname ) )
else :
debug ( " deps: target %s : does not require builtin dependencies... " % ( t . sname ) )
replacing = { }
for dep in t . samba_deps_extended :
bld . ASSERT ( dep in targets , " target %s : dependency target %s not declared " % ( t . sname , dep ) )
dtype = targets [ dep ]
bld . ASSERT ( dtype != ' BUILTIN ' , " target %s : dependency target %s is BUILTIN " % ( t . sname , dep ) )
bld . ASSERT ( dtype != ' PLUGIN ' , " target %s : dependency target %s is PLUGIN " % ( t . sname , dep ) )
if dtype not in [ ' SUBSYSTEM ' , ' LIBRARY ' ] :
debug ( " deps: target %s : keep %s dependency %s " % ( t . sname , dtype , dep ) )
continue
dt = bld . get_tgen_by_name ( dep )
bld . ASSERT ( dt is not None , " target %s : dependency target %s not found by name " % ( t . sname , dep ) )
dt_require_builtin_deps = getattr ( dt , ' samba_require_builtin_deps ' , False )
if not dt_require_builtin_deps and not t_require_builtin_deps :
# both target and dependency don't require builtin linking
continue
sdt = getattr ( dt , ' samba_builtin_subsystem ' , None )
if not t_require_builtin_deps :
if sdt is None :
debug ( " deps: target %s : dependency %s requires builtin deps only " % ( t . sname , dep ) )
continue
debug ( " deps: target %s : dependency %s requires builtin linking " % ( t . sname , dep ) )
bld . ASSERT ( sdt is not None , " target %s : dependency target %s is missing samba_builtin_subsystem " % ( t . sname , dep ) )
sdep = sdt . sname
bld . ASSERT ( sdep in targets , " target %s : builtin dependency target %s (from %s ) not declared " % ( t . sname , sdep , dep ) )
sdt = targets [ sdep ]
bld . ASSERT ( sdt == ' BUILTIN ' , " target %s : builtin dependency target %s (from %s ) is not BUILTIN " % ( t . sname , sdep , dep ) )
replacing [ dep ] = sdep
for i in range ( len ( t . samba_deps_extended ) ) :
dep = t . samba_deps_extended [ i ]
if dep in replacing :
sdep = replacing [ dep ]
debug ( " deps: target %s : replacing dependency %s with builtin subsystem %s " % ( t . sname , dep , sdep ) )
t . samba_deps_extended [ i ] = sdep
2010-10-21 04:19:09 +04:00
def replace_grouping_libraries ( bld , tgt_list ) :
''' replace dependencies based on grouping libraries
If a library is marked as a grouping library , then any target that
depends on a subsystem that is part of that grouping library gets
that dependency replaced with a dependency on the grouping library
'''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
grouping = { }
# find our list of grouping libraries, mapped from the subsystems they depend on
for t in tgt_list :
if not getattr ( t , ' grouping_library ' , False ) :
continue
for dep in t . samba_deps_extended :
2010-10-30 04:22:29 +04:00
bld . ASSERT ( dep in targets , " grouping library target %s not declared in %s " % ( dep , t . sname ) )
2010-10-21 04:19:09 +04:00
if targets [ dep ] == ' SUBSYSTEM ' :
grouping [ dep ] = t . sname
# now replace any dependencies on elements of grouping libraries
for t in tgt_list :
for i in range ( len ( t . samba_deps_extended ) ) :
dep = t . samba_deps_extended [ i ]
if dep in grouping :
if t . sname != grouping [ dep ] :
debug ( " deps: target %s : replacing dependency %s with grouping library %s " % ( t . sname , dep , grouping [ dep ] ) )
t . samba_deps_extended [ i ] = grouping [ dep ]
2010-03-22 08:57:44 +03:00
2010-03-17 12:12:16 +03:00
def build_direct_deps ( bld , tgt_list ) :
''' build the direct_objects and direct_libs sets for each target '''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-29 15:27:17 +04:00
syslib_deps = LOCAL_CACHE ( bld , ' SYSLIB_DEPS ' )
2010-10-21 06:52:47 +04:00
2010-03-17 12:12:16 +03:00
global_deps = bld . env . GLOBAL_DEPENDENCIES
2010-10-21 06:52:47 +04:00
global_deps_exclude = set ( )
for dep in global_deps :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( dep )
2010-10-21 06:52:47 +04:00
for d in t . samba_deps :
# prevent loops from the global dependencies list
global_deps_exclude . add ( d )
global_deps_exclude . add ( d + ' .objlist ' )
2010-03-17 12:12:16 +03:00
for t in tgt_list :
t . direct_objects = set ( )
t . direct_libs = set ( )
t . direct_syslibs = set ( )
2010-10-20 11:17:52 +04:00
deps = t . samba_deps_extended [ : ]
2010-10-21 06:52:47 +04:00
if getattr ( t , ' samba_use_global_deps ' , False ) and not t . sname in global_deps_exclude :
2010-04-12 12:16:54 +04:00
deps . extend ( global_deps )
2010-03-17 12:12:16 +03:00
for d in deps :
2010-03-22 08:57:44 +03:00
if d == t . sname : continue
2010-03-17 12:12:16 +03:00
if not d in targets :
2010-10-27 03:37:58 +04:00
Logs . error ( " Unknown dependency ' %s ' in ' %s ' " % ( d , t . sname ) )
2010-04-08 16:01:27 +04:00
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
if targets [ d ] in [ ' EMPTY ' , ' DISABLED ' ] :
continue
2010-10-21 10:45:23 +04:00
if targets [ d ] == ' PYTHON ' and targets [ t . sname ] != ' PYTHON ' and t . sname . find ( ' .objlist ' ) == - 1 :
# this check should be more restrictive, but for now we have pidl-generated python
# code that directly depends on other python modules
2010-10-21 07:55:19 +04:00
Logs . error ( ' ERROR: Target %s has dependency on python module %s ' % ( t . sname , d ) )
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
if targets [ d ] == ' SYSLIB ' :
t . direct_syslibs . add ( d )
2010-03-29 15:27:17 +04:00
if d in syslib_deps :
for implied in TO_LIST ( syslib_deps [ d ] ) :
2021-08-19 18:31:24 +03:00
if targets [ implied ] == ' SUBSYSTEM ' :
it = bld . get_tgen_by_name ( implied )
sit = getattr ( it , ' samba_builtin_subsystem ' , None )
if sit :
implied = sit . sname
if targets [ implied ] == ' BUILTIN ' :
2010-03-30 09:06:55 +04:00
t . direct_objects . add ( implied )
2010-04-13 05:41:13 +04:00
elif targets [ implied ] == ' SYSLIB ' :
t . direct_syslibs . add ( implied )
elif targets [ implied ] in [ ' LIBRARY ' , ' MODULE ' ] :
2010-03-30 09:06:55 +04:00
t . direct_libs . add ( implied )
2010-04-13 05:41:13 +04:00
else :
Logs . error ( ' Implied dependency %s in %s is of type %s ' % (
implied , t . sname , targets [ implied ] ) )
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
continue
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( d )
2010-03-17 12:12:16 +03:00
if t2 is None :
2010-04-09 15:12:02 +04:00
Logs . error ( " no task %s of type %s in %s " % ( d , targets [ d ] , t . sname ) )
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
if t2 . samba_type in [ ' LIBRARY ' , ' MODULE ' ] :
t . direct_libs . add ( d )
2021-08-19 18:31:24 +03:00
elif t2 . samba_type in [ ' SUBSYSTEM ' , ' BUILTIN ' , ' ASN1 ' , ' PYTHON ' ] :
2010-03-17 12:12:16 +03:00
t . direct_objects . add ( d )
2021-08-21 00:05:57 +03:00
elif t2 . samba_type in [ ' PLUGIN ' ] :
Logs . error ( ' Implicit dependency %s in %s is of type %s ' % (
d , t . sname , t2 . samba_type ) )
sys . exit ( 1 )
2021-08-19 18:31:24 +03:00
2010-03-17 12:12:16 +03:00
debug ( ' deps: built direct dependencies ' )
2010-03-22 08:57:44 +03:00
def dependency_loop ( loops , t , target ) :
''' add a dependency loop to the loops dictionary '''
if t . sname == target :
return
if not target in loops :
loops [ target ] = set ( )
if not t . sname in loops [ target ] :
loops [ target ] . add ( t . sname )
2010-03-17 12:12:16 +03:00
2010-03-22 08:57:44 +03:00
def indirect_libs ( bld , t , chain , loops ) :
2010-03-17 12:12:16 +03:00
''' recursively calculate the indirect library dependencies for a target
An indirect library is a library that results from a dependency on
a subsystem
'''
ret = getattr ( t , ' indirect_libs ' , None )
if ret is not None :
return ret
ret = set ( )
for obj in t . direct_objects :
if obj in chain :
2010-03-22 08:57:44 +03:00
dependency_loop ( loops , t , obj )
2010-03-17 14:07:11 +03:00
continue
2010-03-17 12:12:16 +03:00
chain . add ( obj )
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( obj )
2010-03-22 08:57:44 +03:00
r2 = indirect_libs ( bld , t2 , chain , loops )
2010-03-17 12:12:16 +03:00
chain . remove ( obj )
ret = ret . union ( t2 . direct_libs )
ret = ret . union ( r2 )
2010-03-22 08:57:44 +03:00
for obj in indirect_objects ( bld , t , set ( ) , loops ) :
2010-03-17 12:12:16 +03:00
if obj in chain :
2010-03-22 08:57:44 +03:00
dependency_loop ( loops , t , obj )
2010-03-17 12:12:16 +03:00
continue
chain . add ( obj )
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( obj )
2010-03-22 08:57:44 +03:00
r2 = indirect_libs ( bld , t2 , chain , loops )
2010-03-17 12:12:16 +03:00
chain . remove ( obj )
ret = ret . union ( t2 . direct_libs )
ret = ret . union ( r2 )
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
t . indirect_libs = ret
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
return ret
2010-03-17 14:07:11 +03:00
2010-03-22 08:57:44 +03:00
def indirect_objects ( bld , t , chain , loops ) :
2010-03-17 12:12:16 +03:00
''' recursively calculate the indirect object dependencies for a target
indirect objects are the set of objects from expanding the
subsystem dependencies
'''
ret = getattr ( t , ' indirect_objects ' , None )
if ret is not None : return ret
ret = set ( )
for lib in t . direct_objects :
if lib in chain :
2010-03-22 08:57:44 +03:00
dependency_loop ( loops , t , lib )
2010-03-17 12:12:16 +03:00
continue
chain . add ( lib )
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( lib )
2010-03-22 08:57:44 +03:00
r2 = indirect_objects ( bld , t2 , chain , loops )
2010-03-17 12:12:16 +03:00
chain . remove ( lib )
ret = ret . union ( t2 . direct_objects )
ret = ret . union ( r2 )
t . indirect_objects = ret
return ret
2010-03-22 08:57:44 +03:00
def extended_objects ( bld , t , chain ) :
''' recursively calculate the extended object dependencies for a target
2010-03-17 12:12:16 +03:00
2010-03-22 08:57:44 +03:00
extended objects are the union of :
- direct objects
- indirect objects
- direct and indirect objects of all direct and indirect libraries
2010-03-17 12:12:16 +03:00
'''
2010-03-22 08:57:44 +03:00
ret = getattr ( t , ' extended_objects ' , None )
2010-03-17 12:12:16 +03:00
if ret is not None : return ret
2010-03-22 08:57:44 +03:00
ret = set ( )
2010-03-31 13:13:55 +04:00
ret = ret . union ( t . final_objects )
2010-03-17 12:12:16 +03:00
2010-03-31 13:13:55 +04:00
for lib in t . final_libs :
2010-03-22 08:57:44 +03:00
if lib in chain :
continue
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( lib )
2010-03-22 08:57:44 +03:00
chain . add ( lib )
r2 = extended_objects ( bld , t2 , chain )
chain . remove ( lib )
2010-03-31 13:13:55 +04:00
ret = ret . union ( t2 . final_objects )
2010-03-17 12:12:16 +03:00
ret = ret . union ( r2 )
2010-03-22 08:57:44 +03:00
t . extended_objects = ret
2010-03-17 12:12:16 +03:00
return ret
2010-03-22 08:57:44 +03:00
def includes_objects ( bld , t , chain , inc_loops ) :
2010-03-17 12:12:16 +03:00
''' recursively calculate the includes object dependencies for a target
includes dependencies come from either library or object dependencies
'''
ret = getattr ( t , ' includes_objects ' , None )
if ret is not None :
return ret
ret = t . direct_objects . copy ( )
ret = ret . union ( t . direct_libs )
for obj in t . direct_objects :
if obj in chain :
2010-03-22 08:57:44 +03:00
dependency_loop ( inc_loops , t , obj )
2010-03-17 12:12:16 +03:00
continue
chain . add ( obj )
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( obj )
2010-03-22 08:57:44 +03:00
r2 = includes_objects ( bld , t2 , chain , inc_loops )
2010-03-17 12:12:16 +03:00
chain . remove ( obj )
ret = ret . union ( t2 . direct_objects )
ret = ret . union ( r2 )
for lib in t . direct_libs :
if lib in chain :
2010-03-22 08:57:44 +03:00
dependency_loop ( inc_loops , t , lib )
2010-03-17 12:12:16 +03:00
continue
chain . add ( lib )
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( lib )
2010-04-13 05:41:13 +04:00
if t2 is None :
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
Logs . error ( ' Target %s of type %s not found in direct_libs for %s ' % (
lib , targets [ lib ] , t . sname ) )
sys . exit ( 1 )
2010-03-22 08:57:44 +03:00
r2 = includes_objects ( bld , t2 , chain , inc_loops )
2010-03-17 12:12:16 +03:00
chain . remove ( lib )
ret = ret . union ( t2 . direct_objects )
ret = ret . union ( r2 )
t . includes_objects = ret
return ret
2010-03-22 08:57:44 +03:00
def break_dependency_loops ( bld , tgt_list ) :
''' find and break dependency loops '''
loops = { }
inc_loops = { }
2010-03-17 12:12:16 +03:00
2010-03-22 08:57:44 +03:00
# build up the list of loops
for t in tgt_list :
indirect_objects ( bld , t , set ( ) , loops )
indirect_libs ( bld , t , set ( ) , loops )
includes_objects ( bld , t , set ( ) , inc_loops )
2010-03-17 12:12:16 +03:00
2010-03-22 08:57:44 +03:00
# break the loops
2010-03-17 12:12:16 +03:00
for t in tgt_list :
2010-03-22 08:57:44 +03:00
if t . sname in loops :
for attr in [ ' direct_objects ' , ' indirect_objects ' , ' direct_libs ' , ' indirect_libs ' ] :
objs = getattr ( t , attr , set ( ) )
setattr ( t , attr , objs . difference ( loops [ t . sname ] ) )
for loop in loops :
debug ( ' deps: Found dependency loops for target %s : %s ' , loop , loops [ loop ] )
2010-03-30 09:06:55 +04:00
for loop in inc_loops :
debug ( ' deps: Found include loops for target %s : %s ' , loop , inc_loops [ loop ] )
2010-03-22 08:57:44 +03:00
# expand the loops mapping by one level
for loop in loops . copy ( ) :
for tgt in loops [ loop ] :
if tgt in loops :
loops [ loop ] = loops [ loop ] . union ( loops [ tgt ] )
2010-03-30 09:06:55 +04:00
for loop in inc_loops . copy ( ) :
for tgt in inc_loops [ loop ] :
if tgt in inc_loops :
inc_loops [ loop ] = inc_loops [ loop ] . union ( inc_loops [ tgt ] )
2010-03-22 08:57:44 +03:00
# expand indirect subsystem and library loops
for loop in loops . copy ( ) :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( loop )
2021-08-19 18:31:24 +03:00
if t . samba_type in [ ' SUBSYSTEM ' , ' BUILTIN ' ] :
2010-03-22 09:39:00 +03:00
loops [ loop ] = loops [ loop ] . union ( t . indirect_objects )
loops [ loop ] = loops [ loop ] . union ( t . direct_objects )
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' , ' PYTHON ' ] :
2010-03-22 09:39:00 +03:00
loops [ loop ] = loops [ loop ] . union ( t . indirect_libs )
loops [ loop ] = loops [ loop ] . union ( t . direct_libs )
2010-03-22 08:57:44 +03:00
if loop in loops [ loop ] :
loops [ loop ] . remove ( loop )
2010-03-30 09:06:55 +04:00
# expand indirect includes loops
for loop in inc_loops . copy ( ) :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( loop )
2010-03-30 09:06:55 +04:00
inc_loops [ loop ] = inc_loops [ loop ] . union ( t . includes_objects )
if loop in inc_loops [ loop ] :
inc_loops [ loop ] . remove ( loop )
2010-03-22 08:57:44 +03:00
# add in the replacement dependencies
2010-03-17 12:12:16 +03:00
for t in tgt_list :
2010-03-22 08:57:44 +03:00
for loop in loops :
2010-10-20 11:17:52 +04:00
for attr in [ ' indirect_objects ' , ' indirect_libs ' ] :
2010-03-22 08:57:44 +03:00
objs = getattr ( t , attr , set ( ) )
if loop in objs :
diff = loops [ loop ] . difference ( objs )
if t . sname in diff :
diff . remove ( t . sname )
if diff :
debug ( ' deps: Expanded target %s of type %s from loop %s by %s ' , t . sname , t . samba_type , loop , diff )
objs = objs . union ( diff )
setattr ( t , attr , objs )
2010-03-30 09:06:55 +04:00
for loop in inc_loops :
objs = getattr ( t , ' includes_objects ' , set ( ) )
if loop in objs :
diff = inc_loops [ loop ] . difference ( objs )
if t . sname in diff :
diff . remove ( t . sname )
if diff :
debug ( ' deps: Expanded target %s includes of type %s from loop %s by %s ' , t . sname , t . samba_type , loop , diff )
objs = objs . union ( diff )
setattr ( t , ' includes_objects ' , objs )
2010-03-17 12:12:16 +03:00
2010-03-31 13:13:55 +04:00
def reduce_objects ( bld , tgt_list ) :
''' reduce objects by looking for indirect object dependencies '''
2021-08-19 18:31:24 +03:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-31 13:13:55 +04:00
rely_on = { }
2010-03-17 12:12:16 +03:00
for t in tgt_list :
2010-03-31 13:13:55 +04:00
t . extended_objects = None
2010-03-30 16:08:01 +04:00
2010-04-02 11:16:23 +04:00
changed = False
2021-08-21 00:05:57 +03:00
for type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' , ' PLUGIN ' ] :
2010-03-22 08:57:44 +03:00
for t in tgt_list :
if t . samba_type != type : continue
# if we will indirectly link to a target then we don't need it
new = t . final_objects . copy ( )
for l in t . final_libs :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( l )
2010-03-22 08:57:44 +03:00
t2_obj = extended_objects ( bld , t2 , set ( ) )
dup = new . intersection ( t2_obj )
2010-04-15 07:59:51 +04:00
if t . sname in rely_on :
dup = dup . difference ( rely_on [ t . sname ] )
2010-03-22 08:57:44 +03:00
if dup :
2018-12-17 23:40:55 +03:00
# Do not remove duplicates of BUILTINS
2021-08-20 17:25:02 +03:00
for d in iter ( dup . copy ( ) ) :
2021-08-19 18:31:24 +03:00
dtype = targets [ d ]
if dtype == ' BUILTIN ' :
debug ( ' deps: BUILTIN SKIP: removing dups from %s of type %s : %s also in %s %s ' ,
2021-08-20 17:25:02 +03:00
t . sname , t . samba_type , d , t2 . samba_type , l )
dup . remove ( d )
if len ( dup ) == 0 :
2018-12-17 23:40:55 +03:00
continue
2010-03-22 08:57:44 +03:00
debug ( ' deps: removing dups from %s of type %s : %s also in %s %s ' ,
t . sname , t . samba_type , dup , t2 . samba_type , l )
new = new . difference ( dup )
changed = True
2010-03-30 16:08:01 +04:00
if not l in rely_on :
rely_on [ l ] = set ( )
rely_on [ l ] = rely_on [ l ] . union ( dup )
2021-08-19 18:31:24 +03:00
for n in iter ( new . copy ( ) ) :
# if we got the builtin version as well
# as the native one, we keep using the
# builtin one and remove the rest.
# Otherwise our check_duplicate_sources()
# checks would trigger!
if n . endswith ( ' .builtin.objlist ' ) :
unused = n . replace ( ' .builtin.objlist ' , ' .objlist ' )
if unused in new :
new . remove ( unused )
unused = n . replace ( ' .builtin.objlist ' , ' ' )
if unused in new :
new . remove ( unused )
2010-03-22 08:57:44 +03:00
t . final_objects = new
2010-04-02 11:16:23 +04:00
if not changed :
return False
2010-03-30 16:08:01 +04:00
# add back in any objects that were relied upon by the reduction rules
for r in rely_on :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( r )
2010-03-30 16:08:01 +04:00
t . final_objects = t . final_objects . union ( rely_on [ r ] )
2010-04-02 11:16:23 +04:00
return True
2010-03-31 13:13:55 +04:00
2010-10-29 04:51:17 +04:00
def show_library_loop ( bld , lib1 , lib2 , path , seen ) :
''' show the detailed path of a library loop between lib1 and lib2 '''
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( lib1 )
2010-10-29 04:51:17 +04:00
if not lib2 in getattr ( t , ' final_libs ' , set ( ) ) :
return
for d in t . samba_deps_extended :
if d in seen :
continue
seen . add ( d )
path2 = path + ' => ' + d
if d == lib2 :
Logs . warn ( ' library loop path: ' + path2 )
return
show_library_loop ( bld , d , lib2 , path2 , seen )
seen . remove ( d )
2010-03-31 13:13:55 +04:00
def calculate_final_deps ( bld , tgt_list , loops ) :
''' calculate the final library and object dependencies '''
for t in tgt_list :
# start with the maximum possible list
t . final_libs = t . direct_libs . union ( indirect_libs ( bld , t , set ( ) , loops ) )
t . final_objects = t . direct_objects . union ( indirect_objects ( bld , t , set ( ) , loops ) )
for t in tgt_list :
# don't depend on ourselves
if t . sname in t . final_libs :
t . final_libs . remove ( t . sname )
if t . sname in t . final_objects :
t . final_objects . remove ( t . sname )
2010-04-21 11:13:16 +04:00
# handle any non-shared binaries
for t in tgt_list :
if t . samba_type == ' BINARY ' and bld . NONSHARED_BINARY ( t . sname ) :
2010-10-30 09:37:27 +04:00
subsystem_list = LOCAL_CACHE ( bld , ' INIT_FUNCTIONS ' )
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-04-21 11:13:16 +04:00
# replace lib deps with objlist deps
for l in t . final_libs :
objname = l + ' .objlist '
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( objname )
2010-04-21 11:13:16 +04:00
if t2 is None :
Logs . error ( ' ERROR: subsystem %s not found ' % objname )
sys . exit ( 1 )
t . final_objects . add ( objname )
t . final_objects = t . final_objects . union ( extended_objects ( bld , t2 , set ( ) ) )
2010-10-30 09:37:27 +04:00
if l in subsystem_list :
# its a subsystem - we also need the contents of any modules
for d in subsystem_list [ l ] :
module_name = d [ ' TARGET ' ]
if targets [ module_name ] == ' LIBRARY ' :
objname = module_name + ' .objlist '
elif targets [ module_name ] == ' SUBSYSTEM ' :
objname = module_name
else :
continue
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( objname )
2010-10-30 09:37:27 +04:00
if t2 is None :
Logs . error ( ' ERROR: subsystem %s not found ' % objname )
sys . exit ( 1 )
t . final_objects . add ( objname )
t . final_objects = t . final_objects . union ( extended_objects ( bld , t2 , set ( ) ) )
2010-04-21 11:13:16 +04:00
t . final_libs = set ( )
2010-04-01 02:49:46 +04:00
2010-03-31 13:13:55 +04:00
# find any library loops
for t in tgt_list :
if t . samba_type in [ ' LIBRARY ' , ' PYTHON ' ] :
for l in t . final_libs . copy ( ) :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( l )
2010-03-31 13:13:55 +04:00
if t . sname in t2 . final_libs :
2010-10-13 15:58:25 +04:00
if getattr ( bld . env , " ALLOW_CIRCULAR_LIB_DEPENDENCIES " , False ) :
# we could break this in either direction. If one of the libraries
# has a version number, and will this be distributed publicly, then
# we should make it the lower level library in the DAG
Logs . warn ( ' deps: removing library loop %s from %s ' % ( t . sname , t2 . sname ) )
dependency_loop ( loops , t , t2 . sname )
t2 . final_libs . remove ( t . sname )
else :
Logs . error ( ' ERROR: circular library dependency between %s and %s '
% ( t . sname , t2 . sname ) )
2010-10-29 04:51:17 +04:00
show_library_loop ( bld , t . sname , t2 . sname , t . sname , set ( ) )
show_library_loop ( bld , t2 . sname , t . sname , t2 . sname , set ( ) )
2010-10-13 15:58:25 +04:00
sys . exit ( 1 )
2010-03-31 13:13:55 +04:00
2010-03-22 08:57:44 +03:00
for loop in loops :
debug ( ' deps: Found dependency loops for target %s : %s ' , loop , loops [ loop ] )
2010-03-15 12:43:31 +03:00
# we now need to make corrections for any library loops we broke up
# any target that depended on the target of the loop and doesn't
# depend on the source of the loop needs to get the loop source added
2021-08-21 00:05:57 +03:00
for type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' , ' PLUGIN ' , ' BINARY ' ] :
2010-03-15 12:43:31 +03:00
for t in tgt_list :
if t . samba_type != type : continue
for loop in loops :
2010-03-22 08:57:44 +03:00
if loop in t . final_libs :
diff = loops [ loop ] . difference ( t . final_libs )
if t . sname in diff :
diff . remove ( t . sname )
2010-04-15 07:59:51 +04:00
if t . sname in diff :
diff . remove ( t . sname )
# make sure we don't recreate the loop again!
for d in diff . copy ( ) :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( d )
2010-04-15 07:59:51 +04:00
if t2 . samba_type == ' LIBRARY ' :
if t . sname in t2 . final_libs :
debug ( ' deps: removing expansion %s from %s ' , d , t . sname )
diff . remove ( d )
2010-03-22 08:57:44 +03:00
if diff :
2010-04-15 07:59:51 +04:00
debug ( ' deps: Expanded target %s by loop %s libraries (loop %s ) %s ' , t . sname , loop ,
loops [ loop ] , diff )
2010-03-22 08:57:44 +03:00
t . final_libs = t . final_libs . union ( diff )
2010-03-15 12:43:31 +03:00
2010-03-31 13:13:55 +04:00
# remove objects that are also available in linked libs
2010-04-02 11:16:23 +04:00
count = 0
while reduce_objects ( bld , tgt_list ) :
count + = 1
if count > 100 :
2010-04-09 15:12:02 +04:00
Logs . warn ( " WARNING: Unable to remove all inter-target object duplicates " )
2010-04-02 11:16:23 +04:00
break
debug ( ' deps: Object reduction took %u iterations ' , count )
2010-03-31 13:13:55 +04:00
2010-03-26 05:02:39 +03:00
# add in any syslib dependencies
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if not t . samba_type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' , ' PLUGIN ' , ' SUBSYSTEM ' , ' BUILTIN ' ] :
2010-03-26 05:02:39 +03:00
continue
syslibs = set ( )
for d in t . final_objects :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( d )
2010-03-26 05:02:39 +03:00
syslibs = syslibs . union ( t2 . direct_syslibs )
# this adds the indirect syslibs as well, which may not be needed
# depending on the linker flags
for d in t . final_libs :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( d )
2010-03-26 05:02:39 +03:00
syslibs = syslibs . union ( t2 . direct_syslibs )
t . final_syslibs = syslibs
2010-04-15 07:59:51 +04:00
# find any unresolved library loops
lib_loop_error = False
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' , ' PYTHON ' ] :
2010-04-15 07:59:51 +04:00
for l in t . final_libs . copy ( ) :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( l )
2010-04-15 07:59:51 +04:00
if t . sname in t2 . final_libs :
Logs . error ( ' ERROR: Unresolved library loop %s from %s ' % ( t . sname , t2 . sname ) )
lib_loop_error = True
if lib_loop_error :
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
debug ( ' deps: removed duplicate dependencies ' )
2010-10-20 11:09:45 +04:00
def show_dependencies ( bld , target , seen ) :
''' recursively show the dependencies of target '''
if target in seen :
return
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( target )
2010-10-20 11:09:45 +04:00
if t is None :
Logs . error ( " ERROR: Unable to find target ' %s ' " % target )
sys . exit ( 1 )
Logs . info ( ' %s (OBJECTS): %s ' % ( target , t . direct_objects ) )
Logs . info ( ' %s (LIBS): %s ' % ( target , t . direct_libs ) )
Logs . info ( ' %s (SYSLIBS): %s ' % ( target , t . direct_syslibs ) )
seen . add ( target )
for t2 in t . direct_objects :
show_dependencies ( bld , t2 , seen )
def show_object_duplicates ( bld , tgt_list ) :
''' show a list of object files that are included in more than
one library or binary '''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
used_by = { }
Logs . info ( " showing duplicate objects " )
for t in tgt_list :
2010-10-21 08:30:27 +04:00
if not targets [ t . sname ] in [ ' LIBRARY ' , ' PYTHON ' ] :
2010-10-20 11:09:45 +04:00
continue
for n in getattr ( t , ' final_objects ' , set ( ) ) :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( n )
2010-10-20 11:09:45 +04:00
if not n in used_by :
used_by [ n ] = set ( )
used_by [ n ] . add ( t . sname )
for n in used_by :
if len ( used_by [ n ] ) > 1 :
Logs . info ( " target ' %s ' is used by %s " % ( n , used_by [ n ] ) )
Logs . info ( " showing indirect dependency counts (sorted by count) " )
2022-02-15 10:05:55 +03:00
def indirect_count ( t ) :
return len ( t . indirect_objects )
2010-10-20 11:09:45 +04:00
2022-02-15 10:05:55 +03:00
sorted_list = sorted ( tgt_list , key = indirect_count , reverse = True )
2010-10-20 11:09:45 +04:00
for t in sorted_list :
if len ( t . indirect_objects ) > 1 :
Logs . info ( " %s depends on %u indirect objects " % ( t . sname , len ( t . indirect_objects ) ) )
2010-03-17 12:12:16 +03:00
######################################################################
# this provides a way to save our dependency calculations between runs
2010-03-19 02:49:08 +03:00
savedeps_version = 3
2010-12-08 06:52:43 +03:00
savedeps_inputs = [ ' samba_deps ' , ' samba_includes ' , ' local_include ' , ' local_include_first ' , ' samba_cflags ' ,
2011-02-28 10:52:36 +03:00
' source ' , ' grouping_library ' , ' samba_ldflags ' , ' allow_undefined_symbols ' ,
' use_global_deps ' , ' global_include ' ]
2015-06-29 09:00:08 +03:00
savedeps_outputs = [ ' uselib ' , ' uselib_local ' , ' add_objects ' , ' includes ' ,
2016-03-26 15:18:07 +03:00
' cflags ' , ' ldflags ' , ' samba_deps_extended ' , ' final_libs ' ]
2010-03-17 02:58:07 +03:00
savedeps_outenv = [ ' INC_PATHS ' ]
2011-02-03 05:03:18 +03:00
savedeps_envvars = [ ' NONSHARED_BINARIES ' , ' GLOBAL_DEPENDENCIES ' , ' EXTRA_CFLAGS ' , ' EXTRA_LDFLAGS ' , ' EXTRA_INCLUDES ' ]
2010-10-30 07:33:06 +04:00
savedeps_caches = [ ' GLOBAL_DEPENDENCIES ' , ' TARGET_TYPE ' , ' INIT_FUNCTIONS ' , ' SYSLIB_DEPS ' ]
2010-03-19 02:49:08 +03:00
savedeps_files = [ ' buildtools/wafsamba/samba_deps.py ' ]
2010-03-17 12:12:16 +03:00
def save_samba_deps ( bld , tgt_list ) :
''' save the dependency calculations between builds, to make
further builds faster '''
2018-01-31 12:48:43 +03:00
denv = ConfigSet . ConfigSet ( )
2010-03-17 12:12:16 +03:00
denv . version = savedeps_version
denv . savedeps_inputs = savedeps_inputs
denv . savedeps_outputs = savedeps_outputs
denv . input = { }
denv . output = { }
2010-03-17 02:58:07 +03:00
denv . outenv = { }
2010-03-17 12:12:16 +03:00
denv . caches = { }
2010-04-21 11:29:00 +04:00
denv . envvar = { }
2010-03-19 02:49:08 +03:00
denv . files = { }
for f in savedeps_files :
denv . files [ f ] = os . stat ( os . path . join ( bld . srcnode . abspath ( ) , f ) ) . st_mtime
2010-03-17 12:12:16 +03:00
for c in savedeps_caches :
denv . caches [ c ] = LOCAL_CACHE ( bld , c )
2010-04-21 11:29:00 +04:00
for e in savedeps_envvars :
denv . envvar [ e ] = bld . env [ e ]
2010-03-17 12:12:16 +03:00
for t in tgt_list :
# save all the input attributes for each target
tdeps = { }
for attr in savedeps_inputs :
v = getattr ( t , attr , None )
if v is not None :
tdeps [ attr ] = v
if tdeps != { } :
denv . input [ t . sname ] = tdeps
# save all the output attributes for each target
tdeps = { }
for attr in savedeps_outputs :
v = getattr ( t , attr , None )
if v is not None :
tdeps [ attr ] = v
if tdeps != { } :
denv . output [ t . sname ] = tdeps
2010-03-17 02:58:07 +03:00
tdeps = { }
for attr in savedeps_outenv :
if attr in t . env :
tdeps [ attr ] = t . env [ attr ]
if tdeps != { } :
denv . outenv [ t . sname ] = tdeps
2018-11-15 13:41:07 +03:00
depsfile = os . path . join ( bld . cache_dir , " sambadeps " )
2014-09-27 01:46:01 +04:00
denv . store_fast ( depsfile )
2010-03-17 12:12:16 +03:00
2010-04-01 02:49:46 +04:00
2010-03-17 12:12:16 +03:00
def load_samba_deps ( bld , tgt_list ) :
''' load a previous set of build dependencies if possible '''
2018-11-15 13:41:07 +03:00
depsfile = os . path . join ( bld . cache_dir , " sambadeps " )
2018-01-31 12:48:43 +03:00
denv = ConfigSet . ConfigSet ( )
2010-03-17 12:12:16 +03:00
try :
debug ( ' deps: checking saved dependencies ' )
2014-09-27 01:46:01 +04:00
denv . load_fast ( depsfile )
2010-03-17 12:12:16 +03:00
if ( denv . version != savedeps_version or
denv . savedeps_inputs != savedeps_inputs or
denv . savedeps_outputs != savedeps_outputs ) :
return False
2014-09-27 01:46:01 +04:00
except Exception :
2010-03-17 12:12:16 +03:00
return False
2010-03-19 02:49:08 +03:00
# check if critical files have changed
for f in savedeps_files :
if f not in denv . files :
return False
if denv . files [ f ] != os . stat ( os . path . join ( bld . srcnode . abspath ( ) , f ) ) . st_mtime :
return False
2010-03-17 12:12:16 +03:00
# check if caches are the same
for c in savedeps_caches :
if c not in denv . caches or denv . caches [ c ] != LOCAL_CACHE ( bld , c ) :
return False
2010-04-21 11:29:00 +04:00
# check if caches are the same
for e in savedeps_envvars :
if e not in denv . envvar or denv . envvar [ e ] != bld . env [ e ] :
return False
2010-03-17 12:12:16 +03:00
# check inputs are the same
for t in tgt_list :
tdeps = { }
for attr in savedeps_inputs :
v = getattr ( t , attr , None )
if v is not None :
tdeps [ attr ] = v
if t . sname in denv . input :
olddeps = denv . input [ t . sname ]
else :
olddeps = { }
if tdeps != olddeps :
#print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
return False
2010-04-01 02:49:46 +04:00
# put outputs in place
2010-04-01 15:19:32 +04:00
for t in tgt_list :
2010-03-17 12:12:16 +03:00
if not t . sname in denv . output : continue
tdeps = denv . output [ t . sname ]
for a in tdeps :
setattr ( t , a , tdeps [ a ] )
2010-03-17 02:58:07 +03:00
# put output env vars in place
2010-04-01 15:19:32 +04:00
for t in tgt_list :
2010-03-17 02:58:07 +03:00
if not t . sname in denv . outenv : continue
tdeps = denv . outenv [ t . sname ]
for a in tdeps :
t . env [ a ] = tdeps [ a ]
2010-03-17 12:12:16 +03:00
debug ( ' deps: loaded saved dependencies ' )
return True
2022-01-21 19:06:15 +03:00
def generate_clangdb ( bld ) :
classes = [ ]
for x in ( ' c ' , ' cxx ' ) :
cls = Task . classes . get ( x )
if cls :
classes . append ( cls )
task_classes = tuple ( classes )
tasks = [ ]
for g in bld . groups :
for tg in g :
if isinstance ( tg , Task . Task ) :
lst = [ tg ]
else :
lst = tg . tasks
for task in lst :
try :
2022-05-05 12:32:13 +03:00
task . last_cmd
2022-01-21 19:06:15 +03:00
except AttributeError :
continue
if isinstance ( task , task_classes ) :
tasks . append ( task )
if len ( tasks ) == 0 :
return
database_file = bld . bldnode . make_node ( ' compile_commands.json ' )
Logs . info ( ' Build commands will be stored in %s ' ,
database_file . path_from ( bld . path ) )
try :
root = database_file . read_json ( )
except IOError :
root = [ ]
clang_db = dict ( ( x [ ' file ' ] , x ) for x in root )
for task in tasks :
f_node = task . inputs [ 0 ]
cmd = task . last_cmd
filename = f_node . path_from ( task . get_cwd ( ) )
entry = {
" directory " : task . get_cwd ( ) . abspath ( ) ,
" arguments " : cmd ,
" file " : filename ,
}
clang_db [ filename ] = entry
root = list ( clang_db . values ( ) )
database_file . write_json ( root )
2010-04-01 02:49:46 +04:00
2010-03-17 12:12:16 +03:00
def check_project_rules ( bld ) :
''' check the project rules - ensuring the targets are sane '''
2010-03-22 08:57:44 +03:00
loops = { }
inc_loops = { }
2010-03-17 12:12:16 +03:00
2010-10-29 04:52:25 +04:00
tgt_list = get_tgt_list ( bld )
2010-03-17 12:12:16 +03:00
add_samba_attributes ( bld , tgt_list )
2010-10-20 11:09:45 +04:00
force_project_rules = ( Options . options . SHOWDEPS or
Options . options . SHOW_DUPLICATES )
if not force_project_rules and load_samba_deps ( bld , tgt_list ) :
2010-03-17 14:07:11 +03:00
return
2019-06-12 13:27:04 +03:00
timer = Utils . Timer ( )
2010-10-27 04:47:54 +04:00
2010-12-17 21:16:33 +03:00
bld . new_rules = True
2010-04-09 15:12:02 +04:00
Logs . info ( " Checking project rules ... " )
2010-03-21 03:04:26 +03:00
2010-03-17 12:12:16 +03:00
debug ( ' deps: project rules checking started ' )
2021-08-19 18:31:24 +03:00
replace_builtin_subsystem_deps ( bld , tgt_list )
debug ( " deps: replace_builtin_subsystem_deps: %s " % str ( timer ) )
2010-03-17 12:12:16 +03:00
expand_subsystem_deps ( bld )
2010-10-27 04:47:54 +04:00
2019-06-12 13:27:04 +03:00
debug ( " deps: expand_subsystem_deps: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-10-21 04:19:09 +04:00
replace_grouping_libraries ( bld , tgt_list )
2010-10-27 04:47:54 +04:00
2019-06-12 13:27:04 +03:00
debug ( " deps: replace_grouping_libraries: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-03-17 12:12:16 +03:00
build_direct_deps ( bld , tgt_list )
2010-10-20 11:09:45 +04:00
2019-06-12 13:27:04 +03:00
debug ( " deps: build_direct_deps: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-03-22 08:57:44 +03:00
break_dependency_loops ( bld , tgt_list )
2010-03-17 12:12:16 +03:00
2019-06-12 13:27:04 +03:00
debug ( " deps: break_dependency_loops: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-10-20 11:09:45 +04:00
if Options . options . SHOWDEPS :
show_dependencies ( bld , Options . options . SHOWDEPS , set ( ) )
2010-10-21 08:30:27 +04:00
calculate_final_deps ( bld , tgt_list , loops )
2019-06-12 13:27:04 +03:00
debug ( " deps: calculate_final_deps: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-10-20 11:09:45 +04:00
if Options . options . SHOW_DUPLICATES :
show_object_duplicates ( bld , tgt_list )
2010-03-17 12:12:16 +03:00
# run the various attribute generators
for f in [ build_dependencies , build_includes , add_init_functions ] :
debug ( ' deps: project rules checking %s ' , f )
for t in tgt_list : f ( t )
2019-06-12 13:27:04 +03:00
debug ( " deps: %s : %s " % ( f , str ( timer ) ) )
2010-03-17 12:12:16 +03:00
debug ( ' deps: project rules stage1 completed ' )
2010-03-21 03:04:26 +03:00
if not check_duplicate_sources ( bld , tgt_list ) :
2010-04-09 15:12:02 +04:00
Logs . error ( " Duplicate sources present - aborting " )
2010-03-21 03:04:26 +03:00
sys . exit ( 1 )
2019-06-12 13:27:04 +03:00
debug ( " deps: check_duplicate_sources: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2015-11-19 03:55:43 +03:00
if not bld . check_group_ordering ( tgt_list ) :
2010-05-03 18:04:56 +04:00
Logs . error ( " Bad group ordering - aborting " )
sys . exit ( 1 )
2019-06-12 13:27:04 +03:00
debug ( " deps: check_group_ordering: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-03-17 12:12:16 +03:00
show_final_deps ( bld , tgt_list )
2019-06-12 13:27:04 +03:00
debug ( " deps: show_final_deps: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-03-17 12:12:16 +03:00
debug ( ' deps: project rules checking completed - %u targets checked ' ,
len ( tgt_list ) )
2010-10-17 15:34:17 +04:00
if not bld . is_install :
save_samba_deps ( bld , tgt_list )
2010-03-17 12:12:16 +03:00
2019-06-12 13:27:04 +03:00
debug ( " deps: save_samba_deps: %s " % str ( timer ) )
2010-10-27 04:47:54 +04:00
2010-04-09 15:12:02 +04:00
Logs . info ( " Project rules pass " )
2010-03-21 03:04:26 +03:00
2022-01-21 19:06:15 +03:00
if bld . cmd == ' build ' :
Task . Task . keep_last_cmd = True
bld . add_post_fun ( generate_clangdb )
2010-03-17 12:12:16 +03:00
def CHECK_PROJECT_RULES ( bld ) :
''' enable checking of project targets for sanity '''
if bld . env . added_project_rules :
return
bld . env . added_project_rules = True
bld . add_pre_fun ( check_project_rules )
Build . BuildContext . CHECK_PROJECT_RULES = CHECK_PROJECT_RULES
2010-03-17 14:07:11 +03:00