2010-02-26 14:21:50 +03:00
# a waf tool to add autoconf-like macros to the configure section
# and for SAMBA_ macros for building libraries, binaries etc
import Build , os , Logs , sys , Configure , Options , string , Task , Utils , optparse
2010-02-28 09:34:43 +03:00
from TaskGen import feature , before
2010-02-26 14:21:50 +03:00
from Configure import conf
from Logs import debug
from TaskGen import extension
2010-03-07 07:17:46 +03:00
import shlex
2010-02-26 14:21:50 +03:00
LIB_PATH = " shared "
2010-02-28 09:34:43 +03:00
##########################################################
# create a node with a new name, based on an existing node
def NEW_NODE ( node , name ) :
ret = node . parent . find_or_declare ( [ name ] )
ASSERT ( node , ret is not None , " Unable to find new target with name ' %s ' from ' %s ' " % (
name , node . name ) )
return ret
#############################################################
# set a value in a local cache
# return False if it's already set
def SET_TARGET_TYPE ( ctx , target , value ) :
cache = LOCAL_CACHE ( ctx , ' TARGET_TYPE ' )
if target in cache :
ASSERT ( ctx , cache [ target ] == value ,
" Target ' %s ' re-defined as %s - was %s " % ( target , value , cache [ target ] ) )
debug ( " task_gen: Skipping duplicate target %s (curdir= %s ) " % ( target , ctx . curdir ) )
return False
assumed = LOCAL_CACHE ( ctx , ' ASSUMED_TARGET ' )
if target in assumed :
#if assumed[target] != value:
# print "Target '%s' was assumed of type '%s' but is '%s'" % (target, assumed[target], value)
ASSERT ( ctx , assumed [ target ] == value ,
" Target ' %s ' was assumed of type ' %s ' but is ' %s ' " % ( target , assumed [ target ] , value ) )
predeclared = LOCAL_CACHE ( ctx , ' PREDECLARED_TARGET ' )
if target in predeclared :
ASSERT ( ctx , predeclared [ target ] == value ,
" Target ' %s ' was predeclared of type ' %s ' but is ' %s ' " % ( target , predeclared [ target ] , value ) )
LOCAL_CACHE_SET ( ctx , ' TARGET_TYPE ' , target , value )
debug ( " task_gen: Target ' %s ' created of type ' %s ' in %s " % ( target , value , ctx . curdir ) )
return True
2010-02-26 14:21:50 +03:00
######################################################
# this is used as a decorator to make functions only
# run once. Based on the idea from
# http://stackoverflow.com/questions/815110/is-there-a-decorator-to-simply-cache-function-return-values
runonce_ret = { }
def runonce ( function ) :
def wrapper ( * args ) :
if args in runonce_ret :
return runonce_ret [ args ]
else :
ret = function ( * args )
runonce_ret [ args ] = ret
return ret
return wrapper
################################################################
# magic rpath handling
#
# we want a different rpath when installing and when building
# Note that this should really check if rpath is available on this platform
# and it should also honor an --enable-rpath option
def set_rpath ( bld ) :
if Options . is_install :
if bld . env [ ' RPATH_ON_INSTALL ' ] :
bld . env [ ' RPATH ' ] = [ ' -Wl,-rpath= %s /lib ' % bld . env . PREFIX ]
else :
bld . env [ ' RPATH ' ] = [ ]
else :
rpath = os . path . normpath ( ' %s / %s ' % ( bld . env [ ' BUILD_DIRECTORY ' ] , LIB_PATH ) )
bld . env . append_value ( ' RPATH ' , ' -Wl,-rpath= %s ' % rpath )
Build . BuildContext . set_rpath = set_rpath
#############################################################
# return a named build cache dictionary, used to store
# state inside the following functions
@conf
def LOCAL_CACHE ( ctx , name ) :
if name in ctx . env :
return ctx . env [ name ]
ctx . env [ name ] = { }
return ctx . env [ name ]
#############################################################
# set a value in a local cache
@conf
def LOCAL_CACHE_SET ( ctx , cachename , key , value ) :
cache = LOCAL_CACHE ( ctx , cachename )
cache [ key ] = value
#############################################################
# a build assert call
@conf
def ASSERT ( ctx , expression , msg ) :
if not expression :
sys . stderr . write ( " ERROR: %s \n " % msg )
raise AssertionError
Build . BuildContext . ASSERT = ASSERT
################################################################
# create a list of files by pre-pending each with a subdir name
def SUBDIR ( bld , subdir , list ) :
ret = ' '
2010-03-07 07:17:46 +03:00
for l in to_list ( list ) :
2010-02-26 14:21:50 +03:00
ret = ret + subdir + ' / ' + l + ' '
return ret
Build . BuildContext . SUBDIR = SUBDIR
##############################################
# remove .. elements from a path list
def NORMPATH ( bld , ilist ) :
2010-03-07 07:17:46 +03:00
return " " . join ( [ os . path . normpath ( p ) for p in to_list ( ilist ) ] )
2010-02-26 14:21:50 +03:00
Build . BuildContext . NORMPATH = NORMPATH
#######################################################
# d1 += d2
def dict_concat ( d1 , d2 ) :
for t in d2 :
if t not in d1 :
d1 [ t ] = d2 [ t ]
############################################################
# this overrides the 'waf -v' debug output to be in a nice
# unix like format instead of a python list.
# Thanks to ita on #waf for this
def exec_command ( self , cmd , * * kw ) :
import Utils , Logs
_cmd = cmd
if isinstance ( cmd , list ) :
_cmd = ' ' . join ( cmd )
debug ( ' runner: %s ' % _cmd )
if self . log :
self . log . write ( ' %s \n ' % cmd )
kw [ ' log ' ] = self . log
try :
if not kw . get ( ' cwd ' , None ) :
kw [ ' cwd ' ] = self . cwd
except AttributeError :
self . cwd = kw [ ' cwd ' ] = self . bldnode . abspath ( )
return Utils . exec_command ( cmd , * * kw )
Build . BuildContext . exec_command = exec_command
##########################################################
# add a new top level command to waf
def ADD_COMMAND ( opt , name , function ) :
Utils . g_module . __dict__ [ name ] = function
opt . name = function
Options . Handler . ADD_COMMAND = ADD_COMMAND
2010-03-17 13:53:29 +03:00
@feature ( ' * ' )
@before ( ' apply_core ' , ' exec_rule ' )
2010-02-28 09:34:43 +03:00
def process_depends_on ( self ) :
''' The new depends_on attribute for build rules
allow us to specify a dependency on output from
a source generation rule '''
if getattr ( self , ' depends_on ' , None ) :
lst = self . to_list ( self . depends_on )
for x in lst :
y = self . bld . name_to_obj ( x , self . env )
2010-03-09 00:17:26 +03:00
self . bld . ASSERT ( y is not None , " Failed to find dependency %s of %s " % ( x , self . name ) )
2010-02-28 09:34:43 +03:00
y . post ( )
2010-03-17 13:46:38 +03:00
if getattr ( y , ' more_includes ' , None ) :
self . includes + = " " + y . more_includes
#@feature('cprogram cc cshlib')
#@before('apply_core')
#def process_generated_dependencies(self):
# '''Ensure that any dependent source generation happens
# before any task that requires the output'''
# if getattr(self , 'depends_on', None):
# lst = self.to_list(self.depends_on)
# for x in lst:
# y = self.bld.name_to_obj(x, self.env)
# y.post()
def FIND_TASKGEN ( bld , name ) :
''' find a waf task generator given a target name '''
return bld . name_to_obj ( name )
Build . BuildContext . FIND_TASKGEN = FIND_TASKGEN
2010-02-28 09:34:43 +03:00
2010-02-26 14:21:50 +03:00
#import TaskGen, Task
#
#old_post_run = Task.Task.post_run
#def new_post_run(self):
# self.cached = True
# return old_post_run(self)
#
#for y in ['cc', 'cxx']:
# TaskGen.classes[y].post_run = new_post_run
2010-03-17 13:46:38 +03:00
def ENABLE_MAGIC_ORDERING ( bld ) :
''' enable automatic build order constraint calculation
see page 35 of the waf book '''
2010-03-17 13:53:29 +03:00
print " NOT Enabling magic ordering "
#bld.use_the_magic()
2010-03-17 13:46:38 +03:00
Build . BuildContext . ENABLE_MAGIC_ORDERING = ENABLE_MAGIC_ORDERING
def BUILD_PATH ( bld , relpath ) :
''' return a relative build path, given a relative path
for example , if called in the source4 / librpc directory , with the path
gen_ndr / tables . c , then it will return default / source4 / gen_ndr / tables . c
'''
ret = os . path . normpath ( os . path . join ( os . path . relpath ( bld . curdir , bld . env . TOPDIR ) , relpath ) )
ret = ' default/ %s ' % ret
return ret
Build . BuildContext . BUILD_PATH = BUILD_PATH
2010-03-07 02:37:32 +03:00
# this is a useful way of debugging some of the rules in waf
from TaskGen import feature , after
@feature ( ' dbg ' )
@after ( ' apply_core ' , ' apply_obj_vars_cc ' )
def dbg ( self ) :
if self . target == ' HEIMDAL_HEIM_ASN1 ' :
print " @@@@@@@@@@@@@@2 " , self . includes , self . env . _CCINCFLAGS
2010-03-07 07:17:46 +03:00
def to_list ( str ) :
''' Split a list, preserving quoted strings and existing lists '''
if isinstance ( str , list ) :
return str
return shlex . split ( str )
2010-03-07 16:25:47 +03:00
@conf
def SUBST_ENV_VAR ( conf , varname ) :
''' Substitute an environment variable for any embedded variables '''
return Utils . subst_vars ( conf . env [ varname ] , conf . env )
2010-03-08 12:34:15 +03:00
def ENFORCE_GROUP_ORDERING ( bld ) :
''' enforce group ordering for the project. This
makes the group ordering apply even when you specify
a target with - - target '''
if Options . options . compile_targets :
@feature ( ' * ' )
def force_previous_groups ( self ) :
my_id = id ( self )
bld = self . bld
stop = None
for g in bld . task_manager . groups :
for t in g . tasks_gen :
if id ( t ) == my_id :
stop = id ( g )
break
if stop is None :
return
for g in bld . task_manager . groups :
if id ( g ) == stop :
break
for t in g . tasks_gen :
t . post ( )
Build . BuildContext . ENFORCE_GROUP_ORDERING = ENFORCE_GROUP_ORDERING
2010-03-09 00:17:26 +03:00
# @feature('cc')
# @before('apply_lib_vars')
# def process_objects(self):
# if getattr(self, 'add_objects', None):
# lst = self.to_list(self.add_objects)
# for x in lst:
# y = self.name_to_obj(x)
# if not y:
# raise Utils.WafError('object %r was not found in uselib_local (required by add_objects %r)' % (x, self.name))
# y.post()
# self.env.append_unique('INC_PATHS', y.env.INC_PATHS)