2010-03-17 12:12:16 +03:00
# Samba automatic dependency handling and project rules
2010-03-17 14:07:11 +03:00
2010-04-09 15:12:02 +04:00
import Build , os , re , Environment , Logs
2010-03-17 14:07:11 +03:00
from samba_utils import *
from samba_autoconf import *
2010-03-30 09:06:55 +04:00
from samba_bundled import BUILTIN_LIBRARY
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 )
def TARGET_ALIAS ( bld , target , alias ) :
''' define an alias for a target name '''
cache = LOCAL_CACHE ( bld , ' TARGET_ALIAS ' )
2010-03-18 15:47:48 +03:00
if alias in cache :
2010-04-09 15:12:02 +04:00
Logs . error ( " Target alias %s already set to %s : newalias %s " % ( alias , cache [ alias ] , target ) )
2010-04-08 16:01:27 +04:00
sys . exit ( 1 )
2010-03-17 14:07:11 +03:00
cache [ alias ] = target
Build . BuildContext . TARGET_ALIAS = TARGET_ALIAS
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 14:07:11 +03:00
def EXPAND_ALIAS ( bld , target ) :
''' expand a target name via an alias '''
aliases = LOCAL_CACHE ( bld , ' TARGET_ALIAS ' )
if target in aliases :
return aliases [ target ]
return target
Build . BuildContext . EXPAND_ALIAS = EXPAND_ALIAS
2010-03-17 12:12:16 +03:00
def expand_subsystem_deps ( bld ) :
''' expand the reverse dependencies resulting from subsystem
attributes of modules '''
subsystems = LOCAL_CACHE ( bld , ' INIT_FUNCTIONS ' )
aliases = LOCAL_CACHE ( bld , ' TARGET_ALIAS ' )
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
for s in subsystems :
if s in aliases :
s = aliases [ s ]
bld . ASSERT ( s in targets , " Subsystem target %s not declared " % s )
type = targets [ s ]
if type == ' DISABLED ' or type == ' EMPTY ' :
continue
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
t = bld . name_to_obj ( s , bld . env )
for d in subsystems [ s ] :
type = targets [ d [ ' TARGET ' ] ]
if type != ' DISABLED ' and type != ' EMPTY ' :
2010-06-15 03:00:40 +04:00
bld . ASSERT ( t is not None ,
" Subsystem target %s for %s ( %s ) not found " % ( s , d [ ' TARGET ' ] , type ) )
2010-03-17 12:12:16 +03:00
t . samba_deps_extended . append ( d [ ' TARGET ' ] )
t2 = bld . name_to_obj ( d [ ' TARGET ' ] , bld . env )
t2 . samba_includes_extended . extend ( t . samba_includes_extended )
t2 . samba_deps_extended . extend ( t . samba_deps_extended )
t . samba_deps_extended = unique_list ( t . 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
'''
2010-03-23 23:44:48 +03:00
if self . samba_type in [ ' LIBRARY ' , ' BINARY ' , ' PYTHON ' ] :
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
libs = self . final_syslibs . copy ( )
( ccflags , ldflags ) = library_flags ( self , list ( libs ) )
new_ldflags = getattr ( self , ' ldflags ' , [ ] )
new_ldflags . extend ( ldflags )
self . ldflags = new_ldflags
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 )
if self . samba_type in [ ' SUBSYSTEM ' ] :
# this is needed for the ccflags of libs that come from pkg_config
self . uselib = list ( self . direct_syslibs )
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
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
2010-03-17 14:07:11 +03:00
if getattr ( self , ' local_include ' , True ) == True and getattr ( self , ' local_include_first ' , True ) :
includes . append ( ' . ' )
2010-03-17 12:12:16 +03:00
includes . extend ( self . samba_includes_extended )
2010-03-17 14:07:11 +03:00
if ' EXTRA_INCLUDES ' in bld . env :
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 :
2010-03-17 14:07:11 +03:00
t = bld . name_to_obj ( d , bld . env )
2010-03-17 12:12:16 +03:00
bld . ASSERT ( t is not None , " Unable to find dependency %s for %s " % ( d , self . sname ) )
inclist = getattr ( t , ' samba_includes_extended ' , [ ] )
2010-03-17 14:07:11 +03:00
if getattr ( t , ' local_include ' , True ) == True :
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 :
relpath = os_path_relpath ( inc , mypath )
includes . append ( relpath )
2010-03-17 14:07:11 +03:00
if getattr ( self , ' local_include ' , True ) == True and not getattr ( self , ' local_include_first ' , True ) :
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 )
relinc = os_path_relpath ( absinc , self . bld . srcnode . abspath ( ) )
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 )
if modules == [ ] :
return
2010-03-17 12:12:16 +03:00
sentinal = getattr ( self , ' init_function_sentinal ' , ' NULL ' )
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-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 == [ ] :
cflags . append ( ' -DSTATIC_ %s _MODULES= %s ' % ( m , sentinal ) )
else :
cflags . append ( ' -DSTATIC_ %s _MODULES= %s ' % ( m , ' , ' . join ( init_fn_list ) + ' , ' + sentinal ) )
2010-03-17 14:07:11 +03:00
self . ccflags = cflags
2010-03-17 12:12:16 +03:00
def check_duplicate_sources ( bld , tgt_list ) :
''' see if we are compiling the same source file into multiple
subsystem targets for the same library or binary '''
debug ( ' deps: checking for duplicate sources ' )
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-21 03:04:26 +03:00
ret = True
seen = set ( )
for t in tgt_list :
obj_sources = getattr ( t , ' source ' , ' ' )
2010-04-26 05:11:21 +04:00
tpath = os . path . normpath ( os_path_relpath ( t . path . abspath ( bld . env ) , t . env . BUILD_DIRECTORY + ' /default ' ) )
2010-03-21 03:04:26 +03:00
obj_sources = bld . SUBDIR ( tpath , obj_sources )
t . samba_source_set = set ( TO_LIST ( obj_sources ) )
2010-03-17 12:12:16 +03:00
for t in tgt_list :
if not targets [ t . sname ] in [ ' LIBRARY ' , ' BINARY ' , ' PYTHON ' ] :
continue
sources = [ ]
for obj in t . add_objects :
t2 = t . bld . name_to_obj ( obj , bld . env )
2010-03-21 03:04:26 +03:00
source_set = getattr ( t2 , ' samba_source_set ' , set ( ) )
sources . append ( { ' dep ' : obj , ' src ' : source_set } )
for s in sources :
for s2 in sources :
if s [ ' dep ' ] == s2 [ ' dep ' ] : continue
common = s [ ' src ' ] . intersection ( s2 [ ' src ' ] )
if common . difference ( seen ) :
2010-04-09 15:12:02 +04:00
Logs . error ( " Target %s has duplicate source files in %s and %s : %s " % ( t . sname ,
2010-03-21 03:04:26 +03:00
s [ ' dep ' ] , s2 [ ' dep ' ] ,
common ) )
seen = seen . union ( common )
ret = False
return ret
2010-03-17 12:12:16 +03:00
def check_orpaned_targets ( bld , tgt_list ) :
2010-03-17 14:07:11 +03:00
''' check if any build targets are orphaned '''
target_dict = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-17 12:12:16 +03:00
debug ( ' deps: checking for orphaned targets ' )
for t in tgt_list :
if getattr ( t , ' samba_used ' , False ) == True :
2010-03-17 14:07:11 +03:00
continue
2010-03-17 12:12:16 +03:00
type = target_dict [ t . sname ]
if not type in [ ' BINARY ' , ' LIBRARY ' , ' MODULE ' , ' ET ' , ' PYTHON ' ] :
if re . search ( ' ^PIDL_ ' , t . sname ) is None :
2010-04-09 15:12:02 +04:00
Logs . warn ( " Target %s of type %s is unused by any other target " % ( t . sname , type ) )
2010-03-17 12:12:16 +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 :
t2 = bld . name_to_obj ( d , bld . env )
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
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 :
if not targets [ t . sname ] in [ ' LIBRARY ' , ' BINARY ' , ' PYTHON ' ] :
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 ' ,
t . sname , t . uselib , t . uselib_local , t . add_objects )
def add_samba_attributes ( bld , tgt_list ) :
''' ensure a target has a the required samba attributes '''
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 ) [ : ]
t . ccflags = getattr ( t , ' samba_cflags ' , ' ' )
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-03-17 12:12:16 +03:00
global_deps = bld . env . GLOBAL_DEPENDENCIES
for t in tgt_list :
t . direct_objects = set ( )
t . direct_libs = set ( )
t . direct_syslibs = set ( )
deps = t . samba_deps_extended
2010-04-12 12:16:54 +04:00
if getattr ( t , ' samba_use_global_deps ' , False ) :
deps . extend ( global_deps )
2010-03-17 12:12:16 +03:00
for d in deps :
d = EXPAND_ALIAS ( bld , d )
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-04-09 15:12:02 +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
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 ] ) :
2010-03-30 09:06:55 +04:00
if BUILTIN_LIBRARY ( bld , implied ) :
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
t2 = bld . name_to_obj ( d , bld . env )
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 )
elif t2 . samba_type in [ ' SUBSYSTEM ' , ' ASN1 ' , ' PYTHON ' ] :
t . direct_objects . add ( d )
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 )
t2 = bld . name_to_obj ( obj , bld . env )
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 )
t2 = bld . name_to_obj ( obj , bld . env )
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 )
t2 = bld . name_to_obj ( lib , bld . env )
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
t2 = bld . name_to_obj ( lib , bld . env )
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 )
t2 = bld . name_to_obj ( obj , bld . env )
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 )
t2 = bld . name_to_obj ( lib , bld . env )
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 ( ) :
t = bld . name_to_obj ( loop , bld . env )
if t . samba_type in [ ' SUBSYSTEM ' ] :
2010-03-22 09:39:00 +03:00
loops [ loop ] = loops [ loop ] . union ( t . indirect_objects )
loops [ loop ] = loops [ loop ] . union ( t . direct_objects )
2010-03-23 23:44:48 +03:00
if t . samba_type in [ ' LIBRARY ' , ' 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 ( ) :
t = bld . name_to_obj ( loop , bld . env )
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 :
for attr in [ ' direct_objects ' , ' indirect_objects ' , ' direct_libs ' , ' indirect_libs ' ] :
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 '''
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
2010-03-30 16:08:01 +04:00
for type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' ] :
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 :
t2 = bld . name_to_obj ( l , bld . env )
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 :
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 )
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 :
t = bld . name_to_obj ( r , bld . env )
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
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 ) :
# replace lib deps with objlist deps
for l in t . final_libs :
objname = l + ' .objlist '
t2 = bld . name_to_obj ( objname , bld . env )
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 ( ) ) )
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 ( ) :
t2 = bld . name_to_obj ( l , bld . env )
if t . sname in t2 . final_libs :
# 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
debug ( ' deps: removing library loop %s from %s ' , t . sname , t2 . sname )
dependency_loop ( loops , t , t2 . sname )
t2 . final_libs . remove ( t . sname )
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
2010-03-30 16:08:01 +04:00
for type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' , ' 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 ( ) :
t2 = bld . name_to_obj ( d , bld . env )
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 :
if not t . samba_type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' ] :
continue
syslibs = set ( )
for d in t . final_objects :
t2 = bld . name_to_obj ( d , bld . env )
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 :
t2 = bld . name_to_obj ( d , bld . env )
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 :
if t . samba_type in [ ' LIBRARY ' , ' PYTHON ' ] :
for l in t . final_libs . copy ( ) :
t2 = bld . name_to_obj ( l , bld . env )
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 ' )
######################################################################
# this provides a way to save our dependency calculations between runs
2010-03-19 02:49:08 +03:00
savedeps_version = 3
2010-03-21 03:04:26 +03:00
savedeps_inputs = [ ' samba_deps ' , ' samba_includes ' , ' local_include ' , ' local_include_first ' , ' samba_cflags ' , ' source ' ]
2010-03-17 12:12:16 +03:00
savedeps_outputs = [ ' uselib ' , ' uselib_local ' , ' add_objects ' , ' includes ' , ' ccflags ' ]
2010-03-17 02:58:07 +03:00
savedeps_outenv = [ ' INC_PATHS ' ]
2010-04-21 11:29:00 +04:00
savedeps_envvars = [ ' NONSHARED_BINARIES ' , ' GLOBAL_DEPENDENCIES ' ]
2010-03-29 15:27:17 +04:00
savedeps_caches = [ ' GLOBAL_DEPENDENCIES ' , ' TARGET_ALIAS ' , ' 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 '''
denv = Environment . Environment ( )
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
2010-03-17 12:12:16 +03:00
depsfile = os . path . join ( bld . bdir , " sambadeps " )
denv . store ( depsfile )
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 '''
depsfile = os . path . join ( bld . bdir , " sambadeps " )
denv = Environment . Environment ( )
try :
debug ( ' deps: checking saved dependencies ' )
denv . load ( depsfile )
if ( denv . version != savedeps_version or
denv . savedeps_inputs != savedeps_inputs or
denv . savedeps_outputs != savedeps_outputs ) :
return False
except :
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
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 '''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2010-03-22 08:57:44 +03:00
loops = { }
inc_loops = { }
2010-03-17 12:12:16 +03:00
# build a list of task generators we are interested in
tgt_list = [ ]
for tgt in targets :
type = targets [ tgt ]
if not type in [ ' SUBSYSTEM ' , ' MODULE ' , ' BINARY ' , ' LIBRARY ' , ' ASN1 ' , ' PYTHON ' ] :
continue
t = bld . name_to_obj ( tgt , bld . env )
2010-03-18 15:47:48 +03:00
if t is None :
2010-04-09 15:12:02 +04:00
Logs . error ( " Target %s of type %s has no task generator " % ( tgt , type ) )
2010-04-08 16:01:27 +04:00
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
tgt_list . append ( t )
add_samba_attributes ( bld , tgt_list )
if load_samba_deps ( bld , tgt_list ) :
2010-03-17 14:07:11 +03:00
return
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 ' )
expand_subsystem_deps ( bld )
build_direct_deps ( bld , tgt_list )
2010-03-22 08:57:44 +03:00
break_dependency_loops ( bld , tgt_list )
calculate_final_deps ( bld , tgt_list , loops )
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 )
debug ( ' deps: project rules stage1 completed ' )
#check_orpaned_targets(bld, tgt_list)
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 )
2010-05-03 18:04:56 +04:00
if not check_group_ordering ( bld , tgt_list ) :
Logs . error ( " Bad group ordering - aborting " )
sys . exit ( 1 )
2010-03-17 12:12:16 +03:00
show_final_deps ( bld , tgt_list )
debug ( ' deps: project rules checking completed - %u targets checked ' ,
len ( tgt_list ) )
save_samba_deps ( bld , tgt_list )
2010-04-09 15:12:02 +04:00
Logs . info ( " Project rules pass " )
2010-03-21 03:04:26 +03:00
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