@ -5014,7 +5014,7 @@ recommended as it is not supported on some platforms''')
def test_wrap_git ( self ) :
with tempfile . TemporaryDirectory ( ) as tmpdir :
srcdir = os . path . join ( tmpdir , ' src ' )
shutil . copytree ( os . path . join ( self . unit_test_dir , ' 7 8 wrap-git' ) , srcdir )
shutil . copytree ( os . path . join ( self . unit_test_dir , ' 81 wrap-git ' ) , srcdir )
upstream = os . path . join ( srcdir , ' subprojects ' , ' wrap_git_upstream ' )
upstream_uri = Path ( upstream ) . as_uri ( )
_git_init ( upstream )
@ -6473,7 +6473,7 @@ class LinuxlikeTests(BasePlatformTests):
if is_osx ( ) :
raise unittest . SkipTest ( ' Global RPATHs via LDFLAGS not yet supported on MacOS (does anybody need it?) ' )
testdir = os . path . join ( self . unit_test_dir , ' 77 global-rpath' )
testdir = os . path . join ( self . unit_test_dir , ' 80 global-rpath' )
oldinstalldir = self . installdir
# Build and install an external library without DESTDIR.
@ -6846,7 +6846,7 @@ class LinuxlikeTests(BasePlatformTests):
oldinstalldir = self . installdir
# Build and install both external libraries without DESTDIR
val1dir = os . path . join ( self . unit_test_dir , ' 76 pkgconfig prefixes ' , ' val1 ' )
val1dir = os . path . join ( self . unit_test_dir , ' 77 pkgconfig prefixes ' , ' val1 ' )
val1prefix = os . path . join ( oldinstalldir , ' val1 ' )
self . prefix = val1prefix
self . installdir = val1prefix
@ -6857,7 +6857,7 @@ class LinuxlikeTests(BasePlatformTests):
env1 = { }
env1 [ ' PKG_CONFIG_PATH ' ] = os . path . join ( val1prefix , self . libdir , ' pkgconfig ' )
val2dir = os . path . join ( self . unit_test_dir , ' 76 pkgconfig prefixes ' , ' val2 ' )
val2dir = os . path . join ( self . unit_test_dir , ' 77 pkgconfig prefixes ' , ' val2 ' )
val2prefix = os . path . join ( oldinstalldir , ' val2 ' )
self . prefix = val2prefix
self . installdir = val2prefix
@ -6869,7 +6869,7 @@ class LinuxlikeTests(BasePlatformTests):
# Build, install, and run the client program
env2 = { }
env2 [ ' PKG_CONFIG_PATH ' ] = os . path . join ( val2prefix , self . libdir , ' pkgconfig ' )
testdir = os . path . join ( self . unit_test_dir , ' 76 pkgconfig prefixes ' , ' client ' )
testdir = os . path . join ( self . unit_test_dir , ' 77 pkgconfig prefixes ' , ' client ' )
testprefix = os . path . join ( oldinstalldir , ' client ' )
self . prefix = testprefix
self . installdir = testprefix
@ -7180,7 +7180,7 @@ class LinuxCrossArmTests(BaseLinuxCrossTests):
def test_cross_libdir_subproject ( self ) :
# Guard against a regression where calling "subproject"
# would reset the value of libdir to its default value.
testdir = os . path . join ( self . unit_test_dir , ' 76 subdir libdir ' )
testdir = os . path . join ( self . unit_test_dir , ' 78 subdir libdir ' )
self . init ( testdir , extra_args = [ ' --libdir=fuf ' ] )
for i in self . introspect ( ' --buildoptions ' ) :
if i [ ' name ' ] == ' libdir ' :
@ -7672,7 +7672,12 @@ class NativeFileTests(BasePlatformTests):
for section , entries in values . items ( ) :
f . write ( ' [ {} ] \n ' . format ( section ) )
for k , v in entries . items ( ) :
f . write ( " {} = ' {} ' \n " . format ( k , v ) )
if isinstance ( v , ( bool , int , float ) ) :
f . write ( " {} = {} \n " . format ( k , v ) )
elif isinstance ( v , list ) :
f . write ( " {} =[ {} ] \n " . format ( k , ' , ' . join ( [ " ' {} ' " . format ( w ) for w in v ] ) ) )
else :
f . write ( " {} = ' {} ' \n " . format ( k , v ) )
return filename
def helper_create_binary_wrapper ( self , binary , dir_ = None , extra_args = None , * * kwargs ) :
@ -7996,6 +8001,219 @@ class NativeFileTests(BasePlatformTests):
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
self . build ( )
def test_user_options ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 43 options ' )
for opt , value in [ ( ' testoption ' , ' some other val ' ) , ( ' other_one ' , True ) ,
( ' combo_opt ' , ' one ' ) , ( ' array_opt ' , [ ' two ' ] ) ,
( ' integer_opt ' , 0 ) ] :
config = self . helper_create_native_file ( { ' project options ' : { opt : value } } )
with self . assertRaises ( subprocess . CalledProcessError ) as cm :
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
self . assertRegex ( cm . exception . stdout , r ' Incorrect value to [a-z]+ option ' )
def test_user_options_command_line_overrides ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 43 options ' )
config = self . helper_create_native_file ( { ' project options ' : { ' other_one ' : True } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config , ' -Dother_one=false ' ] )
def test_user_options_subproject ( self ) :
testcase = os . path . join ( self . unit_test_dir , ' 79 user options for subproject ' )
s = os . path . join ( testcase , ' subprojects ' )
if not os . path . exists ( s ) :
os . mkdir ( s )
s = os . path . join ( s , ' sub ' )
if not os . path . exists ( s ) :
sub = os . path . join ( self . common_test_dir , ' 43 options ' )
shutil . copytree ( sub , s )
for opt , value in [ ( ' testoption ' , ' some other val ' ) , ( ' other_one ' , True ) ,
( ' combo_opt ' , ' one ' ) , ( ' array_opt ' , [ ' two ' ] ) ,
( ' integer_opt ' , 0 ) ] :
config = self . helper_create_native_file ( { ' sub:project options ' : { opt : value } } )
with self . assertRaises ( subprocess . CalledProcessError ) as cm :
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
self . assertRegex ( cm . exception . stdout , r ' Incorrect value to [a-z]+ option ' )
def test_option_bool ( self ) :
# Bools are allowed to be unquoted
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' werror ' : True } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
# Test that no-per subproject options are inherited from the parent
if ' werror ' in each [ ' name ' ] :
self . assertEqual ( each [ ' value ' ] , True )
break
else :
self . fail ( ' Did not find werror in build options? ' )
def test_option_integer ( self ) :
# Bools are allowed to be unquoted
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' unity_size ' : 100 } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
# Test that no-per subproject options are inherited from the parent
if ' unity_size ' in each [ ' name ' ] :
self . assertEqual ( each [ ' value ' ] , 100 )
break
else :
self . fail ( ' Did not find unity_size in build options? ' )
def test_builtin_options ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 2 cpp ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' cpp_std ' : ' c++14 ' } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' cpp_std ' :
self . assertEqual ( each [ ' value ' ] , ' c++14 ' )
break
else :
self . fail ( ' Did not find werror in build options? ' )
def test_builtin_options_env_overrides_conf ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 2 cpp ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' pkg_config_path ' : ' /foo ' } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] , override_envvars = { ' PKG_CONFIG_PATH ' : ' /bar ' } )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' pkg_config_path ' :
self . assertEqual ( each [ ' value ' ] , [ ' /bar ' ] )
break
else :
self . fail ( ' Did not find pkg_config_path in build options? ' )
def test_builtin_options_subprojects ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 102 subproject subdir ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' default_library ' : ' both ' , ' c_args ' : [ ' -Dfoo ' ] } , ' sub:built-in options ' : { ' default_library ' : ' static ' } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
found = 0
for each in configuration :
# Test that no-per subproject options are inherited from the parent
if ' c_args ' in each [ ' name ' ] :
# This path will be hit twice, once for build and once for host,
self . assertEqual ( each [ ' value ' ] , [ ' -Dfoo ' ] )
found + = 1
elif each [ ' name ' ] == ' default_library ' :
self . assertEqual ( each [ ' value ' ] , ' both ' )
found + = 1
elif each [ ' name ' ] == ' sub:default_library ' :
self . assertEqual ( each [ ' value ' ] , ' static ' )
found + = 1
self . assertEqual ( found , 4 , ' Did not find all three sections ' )
def test_builtin_options_subprojects_overrides_buildfiles ( self ) :
# If the buildfile says subproject(... default_library: shared), ensure that's overwritten
testcase = os . path . join ( self . common_test_dir , ' 230 persubproject options ' )
config = self . helper_create_native_file ( { ' sub2:built-in options ' : { ' default_library ' : ' shared ' } } )
with self . assertRaises ( subprocess . CalledProcessError ) as cm :
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
self . assertIn ( cm . exception . stdout , ' Parent should override default_library ' )
def test_builtin_options_subprojects_inherits_parent_override ( self ) :
# If the buildfile says subproject(... default_library: shared), ensure that's overwritten
testcase = os . path . join ( self . common_test_dir , ' 230 persubproject options ' )
config = self . helper_create_native_file ( { ' built-in options ' : { ' default_library ' : ' both ' } } )
with self . assertRaises ( subprocess . CalledProcessError ) as cm :
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
self . assertIn ( cm . exception . stdout , ' Parent should override default_library ' )
def test_builtin_options_compiler_properties ( self ) :
# the properties section can have lang_args, and those need to be
# overwritten by the built-in options
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( {
' built-in options ' : { ' c_args ' : [ ' -DFOO ' ] } ,
' properties ' : { ' c_args ' : [ ' -DBAR ' ] } ,
} )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' c_args ' :
self . assertEqual ( each [ ' value ' ] , [ ' -DFOO ' ] )
break
else :
self . fail ( ' Did not find c_args in build options? ' )
def test_builtin_options_compiler_properties_legacy ( self ) :
# The legacy placement in properties is still valid if a 'built-in
# options' setting is present, but doesn't have the lang_args
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( {
' built-in options ' : { ' default_library ' : ' static ' } ,
' properties ' : { ' c_args ' : [ ' -DBAR ' ] } ,
} )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' c_args ' :
self . assertEqual ( each [ ' value ' ] , [ ' -DBAR ' ] )
break
else :
self . fail ( ' Did not find c_args in build options? ' )
def test_builtin_options_paths ( self ) :
# the properties section can have lang_args, and those need to be
# overwritten by the built-in options
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( {
' built-in options ' : { ' bindir ' : ' foo ' } ,
' paths ' : { ' bindir ' : ' bar ' } ,
} )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' bindir ' :
self . assertEqual ( each [ ' value ' ] , ' foo ' )
break
else :
self . fail ( ' Did not find bindir in build options? ' )
def test_builtin_options_paths_legacy ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( {
' built-in options ' : { ' default_library ' : ' static ' } ,
' paths ' : { ' bindir ' : ' bar ' } ,
} )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' bindir ' :
self . assertEqual ( each [ ' value ' ] , ' bar ' )
break
else :
self . fail ( ' Did not find bindir in build options? ' )
def test_builtin_options_paths_legacy ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 1 trivial ' )
config = self . helper_create_native_file ( {
' built-in options ' : { ' default_library ' : ' static ' } ,
' paths ' : { ' bindir ' : ' bar ' } ,
} )
self . init ( testcase , extra_args = [ ' --native-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' bindir ' :
self . assertEqual ( each [ ' value ' ] , ' bar ' )
break
else :
self . fail ( ' Did not find bindir in build options? ' )
class CrossFileTests ( BasePlatformTests ) :
@ -8005,6 +8223,11 @@ class CrossFileTests(BasePlatformTests):
This is mainly aimed to testing overrides from cross files .
"""
def setUp ( self ) :
super ( ) . setUp ( )
self . current_config = 0
self . current_wrapper = 0
def _cross_file_generator ( self , * , needs_exe_wrapper : bool = False ,
exe_wrapper : T . Optional [ T . List [ str ] ] = None ) - > str :
if is_windows ( ) :
@ -8133,6 +8356,21 @@ class CrossFileTests(BasePlatformTests):
self . init ( testdir , extra_args = [ ' --cross-file= ' + name ] , inprocess = True )
self . wipe ( )
def helper_create_cross_file ( self , values ) :
""" Create a config file as a temporary file.
values should be a nested dictionary structure of { section : { key :
value } }
"""
filename = os . path . join ( self . builddir , ' generated {} .config ' . format ( self . current_config ) )
self . current_config + = 1
with open ( filename , ' wt ' ) as f :
for section , entries in values . items ( ) :
f . write ( ' [ {} ] \n ' . format ( section ) )
for k , v in entries . items ( ) :
f . write ( " {} = ' {} ' \n " . format ( k , v ) )
return filename
def test_cross_file_dirs ( self ) :
testcase = os . path . join ( self . unit_test_dir , ' 60 native file override ' )
self . init ( testcase , default_args = False ,
@ -8189,6 +8427,89 @@ class CrossFileTests(BasePlatformTests):
' -Ddef_sharedstatedir=sharedstatebar ' ,
' -Ddef_sysconfdir=sysconfbar ' ] )
def test_user_options ( self ) :
# This is just a touch test for cross file, since the implementation
# shares code after loading from the files
testcase = os . path . join ( self . common_test_dir , ' 43 options ' )
config = self . helper_create_cross_file ( { ' project options ' : { ' testoption ' : ' some other value ' } } )
with self . assertRaises ( subprocess . CalledProcessError ) as cm :
self . init ( testcase , extra_args = [ ' --cross-file ' , config ] )
self . assertRegex ( cm . exception . stdout , r ' Incorrect value to [a-z]+ option ' )
def test_builtin_options ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 2 cpp ' )
config = self . helper_create_cross_file ( { ' built-in options ' : { ' cpp_std ' : ' c++14 ' } } )
self . init ( testcase , extra_args = [ ' --cross-file ' , config ] )
configuration = self . introspect ( ' --buildoptions ' )
for each in configuration :
if each [ ' name ' ] == ' cpp_std ' :
self . assertEqual ( each [ ' value ' ] , ' c++14 ' )
break
else :
self . fail ( ' No c++ standard set? ' )
def test_builtin_options_per_machine ( self ) :
""" Test options that are allowed to be set on a per-machine basis.
Such options could be passed twice , once for the build machine , and
once for the host machine . I ' ve picked pkg-config path, but any would
do that can be set for both .
"""
testcase = os . path . join ( self . common_test_dir , ' 2 cpp ' )
cross = self . helper_create_cross_file ( { ' built-in options ' : { ' pkg_config_path ' : ' /cross/path ' , ' cpp_std ' : ' c++17 ' } } )
native = self . helper_create_cross_file ( { ' built-in options ' : { ' pkg_config_path ' : ' /native/path ' , ' cpp_std ' : ' c++14 ' } } )
# Ensure that PKG_CONFIG_PATH is not set in the environment
with mock . patch . dict ( ' os.environ ' ) :
for k in [ ' PKG_CONFIG_PATH ' , ' PKG_CONFIG_PATH_FOR_BUILD ' ] :
try :
del os . environ [ k ]
except KeyError :
pass
self . init ( testcase , extra_args = [ ' --cross-file ' , cross , ' --native-file ' , native ] )
configuration = self . introspect ( ' --buildoptions ' )
found = 0
for each in configuration :
if each [ ' name ' ] == ' pkg_config_path ' :
self . assertEqual ( each [ ' value ' ] , [ ' /cross/path ' ] )
found + = 1
elif each [ ' name ' ] == ' cpp_std ' :
self . assertEqual ( each [ ' value ' ] , ' c++17 ' )
found + = 1
elif each [ ' name ' ] == ' build.pkg_config_path ' :
self . assertEqual ( each [ ' value ' ] , [ ' /native/path ' ] )
found + = 1
elif each [ ' name ' ] == ' build.cpp_std ' :
self . assertEqual ( each [ ' value ' ] , ' c++14 ' )
found + = 1
if found == 4 :
break
self . assertEqual ( found , 4 , ' Did not find all sections. ' )
def test_builtin_options_env_overrides_conf ( self ) :
testcase = os . path . join ( self . common_test_dir , ' 2 cpp ' )
config = self . helper_create_cross_file ( { ' built-in options ' : { ' pkg_config_path ' : ' /foo ' } } )
cross = self . helper_create_cross_file ( { ' built-in options ' : { ' pkg_config_path ' : ' /foo ' } } )
self . init ( testcase , extra_args = [ ' --native-file ' , config , ' --cross-file ' , cross ] ,
override_envvars = { ' PKG_CONFIG_PATH ' : ' /bar ' , ' PKG_CONFIG_PATH_FOR_BUILD ' : ' /dir ' } )
configuration = self . introspect ( ' --buildoptions ' )
found = 0
for each in configuration :
if each [ ' name ' ] == ' pkg_config_path ' :
self . assertEqual ( each [ ' value ' ] , [ ' /bar ' ] )
found + = 1
elif each [ ' name ' ] == ' build.pkg_config_path ' :
self . assertEqual ( each [ ' value ' ] , [ ' /dir ' ] )
found + = 1
if found == 2 :
break
self . assertEqual ( found , 2 , ' Did not find all sections. ' )
class TAPParserTests ( unittest . TestCase ) :
def assert_test ( self , events , * * kwargs ) :
if ' explanation ' not in kwargs :