@ -26,17 +26,19 @@ from .wrap import WrapMode
import ast
import ast
import argparse
import argparse
import configparser
import configparser
from typing import Optional , Any , TypeVar , Generic , Type , List
from typing import Optional , Any , TypeVar , Generic , Type , List , Union
version = ' 0.50.999 '
version = ' 0.50.999 '
backendlist = [ ' ninja ' , ' vs ' , ' vs2010 ' , ' vs2015 ' , ' vs2017 ' , ' vs2019 ' , ' xcode ' ]
backendlist = [ ' ninja ' , ' vs ' , ' vs2010 ' , ' vs2015 ' , ' vs2017 ' , ' vs2019 ' , ' xcode ' ]
default_yielding = False
default_yielding = False
class UserOption :
# Can't bind this near the class method it seems, sadly.
def __init__ ( self , name , description , choices , yielding ) :
_T = TypeVar ( ' _T ' )
class UserOption ( Generic [ _T ] ) :
def __init__ ( self , description , choices , yielding ) :
super ( ) . __init__ ( )
super ( ) . __init__ ( )
self . name = name
self . choices = choices
self . choices = choices
self . description = description
self . description = description
if yielding is None :
if yielding is None :
@ -51,31 +53,31 @@ class UserOption:
# Check that the input is a valid value and return the
# Check that the input is a valid value and return the
# "cleaned" or "native" version. For example the Boolean
# "cleaned" or "native" version. For example the Boolean
# option could take the string "true" and return True.
# option could take the string "true" and return True.
def validate_value ( self , value ) :
def validate_value ( self , value : Any ) - > _T :
raise RuntimeError ( ' Derived option class did not override validate_value. ' )
raise RuntimeError ( ' Derived option class did not override validate_value. ' )
def set_value ( self , newvalue ) :
def set_value ( self , newvalue ) :
self . value = self . validate_value ( newvalue )
self . value = self . validate_value ( newvalue )
class UserStringOption ( UserOption ) :
class UserStringOption ( UserOption [ str ] ) :
def __init__ ( self , name , description , value , choices = None , yielding = None ) :
def __init__ ( self , description , value , choices = None , yielding = None ) :
super ( ) . __init__ ( name , description , choices , yielding )
super ( ) . __init__ ( description , choices , yielding )
self . set_value ( value )
self . set_value ( value )
def validate_value ( self , value ) :
def validate_value ( self , value ) :
if not isinstance ( value , str ) :
if not isinstance ( value , str ) :
raise MesonException ( ' Value " %s " for string option " %s " is not a string.' % ( str ( value ) , self . nam e ) )
raise MesonException ( ' Value " %s " for string option is not a string. ' % str ( value ) )
return value
return value
class UserBooleanOption ( UserOption ) :
class UserBooleanOption ( UserOption [ bool ] ) :
def __init__ ( self , name , description , value , yielding = None ) :
def __init__ ( self , description , value , yielding = None ) :
super ( ) . __init__ ( name , description , [ True , False ] , yielding )
super ( ) . __init__ ( description , [ True , False ] , yielding )
self . set_value ( value )
self . set_value ( value )
def __bool__ ( self ) :
def __bool__ ( self ) - > bool :
return self . value
return self . value
def validate_value ( self , value ) :
def validate_value ( self , value ) - > bool :
if isinstance ( value , bool ) :
if isinstance ( value , bool ) :
return value
return value
if value . lower ( ) == ' true ' :
if value . lower ( ) == ' true ' :
@ -84,9 +86,9 @@ class UserBooleanOption(UserOption):
return False
return False
raise MesonException ( ' Value %s is not boolean (true or false). ' % value )
raise MesonException ( ' Value %s is not boolean (true or false). ' % value )
class UserIntegerOption ( UserOption ) :
class UserIntegerOption ( UserOption [ int ] ) :
def __init__ ( self , name , description , min_value , max_value , value , yielding = None ) :
def __init__ ( self , description , min_value , max_value , value , yielding = None ) :
super ( ) . __init__ ( name , description , [ True , False ] , yielding )
super ( ) . __init__ ( description , [ True , False ] , yielding )
self . min_value = min_value
self . min_value = min_value
self . max_value = max_value
self . max_value = max_value
self . set_value ( value )
self . set_value ( value )
@ -97,7 +99,7 @@ class UserIntegerOption(UserOption):
c . append ( ' <= ' + str ( max_value ) )
c . append ( ' <= ' + str ( max_value ) )
self . choices = ' , ' . join ( c )
self . choices = ' , ' . join ( c )
def validate_value ( self , value ) :
def validate_value ( self , value ) - > int :
if isinstance ( value , str ) :
if isinstance ( value , str ) :
value = self . toint ( value )
value = self . toint ( value )
if not isinstance ( value , int ) :
if not isinstance ( value , int ) :
@ -108,15 +110,15 @@ class UserIntegerOption(UserOption):
raise MesonException ( ' New value %d is more than maximum value %d . ' % ( value , self . max_value ) )
raise MesonException ( ' New value %d is more than maximum value %d . ' % ( value , self . max_value ) )
return value
return value
def toint ( self , valuestring ) :
def toint ( self , valuestring ) - > int :
try :
try :
return int ( valuestring )
return int ( valuestring )
except ValueError :
except ValueError :
raise MesonException ( ' Value string " %s " is not convertable to an integer. ' % valuestring )
raise MesonException ( ' Value string " %s " is not convertable to an integer. ' % valuestring )
class UserUmaskOption ( UserIntegerOption ) :
class UserUmaskOption ( UserIntegerOption , UserOption [ Union [ str , int ] ] ) :
def __init__ ( self , name , description , value , yielding = None ) :
def __init__ ( self , description , value , yielding = None ) :
super ( ) . __init__ ( name , description , 0 , 0o777 , value , yielding )
super ( ) . __init__ ( description , 0 , 0o777 , value , yielding )
self . choices = [ ' preserve ' , ' 0000-0777 ' ]
self . choices = [ ' preserve ' , ' 0000-0777 ' ]
def printable_value ( self ) :
def printable_value ( self ) :
@ -135,9 +137,9 @@ class UserUmaskOption(UserIntegerOption):
except ValueError as e :
except ValueError as e :
raise MesonException ( ' Invalid mode: {} ' . format ( e ) )
raise MesonException ( ' Invalid mode: {} ' . format ( e ) )
class UserComboOption ( UserOption ) :
class UserComboOption ( UserOption [ str ] ) :
def __init__ ( self , name , description , choices , value , yielding = None ) :
def __init__ ( self , description , choices : List [ str ] , value , yielding = None ) :
super ( ) . __init__ ( name , description , choices , yielding )
super ( ) . __init__ ( description , choices , yielding )
if not isinstance ( self . choices , list ) :
if not isinstance ( self . choices , list ) :
raise MesonException ( ' Combo choices must be an array. ' )
raise MesonException ( ' Combo choices must be an array. ' )
for i in self . choices :
for i in self . choices :
@ -148,17 +150,17 @@ class UserComboOption(UserOption):
def validate_value ( self , value ) :
def validate_value ( self , value ) :
if value not in self . choices :
if value not in self . choices :
optionsstring = ' , ' . join ( [ ' " %s " ' % ( item , ) for item in self . choices ] )
optionsstring = ' , ' . join ( [ ' " %s " ' % ( item , ) for item in self . choices ] )
raise MesonException ( ' Value " %s " for combo option " %s " is not one of the choices. Possible choices are: %s . ' % ( value , self . nam e , optionsstring ) )
raise MesonException ( ' Value " %s " for combo option is not one of the choices. Possible choices are: %s . ' % ( value , optionsstring ) )
return value
return value
class UserArrayOption ( UserOption ) :
class UserArrayOption ( UserOption [ List [ str ] ] ) :
def __init__ ( self , name , description , value , shlex_split = False , user_input = False , allow_dups = False , * * kwargs ) :
def __init__ ( self , description , value , shlex_split = False , user_input = False , allow_dups = False , * * kwargs ) :
super ( ) . __init__ ( name , description , kwargs . get ( ' choices ' , [ ] ) , yielding = kwargs . get ( ' yielding ' , None ) )
super ( ) . __init__ ( description , kwargs . get ( ' choices ' , [ ] ) , yielding = kwargs . get ( ' yielding ' , None ) )
self . shlex_split = shlex_split
self . shlex_split = shlex_split
self . allow_dups = allow_dups
self . allow_dups = allow_dups
self . value = self . validate_value ( value , user_input = user_input )
self . value = self . validate_value ( value , user_input = user_input )
def validate_value ( self , value , user_input = True ) :
def validate_value ( self , value , user_input = True ) - > List [ str ] :
# User input is for options defined on the command line (via -D
# User input is for options defined on the command line (via -D
# options). Users can put their input in as a comma separated
# options). Users can put their input in as a comma separated
# string, but for defining options in meson_options.txt the format
# string, but for defining options in meson_options.txt the format
@ -182,8 +184,8 @@ class UserArrayOption(UserOption):
raise MesonException ( ' " {0} " should be a string array, but it is not ' . format ( str ( newvalue ) ) )
raise MesonException ( ' " {0} " should be a string array, but it is not ' . format ( str ( newvalue ) ) )
if not self . allow_dups and len ( set ( newvalue ) ) != len ( newvalue ) :
if not self . allow_dups and len ( set ( newvalue ) ) != len ( newvalue ) :
msg = ' Duplicated values in array option " %s " is deprecated. ' \
msg = ' Duplicated values in array option is deprecated. ' \
' This will become a hard error in the future. ' % ( self . name )
' This will become a hard error in the future. '
mlog . deprecation ( msg )
mlog . deprecation ( msg )
for i in newvalue :
for i in newvalue :
if not isinstance ( i , str ) :
if not isinstance ( i , str ) :
@ -199,8 +201,8 @@ class UserArrayOption(UserOption):
class UserFeatureOption ( UserComboOption ) :
class UserFeatureOption ( UserComboOption ) :
static_choices = [ ' enabled ' , ' disabled ' , ' auto ' ]
static_choices = [ ' enabled ' , ' disabled ' , ' auto ' ]
def __init__ ( self , name , description , value , yielding = None ) :
def __init__ ( self , description , value , yielding = None ) :
super ( ) . __init__ ( name , description , self . static_choices , value , yielding )
super ( ) . __init__ ( description , self . static_choices , value , yielding )
def is_enabled ( self ) :
def is_enabled ( self ) :
return self . value == ' enabled '
return self . value == ' enabled '
@ -334,22 +336,20 @@ class CoreData:
# Create builtin options with default values
# Create builtin options with default values
self . builtins = { }
self . builtins = { }
for key , opt in builtin_options . items ( ) :
for key , opt in builtin_options . items ( ) :
self . builtins [ key ] = opt . init_option ( key )
self . builtins [ key ] = opt . init_option ( )
if opt . separate_cross :
if opt . separate_cross :
self . builtins [ ' cross_ ' + key ] = opt . init_option ( key )
self . builtins [ ' cross_ ' + key ] = opt . init_option ( )
def init_backend_options ( self , backend_name ) :
def init_backend_options ( self , backend_name ) :
if backend_name == ' ninja ' :
if backend_name == ' ninja ' :
self . backend_options [ ' backend_max_links ' ] = \
self . backend_options [ ' backend_max_links ' ] = \
UserIntegerOption (
UserIntegerOption (
' backend_max_links ' ,
' Maximum number of linker processes to run or 0 for no '
' Maximum number of linker processes to run or 0 for no '
' limit ' ,
' limit ' ,
0 , None , 0 )
0 , None , 0 )
elif backend_name . startswith ( ' vs ' ) :
elif backend_name . startswith ( ' vs ' ) :
self . backend_options [ ' backend_startup_project ' ] = \
self . backend_options [ ' backend_startup_project ' ] = \
UserStringOption (
UserStringOption (
' backend_startup_project ' ,
' Default project to execute in Visual Studio ' ,
' Default project to execute in Visual Studio ' ,
' ' )
' ' )
@ -433,7 +433,11 @@ class CoreData:
for opts in self . get_all_options ( ) :
for opts in self . get_all_options ( ) :
if option_name in opts :
if option_name in opts :
opt = opts [ option_name ]
opt = opts [ option_name ]
return opt . validate_value ( override_value )
try :
return opt . validate_value ( override_value )
except MesonException as e :
raise type ( e ) ( ( ' Validation failed for option %s : ' % option_name ) + str ( e ) ) \
. with_traceback ( sys . exc_into ( ) [ 2 ] )
raise MesonException ( ' Tried to validate unknown option %s . ' % option_name )
raise MesonException ( ' Tried to validate unknown option %s . ' % option_name )
def get_external_args ( self , for_machine : MachineChoice , lang ) :
def get_external_args ( self , for_machine : MachineChoice , lang ) :
@ -695,9 +699,9 @@ def parse_cmd_line_options(args):
delattr ( args , name )
delattr ( args , name )
_U = TypeVar ( ' _U ' , bound = UserOption )
_U = TypeVar ( ' _U ' , bound = UserOption [ _T ] )
class BuiltinOption ( Generic [ _U ] ) :
class BuiltinOption ( Generic [ _T , _ U ] ) :
""" Class for a builtin option type.
""" Class for a builtin option type.
@ -713,12 +717,12 @@ class BuiltinOption(Generic[_U]):
self . yielding = yielding
self . yielding = yielding
self . separate_cross = separate_cross
self . separate_cross = separate_cross
def init_option ( self , name : str ) - > _U :
def init_option ( self ) - > _U :
""" Create an instance of opt_type and return it. """
""" Create an instance of opt_type and return it. """
keywords = { ' yielding ' : self . yielding , ' value ' : self . default }
keywords = { ' yielding ' : self . yielding , ' value ' : self . default }
if self . choices :
if self . choices :
keywords [ ' choices ' ] = self . choices
keywords [ ' choices ' ] = self . choices
return self . opt_type ( name , self . description , * * keywords )
return self . opt_type ( self . description , * * keywords )
def _argparse_action ( self ) - > Optional [ str ] :
def _argparse_action ( self ) - > Optional [ str ] :
if self . default is True :
if self . default is True :