2010-03-17 12:12:16 +03:00
# Samba automatic dependency handling and project rules
2010-03-17 14:07:11 +03:00
2010-03-17 12:12:16 +03:00
import Build , os , re , Environment
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 :
print ( " Target alias %s already set to %s : newalias %s " % ( alias , cache [ alias ] , target ) )
raise
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 )
bld . ASSERT ( t is not None , " Subsystem target %s not found " % s )
for d in subsystems [ s ] :
type = targets [ d [ ' TARGET ' ] ]
if type != ' DISABLED ' and type != ' EMPTY ' :
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 = [ ]
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 ' , ' ' )
tpath = os_path_relpath ( t . path . abspath ( bld . env ) , t . env [ ' BUILD_DIRECTORY ' ] + ' /default ' )
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 ) :
print ( " Target %s has duplicate source files in %s and %s : %s " % ( t . sname ,
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 :
print " Target %s of type %s is unused by any other target " % ( t . sname , type )
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
deps . extend ( global_deps )
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 :
print " Unknown dependency %s in %s " % ( d , t . sname )
raise
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 )
else :
t . direct_libs . add ( implied )
2010-03-17 12:12:16 +03:00
continue
t2 = bld . name_to_obj ( d , bld . env )
if t2 is None :
print " no task %s type %s " % ( d , targets [ d ] )
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 ( )
ret = ret . union ( t . direct_objects )
ret = ret . union ( t . indirect_objects )
2010-03-17 12:12:16 +03:00
2010-03-22 08:57:44 +03:00
for lib in t . direct_libs :
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 )
ret = ret . union ( t2 . direct_objects )
ret = ret . union ( t2 . indirect_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-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-22 08:57:44 +03:00
def calculate_final_deps ( bld , tgt_list , loops ) :
2010-03-17 12:12:16 +03:00
''' calculate the final library and object dependencies '''
for t in tgt_list :
# start with the maximum possible list
2010-03-22 08:57:44 +03:00
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 ) )
2010-03-17 12:12:16 +03:00
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 )
# 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 :
2010-03-18 15:47:48 +03:00
# 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
2010-03-22 08:57:44 +03:00
debug ( ' deps: removing library loop %s from %s ' , t . sname , t2 . sname )
dependency_loop ( loops , t , t2 . sname )
2010-03-17 12:12:16 +03:00
t2 . final_libs . remove ( t . sname )
2010-03-30 15:39:18 +04:00
for type in [ ' BINARY ' , ' PYTHON ' ] :
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 )
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
t . final_objects = new
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-22 08:57:44 +03:00
for type in [ ' BINARY ' , ' PYTHON ' , ' LIBRARY ' ] :
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 )
if diff :
debug ( ' deps: Expanded target %s by loop %s libraries %s ' , t . sname , loop , diff )
t . final_libs = t . final_libs . union ( diff )
2010-03-15 12:43:31 +03: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-03-17 12:12:16 +03:00
debug ( ' deps: removed duplicate dependencies ' )
2010-03-28 15:01:04 +04:00
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-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-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-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 )
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 )
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
# 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
# put outputs in place
for t in tgt_list :
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
for t in tgt_list :
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
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 :
print " Target %s of type %s has no task generator " % ( tgt , type )
raise
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-03-21 03:04:26 +03:00
print " Checking project rules ... "
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 ) :
print " Duplicate sources present - 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-03-21 03:04:26 +03:00
print " Project rules pass "
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