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
2019-02-12 09:16:06 +03:00
import errno
2016-03-26 15:18:07 +03:00
import os , sys , re , fnmatch , shlex , inspect
2017-02-08 09:58:40 +03:00
from optparse import SUPPRESS_HELP
2018-01-31 12:48:43 +03:00
from waflib import Build , Options , Utils , Task , Logs , Configure , Errors , Context
2018-10-28 00:32:35 +03:00
from waflib import Scripting
2018-01-31 12:48:43 +03:00
from waflib . TaskGen import feature , before , after
from waflib . Configure import ConfigurationContext
from waflib . Logs import debug
from waflib import ConfigSet
2018-09-03 13:04:58 +03:00
from waflib . Build import CACHE_SUFFIX
2010-02-26 14:21:50 +03:00
2010-03-20 08:27:48 +03:00
# TODO: make this a --option
2010-02-26 14:21:50 +03:00
LIB_PATH = " shared "
2010-02-28 09:34:43 +03:00
2019-02-06 18:27:41 +03:00
PY3 = sys . version_info [ 0 ] == 3
if PY3 :
# helper function to get a string from a variable that maybe 'str' or
# 'bytes' if 'bytes' then it is decoded using 'utf8'. If 'str' is passed
# it is returned unchanged
# Using this function is PY2/PY3 code should ensure in most cases
# the PY2 code runs unchanged in PY2 whereas the code in PY3 possibly
# decodes the variable (see PY2 implementation of this function below)
def get_string ( bytesorstring ) :
tmp = bytesorstring
if isinstance ( bytesorstring , bytes ) :
tmp = bytesorstring . decode ( ' utf8 ' )
elif not isinstance ( bytesorstring , str ) :
raise ValueError ( ' Expected byte of string for %s : %s ' % ( type ( bytesorstring ) , bytesorstring ) )
return tmp
else :
# Helper function to return string.
# if 'str' or 'unicode' passed in they are returned unchanged
# otherwise an exception is generated
# Using this function is PY2/PY3 code should ensure in most cases
# the PY2 code runs unchanged in PY2 whereas the code in PY3 possibly
# decodes the variable (see PY3 implementation of this function above)
def get_string ( bytesorstring ) :
tmp = bytesorstring
if not ( isinstance ( bytesorstring , str ) or isinstance ( bytesorstring , unicode ) ) :
raise ValueError ( ' Expected str or unicode for %s : %s ' % ( type ( bytesorstring ) , bytesorstring ) )
return tmp
2010-10-06 13:11:01 +04:00
# sigh, python octal constants are a mess
MODE_644 = int ( ' 644 ' , 8 )
2018-11-17 15:11:52 +03:00
MODE_744 = int ( ' 744 ' , 8 )
2010-10-06 13:11:01 +04:00
MODE_755 = int ( ' 755 ' , 8 )
2018-11-17 15:11:52 +03:00
MODE_777 = int ( ' 777 ' , 8 )
2010-10-06 13:11:01 +04:00
2016-03-26 15:18:07 +03:00
def conf ( f ) :
# override in order to propagate the argument "mandatory"
def fun ( * k , * * kw ) :
mandatory = True
if ' mandatory ' in kw :
mandatory = kw [ ' mandatory ' ]
del kw [ ' mandatory ' ]
try :
return f ( * k , * * kw )
except Errors . ConfigurationError :
if mandatory :
raise
fun . __name__ = f . __name__
if ' mandatory ' in inspect . getsource ( f ) :
fun = f
setattr ( Configure . ConfigurationContext , f . __name__ , fun )
setattr ( Build . BuildContext , f . __name__ , fun )
return f
Configure . conf = conf
Configure . conftest = conf
2010-03-24 08:25:37 +03:00
@conf
2010-02-28 09:34:43 +03:00
def SET_TARGET_TYPE ( ctx , target , value ) :
2010-03-28 15:01:04 +04:00
''' set the target type of a target '''
2010-02-28 09:34:43 +03:00
cache = LOCAL_CACHE ( ctx , ' TARGET_TYPE ' )
2010-04-12 10:21:21 +04:00
if target in cache and cache [ target ] != ' EMPTY ' :
2018-01-31 12:48:43 +03:00
Logs . error ( " ERROR: Target ' %s ' in directory %s re-defined as %s - was %s " % ( target , ctx . path . abspath ( ) , value , cache [ target ] ) )
2010-04-15 08:43:43 +04:00
sys . exit ( 1 )
2010-02-28 09:34:43 +03:00
LOCAL_CACHE_SET ( ctx , ' TARGET_TYPE ' , target , value )
2018-01-31 12:48:43 +03:00
debug ( " task_gen: Target ' %s ' created of type ' %s ' in %s " % ( target , value , ctx . path . abspath ( ) ) )
2010-02-28 09:34:43 +03:00
return True
2010-03-20 09:10:51 +03:00
def GET_TARGET_TYPE ( ctx , target ) :
''' get target type from cache '''
cache = LOCAL_CACHE ( ctx , ' TARGET_TYPE ' )
if not target in cache :
return None
return cache [ target ]
2010-03-25 06:20:45 +03:00
def ADD_LD_LIBRARY_PATH ( path ) :
''' add something to LD_LIBRARY_PATH '''
if ' LD_LIBRARY_PATH ' in os . environ :
oldpath = os . environ [ ' LD_LIBRARY_PATH ' ]
else :
oldpath = ' '
newpath = oldpath . split ( ' : ' )
if not path in newpath :
newpath . append ( path )
os . environ [ ' LD_LIBRARY_PATH ' ] = ' : ' . join ( newpath )
2010-03-28 15:01:04 +04:00
2010-11-30 03:10:31 +03:00
def needs_private_lib ( bld , target ) :
''' return True if a target links to a private library '''
2011-12-04 18:36:27 +04:00
for lib in getattr ( target , " final_libs " , [ ] ) :
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( lib )
2010-11-30 03:10:31 +03:00
if t and getattr ( t , ' private_library ' , False ) :
return True
2010-11-30 14:01:07 +03:00
return False
2010-11-30 03:10:31 +03:00
def install_rpath ( target ) :
2010-03-18 15:47:48 +03:00
''' the rpath value for installation '''
2010-11-30 03:10:31 +03:00
bld = target . bld
2010-03-23 17:00:48 +03:00
bld . env [ ' RPATH ' ] = [ ]
2010-11-05 02:03:20 +03:00
ret = set ( )
2010-03-20 15:41:15 +03:00
if bld . env . RPATH_ON_INSTALL :
2010-11-05 02:20:16 +03:00
ret . add ( bld . EXPAND_VARIABLES ( bld . env . LIBDIR ) )
2010-11-30 03:10:31 +03:00
if bld . env . RPATH_ON_INSTALL_PRIVATE and needs_private_lib ( bld , target ) :
2010-11-05 02:20:16 +03:00
ret . add ( bld . EXPAND_VARIABLES ( bld . env . PRIVATELIBDIR ) )
2010-11-05 02:03:20 +03:00
return list ( ret )
2010-03-18 15:47:48 +03:00
2010-02-26 14:21:50 +03:00
2010-03-23 17:00:48 +03:00
def build_rpath ( bld ) :
''' the rpath value for build '''
2010-11-05 04:30:01 +03:00
rpaths = [ os . path . normpath ( ' %s / %s ' % ( bld . env . BUILD_DIRECTORY , d ) ) for d in ( " shared " , " shared/private " ) ]
2010-03-23 17:00:48 +03:00
bld . env [ ' RPATH ' ] = [ ]
if bld . env . RPATH_ON_BUILD :
2010-11-05 04:30:01 +03:00
return rpaths
for rpath in rpaths :
ADD_LD_LIBRARY_PATH ( rpath )
2010-03-23 17:00:48 +03:00
return [ ]
2010-02-26 14:21:50 +03:00
@conf
def LOCAL_CACHE ( ctx , name ) :
2010-03-28 15:01:04 +04:00
''' return a named build cache dictionary, used to store
state inside other functions '''
2010-02-26 14:21:50 +03:00
if name in ctx . env :
return ctx . env [ name ]
ctx . env [ name ] = { }
return ctx . env [ name ]
@conf
def LOCAL_CACHE_SET ( ctx , cachename , key , value ) :
2010-03-28 15:01:04 +04:00
''' set a value in a local cache '''
2010-02-26 14:21:50 +03:00
cache = LOCAL_CACHE ( ctx , cachename )
cache [ key ] = value
2010-03-28 15:01:04 +04:00
2010-02-26 14:21:50 +03:00
@conf
def ASSERT ( ctx , expression , msg ) :
2010-03-28 15:01:04 +04:00
''' a build assert call '''
2010-02-26 14:21:50 +03:00
if not expression :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( " ERROR: %s \n " % msg )
2010-02-26 14:21:50 +03:00
Build . BuildContext . ASSERT = ASSERT
2010-03-28 15:01:04 +04:00
2010-02-26 14:21:50 +03:00
def SUBDIR ( bld , subdir , list ) :
2010-03-28 15:01:04 +04:00
''' create a list of files by pre-pending each with a subdir name '''
2010-02-26 14:21:50 +03:00
ret = ' '
2010-03-20 08:27:48 +03:00
for l in TO_LIST ( list ) :
2010-03-17 12:12:16 +03:00
ret = ret + os . path . normpath ( os . path . join ( subdir , l ) ) + ' '
2010-02-26 14:21:50 +03:00
return ret
Build . BuildContext . SUBDIR = SUBDIR
2010-03-28 15:01:04 +04:00
2010-02-26 14:21:50 +03:00
def dict_concat ( d1 , d2 ) :
2010-03-28 15:01:04 +04:00
''' concatenate two dictionaries d1 += d2 '''
2010-02-26 14:21:50 +03:00
for t in d2 :
if t not in d1 :
d1 [ t ] = d2 [ t ]
def ADD_COMMAND ( opt , name , function ) :
2010-03-28 15:01:04 +04:00
''' add a new top level command to waf '''
2018-01-31 12:48:43 +03:00
Context . g_module . __dict__ [ name ] = function
2010-02-26 14:21:50 +03:00
opt . name = function
2018-01-31 12:48:43 +03:00
Options . OptionsContext . ADD_COMMAND = ADD_COMMAND
2010-02-26 14:21:50 +03:00
2015-10-03 23:29:15 +03:00
@feature ( ' c ' , ' cc ' , ' cshlib ' , ' cprogram ' )
2010-03-17 13:53:29 +03:00
@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 :
2015-06-26 23:32:43 +03:00
y = self . bld . get_tgen_by_name ( x )
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
2010-03-20 08:27:48 +03:00
def unique_list ( seq ) :
''' return a uniquified list in the same order as the existing list '''
seen = { }
result = [ ]
for item in seq :
if item in seen : continue
seen [ item ] = True
result . append ( item )
return result
2010-03-28 15:01:04 +04:00
2010-09-27 02:24:04 +04:00
def TO_LIST ( str , delimiter = None ) :
2010-03-07 07:17:46 +03:00
''' Split a list, preserving quoted strings and existing lists '''
2010-03-23 20:48:32 +03:00
if str is None :
return [ ]
2010-03-07 07:17:46 +03:00
if isinstance ( str , list ) :
2015-01-07 11:41:02 +03:00
# we need to return a new independent list...
return list ( str )
2012-05-21 19:38:56 +04:00
if len ( str ) == 0 :
return [ ]
2010-09-27 02:24:04 +04:00
lst = str . split ( delimiter )
2010-03-20 08:27:48 +03:00
# the string may have had quotes in it, now we
# check if we did have quotes, and use the slower shlex
# if we need to
for e in lst :
if e [ 0 ] == ' " ' :
return shlex . split ( str )
return lst
2010-03-07 16:25:47 +03:00
2010-03-27 13:29:18 +03:00
def subst_vars_error ( string , env ) :
''' substitute vars, throw an error if a variable is not defined '''
lst = re . split ( ' ( \ $ \ { \ w+ \ }) ' , string )
out = [ ]
for v in lst :
if re . match ( ' \ $ \ { \ w+ \ } ' , v ) :
vname = v [ 2 : - 1 ]
if not vname in env :
2018-01-31 12:48:43 +03:00
raise KeyError ( " Failed to find variable %s in %s in env %s < %s > " % ( vname , string , env . __class__ , str ( env ) ) )
2010-03-27 13:29:18 +03:00
v = env [ vname ]
2016-03-26 15:18:07 +03:00
if isinstance ( v , list ) :
v = ' ' . join ( v )
2010-03-27 13:29:18 +03:00
out . append ( v )
return ' ' . join ( out )
2010-03-28 15:01:04 +04:00
2010-03-07 16:25:47 +03:00
@conf
2010-03-20 08:27:48 +03:00
def SUBST_ENV_VAR ( ctx , varname ) :
2010-03-07 16:25:47 +03:00
''' Substitute an environment variable for any embedded variables '''
2010-03-27 13:29:18 +03:00
return subst_vars_error ( ctx . env [ varname ] , ctx . env )
2010-03-20 08:27:48 +03:00
Build . BuildContext . SUBST_ENV_VAR = SUBST_ENV_VAR
2010-03-08 12:34:15 +03:00
2010-03-29 10:12:37 +04:00
def recursive_dirlist ( dir , relbase , pattern = None ) :
2010-03-17 12:12:16 +03:00
''' recursive directory list '''
ret = [ ]
for f in os . listdir ( dir ) :
f2 = dir + ' / ' + f
if os . path . isdir ( f2 ) :
ret . extend ( recursive_dirlist ( f2 , relbase ) )
else :
2010-03-29 10:12:37 +04:00
if pattern and not fnmatch . fnmatch ( f , pattern ) :
continue
2019-11-04 07:07:44 +03:00
ret . append ( os . path . relpath ( f2 , relbase ) )
2010-03-17 12:12:16 +03:00
return ret
2019-02-12 09:16:06 +03:00
def symlink ( src , dst , force = True ) :
""" Can create symlink by force """
try :
os . symlink ( src , dst )
except OSError as exc :
if exc . errno == errno . EEXIST and force :
os . remove ( dst )
os . symlink ( src , dst )
else :
raise
2010-03-17 12:12:16 +03:00
def mkdir_p ( dir ) :
''' like mkdir -p '''
2011-03-04 09:11:20 +03:00
if not dir :
return
if dir . endswith ( " / " ) :
mkdir_p ( dir [ : - 1 ] )
return
if os . path . isdir ( dir ) :
2010-03-17 12:12:16 +03:00
return
mkdir_p ( os . path . dirname ( dir ) )
os . mkdir ( dir )
2010-03-19 06:25:50 +03:00
2010-03-28 15:01:04 +04:00
2010-03-19 11:49:42 +03:00
def SUBST_VARS_RECURSIVE ( string , env ) :
''' recursively expand variables '''
if string is None :
return string
limit = 100
while ( string . find ( ' $ { ' ) != - 1 and limit > 0 ) :
2010-03-27 13:29:18 +03:00
string = subst_vars_error ( string , env )
2010-03-19 11:49:42 +03:00
limit - = 1
return string
2010-03-28 15:01:04 +04:00
2010-03-25 01:23:10 +03:00
@conf
def EXPAND_VARIABLES ( ctx , varstr , vars = None ) :
''' expand variables from a user supplied dictionary
This is most useful when you pass vars = locals ( ) to expand
all your local variables in strings
'''
if isinstance ( varstr , list ) :
ret = [ ]
for s in varstr :
ret . append ( EXPAND_VARIABLES ( ctx , s , vars = vars ) )
return ret
2010-12-09 03:10:45 +03:00
if not isinstance ( varstr , str ) :
return varstr
2018-01-31 12:48:43 +03:00
env = ConfigSet . ConfigSet ( )
2010-03-25 01:23:10 +03:00
ret = varstr
# substitute on user supplied dict if avaiilable
if vars is not None :
for v in vars . keys ( ) :
env [ v ] = vars [ v ]
ret = SUBST_VARS_RECURSIVE ( ret , env )
# if anything left, subst on the environment as well
2010-03-27 01:46:27 +03:00
if ret . find ( ' $ { ' ) != - 1 :
2010-03-25 01:23:10 +03:00
ret = SUBST_VARS_RECURSIVE ( ret , ctx . env )
# make sure there is nothing left. Also check for the common
# typo of $( instead of ${
if ret . find ( ' $ { ' ) != - 1 or ret . find ( ' $( ' ) != - 1 :
2010-04-09 15:12:02 +04:00
Logs . error ( ' Failed to substitute all variables in varstr= %s ' % ret )
2010-03-31 11:04:18 +04:00
sys . exit ( 1 )
2010-03-25 01:23:10 +03:00
return ret
Build . BuildContext . EXPAND_VARIABLES = EXPAND_VARIABLES
2010-03-19 11:49:42 +03:00
2010-03-19 06:25:50 +03:00
def RUN_COMMAND ( cmd ,
env = None ,
shell = False ) :
''' run a external command, return exit code or signal '''
if env :
2010-03-19 11:49:42 +03:00
cmd = SUBST_VARS_RECURSIVE ( cmd , env )
2010-03-19 06:25:50 +03:00
status = os . system ( cmd )
if os . WIFEXITED ( status ) :
return os . WEXITSTATUS ( status )
if os . WIFSIGNALED ( status ) :
return - os . WTERMSIG ( status )
2018-10-28 00:33:26 +03:00
Logs . error ( " Unknown exit reason %d for command: %s " % ( status , cmd ) )
2010-03-19 06:25:50 +03:00
return - 1
2010-03-24 08:37:41 +03:00
2015-06-08 15:17:12 +03:00
def RUN_PYTHON_TESTS ( testfiles , pythonpath = None , extra_env = None ) :
2015-03-10 20:19:14 +03:00
env = LOAD_ENVIRONMENT ( )
if pythonpath is None :
2018-02-02 17:34:31 +03:00
pythonpath = os . path . join ( Context . g_module . out , ' python ' )
2015-03-10 20:19:14 +03:00
result = 0
for interp in env . python_interpreters :
2016-03-26 15:18:07 +03:00
if not isinstance ( interp , str ) :
interp = ' ' . join ( interp )
2015-03-10 20:19:14 +03:00
for testfile in testfiles :
cmd = " PYTHONPATH= %s %s %s " % ( pythonpath , interp , testfile )
2015-06-08 15:17:12 +03:00
if extra_env :
for key , value in extra_env . items ( ) :
cmd = " %s = %s %s " % ( key , value , cmd )
2015-03-10 20:19:14 +03:00
print ( ' Running Python test with %s : %s ' % ( interp , testfile ) )
ret = RUN_COMMAND ( cmd )
if ret :
print ( ' Python test failed: %s ' % cmd )
result = ret
return result
2010-03-24 08:37:41 +03:00
# make sure we have md5. some systems don't have it
try :
from hashlib import md5
2012-12-08 19:57:20 +04:00
# Even if hashlib.md5 exists, it may be unusable.
# Try to use MD5 function. In FIPS mode this will cause an exception
# and we'll get to the replacement code
2018-07-31 19:02:54 +03:00
foo = md5 ( b ' abcd ' )
2010-03-24 08:37:41 +03:00
except :
try :
import md5
2012-12-08 19:57:20 +04:00
# repeat the same check here, mere success of import is not enough.
# Try to use MD5 function. In FIPS mode this will cause an exception
2018-07-31 19:02:54 +03:00
foo = md5 . md5 ( b ' abcd ' )
2010-03-24 08:37:41 +03:00
except :
2018-01-31 12:48:43 +03:00
Context . SIG_NIL = hash ( ' abcd ' )
2010-03-24 08:37:41 +03:00
class replace_md5 ( object ) :
def __init__ ( self ) :
self . val = None
def update ( self , val ) :
self . val = hash ( ( self . val , val ) )
def digest ( self ) :
return str ( self . val )
def hexdigest ( self ) :
return self . digest ( ) . encode ( ' hex ' )
2010-03-25 04:26:50 +03:00
def replace_h_file ( filename ) :
2010-03-25 04:18:16 +03:00
f = open ( filename , ' rb ' )
m = replace_md5 ( )
while ( filename ) :
filename = f . read ( 100000 )
m . update ( filename )
f . close ( )
return m . digest ( )
2010-03-25 04:26:50 +03:00
Utils . md5 = replace_md5
2010-03-25 04:35:18 +03:00
Task . md5 = replace_md5
2010-03-25 04:26:50 +03:00
Utils . h_file = replace_h_file
2010-03-27 01:46:27 +03:00
2010-03-29 10:12:37 +04:00
def LOAD_ENVIRONMENT ( ) :
''' load the configuration environment, allowing access to env vars
from new commands '''
2018-01-31 12:48:43 +03:00
env = ConfigSet . ConfigSet ( )
2010-06-28 07:39:00 +04:00
try :
2018-09-03 13:04:58 +03:00
p = os . path . join ( Context . g_module . out , ' c4che/default ' + CACHE_SUFFIX )
2018-01-31 12:48:43 +03:00
env . load ( p )
2016-03-26 15:18:07 +03:00
except ( OSError , IOError ) :
2010-06-28 07:39:00 +04:00
pass
2010-03-29 10:12:37 +04:00
return env
2010-03-29 14:28:49 +04:00
def IS_NEWER ( bld , file1 , file2 ) :
''' return True if file1 is newer than file2 '''
2018-01-31 12:48:43 +03:00
curdir = bld . path . abspath ( )
t1 = os . stat ( os . path . join ( curdir , file1 ) ) . st_mtime
t2 = os . stat ( os . path . join ( curdir , file2 ) ) . st_mtime
2010-03-29 14:28:49 +04:00
return t1 > t2
Build . BuildContext . IS_NEWER = IS_NEWER
2010-04-02 05:26:27 +04:00
2010-04-04 07:08:05 +04:00
@conf
def RECURSE ( ctx , directory ) :
''' recurse into a directory, relative to the curdir or top level '''
try :
visited_dirs = ctx . visited_dirs
2018-01-31 12:48:43 +03:00
except AttributeError :
2010-04-04 07:08:05 +04:00
visited_dirs = ctx . visited_dirs = set ( )
2018-01-31 12:48:43 +03:00
d = os . path . join ( ctx . path . abspath ( ) , directory )
2010-04-04 07:08:05 +04:00
if os . path . exists ( d ) :
abspath = os . path . abspath ( d )
else :
2018-02-02 17:34:31 +03:00
abspath = os . path . abspath ( os . path . join ( Context . g_module . top , directory ) )
2010-04-04 07:08:05 +04:00
ctxclass = ctx . __class__ . __name__
key = ctxclass + ' : ' + abspath
if key in visited_dirs :
# already done it
return
visited_dirs . add ( key )
2019-11-04 07:07:44 +03:00
relpath = os . path . relpath ( abspath , ctx . path . abspath ( ) )
2020-12-15 15:39:40 +03:00
if ctxclass in [ ' OptionsContext ' ,
' ConfigurationContext ' ,
' BuildContext ' ,
' CleanContext ' ,
' InstallContext ' ,
' UninstallContext ' ,
2022-01-21 19:05:57 +03:00
' ListContext ' ] :
2018-01-31 12:48:43 +03:00
return ctx . recurse ( relpath )
2016-03-26 15:18:07 +03:00
if ' waflib.extras.compat15 ' in sys . modules :
return ctx . recurse ( relpath )
2018-01-31 12:48:43 +03:00
Logs . error ( ' Unknown RECURSE context class: {} ' . format ( ctxclass ) )
2010-04-04 07:08:05 +04:00
raise
2018-01-31 12:48:43 +03:00
Options . OptionsContext . RECURSE = RECURSE
2010-04-04 07:08:05 +04:00
Build . BuildContext . RECURSE = RECURSE
2010-04-14 17:37:47 +04:00
2018-11-13 17:58:17 +03:00
def CHECK_MAKEFLAGS ( options ) :
2010-04-14 17:37:47 +04:00
''' check for MAKEFLAGS environment variable in case we are being
called from a Makefile try to honor a few make command line flags '''
if not ' WAF_MAKE ' in os . environ :
return
makeflags = os . environ . get ( ' MAKEFLAGS ' )
2011-03-15 05:56:46 +03:00
if makeflags is None :
2018-11-13 17:58:17 +03:00
makeflags = " "
2010-04-14 17:37:47 +04:00
jobs_set = False
2018-09-06 13:40:10 +03:00
jobs = None
2010-09-02 10:45:50 +04:00
# we need to use shlex.split to cope with the escaping of spaces
# in makeflags
for opt in shlex . split ( makeflags ) :
2010-04-14 17:37:47 +04:00
# options can come either as -x or as x
2010-04-18 13:41:47 +04:00
if opt [ 0 : 2 ] == ' V= ' :
2018-11-13 17:58:17 +03:00
options . verbose = Logs . verbose = int ( opt [ 2 : ] )
2010-04-18 13:41:47 +04:00
if Logs . verbose > 0 :
2010-04-19 07:43:12 +04:00
Logs . zones = [ ' runner ' ]
2010-04-18 13:41:47 +04:00
if Logs . verbose > 2 :
Logs . zones = [ ' * ' ]
elif opt [ 0 ] . isupper ( ) and opt . find ( ' = ' ) != - 1 :
2011-10-20 07:57:13 +04:00
# this allows us to set waf options on the make command line
# for example, if you do "make FOO=blah", then we set the
# option 'FOO' in Options.options, to blah. If you look in wafsamba/wscript
# you will see that the command line accessible options have their dest=
# set to uppercase, to allow for passing of options from make in this way
# this is also how "make test TESTS=testpattern" works, and
# "make VERBOSE=1" as well as things like "make SYMBOLCHECK=1"
2010-04-18 13:41:47 +04:00
loc = opt . find ( ' = ' )
2018-11-13 17:58:17 +03:00
setattr ( options , opt [ 0 : loc ] , opt [ loc + 1 : ] )
2010-04-18 13:41:47 +04:00
elif opt [ 0 ] != ' - ' :
2010-04-14 17:37:47 +04:00
for v in opt :
2018-09-06 13:40:10 +03:00
if re . search ( r ' j[0-9]*$ ' , v ) :
2010-04-14 17:37:47 +04:00
jobs_set = True
2018-09-06 13:40:10 +03:00
jobs = opt . strip ( ' j ' )
2010-04-14 17:37:47 +04:00
elif v == ' k ' :
2018-11-13 17:58:17 +03:00
options . keep = True
2018-09-06 13:40:10 +03:00
elif re . search ( r ' -j[0-9]*$ ' , opt ) :
2010-04-14 17:37:47 +04:00
jobs_set = True
2018-09-06 13:40:10 +03:00
jobs = opt . strip ( ' -j ' )
2010-04-14 17:37:47 +04:00
elif opt == ' -k ' :
2018-11-13 17:58:17 +03:00
options . keep = True
2010-04-14 17:37:47 +04:00
if not jobs_set :
# default to one job
2018-11-13 17:58:17 +03:00
options . jobs = 1
2018-09-06 13:40:10 +03:00
elif jobs_set and jobs :
2018-11-13 17:58:17 +03:00
options . jobs = int ( jobs )
waflib_options_parse_cmd_args = Options . OptionsContext . parse_cmd_args
def wafsamba_options_parse_cmd_args ( self , _args = None , cwd = None , allow_unknown = False ) :
( options , commands , envvars ) = \
waflib_options_parse_cmd_args ( self ,
_args = _args ,
cwd = cwd ,
allow_unknown = allow_unknown )
CHECK_MAKEFLAGS ( options )
2018-11-15 21:35:27 +03:00
if options . jobs == 1 :
#
# waflib.Runner.Parallel processes jobs inline if the possible number
# of jobs is just 1. But (at least in waf <= 2.0.12) it still calls
# create a waflib.Runner.Spawner() which creates a single
# waflib.Runner.Consumer() thread that tries to process jobs from the
# queue.
#
# This has strange effects, which are not noticed typically,
# but at least on AIX python has broken threading and fails
# in random ways.
#
# So we just add a dummy Spawner class.
class NoOpSpawner ( object ) :
def __init__ ( self , master ) :
return
from waflib import Runner
Runner . Spawner = NoOpSpawner
2018-11-13 17:58:17 +03:00
return options , commands , envvars
Options . OptionsContext . parse_cmd_args = wafsamba_options_parse_cmd_args
2010-04-18 06:43:15 +04:00
option_groups = { }
def option_group ( opt , name ) :
''' find or create an option group '''
global option_groups
if name in option_groups :
return option_groups [ name ]
gr = opt . add_option_group ( name )
option_groups [ name ] = gr
return gr
2018-01-31 12:48:43 +03:00
Options . OptionsContext . option_group = option_group
2010-04-18 06:43:15 +04:00
def save_file ( filename , contents , create_dir = False ) :
''' save data to a file '''
if create_dir :
mkdir_p ( os . path . dirname ( filename ) )
try :
f = open ( filename , ' w ' )
f . write ( contents )
f . close ( )
except :
return False
return True
def load_file ( filename ) :
''' return contents of a file '''
try :
f = open ( filename , ' r ' )
r = f . read ( )
f . close ( )
except :
return None
return r
2010-05-06 16:51:28 +04:00
def reconfigure ( ctx ) :
''' rerun configure if necessary '''
2018-12-27 12:51:41 +03:00
if not os . path . exists ( os . environ . get ( ' WAFLOCK ' , ' .lock-wscript ' ) ) :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( ' configure has not been run ' )
import samba_wildcard
2010-05-06 16:51:28 +04:00
bld = samba_wildcard . fake_build_environment ( )
Configure . autoconfig = True
Scripting . check_configured ( bld )
2010-10-17 14:58:22 +04:00
def map_shlib_extension ( ctx , name , python = False ) :
''' map a filename with a shared library extension of .so to the real shlib name '''
if name is None :
return None
2010-10-21 01:54:36 +04:00
if name [ - 1 : ] . isdigit ( ) :
# some libraries have specified versions in the wscript rule
return name
2010-10-17 14:58:22 +04:00
( root1 , ext1 ) = os . path . splitext ( name )
if python :
2014-11-12 21:49:45 +03:00
return ctx . env . pyext_PATTERN % root1
2010-10-17 14:58:22 +04:00
else :
2016-03-26 15:18:07 +03:00
( root2 , ext2 ) = os . path . splitext ( ctx . env . cshlib_PATTERN )
2010-10-17 14:58:22 +04:00
return root1 + ext2
Build . BuildContext . map_shlib_extension = map_shlib_extension
2011-02-17 06:42:19 +03:00
def apply_pattern ( filename , pattern ) :
''' apply a filename pattern to a filename that may have a directory component '''
dirname = os . path . dirname ( filename )
if not dirname :
return pattern % filename
basename = os . path . basename ( filename )
return os . path . join ( dirname , pattern % basename )
2010-10-17 14:58:22 +04:00
def make_libname ( ctx , name , nolibprefix = False , version = None , python = False ) :
""" make a library filename
Options :
nolibprefix : don ' t include the lib prefix
version : add a version number
python : if we should use python module name conventions """
if python :
2011-02-17 06:42:19 +03:00
libname = apply_pattern ( name , ctx . env . pyext_PATTERN )
2010-10-17 14:58:22 +04:00
else :
2016-03-26 15:18:07 +03:00
libname = apply_pattern ( name , ctx . env . cshlib_PATTERN )
2010-10-17 14:58:22 +04:00
if nolibprefix and libname [ 0 : 3 ] == ' lib ' :
libname = libname [ 3 : ]
if version :
if version [ 0 ] == ' . ' :
version = version [ 1 : ]
( root , ext ) = os . path . splitext ( libname )
if ext == " .dylib " :
# special case - version goes before the prefix
libname = " %s . %s %s " % ( root , version , ext )
else :
libname = " %s %s . %s " % ( root , ext , version )
return libname
Build . BuildContext . make_libname = make_libname
2010-10-29 04:52:25 +04:00
def get_tgt_list ( bld ) :
''' return a list of build objects for samba '''
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
# build a list of task generators we are interested in
tgt_list = [ ]
for tgt in targets :
type = targets [ tgt ]
2021-08-21 00:05:57 +03:00
if not type in [ ' SUBSYSTEM ' , ' BUILTIN ' , ' MODULE ' , ' BINARY ' , ' LIBRARY ' , ' PLUGIN ' , ' ASN1 ' , ' PYTHON ' ] :
2010-10-29 04:52:25 +04:00
continue
2015-06-26 23:32:43 +03:00
t = bld . get_tgen_by_name ( tgt )
2010-10-29 04:52:25 +04:00
if t is None :
Logs . error ( " Target %s of type %s has no task generator " % ( tgt , type ) )
sys . exit ( 1 )
tgt_list . append ( t )
return tgt_list
2012-04-13 18:53:04 +04:00
2018-01-31 12:48:43 +03:00
from waflib . Context import WSCRIPT_FILE
2012-04-14 09:16:20 +04:00
def PROCESS_SEPARATE_RULE ( self , rule ) :
2012-04-13 18:53:04 +04:00
''' cause waf to process additional script based on `rule ' .
You should have file named wscript_ < stage > _rule in the current directory
where stage is either ' configure ' or ' build '
'''
stage = ' '
2015-10-28 23:04:28 +03:00
if isinstance ( self , Configure . ConfigurationContext ) :
2012-04-13 18:53:04 +04:00
stage = ' configure '
2015-10-28 23:04:28 +03:00
elif isinstance ( self , Build . BuildContext ) :
2012-04-13 18:53:04 +04:00
stage = ' build '
2018-01-31 12:48:43 +03:00
file_path = os . path . join ( self . path . abspath ( ) , WSCRIPT_FILE + ' _ ' + stage + ' _ ' + rule )
node = self . root . find_node ( file_path )
if node :
try :
cache = self . recurse_cache
except AttributeError :
cache = self . recurse_cache = { }
if node not in cache :
cache [ node ] = True
self . pre_recurse ( node )
try :
2020-02-05 18:58:26 +03:00
function_code = node . read ( ' r ' , None )
2018-01-31 12:48:43 +03:00
exec ( compile ( function_code , node . abspath ( ) , ' exec ' ) , self . exec_dict )
finally :
self . post_recurse ( node )
2012-04-13 18:53:04 +04:00
2012-04-14 09:16:20 +04:00
Build . BuildContext . PROCESS_SEPARATE_RULE = PROCESS_SEPARATE_RULE
ConfigurationContext . PROCESS_SEPARATE_RULE = PROCESS_SEPARATE_RULE
2012-05-21 13:45:12 +04:00
def AD_DC_BUILD_IS_ENABLED ( self ) :
if self . CONFIG_SET ( ' AD_DC_BUILD_IS_ENABLED ' ) :
return True
return False
Build . BuildContext . AD_DC_BUILD_IS_ENABLED = AD_DC_BUILD_IS_ENABLED
2015-11-05 02:39:25 +03:00
@feature ( ' cprogram ' , ' cshlib ' , ' cstaticlib ' )
@after ( ' apply_lib_vars ' )
@before ( ' apply_obj_vars ' )
def samba_before_apply_obj_vars ( self ) :
""" before apply_obj_vars for uselib, this removes the standard paths """
def is_standard_libpath ( env , path ) :
for _path in env . STANDARD_LIBPATH :
if _path == os . path . normpath ( path ) :
return True
return False
v = self . env
for i in v [ ' RPATH ' ] :
if is_standard_libpath ( v , i ) :
v [ ' RPATH ' ] . remove ( i )
for i in v [ ' LIBPATH ' ] :
if is_standard_libpath ( v , i ) :
v [ ' LIBPATH ' ] . remove ( i )
2020-06-03 07:06:34 +03:00
# Samba options are mostly on by default (administrators and packagers
# specify features to remove, not add), which is why default=True
2017-02-08 09:58:40 +03:00
def samba_add_onoff_option ( opt , option , help = ( ) , dest = None , default = True ,
with_name = " with " , without_name = " without " ) :
if default is None :
default_str = " auto "
elif default is True :
default_str = " yes "
elif default is False :
default_str = " no "
else :
default_str = str ( default )
if help == ( ) :
help = ( " Build with %s support (default= %s ) " % ( option , default_str ) )
if dest is None :
dest = " with_ %s " % option . replace ( ' - ' , ' _ ' )
with_val = " -- %s - %s " % ( with_name , option )
without_val = " -- %s - %s " % ( without_name , option )
opt . add_option ( with_val , help = help , action = " store_true " , dest = dest ,
default = default )
opt . add_option ( without_val , help = SUPPRESS_HELP , action = " store_false " ,
dest = dest )
2018-01-31 12:48:43 +03:00
Options . OptionsContext . samba_add_onoff_option = samba_add_onoff_option