2015-02-09 02:34:33 +08:00
# Copyright 2012-2015 The Meson development team
2012-12-27 02:58:48 +08:00
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2014-03-17 06:37:47 +08:00
import mparser
2012-12-27 06:04:28 +08:00
import environment
2013-03-10 05:53:02 +08:00
import coredata
2013-04-01 19:08:54 +08:00
import dependencies
2013-07-09 01:47:55 +08:00
import mlog
2013-09-24 03:34:41 +08:00
import build
2013-12-10 02:26:12 +08:00
import optinterpreter
2015-02-03 02:25:35 +08:00
import wrap
2015-02-14 08:56:27 +08:00
import mesonlib
2015-02-21 08:48:32 +08:00
import os , sys , platform , subprocess , shutil , uuid , re
2015-04-22 23:03:18 +08:00
from functools import wraps
2015-04-21 21:27:58 +08:00
2015-03-05 05:53:35 +08:00
import importlib
2012-12-27 02:58:48 +08:00
2013-04-07 01:32:56 +08:00
class InterpreterException ( coredata . MesonException ) :
2012-12-27 02:58:48 +08:00
pass
class InvalidCode ( InterpreterException ) :
pass
2013-10-08 05:15:34 +08:00
class InvalidArguments ( InterpreterException ) :
pass
2015-04-22 23:03:18 +08:00
# Decorators for method calls.
2015-04-23 00:40:09 +08:00
def check_stringlist ( a , msg = ' Arguments must be strings. ' ) :
if not isinstance ( a , list ) :
2015-10-03 03:06:26 +08:00
mlog . debug ( ' Not a list: ' , str ( a ) )
2015-04-23 00:40:09 +08:00
raise InvalidArguments ( ' Argument not a list. ' )
2015-05-08 04:40:50 +08:00
if not all ( isinstance ( s , str ) for s in a ) :
2015-10-03 03:06:26 +08:00
mlog . debug ( ' Element not a string: ' , str ( a ) )
2015-05-08 04:40:50 +08:00
raise InvalidArguments ( msg )
2015-04-23 00:40:09 +08:00
2015-06-15 05:26:19 +08:00
def noPosargs ( f ) :
@wraps ( f )
def wrapped ( self , node , args , kwargs ) :
if len ( args ) != 0 :
raise InvalidArguments ( ' Function does not take positional arguments. ' )
return f ( self , node , args , kwargs )
return wrapped
2015-04-22 23:03:18 +08:00
def noKwargs ( f ) :
@wraps ( f )
def wrapped ( self , node , args , kwargs ) :
if len ( kwargs ) != 0 :
raise InvalidArguments ( ' Function does not take keyword arguments. ' )
return f ( self , node , args , kwargs )
return wrapped
2015-04-22 23:27:34 +08:00
def stringArgs ( f ) :
@wraps ( f )
def wrapped ( self , node , args , kwargs ) :
assert ( isinstance ( args , list ) )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2015-04-22 23:27:34 +08:00
return f ( self , node , args , kwargs )
return wrapped
2015-05-08 04:40:50 +08:00
def stringifyUserArguments ( args ) :
if isinstance ( args , list ) :
return ' [ %s ] ' % ' , ' . join ( [ stringifyUserArguments ( x ) for x in args ] )
elif isinstance ( args , int ) :
return str ( args )
elif isinstance ( args , str ) :
return " ' %s ' " % args
raise InvalidArguments ( ' Function accepts only strings, integers, lists and lists thereof. ' )
2012-12-30 00:18:41 +08:00
class InterpreterObject ( ) :
2013-01-12 19:53:19 +08:00
def __init__ ( self ) :
self . methods = { }
2013-02-10 07:51:39 +08:00
def method_call ( self , method_name , args , kwargs ) :
2013-01-12 19:53:19 +08:00
if method_name in self . methods :
2013-02-10 07:51:39 +08:00
return self . methods [ method_name ] ( args , kwargs )
2013-01-12 19:53:19 +08:00
raise InvalidCode ( ' Unknown method " %s " in object. ' % method_name )
2013-07-27 19:18:11 +08:00
class TryRunResultHolder ( InterpreterObject ) :
def __init__ ( self , res ) :
super ( ) . __init__ ( )
self . res = res
self . methods . update ( { ' returncode ' : self . returncode_method ,
' compiled ' : self . compiled_method ,
' stdout ' : self . stdout_method ,
' stderr ' : self . stderr_method ,
2015-06-19 15:24:49 +08:00
} )
2014-08-07 17:34:35 +08:00
2013-07-27 19:18:11 +08:00
def returncode_method ( self , args , kwargs ) :
return self . res . returncode
2014-02-13 04:37:25 +08:00
2013-07-27 19:18:11 +08:00
def compiled_method ( self , args , kwargs ) :
return self . res . compiled
2014-08-07 17:34:35 +08:00
2013-07-27 19:18:11 +08:00
def stdout_method ( self , args , kwargs ) :
return self . res . stdout
2014-02-13 04:37:25 +08:00
2013-07-27 19:18:11 +08:00
def stderr_method ( self , args , kwargs ) :
return self . res . stderr
2013-06-30 06:36:17 +08:00
class RunProcess ( InterpreterObject ) :
2014-07-28 04:48:59 +08:00
def __init__ ( self , command_array , source_dir , build_dir , subdir , in_builddir = False ) :
2013-06-30 06:36:17 +08:00
super ( ) . __init__ ( )
2014-07-28 04:48:59 +08:00
pc = self . run_command ( command_array , source_dir , build_dir , subdir , in_builddir )
2013-06-30 06:36:17 +08:00
( stdout , stderr ) = pc . communicate ( )
self . returncode = pc . returncode
2014-04-17 02:30:14 +08:00
self . stdout = stdout . decode ( ) . replace ( ' \r \n ' , ' \n ' )
self . stderr = stderr . decode ( ) . replace ( ' \r \n ' , ' \n ' )
2013-06-30 06:36:17 +08:00
self . methods . update ( { ' returncode ' : self . returncode_method ,
' stdout ' : self . stdout_method ,
' stderr ' : self . stderr_method ,
2015-06-19 15:24:49 +08:00
} )
2014-08-07 17:34:35 +08:00
2014-07-28 04:48:59 +08:00
def run_command ( self , command_array , source_dir , build_dir , subdir , in_builddir ) :
2013-07-01 03:30:11 +08:00
cmd_name = command_array [ 0 ]
2014-04-17 00:09:19 +08:00
env = { ' MESON_SOURCE_ROOT ' : source_dir ,
' MESON_BUILD_ROOT ' : build_dir ,
' MESON_SUBDIR ' : subdir }
2014-07-28 04:48:59 +08:00
if in_builddir :
cwd = os . path . join ( build_dir , subdir )
else :
cwd = os . path . join ( source_dir , subdir )
2014-04-17 00:09:19 +08:00
child_env = os . environ . copy ( )
child_env . update ( env )
2013-07-01 03:30:11 +08:00
try :
2014-04-17 00:09:19 +08:00
return subprocess . Popen ( command_array , stdout = subprocess . PIPE , stderr = subprocess . PIPE ,
env = child_env , cwd = cwd )
2013-07-01 03:30:11 +08:00
except FileNotFoundError :
pass
2013-07-01 23:12:30 +08:00
# Was not a command, is a program in path?
exe = shutil . which ( cmd_name )
if exe is not None :
command_array = [ exe ] + command_array [ 1 : ]
2014-04-17 00:09:19 +08:00
return subprocess . Popen ( command_array , stdout = subprocess . PIPE , stderr = subprocess . PIPE ,
env = child_env , cwd = cwd )
2013-07-01 23:12:30 +08:00
# No? Maybe it is a script in the source tree.
2014-04-17 00:09:19 +08:00
fullpath = os . path . join ( source_dir , subdir , cmd_name )
2013-07-01 03:30:11 +08:00
command_array = [ fullpath ] + command_array [ 1 : ]
try :
2014-04-17 00:09:19 +08:00
return subprocess . Popen ( command_array , stdout = subprocess . PIPE , stderr = subprocess . PIPE ,
env = child_env , cwd = cwd )
2013-07-01 03:30:11 +08:00
except FileNotFoundError :
raise InterpreterException ( ' Could not execute command " %s " . ' % cmd_name )
2013-06-30 06:36:17 +08:00
def returncode_method ( self , args , kwargs ) :
return self . returncode
def stdout_method ( self , args , kwargs ) :
return self . stdout
def stderr_method ( self , args , kwargs ) :
return self . stderr
2013-09-28 23:54:09 +08:00
class ConfigureFileHolder ( InterpreterObject ) :
def __init__ ( self , subdir , sourcename , targetname , configuration_data ) :
InterpreterObject . __init__ ( self )
self . held_object = build . ConfigureFile ( subdir , sourcename , targetname , configuration_data )
class ConfigurationDataHolder ( InterpreterObject ) :
2013-05-25 03:21:48 +08:00
def __init__ ( self ) :
super ( ) . __init__ ( )
2015-07-27 05:25:45 +08:00
self . used = False # These objects become immutable after use in configure_file.
2013-09-28 23:54:09 +08:00
self . held_object = build . ConfigurationData ( )
2013-06-02 21:01:29 +08:00
self . methods . update ( { ' set ' : self . set_method ,
' set10 ' : self . set10_method ,
2015-11-10 06:58:25 +08:00
' has ' : self . has_method ,
2015-06-19 15:24:49 +08:00
} )
2013-06-02 21:01:29 +08:00
2013-05-25 03:21:48 +08:00
def is_used ( self ) :
return self . used
2013-06-20 23:03:30 +08:00
2013-05-25 03:21:48 +08:00
def mark_used ( self ) :
self . used = True
2013-06-02 21:01:29 +08:00
def validate_args ( self , args ) :
2013-05-25 03:21:48 +08:00
if len ( args ) != 2 :
raise InterpreterException ( " Configuration set requires 2 arguments. " )
if self . used :
raise InterpreterException ( " Can not set values on configuration object that has been used. " )
name = args [ 0 ]
val = args [ 1 ]
if not isinstance ( name , str ) :
raise InterpreterException ( " First argument to set must be a string. " )
2013-06-02 21:01:29 +08:00
return ( name , val )
2013-06-20 23:03:30 +08:00
2013-06-02 21:01:29 +08:00
def set_method ( self , args , kwargs ) :
( name , val ) = self . validate_args ( args )
2013-09-28 23:54:09 +08:00
self . held_object . values [ name ] = val
2013-06-20 23:03:30 +08:00
2013-06-02 21:01:29 +08:00
def set10_method ( self , args , kwargs ) :
( name , val ) = self . validate_args ( args )
if val :
2013-09-28 23:54:09 +08:00
self . held_object . values [ name ] = 1
2013-06-02 21:01:29 +08:00
else :
2013-09-28 23:54:09 +08:00
self . held_object . values [ name ] = 0
2013-06-02 21:01:29 +08:00
2015-11-10 06:58:25 +08:00
def has_method ( self , args , kwargs ) :
return args [ 0 ] in self . held_object . values
2013-06-02 21:01:29 +08:00
def get ( self , name ) :
2013-09-28 23:54:09 +08:00
return self . held_object . values [ name ]
2013-06-20 23:03:30 +08:00
2013-05-25 03:21:48 +08:00
def keys ( self ) :
2013-09-28 23:54:09 +08:00
return self . held_object . values . keys ( )
2013-05-25 03:21:48 +08:00
2013-03-10 05:08:22 +08:00
# Interpreter objects can not be pickled so we must have
# these wrappers.
2013-03-10 03:12:03 +08:00
2015-02-21 09:52:16 +08:00
class DependencyHolder ( InterpreterObject ) :
def __init__ ( self , dep ) :
InterpreterObject . __init__ ( self )
self . held_object = dep
self . methods . update ( { ' found ' : self . found_method } )
def found_method ( self , args , kwargs ) :
return self . held_object . found ( )
2015-06-15 05:26:19 +08:00
class InternalDependencyHolder ( InterpreterObject ) :
def __init__ ( self , dep ) :
InterpreterObject . __init__ ( self )
self . held_object = dep
self . methods . update ( { ' found ' : self . found_method } )
def found_method ( self , args , kwargs ) :
return True
2013-03-10 05:08:22 +08:00
class ExternalProgramHolder ( InterpreterObject ) :
def __init__ ( self , ep ) :
InterpreterObject . __init__ ( self )
2014-11-08 01:00:57 +08:00
self . held_object = ep
2013-03-10 05:08:22 +08:00
self . methods . update ( { ' found ' : self . found_method } )
2013-03-10 03:12:03 +08:00
def found_method ( self , args , kwargs ) :
return self . found ( )
2013-03-10 05:08:22 +08:00
def found ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . found ( )
2013-03-10 05:08:22 +08:00
2013-03-10 03:12:03 +08:00
def get_command ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . fullpath
2013-03-10 03:12:03 +08:00
def get_name ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . name
2013-03-10 03:12:03 +08:00
2013-03-10 05:08:22 +08:00
class ExternalLibraryHolder ( InterpreterObject ) :
def __init__ ( self , el ) :
2013-03-10 04:42:01 +08:00
InterpreterObject . __init__ ( self )
2014-11-08 01:00:57 +08:00
self . held_object = el
2013-03-10 05:08:22 +08:00
self . methods . update ( { ' found ' : self . found_method } )
2013-03-10 04:42:01 +08:00
def found ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . found ( )
2013-03-10 04:42:01 +08:00
def found_method ( self , args , kwargs ) :
return self . found ( )
def get_filename ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . fullpath
2013-03-10 04:42:01 +08:00
def get_name ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . name
2014-08-07 17:34:35 +08:00
2014-06-22 22:10:00 +08:00
def get_compile_args ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . get_compile_args ( )
2014-08-07 17:34:35 +08:00
2014-06-22 22:10:00 +08:00
def get_link_args ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . get_link_args ( )
2014-08-07 17:34:35 +08:00
2014-06-22 22:10:00 +08:00
def get_exe_args ( self ) :
2014-11-08 01:00:57 +08:00
return self . held_object . get_exe_args ( )
2013-03-10 04:42:01 +08:00
2013-09-24 04:08:50 +08:00
class GeneratorHolder ( InterpreterObject ) :
2014-07-26 22:46:40 +08:00
def __init__ ( self , interpreter , args , kwargs ) :
2013-09-24 04:08:50 +08:00
super ( ) . __init__ ( )
2014-07-26 22:46:40 +08:00
self . interpreter = interpreter
2014-11-08 01:05:15 +08:00
self . held_object = build . Generator ( args , kwargs )
2013-02-24 02:37:33 +08:00
self . methods . update ( { ' process ' : self . process_method } )
def process_method ( self , args , kwargs ) :
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2015-11-29 01:47:52 +08:00
extras = mesonlib . stringlistify ( kwargs . get ( ' extra_args ' , [ ] ) )
gl = GeneratedListHolder ( self , extras )
2014-07-26 22:46:40 +08:00
[ gl . add_file ( os . path . join ( self . interpreter . subdir , a ) ) for a in args ]
2013-02-24 03:13:01 +08:00
return gl
2013-09-24 04:08:50 +08:00
class GeneratedListHolder ( InterpreterObject ) :
2015-11-29 01:47:52 +08:00
def __init__ ( self , arg1 , extra_args = [ ] ) :
2013-09-24 04:08:50 +08:00
super ( ) . __init__ ( )
2015-03-14 01:59:12 +08:00
if isinstance ( arg1 , GeneratorHolder ) :
2015-11-29 01:47:52 +08:00
self . held_object = build . GeneratedList ( arg1 . held_object , extra_args )
2015-03-14 01:38:53 +08:00
else :
self . held_object = arg1
2013-06-01 18:19:08 +08:00
2013-09-24 04:08:50 +08:00
def add_file ( self , a ) :
2014-11-08 01:05:15 +08:00
self . held_object . add_file ( a )
2013-02-24 02:37:33 +08:00
2015-07-26 04:08:13 +08:00
class BuildMachine ( InterpreterObject ) :
2013-08-24 06:46:36 +08:00
def __init__ ( self ) :
InterpreterObject . __init__ ( self )
2015-08-17 03:50:09 +08:00
self . methods . update ( { ' system ' : self . system_method ,
2015-10-16 01:20:38 +08:00
' cpu_family ' : self . cpu_family_method ,
2015-07-31 06:05:18 +08:00
' cpu ' : self . cpu_method ,
2015-07-26 03:50:35 +08:00
' endian ' : self . endian_method ,
2015-06-19 15:24:49 +08:00
} )
2013-08-24 06:46:36 +08:00
2015-07-26 04:08:13 +08:00
# Python is inconsistent in its platform module.
# It returns different values for the same cpu.
# For x86 it might return 'x86', 'i686' or somesuch.
# Do some canonicalization.
2015-10-16 01:20:38 +08:00
def cpu_family_method ( self , args , kwargs ) :
2015-07-26 04:08:13 +08:00
trial = platform . machine ( ) . lower ( )
if trial . startswith ( ' i ' ) and trial . endswith ( ' 86 ' ) :
return ' x86 '
if trial . startswith ( ' arm ' ) :
return ' arm '
# Add fixes here as bugs are reported.
return trial
2015-10-16 01:20:38 +08:00
def cpu_method ( self , args , kwargs ) :
return platform . machine ( ) . lower ( )
2015-08-17 03:50:09 +08:00
def system_method ( self , args , kwargs ) :
2013-08-24 06:46:36 +08:00
return platform . system ( ) . lower ( )
2015-07-26 03:50:35 +08:00
def endian_method ( self , args , kwargs ) :
return sys . byteorder
# This class will provide both host_machine and
# target_machine
class CrossMachineInfo ( InterpreterObject ) :
def __init__ ( self , cross_info ) :
2013-01-28 03:45:02 +08:00
InterpreterObject . __init__ ( self )
2015-10-19 06:56:20 +08:00
minimum_cross_info = { ' cpu ' , ' cpu_family ' , ' endian ' , ' system ' }
if set ( cross_info ) < minimum_cross_info :
raise InterpreterException (
' Machine info is currently {} \n ' . format ( cross_info ) +
' but is missing {} . ' . format ( minimum_cross_info - set ( cross_info ) ) )
2015-07-26 03:50:35 +08:00
self . info = cross_info
2015-08-17 03:50:09 +08:00
self . methods . update ( { ' system ' : self . system_method ,
2015-07-26 03:50:35 +08:00
' cpu ' : self . cpu_method ,
2015-10-16 01:20:38 +08:00
' cpu_family ' : self . cpu_family_method ,
2015-07-26 03:50:35 +08:00
' endian ' : self . endian_method ,
2015-06-19 15:24:49 +08:00
} )
2013-01-28 03:45:02 +08:00
2015-08-17 03:50:09 +08:00
def system_method ( self , args , kwargs ) :
return self . info [ ' system ' ]
2014-08-07 17:34:35 +08:00
2015-07-26 03:50:35 +08:00
def cpu_method ( self , args , kwargs ) :
return self . info [ ' cpu ' ]
2015-10-16 01:20:38 +08:00
def cpu_family_method ( self , args , kwargs ) :
return self . info [ ' cpu_family ' ]
2015-07-26 03:50:35 +08:00
def endian_method ( self , args , kwargs ) :
return self . info [ ' endian ' ]
2013-01-28 03:45:02 +08:00
2013-09-24 04:08:50 +08:00
class IncludeDirsHolder ( InterpreterObject ) :
2015-10-04 04:18:40 +08:00
def __init__ ( self , idobj ) :
2013-09-24 04:08:50 +08:00
super ( ) . __init__ ( )
2015-10-04 04:18:40 +08:00
self . held_object = idobj
2013-01-26 06:28:13 +08:00
2013-01-12 19:53:19 +08:00
class Headers ( InterpreterObject ) :
2013-01-26 06:28:13 +08:00
2014-11-04 00:23:29 +08:00
def __init__ ( self , src_subdir , sources , kwargs ) :
2013-01-12 19:53:19 +08:00
InterpreterObject . __init__ ( self )
self . sources = sources
2014-11-04 00:23:29 +08:00
self . source_subdir = src_subdir
self . install_subdir = kwargs . get ( ' subdir ' , ' ' )
2014-02-13 04:37:25 +08:00
self . custom_install_dir = kwargs . get ( ' install_dir ' , None )
if self . custom_install_dir is not None :
if not isinstance ( self . custom_install_dir , str ) :
raise InterpreterException ( ' Custom_install_dir must be a string. ' )
2013-01-12 19:53:19 +08:00
2014-11-04 00:23:29 +08:00
def set_install_subdir ( self , subdir ) :
self . install_subdir = subdir
2013-01-12 19:53:19 +08:00
2014-11-04 00:23:29 +08:00
def get_install_subdir ( self ) :
return self . install_subdir
def get_source_subdir ( self ) :
return self . source_subdir
2014-08-07 17:34:35 +08:00
2013-01-12 19:53:19 +08:00
def get_sources ( self ) :
return self . sources
2013-01-14 01:25:54 +08:00
2014-02-13 04:37:25 +08:00
def get_custom_install_dir ( self ) :
return self . custom_install_dir
2015-12-23 21:10:27 +08:00
class DataHolder ( InterpreterObject ) :
2015-02-16 01:35:53 +08:00
def __init__ ( self , in_sourcetree , source_subdir , sources , kwargs ) :
2015-12-23 21:10:27 +08:00
super ( ) . __init__ ( )
kwsource = mesonlib . stringlistify ( kwargs . get ( ' sources ' , [ ] ) )
sources + = kwsource
check_stringlist ( sources )
install_dir = kwargs . get ( ' install_dir ' , None )
if not isinstance ( install_dir , str ) :
2014-02-13 04:50:45 +08:00
raise InterpreterException ( ' Custom_install_dir must be a string. ' )
2015-12-23 21:10:27 +08:00
self . held_object = build . Data ( in_sourcetree , source_subdir , sources , install_dir )
2013-01-14 01:25:54 +08:00
2014-11-04 00:37:23 +08:00
def get_source_subdir ( self ) :
2015-12-23 21:10:27 +08:00
return self . held_object . source_subdir
2013-01-14 01:25:54 +08:00
def get_sources ( self ) :
2015-12-23 21:10:27 +08:00
return self . held_object . sources
2013-01-14 01:25:54 +08:00
2015-02-16 01:13:21 +08:00
def get_install_dir ( self ) :
2015-12-23 21:10:27 +08:00
return self . held_object . install_dir
2014-02-13 04:50:45 +08:00
2014-11-04 05:28:47 +08:00
class InstallDir ( InterpreterObject ) :
def __init__ ( self , source_subdir , installable_subdir , install_dir ) :
InterpreterObject . __init__ ( self )
self . source_subdir = source_subdir
self . installable_subdir = installable_subdir
self . install_dir = install_dir
2013-01-12 20:31:43 +08:00
class Man ( InterpreterObject ) :
2014-11-04 00:30:24 +08:00
def __init__ ( self , source_subdir , sources , kwargs ) :
2013-01-12 20:31:43 +08:00
InterpreterObject . __init__ ( self )
2014-11-04 00:30:24 +08:00
self . source_subdir = source_subdir
2013-01-12 20:31:43 +08:00
self . sources = sources
self . validate_sources ( )
2014-02-13 04:50:45 +08:00
if len ( kwargs ) > 1 :
raise InvalidArguments ( ' Man function takes at most one keyword arguments. ' )
self . custom_install_dir = kwargs . get ( ' install_dir ' , None )
if self . custom_install_dir is not None and not isinstance ( self . custom_install_dir , str ) :
raise InterpreterException ( ' Custom_install_dir must be a string. ' )
2013-01-12 20:31:43 +08:00
def validate_sources ( self ) :
for s in self . sources :
num = int ( s . split ( ' . ' ) [ - 1 ] )
if num < 1 or num > 8 :
raise InvalidArguments ( ' Man file must have a file extension of a number between 1 and 8 ' )
2014-02-13 04:50:45 +08:00
def get_custom_install_dir ( self ) :
return self . custom_install_dir
2013-01-12 20:31:43 +08:00
def get_sources ( self ) :
return self . sources
2012-12-30 00:18:41 +08:00
2014-11-04 00:30:24 +08:00
def get_source_subdir ( self ) :
return self . source_subdir
2013-11-05 07:47:09 +08:00
class GeneratedObjectsHolder ( InterpreterObject ) :
def __init__ ( self , held_object ) :
super ( ) . __init__ ( )
self . held_object = held_object
2013-09-24 03:34:41 +08:00
class BuildTargetHolder ( InterpreterObject ) :
2015-09-17 23:48:26 +08:00
def __init__ ( self , target , interp ) :
2013-11-05 07:47:09 +08:00
super ( ) . __init__ ( )
2015-03-09 23:16:32 +08:00
self . held_object = target
2015-09-17 23:48:26 +08:00
self . interpreter = interp
2015-07-22 02:34:18 +08:00
self . methods . update ( { ' extract_objects ' : self . extract_objects_method ,
2015-09-04 05:37:28 +08:00
' extract_all_objects ' : self . extract_all_objects_method ,
' get_id ' : self . get_id_method ,
2015-09-17 23:48:26 +08:00
' outdir ' : self . outdir_method ,
2015-10-04 04:18:40 +08:00
' private_dir_include ' : self . private_dir_include_method ,
2015-09-04 05:37:28 +08:00
} )
2013-11-05 07:47:09 +08:00
2013-09-29 23:56:37 +08:00
def is_cross ( self ) :
2013-11-05 07:47:09 +08:00
return self . held_object . is_cross ( )
2015-10-04 04:18:40 +08:00
def private_dir_include_method ( self , args , kwargs ) :
2016-01-03 03:34:39 +08:00
return IncludeDirsHolder ( build . IncludeDirs ( ' ' , [ ] , False ,
2015-10-04 04:18:40 +08:00
[ self . interpreter . backend . get_target_private_dir ( self . held_object ) ] ) )
2015-09-17 23:48:26 +08:00
def outdir_method ( self , args , kwargs ) :
return self . interpreter . backend . get_target_dir ( self . held_object )
2013-11-05 07:47:09 +08:00
def extract_objects_method ( self , args , kwargs ) :
gobjs = self . held_object . extract_objects ( args )
return GeneratedObjectsHolder ( gobjs )
2013-01-13 23:59:34 +08:00
2015-07-22 02:34:18 +08:00
def extract_all_objects_method ( self , args , kwargs ) :
gobjs = self . held_object . extract_all_objects ( )
return GeneratedObjectsHolder ( gobjs )
2015-09-04 05:37:28 +08:00
def get_id_method ( self , args , kwargs ) :
return self . held_object . get_id ( )
2013-09-24 03:34:41 +08:00
class ExecutableHolder ( BuildTargetHolder ) :
2015-09-17 23:48:26 +08:00
def __init__ ( self , target , interp ) :
super ( ) . __init__ ( target , interp )
2012-12-30 00:18:41 +08:00
2013-09-24 03:34:41 +08:00
class StaticLibraryHolder ( BuildTargetHolder ) :
2015-09-17 23:48:26 +08:00
def __init__ ( self , target , interp ) :
super ( ) . __init__ ( target , interp )
2013-01-06 00:13:38 +08:00
2013-09-24 03:34:41 +08:00
class SharedLibraryHolder ( BuildTargetHolder ) :
2015-09-17 23:48:26 +08:00
def __init__ ( self , target , interp ) :
super ( ) . __init__ ( target , interp )
2013-01-12 08:25:06 +08:00
2014-03-11 05:33:24 +08:00
class JarHolder ( BuildTargetHolder ) :
2015-09-17 23:48:26 +08:00
def __init__ ( self , target , interp ) :
super ( ) . __init__ ( target , interp )
2014-03-11 05:33:24 +08:00
2014-05-19 05:59:35 +08:00
class CustomTargetHolder ( InterpreterObject ) :
2015-03-06 23:36:43 +08:00
def __init__ ( self , object_to_hold ) :
self . held_object = object_to_hold
2014-05-19 05:59:35 +08:00
def is_cross ( self ) :
return self . held_object . is_cross ( )
def extract_objects_method ( self , args , kwargs ) :
gobjs = self . held_object . extract_objects ( args )
return GeneratedObjectsHolder ( gobjs )
2014-06-12 03:38:36 +08:00
class RunTargetHolder ( InterpreterObject ) :
def __init__ ( self , name , command , args , subdir ) :
self . held_object = build . RunTarget ( name , command , args , subdir )
2013-01-07 01:13:30 +08:00
class Test ( InterpreterObject ) :
2015-12-10 00:00:06 +08:00
def __init__ ( self , name , suite , exe , is_parallel , cmd_args , env , should_fail , valgrind_args , timeout , workdir ) :
2013-01-07 01:13:30 +08:00
InterpreterObject . __init__ ( self )
self . name = name
2015-12-10 00:00:06 +08:00
self . suite = suite
2013-01-07 01:13:30 +08:00
self . exe = exe
2013-09-13 05:50:45 +08:00
self . is_parallel = is_parallel
2013-10-19 03:04:07 +08:00
self . cmd_args = cmd_args
self . env = env
2015-03-24 05:11:04 +08:00
self . should_fail = should_fail
2014-08-24 06:41:12 +08:00
self . valgrind_args = valgrind_args
2015-07-23 04:57:00 +08:00
self . timeout = timeout
2015-12-08 21:45:51 +08:00
self . workdir = workdir
2014-08-07 17:34:35 +08:00
2013-01-07 01:13:30 +08:00
def get_exe ( self ) :
return self . exe
2014-08-07 17:34:35 +08:00
2013-01-07 01:13:30 +08:00
def get_name ( self ) :
return self . name
2013-12-09 08:43:28 +08:00
class SubprojectHolder ( InterpreterObject ) :
2013-12-09 08:59:15 +08:00
def __init__ ( self , subinterpreter ) :
2013-12-09 08:43:28 +08:00
super ( ) . __init__ ( )
2013-12-09 08:59:15 +08:00
self . subinterpreter = subinterpreter
2015-06-19 15:24:49 +08:00
self . methods . update ( { ' get_variable ' : self . get_variable_method ,
} )
2013-12-09 08:59:15 +08:00
def get_variable_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Get_variable takes one argument. ' )
varname = args [ 0 ]
if not isinstance ( varname , str ) :
raise InterpreterException ( ' Get_variable takes a string argument. ' )
return self . subinterpreter . variables [ varname ]
2013-12-09 08:43:28 +08:00
2013-04-21 22:46:58 +08:00
class CompilerHolder ( InterpreterObject ) :
2013-08-25 04:10:44 +08:00
def __init__ ( self , compiler , env ) :
2013-04-21 22:46:58 +08:00
InterpreterObject . __init__ ( self )
self . compiler = compiler
2013-08-25 04:10:44 +08:00
self . environment = env
2013-04-22 05:51:25 +08:00
self . methods . update ( { ' compiles ' : self . compiles_method ,
2015-10-21 01:46:42 +08:00
' links ' : self . links_method ,
2013-04-22 05:51:25 +08:00
' get_id ' : self . get_id_method ,
2013-06-01 05:35:11 +08:00
' sizeof ' : self . sizeof_method ,
2013-06-04 04:57:20 +08:00
' has_header ' : self . has_header_method ,
2013-07-27 19:18:11 +08:00
' run ' : self . run_method ,
2013-07-31 02:44:40 +08:00
' has_function ' : self . has_function_method ,
2013-07-31 03:06:42 +08:00
' has_member ' : self . has_member_method ,
2015-05-22 00:10:01 +08:00
' has_type ' : self . has_type_method ,
2013-07-31 05:41:26 +08:00
' alignment ' : self . alignment_method ,
2015-05-09 21:17:20 +08:00
' version ' : self . version_method ,
' cmd_array ' : self . cmd_array_method ,
2015-06-19 15:24:49 +08:00
} )
2013-04-22 05:51:25 +08:00
2013-08-28 23:47:59 +08:00
def version_method ( self , args , kwargs ) :
return self . compiler . version
2015-05-09 21:17:20 +08:00
def cmd_array_method ( self , args , kwargs ) :
return self . compiler . exelist
2015-10-23 03:33:58 +08:00
def determine_args ( self , kwargs ) :
nobuiltins = kwargs . get ( ' no_builtin_args ' , False )
if not isinstance ( nobuiltins , bool ) :
raise InterpreterException ( ' Type of no_builtin_args not a boolean. ' )
args = [ ]
if not nobuiltins :
opts = self . environment . coredata . compiler_options
args + = self . compiler . get_option_compile_args ( opts )
args + = self . compiler . get_option_link_args ( opts )
args + = mesonlib . stringlistify ( kwargs . get ( ' args ' , [ ] ) )
return args
2013-07-31 05:41:26 +08:00
def alignment_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Alignment method takes exactly one positional argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-07-31 05:41:26 +08:00
typename = args [ 0 ]
2015-10-23 00:36:48 +08:00
extra_args = mesonlib . stringlistify ( kwargs . get ( ' args ' , [ ] ) )
result = self . compiler . alignment ( typename , self . environment , extra_args )
2013-07-31 05:41:26 +08:00
mlog . log ( ' Checking for alignment of " ' , mlog . bold ( typename ) , ' " : ' , result , sep = ' ' )
return result
2013-07-27 19:18:11 +08:00
def run_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Run method takes exactly one positional argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-07-27 19:18:11 +08:00
code = args [ 0 ]
2013-08-01 02:36:15 +08:00
testname = kwargs . get ( ' name ' , ' ' )
if not isinstance ( testname , str ) :
raise InterpreterException ( ' Testname argument must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
result = self . compiler . run ( code , extra_args )
2013-08-01 02:36:15 +08:00
if len ( testname ) > 0 :
if not result . compiled :
h = mlog . red ( ' DID NOT COMPILE ' )
elif result . returncode == 0 :
h = mlog . green ( ' YES ' )
else :
h = mlog . red ( ' NO ( %d ) ' % result . returncode )
mlog . log ( ' Checking if " ' , mlog . bold ( testname ) , ' " runs : ' , h , sep = ' ' )
2013-07-27 19:18:11 +08:00
return TryRunResultHolder ( result )
2013-04-22 05:51:25 +08:00
def get_id_method ( self , args , kwargs ) :
return self . compiler . get_id ( )
2013-07-31 02:44:40 +08:00
2013-07-31 03:06:42 +08:00
def has_member_method ( self , args , kwargs ) :
if len ( args ) != 2 :
raise InterpreterException ( ' Has_member takes exactly two arguments. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-07-31 03:06:42 +08:00
typename = args [ 0 ]
membername = args [ 1 ]
prefix = kwargs . get ( ' prefix ' , ' ' )
if not isinstance ( prefix , str ) :
raise InterpreterException ( ' Prefix argument of has_function must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
had = self . compiler . has_member ( typename , membername , prefix , extra_args )
2013-07-31 03:06:42 +08:00
if had :
hadtxt = mlog . green ( ' YES ' )
else :
hadtxt = mlog . red ( ' NO ' )
2014-08-07 17:34:35 +08:00
mlog . log ( ' Checking whether type " ' , mlog . bold ( typename ) ,
2013-07-31 03:06:42 +08:00
' " has member " ' , mlog . bold ( membername ) , ' " : ' , hadtxt , sep = ' ' )
return had
2013-07-31 02:44:40 +08:00
def has_function_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Has_function takes exactly one argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-07-31 02:44:40 +08:00
funcname = args [ 0 ]
prefix = kwargs . get ( ' prefix ' , ' ' )
if not isinstance ( prefix , str ) :
raise InterpreterException ( ' Prefix argument of has_function must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
had = self . compiler . has_function ( funcname , prefix , self . environment , extra_args )
2013-07-31 02:44:40 +08:00
if had :
hadtxt = mlog . green ( ' YES ' )
else :
hadtxt = mlog . red ( ' NO ' )
mlog . log ( ' Checking for function " ' , mlog . bold ( funcname ) , ' " : ' , hadtxt , sep = ' ' )
2015-05-22 00:10:01 +08:00
return had
def has_type_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Has_type takes exactly one argument. ' )
check_stringlist ( args )
typename = args [ 0 ]
prefix = kwargs . get ( ' prefix ' , ' ' )
if not isinstance ( prefix , str ) :
raise InterpreterException ( ' Prefix argument of has_type must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
had = self . compiler . has_type ( typename , prefix , extra_args )
2015-05-22 00:10:01 +08:00
if had :
hadtxt = mlog . green ( ' YES ' )
else :
hadtxt = mlog . red ( ' NO ' )
mlog . log ( ' Checking for type " ' , mlog . bold ( typename ) , ' " : ' , hadtxt , sep = ' ' )
2013-07-31 02:44:40 +08:00
return had
2013-06-01 05:35:11 +08:00
def sizeof_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Sizeof takes exactly one argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-06-01 05:47:29 +08:00
element = args [ 0 ]
prefix = kwargs . get ( ' prefix ' , ' ' )
if not isinstance ( prefix , str ) :
raise InterpreterException ( ' Prefix argument of sizeof must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
esize = self . compiler . sizeof ( element , prefix , self . environment , extra_args )
2013-07-09 02:02:47 +08:00
mlog . log ( ' Checking for size of " %s " : %d ' % ( element , esize ) )
2013-06-05 23:22:51 +08:00
return esize
2013-04-21 22:46:58 +08:00
def compiles_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' compiles method takes exactly one argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2015-10-21 01:55:10 +08:00
code = args [ 0 ]
2013-08-01 02:28:45 +08:00
testname = kwargs . get ( ' name ' , ' ' )
2013-08-01 02:25:46 +08:00
if not isinstance ( testname , str ) :
raise InterpreterException ( ' Testname argument must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
result = self . compiler . compiles ( code , extra_args )
2013-08-01 02:25:46 +08:00
if len ( testname ) > 0 :
if result :
h = mlog . green ( ' YES ' )
else :
h = mlog . red ( ' NO ' )
mlog . log ( ' Checking if " ' , mlog . bold ( testname ) , ' " compiles : ' , h , sep = ' ' )
return result
2013-07-31 02:44:40 +08:00
2015-10-21 01:46:42 +08:00
def links_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' links method takes exactly one argument. ' )
check_stringlist ( args )
2015-10-21 01:55:10 +08:00
code = args [ 0 ]
2015-10-21 01:46:42 +08:00
testname = kwargs . get ( ' name ' , ' ' )
if not isinstance ( testname , str ) :
raise InterpreterException ( ' Testname argument must be a string. ' )
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
result = self . compiler . links ( code , extra_args )
2015-10-21 01:46:42 +08:00
if len ( testname ) > 0 :
if result :
h = mlog . green ( ' YES ' )
else :
h = mlog . red ( ' NO ' )
mlog . log ( ' Checking if " ' , mlog . bold ( testname ) , ' " links : ' , h , sep = ' ' )
return result
2013-06-04 04:57:20 +08:00
def has_header_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' has_header method takes exactly one argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-06-04 04:57:20 +08:00
string = args [ 0 ]
2015-10-23 03:33:58 +08:00
extra_args = self . determine_args ( kwargs )
2015-10-23 00:36:48 +08:00
haz = self . compiler . has_header ( string , extra_args )
2013-07-09 02:02:47 +08:00
if haz :
h = mlog . green ( ' YES ' )
else :
h = mlog . red ( ' NO ' )
mlog . log ( ' Has header " %s " : ' % string , h )
2013-06-05 23:22:51 +08:00
return haz
2013-04-21 22:46:58 +08:00
2015-03-06 23:36:43 +08:00
class ModuleState :
pass
2015-03-05 05:53:35 +08:00
class ModuleHolder ( InterpreterObject ) :
2015-03-14 01:55:09 +08:00
def __init__ ( self , modname , module , interpreter ) :
2015-03-05 05:53:35 +08:00
InterpreterObject . __init__ ( self )
self . modname = modname
2015-03-14 01:55:09 +08:00
self . held_object = module
2015-03-06 23:36:43 +08:00
self . interpreter = interpreter
2015-03-05 05:53:35 +08:00
def method_call ( self , method_name , args , kwargs ) :
try :
2015-03-14 01:55:09 +08:00
fn = getattr ( self . held_object , method_name )
2015-03-05 05:53:35 +08:00
except AttributeError :
raise InvalidArguments ( ' Module %s does not have method %s . ' % ( self . modname , method_name ) )
2015-03-06 23:36:43 +08:00
state = ModuleState ( )
state . build_to_src = os . path . relpath ( self . interpreter . environment . get_source_dir ( ) ,
2015-06-19 15:24:49 +08:00
self . interpreter . environment . get_build_dir ( ) )
2015-03-06 23:36:43 +08:00
state . subdir = self . interpreter . subdir
2015-03-09 23:16:32 +08:00
state . environment = self . interpreter . environment
2015-03-19 19:07:50 +08:00
state . project_name = self . interpreter . build . project_name
2015-08-25 06:43:04 +08:00
state . project_version = self . interpreter . build . dep_manifest [ self . interpreter . active_projectname ]
2015-03-21 05:30:12 +08:00
state . compilers = self . interpreter . build . compilers
2015-03-19 19:07:50 +08:00
state . targets = self . interpreter . build . targets
2015-03-21 06:50:42 +08:00
state . headers = self . interpreter . build . get_headers ( )
2015-03-21 07:04:59 +08:00
state . man = self . interpreter . build . get_man ( )
2015-03-24 16:06:17 +08:00
state . global_args = self . interpreter . build . global_args
2015-03-06 23:36:43 +08:00
value = fn ( state , args , kwargs )
return self . interpreter . module_method_callback ( value )
2015-03-05 05:53:35 +08:00
2013-04-21 22:46:58 +08:00
class MesonMain ( InterpreterObject ) :
2014-03-08 02:02:36 +08:00
def __init__ ( self , build , interpreter ) :
2013-04-21 22:46:58 +08:00
InterpreterObject . __init__ ( self )
self . build = build
2014-03-08 02:02:36 +08:00
self . interpreter = interpreter
2013-08-31 04:43:27 +08:00
self . methods . update ( { ' get_compiler ' : self . get_compiler_method ,
' is_cross_build ' : self . is_cross_build_method ,
2013-08-31 04:56:09 +08:00
' has_exe_wrapper ' : self . has_exe_wrapper_method ,
2013-12-27 06:25:45 +08:00
' is_unity ' : self . is_unity_method ,
2014-10-06 02:57:42 +08:00
' is_subproject ' : self . is_subproject_method ,
2014-03-08 02:02:36 +08:00
' current_source_dir ' : self . current_source_dir_method ,
2014-04-28 05:34:12 +08:00
' current_build_dir ' : self . current_build_dir_method ,
2015-06-07 19:21:24 +08:00
' source_root ' : self . source_root_method ,
' build_root ' : self . build_root_method ,
2015-07-30 07:01:47 +08:00
' add_install_script ' : self . add_install_script_method ,
2015-08-22 01:50:40 +08:00
' install_dependency_manifest ' : self . install_dependency_manifest_method ,
' project_version ' : self . project_version_method ,
2015-06-19 15:24:49 +08:00
} )
2013-08-31 04:43:27 +08:00
2015-07-30 07:01:47 +08:00
def add_install_script_method ( self , args , kwargs ) :
2014-07-09 21:30:58 +08:00
if len ( args ) != 1 :
raise InterpreterException ( ' Set_install_script takes exactly one argument. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2014-07-09 21:30:58 +08:00
scriptbase = args [ 0 ]
2014-08-07 17:34:35 +08:00
scriptfile = os . path . join ( self . interpreter . environment . source_dir ,
2014-07-09 21:30:58 +08:00
self . interpreter . subdir , scriptbase )
if not os . path . isfile ( scriptfile ) :
raise InterpreterException ( ' Can not find install script %s . ' % scriptbase )
2015-07-30 07:01:47 +08:00
self . build . install_scripts . append ( build . InstallScript ( [ scriptfile ] ) )
2014-07-09 21:30:58 +08:00
2014-03-08 02:02:36 +08:00
def current_source_dir_method ( self , args , kwargs ) :
src = self . interpreter . environment . source_dir
sub = self . interpreter . subdir
if sub == ' ' :
return src
return os . path . join ( src , sub )
2014-04-28 05:34:12 +08:00
def current_build_dir_method ( self , args , kwargs ) :
src = self . interpreter . environment . build_dir
sub = self . interpreter . subdir
if sub == ' ' :
return src
return os . path . join ( src , sub )
2015-06-07 19:21:24 +08:00
def source_root_method ( self , args , kwargs ) :
return self . interpreter . environment . source_dir
def build_root_method ( self , args , kwargs ) :
return self . interpreter . environment . build_dir
2013-08-31 04:56:09 +08:00
def has_exe_wrapper_method ( self , args , kwargs ) :
2015-07-27 04:50:04 +08:00
if self . is_cross_build_method ( None , None ) and ' binaries ' in self . build . environment . cross_info . config :
2015-07-26 03:01:25 +08:00
return ' exe_wrap ' in self . build . environment . cross_info . config [ ' binaries ' ]
2015-07-26 03:50:35 +08:00
return True # This is semantically confusing.
2013-12-27 06:25:45 +08:00
2013-08-31 04:43:27 +08:00
def is_cross_build_method ( self , args , kwargs ) :
return self . build . environment . is_cross_build ( )
2013-08-25 04:10:44 +08:00
2013-04-21 22:46:58 +08:00
def get_compiler_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' get_compiler_method must have one and only one argument. ' )
cname = args [ 0 ]
2013-08-31 04:43:27 +08:00
native = kwargs . get ( ' native ' , None )
if native is None :
if self . build . environment . is_cross_build ( ) :
native = False
else :
native = True
if not isinstance ( native , bool ) :
raise InterpreterException ( ' Type of " native " must be a boolean. ' )
if native :
clist = self . build . compilers
else :
clist = self . build . cross_compilers
for c in clist :
2013-04-21 22:46:58 +08:00
if c . get_language ( ) == cname :
2013-08-25 04:10:44 +08:00
return CompilerHolder ( c , self . build . environment )
2013-04-21 22:46:58 +08:00
raise InterpreterException ( ' Tried to access compiler for unspecified language " %s " . ' % cname )
2013-12-27 06:25:45 +08:00
def is_unity_method ( self , args , kwargs ) :
2015-11-03 09:03:54 +08:00
return self . build . environment . coredata . get_builtin_option ( ' unity ' )
2013-12-27 06:25:45 +08:00
2014-10-06 02:57:42 +08:00
def is_subproject_method ( self , args , kwargs ) :
2015-05-16 01:01:21 +08:00
return self . interpreter . is_subproject ( )
2014-10-06 02:57:42 +08:00
2015-08-22 01:50:40 +08:00
def install_dependency_manifest_method ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Must specify manifest install file name ' )
if not isinstance ( args [ 0 ] , str ) :
raise InterpreterException ( ' Argument must be a string. ' )
self . build . dep_manifest_name = args [ 0 ]
def project_version_method ( self , args , kwargs ) :
2015-11-30 03:30:14 +08:00
return self . build . dep_manifest [ self . interpreter . active_projectname ] [ ' version ' ]
2015-08-22 01:50:40 +08:00
2012-12-27 02:58:48 +08:00
class Interpreter ( ) :
2013-01-02 02:13:46 +08:00
2015-09-17 23:48:26 +08:00
def __init__ ( self , build , backend , subproject = ' ' , subdir = ' ' , subproject_dir = ' subprojects ' ) :
2013-01-12 04:59:49 +08:00
self . build = build
2015-09-17 23:48:26 +08:00
self . backend = backend
2013-12-09 08:43:28 +08:00
self . subproject = subproject
2014-03-09 05:13:49 +08:00
self . subdir = subdir
self . source_root = build . environment . get_source_dir ( )
2015-05-16 01:01:21 +08:00
self . subproject_dir = subproject_dir
2014-03-09 05:13:49 +08:00
option_file = os . path . join ( self . source_root , self . subdir , ' meson_options.txt ' )
2013-12-10 02:26:12 +08:00
if os . path . exists ( option_file ) :
2015-07-26 03:50:35 +08:00
oi = optinterpreter . OptionInterpreter ( self . subproject , \
2015-10-18 08:33:34 +08:00
self . build . environment . cmd_line_options . projectoptions )
2013-12-10 02:26:12 +08:00
oi . process ( option_file )
self . build . environment . merge_options ( oi . options )
2014-03-09 05:13:49 +08:00
mesonfile = os . path . join ( self . source_root , self . subdir , environment . build_filename )
if not os . path . isfile ( mesonfile ) :
raise InvalidArguments ( ' Missing Meson file in %s ' % mesonfile )
code = open ( mesonfile ) . read ( )
2013-02-17 03:14:04 +08:00
if len ( code . strip ( ) ) == 0 :
raise InvalidCode ( ' Builder file is empty. ' )
assert ( isinstance ( code , str ) )
2013-06-02 19:25:35 +08:00
try :
2014-03-17 06:37:47 +08:00
self . ast = mparser . Parser ( code ) . parse ( )
2013-06-02 19:25:35 +08:00
except coredata . MesonException as me :
me . file = environment . build_filename
raise me
2012-12-27 02:58:48 +08:00
self . sanity_check_ast ( )
2012-12-30 07:31:39 +08:00
self . variables = { }
2013-01-28 03:45:02 +08:00
self . builtin = { }
2015-07-26 04:08:13 +08:00
self . builtin [ ' build_machine ' ] = BuildMachine ( )
2015-07-26 03:50:35 +08:00
if not self . build . environment . is_cross_build ( ) :
self . builtin [ ' host_machine ' ] = self . builtin [ ' build_machine ' ]
self . builtin [ ' target_machine ' ] = self . builtin [ ' build_machine ' ]
else :
cross_info = self . build . environment . cross_info
if cross_info . has_host ( ) :
self . builtin [ ' host_machine ' ] = CrossMachineInfo ( cross_info . config [ ' host_machine ' ] )
else :
self . builtin [ ' host_machine ' ] = self . builtin [ ' build_machine ' ]
if cross_info . has_target ( ) :
self . builtin [ ' target_machine ' ] = CrossMachineInfo ( cross_info . config [ ' target_machine ' ] )
else :
self . builtin [ ' target_machine ' ] = self . builtin [ ' host_machine ' ]
2014-03-08 02:02:36 +08:00
self . builtin [ ' meson ' ] = MesonMain ( build , self )
2013-01-12 04:59:49 +08:00
self . environment = build . environment
2013-01-07 00:48:16 +08:00
self . build_func_dict ( )
2014-03-09 06:04:07 +08:00
self . build_def_files = [ os . path . join ( self . subdir , environment . build_filename ) ]
2013-04-21 22:46:58 +08:00
self . coredata = self . environment . get_coredata ( )
2013-02-24 02:37:33 +08:00
self . generators = [ ]
2013-03-16 04:27:03 +08:00
self . visited_subdirs = { }
2014-06-22 22:10:00 +08:00
self . global_args_frozen = False
2013-12-09 08:43:28 +08:00
self . subprojects = { }
2014-02-24 04:41:49 +08:00
self . subproject_stack = [ ]
2013-01-07 00:48:16 +08:00
def build_func_dict ( self ) :
2014-08-07 17:34:35 +08:00
self . funcs = { ' project ' : self . func_project ,
2013-01-07 00:48:16 +08:00
' message ' : self . func_message ,
2013-07-09 01:51:10 +08:00
' error ' : self . func_error ,
2013-01-07 00:48:16 +08:00
' executable ' : self . func_executable ,
2013-06-02 19:06:43 +08:00
' dependency ' : self . func_dependency ,
2013-01-07 00:48:16 +08:00
' static_library ' : self . func_static_lib ,
2013-01-07 01:13:30 +08:00
' shared_library ' : self . func_shared_lib ,
2015-11-03 23:26:09 +08:00
' library ' : self . func_library ,
2014-03-11 05:33:24 +08:00
' jar ' : self . func_jar ,
2015-06-07 03:15:30 +08:00
' build_target ' : self . func_build_target ,
2014-05-19 05:59:35 +08:00
' custom_target ' : self . func_custom_target ,
2014-06-12 03:38:36 +08:00
' run_target ' : self . func_run_target ,
2013-02-24 02:37:33 +08:00
' generator ' : self . func_generator ,
2013-06-02 18:18:15 +08:00
' test ' : self . func_test ,
2015-11-26 05:29:06 +08:00
' benchmark ' : self . func_benchmark ,
2014-10-12 01:41:57 +08:00
' install_headers ' : self . func_install_headers ,
2014-10-12 01:48:05 +08:00
' install_man ' : self . func_install_man ,
2013-01-14 01:25:54 +08:00
' subdir ' : self . func_subdir ,
2014-10-12 01:56:32 +08:00
' install_data ' : self . func_install_data ,
2014-11-04 05:28:47 +08:00
' install_subdir ' : self . func_install_subdir ,
2013-01-26 06:28:13 +08:00
' configure_file ' : self . func_configure_file ,
' include_directories ' : self . func_include_directories ,
2013-01-26 07:44:56 +08:00
' add_global_arguments ' : self . func_add_global_arguments ,
2015-07-26 04:20:37 +08:00
' add_languages ' : self . func_add_languages ,
2013-03-10 03:12:03 +08:00
' find_program ' : self . func_find_program ,
2013-03-10 04:42:01 +08:00
' find_library ' : self . func_find_library ,
2013-05-25 03:21:48 +08:00
' configuration_data ' : self . func_configuration_data ,
2013-06-30 06:36:17 +08:00
' run_command ' : self . func_run_command ,
2013-09-12 05:30:21 +08:00
' gettext ' : self . func_gettext ,
2013-10-17 02:23:29 +08:00
' option ' : self . func_option ,
2013-10-17 03:33:33 +08:00
' get_option ' : self . func_get_option ,
2013-12-09 08:43:28 +08:00
' subproject ' : self . func_subproject ,
2015-02-09 02:34:33 +08:00
' vcs_tag ' : self . func_vcs_tag ,
2015-02-21 08:31:34 +08:00
' set_variable ' : self . func_set_variable ,
2015-10-06 01:47:17 +08:00
' is_variable ' : self . func_is_variable ,
' get_variable ' : self . func_get_variable ,
2015-03-05 05:53:35 +08:00
' import ' : self . func_import ,
2015-05-02 20:47:03 +08:00
' files ' : self . func_files ,
2015-06-15 05:26:19 +08:00
' declare_dependency ' : self . func_declare_dependency ,
2015-10-18 08:33:34 +08:00
' assert ' : self . func_assert ,
2015-06-19 15:24:49 +08:00
}
2013-02-25 05:11:14 +08:00
2015-03-06 23:36:43 +08:00
def module_method_callback ( self , invalues ) :
unwrap_single = False
if invalues is None :
return
if not isinstance ( invalues , list ) :
unwrap_single = True
invalues = [ invalues ]
outvalues = [ ]
for v in invalues :
if isinstance ( v , build . CustomTarget ) :
if v . name in self . build . targets :
raise InterpreterException ( ' Tried to create target %s which already exists. ' % v . name )
self . build . targets [ v . name ] = v
outvalues . append ( CustomTargetHolder ( v ) )
elif isinstance ( v , int ) or isinstance ( v , str ) :
outvalues . append ( v )
2015-03-09 23:16:32 +08:00
elif isinstance ( v , build . Executable ) :
if v . name in self . build . targets :
raise InterpreterException ( ' Tried to create target %s which already exists. ' % v . name )
self . build . targets [ v . name ] = v
outvalues . append ( ExecutableHolder ( v ) )
2015-03-14 01:38:53 +08:00
elif isinstance ( v , list ) :
outvalues . append ( self . module_method_callback ( v ) )
elif isinstance ( v , build . GeneratedList ) :
outvalues . append ( GeneratedListHolder ( v ) )
2015-07-30 05:52:44 +08:00
elif isinstance ( v , build . RunTarget ) :
if v . name in self . build . targets :
raise InterpreterException ( ' Tried to create target %s which already exists. ' % v . name )
self . build . targets [ v . name ] = v
2015-07-30 07:01:47 +08:00
elif isinstance ( v , build . InstallScript ) :
self . build . install_scripts . append ( v )
2015-12-23 21:10:27 +08:00
elif isinstance ( v , build . Data ) :
self . build . data . append ( v )
2015-03-06 23:36:43 +08:00
else :
2015-03-14 01:38:53 +08:00
print ( v )
2015-03-06 23:36:43 +08:00
raise InterpreterException ( ' Module returned a value of unknown type. ' )
if len ( outvalues ) == 1 and unwrap_single :
return outvalues [ 0 ]
return outvalues
2013-02-17 03:14:04 +08:00
def get_build_def_files ( self ) :
return self . build_def_files
2013-01-26 06:28:13 +08:00
2013-01-14 07:13:55 +08:00
def get_variables ( self ) :
return self . variables
2013-01-02 02:08:03 +08:00
2012-12-27 02:58:48 +08:00
def sanity_check_ast ( self ) :
2014-03-17 06:37:47 +08:00
if not isinstance ( self . ast , mparser . CodeBlockNode ) :
2012-12-27 02:58:48 +08:00
raise InvalidCode ( ' AST is of invalid type. Possibly a bug in the parser. ' )
2014-03-17 04:26:22 +08:00
if len ( self . ast . lines ) == 0 :
2012-12-27 02:58:48 +08:00
raise InvalidCode ( ' No statements in code. ' )
2014-03-17 04:26:22 +08:00
first = self . ast . lines [ 0 ]
2014-03-17 06:37:47 +08:00
if not isinstance ( first , mparser . FunctionNode ) or first . func_name != ' project ' :
2012-12-27 02:58:48 +08:00
raise InvalidCode ( ' First statement must be a call to project ' )
2012-12-30 00:18:41 +08:00
2012-12-27 05:37:41 +08:00
def run ( self ) :
2013-01-13 23:59:34 +08:00
self . evaluate_codeblock ( self . ast )
2014-06-28 00:02:08 +08:00
mlog . log ( ' Build targets in project: ' , mlog . bold ( str ( len ( self . build . targets ) ) ) )
2013-01-13 23:59:34 +08:00
def evaluate_codeblock ( self , node ) :
2013-01-26 03:25:52 +08:00
if node is None :
return
2014-03-17 06:37:47 +08:00
if not isinstance ( node , mparser . CodeBlockNode ) :
2013-05-27 03:32:54 +08:00
e = InvalidCode ( ' Tried to execute a non-codeblock. Possibly a bug in the parser. ' )
2014-03-17 04:26:22 +08:00
e . lineno = node . lineno
e . colno = node . colno
2013-05-27 03:32:54 +08:00
raise e
2014-03-17 04:26:22 +08:00
statements = node . lines
2012-12-27 05:37:41 +08:00
i = 0
while i < len ( statements ) :
cur = statements [ i ]
2013-05-27 03:32:54 +08:00
try :
self . evaluate_statement ( cur )
except Exception as e :
2014-09-18 23:49:36 +08:00
if not ( hasattr ( e , ' lineno ' ) ) :
e . lineno = cur . lineno
e . colno = cur . colno
e . file = os . path . join ( self . subdir , ' meson.build ' )
2013-05-27 03:32:54 +08:00
raise e
2015-07-27 05:25:45 +08:00
i + = 1 # In THE FUTURE jump over blocks and stuff.
2012-12-30 07:31:39 +08:00
2013-01-28 03:45:02 +08:00
def get_variable ( self , varname ) :
if varname in self . builtin :
return self . builtin [ varname ]
if varname in self . variables :
return self . variables [ varname ]
2013-03-10 07:37:20 +08:00
raise InvalidCode ( ' Unknown variable " %s " . ' % varname )
2013-01-28 03:45:02 +08:00
2015-02-21 08:31:34 +08:00
def func_set_variable ( self , node , args , kwargs ) :
if len ( args ) != 2 :
raise InvalidCode ( ' Set_variable takes two arguments. ' )
varname = args [ 0 ]
value = self . to_native ( args [ 1 ] )
self . set_variable ( varname , value )
2015-10-06 01:47:17 +08:00
@noKwargs
def func_get_variable ( self , node , args , kwargs ) :
if len ( args ) < 1 or len ( args ) > 2 :
raise InvalidCode ( ' Get_variable takes one or two arguments. ' )
varname = args [ 0 ]
if not isinstance ( varname , str ) :
raise InterpreterException ( ' First argument must be a string. ' )
try :
return self . variables [ varname ]
except KeyError :
pass
if len ( args ) == 2 :
return args [ 1 ]
raise InterpreterException ( ' Tried to get unknown variable " %s " . ' % varname )
@stringArgs
@noKwargs
def func_is_variable ( self , node , args , kwargs ) :
if len ( args ) != 1 :
raise InvalidCode ( ' Is_variable takes two arguments. ' )
varname = args [ 0 ]
return varname in self . variables
2015-04-23 00:40:09 +08:00
@stringArgs
2015-04-22 23:03:18 +08:00
@noKwargs
2015-03-05 05:53:35 +08:00
def func_import ( self , node , args , kwargs ) :
if len ( args ) != 1 :
raise InvalidCode ( ' Import takes one argument. ' )
modname = args [ 0 ]
2015-03-14 01:55:09 +08:00
if not modname in self . environment . coredata . modules :
module = importlib . import_module ( ' modules. ' + modname ) . initialize ( )
self . environment . coredata . modules [ modname ] = module
return ModuleHolder ( modname , self . environment . coredata . modules [ modname ] , self )
2015-03-05 05:53:35 +08:00
2015-04-23 00:40:09 +08:00
@stringArgs
2015-04-22 23:03:18 +08:00
@noKwargs
2015-05-02 20:47:03 +08:00
def func_files ( self , node , args , kwargs ) :
2015-06-15 05:26:19 +08:00
return [ mesonlib . File . from_source_file ( self . environment . source_dir , self . subdir , fname ) for fname in args ]
@noPosargs
def func_declare_dependency ( self , node , args , kwargs ) :
incs = kwargs . get ( ' include_directories ' , [ ] )
if not isinstance ( incs , list ) :
incs = [ incs ]
libs = kwargs . get ( ' link_with ' , [ ] )
if not isinstance ( libs , list ) :
libs = [ libs ]
sources = kwargs . get ( ' sources ' , [ ] )
if not isinstance ( sources , list ) :
sources = [ sources ]
sources = self . source_strings_to_files ( self . flatten ( sources ) )
2015-11-05 05:57:26 +08:00
deps = kwargs . get ( ' dependencies ' , [ ] )
if not isinstance ( deps , list ) :
deps = [ deps ]
final_deps = [ ]
for d in deps :
try :
d = d . held_object
except Exception :
pass
if not isinstance ( d , ( dependencies . Dependency , dependencies . ExternalLibrary ) ) :
raise InterpreterException ( ' Dependencies must be external deps ' )
final_deps . append ( d )
2015-11-05 06:54:00 +08:00
dep = dependencies . InternalDependency ( incs , libs , sources , final_deps )
2015-06-15 05:26:19 +08:00
return InternalDependencyHolder ( dep )
2015-04-21 21:27:58 +08:00
2015-10-18 08:33:34 +08:00
@noKwargs
def func_assert ( self , node , args , kwargs ) :
if len ( args ) != 2 :
raise InterpreterException ( ' Assert takes exactly two arguments ' )
value , message = args
if not isinstance ( value , bool ) :
raise InterpreterException ( ' Assert value not bool. ' )
if not isinstance ( message , str ) :
raise InterpreterException ( ' Assert message not a string. ' )
if not value :
raise InterpreterException ( ' Assert failed: ' + message )
2013-01-28 03:45:02 +08:00
def set_variable ( self , varname , variable ) :
2015-02-21 08:31:34 +08:00
if variable is None :
raise InvalidCode ( ' Can not assign None to variable. ' )
2015-02-21 08:48:32 +08:00
if not isinstance ( varname , str ) :
raise InvalidCode ( ' First argument to set_variable must be a string. ' )
2015-02-21 08:31:34 +08:00
if not self . is_assignable ( variable ) :
raise InvalidCode ( ' Assigned value not of assignable type. ' )
2015-12-03 21:41:38 +08:00
if re . match ( ' [_a-zA-Z][_0-9a-zA-Z]*$ ' , varname ) is None :
2015-02-21 08:48:32 +08:00
raise InvalidCode ( ' Invalid variable name: ' + varname )
2013-01-28 03:45:02 +08:00
if varname in self . builtin :
raise InvalidCode ( ' Tried to overwrite internal variable " %s " ' % varname )
self . variables [ varname ] = variable
2012-12-30 08:06:51 +08:00
def evaluate_statement ( self , cur ) :
2014-03-17 06:37:47 +08:00
if isinstance ( cur , mparser . FunctionNode ) :
2012-12-30 07:31:39 +08:00
return self . function_call ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . AssignmentNode ) :
2012-12-30 07:31:39 +08:00
return self . assignment ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . MethodNode ) :
2012-12-30 09:20:53 +08:00
return self . method_call ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . StringNode ) :
2014-03-17 06:22:39 +08:00
return cur . value
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . BooleanNode ) :
2014-03-17 06:22:39 +08:00
return cur . value
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . IfClauseNode ) :
2013-01-26 03:06:08 +08:00
return self . evaluate_if ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . IdNode ) :
2014-03-17 04:55:22 +08:00
return self . get_variable ( cur . value )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . ComparisonNode ) :
2013-01-26 03:59:53 +08:00
return self . evaluate_comparison ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . ArrayNode ) :
2013-01-26 04:42:11 +08:00
return self . evaluate_arraystatement ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . NumberNode ) :
2014-11-08 09:41:05 +08:00
return cur . value
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . AndNode ) :
2013-07-27 22:06:37 +08:00
return self . evaluate_andstatement ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . OrNode ) :
2013-07-27 22:15:22 +08:00
return self . evaluate_orstatement ( cur )
2014-03-17 06:37:47 +08:00
elif isinstance ( cur , mparser . NotNode ) :
2013-07-27 22:21:59 +08:00
return self . evaluate_notstatement ( cur )
2015-05-10 00:52:10 +08:00
elif isinstance ( cur , mparser . UMinusNode ) :
return self . evaluate_uminusstatement ( cur )
2014-11-08 09:41:05 +08:00
elif isinstance ( cur , mparser . ArithmeticNode ) :
return self . evaluate_arithmeticstatement ( cur )
2014-11-06 02:38:35 +08:00
elif isinstance ( cur , mparser . ForeachClauseNode ) :
return self . evaluate_foreach ( cur )
2015-08-14 21:05:58 +08:00
elif isinstance ( cur , mparser . PlusAssignmentNode ) :
return self . evaluate_plusassign ( cur )
2015-08-20 04:34:49 +08:00
elif isinstance ( cur , mparser . IndexNode ) :
return self . evaluate_indexing ( cur )
2014-11-08 09:41:05 +08:00
elif self . is_elementary_type ( cur ) :
return cur
2012-12-30 07:31:39 +08:00
else :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( " Unknown statement. " )
2012-12-30 00:18:41 +08:00
2012-12-29 21:45:43 +08:00
def validate_arguments ( self , args , argcount , arg_types ) :
if argcount is not None :
if argcount != len ( args ) :
2015-07-27 05:25:45 +08:00
raise InvalidArguments ( ' Expected %d arguments, got %d . ' %
2015-06-14 19:26:00 +08:00
( argcount , len ( args ) ) )
2012-12-29 21:45:43 +08:00
for i in range ( min ( len ( args ) , len ( arg_types ) ) ) :
wanted = arg_types [ i ]
actual = args [ i ]
if wanted != None :
if not isinstance ( actual , wanted ) :
raise InvalidArguments ( ' Incorrect argument type. ' )
2014-08-07 17:34:35 +08:00
2013-06-30 06:36:17 +08:00
def func_run_command ( self , node , args , kwargs ) :
2014-04-20 18:58:20 +08:00
if len ( args ) < 1 :
raise InterpreterException ( ' Not enough arguments ' )
cmd = args [ 0 ]
cargs = args [ 1 : ]
if isinstance ( cmd , ExternalProgramHolder ) :
cmd = cmd . get_command ( )
2015-04-22 23:27:34 +08:00
elif isinstance ( cmd , str ) :
cmd = [ cmd ]
else :
2014-04-20 18:58:20 +08:00
raise InterpreterException ( ' First argument is of incorrect type. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( cargs , ' Run_command arguments must be strings. ' )
2014-09-20 19:08:48 +08:00
args = cmd + cargs
2014-07-28 04:48:59 +08:00
in_builddir = kwargs . get ( ' in_builddir ' , False )
if not isinstance ( in_builddir , bool ) :
raise InterpreterException ( ' in_builddir must be boolean. ' )
return RunProcess ( args , self . environment . source_dir , self . environment . build_dir ,
self . subdir , in_builddir )
2013-06-30 06:36:17 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2013-09-12 05:30:21 +08:00
def func_gettext ( self , nodes , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Gettext requires one positional argument (package name). ' )
packagename = args [ 0 ]
languages = kwargs . get ( ' languages ' , None )
2015-04-23 00:40:09 +08:00
check_stringlist ( languages , ' Argument languages must be a list of strings. ' )
2013-09-12 05:30:21 +08:00
# TODO: check that elements are strings
if len ( self . build . pot ) > 0 :
2013-12-09 09:18:51 +08:00
raise InterpreterException ( ' More than one gettext definition currently not supported. ' )
2013-09-12 23:55:35 +08:00
self . build . pot . append ( ( packagename , languages , self . subdir ) )
2013-09-12 05:30:21 +08:00
2013-10-17 02:23:29 +08:00
def func_option ( self , nodes , args , kwargs ) :
raise InterpreterException ( ' Tried to call option() in build description file. All options must be in the option file. ' )
2015-04-22 23:27:34 +08:00
@stringArgs
2013-12-09 08:43:28 +08:00
def func_subproject ( self , nodes , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Subproject takes exactly one argument ' )
dirname = args [ 0 ]
2015-10-28 06:29:06 +08:00
return self . do_subproject ( dirname , kwargs )
def do_subproject ( self , dirname , kwargs ) :
2013-12-09 09:41:19 +08:00
if self . subdir != ' ' :
2014-03-09 05:13:49 +08:00
segs = os . path . split ( self . subdir )
2015-05-16 01:01:21 +08:00
if len ( segs ) != 2 or segs [ 0 ] != self . subproject_dir :
2014-03-09 05:13:49 +08:00
raise InterpreterException ( ' Subprojects must be defined at the root directory. ' )
2014-02-24 04:41:49 +08:00
if dirname in self . subproject_stack :
2014-02-24 06:43:45 +08:00
fullstack = self . subproject_stack + [ dirname ]
2014-02-24 04:41:49 +08:00
incpath = ' => ' . join ( fullstack )
raise InterpreterException ( ' Recursive include of subprojects: %s . ' % incpath )
2015-04-09 04:32:31 +08:00
if dirname in self . subprojects :
2014-02-24 04:41:49 +08:00
return self . subprojects [ dirname ]
2015-05-16 01:01:21 +08:00
r = wrap . Resolver ( os . path . join ( self . build . environment . get_source_dir ( ) , self . subproject_dir ) )
2015-03-20 21:45:32 +08:00
resolved = r . resolve ( dirname )
if resolved is None :
raise InterpreterException ( ' Subproject directory does not exist and can not be downloaded. ' )
2015-05-16 01:01:21 +08:00
subdir = os . path . join ( self . subproject_dir , resolved )
2015-02-07 00:58:37 +08:00
os . makedirs ( os . path . join ( self . build . environment . get_build_dir ( ) , subdir ) , exist_ok = True )
2014-06-22 22:10:00 +08:00
self . global_args_frozen = True
2013-12-09 09:18:51 +08:00
mlog . log ( ' \n Executing subproject ' , mlog . bold ( dirname ) , ' . \n ' , sep = ' ' )
2015-09-17 23:48:26 +08:00
subi = Interpreter ( self . build , self . backend , dirname , subdir , self . subproject_dir )
2015-04-09 05:46:33 +08:00
subi . subprojects = self . subprojects
2014-03-09 05:13:49 +08:00
2014-02-24 06:43:45 +08:00
subi . subproject_stack = self . subproject_stack + [ dirname ]
2015-08-22 01:50:40 +08:00
current_active = self . active_projectname
2013-12-09 08:43:28 +08:00
subi . run ( )
2015-10-16 05:03:51 +08:00
if ' version ' in kwargs :
pv = subi . project_version
wanted = kwargs [ ' version ' ]
if not mesonlib . version_compare ( pv , wanted ) :
raise InterpreterException ( ' Subproject %s version is %s but %s required. ' % ( dirname , pv , wanted ) )
2015-08-22 01:50:40 +08:00
self . active_projectname = current_active
2014-02-24 04:30:41 +08:00
mlog . log ( ' \n Subproject ' , mlog . bold ( dirname ) , ' finished. ' )
2013-12-10 02:39:53 +08:00
self . build . subprojects [ dirname ] = True
2015-04-09 04:32:31 +08:00
self . subprojects . update ( subi . subprojects )
2013-12-09 08:59:15 +08:00
self . subprojects [ dirname ] = SubprojectHolder ( subi )
2014-03-09 06:04:07 +08:00
self . build_def_files + = subi . build_def_files
2013-12-09 08:43:28 +08:00
return self . subprojects [ dirname ]
2015-04-22 23:27:34 +08:00
@stringArgs
2015-04-22 23:03:18 +08:00
@noKwargs
2013-10-17 03:33:33 +08:00
def func_get_option ( self , nodes , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Argument required for get_option. ' )
optname = args [ 0 ]
2014-11-17 00:30:38 +08:00
try :
return self . environment . get_coredata ( ) . get_builtin_option ( optname )
except RuntimeError :
pass
2015-10-07 21:54:02 +08:00
try :
return self . environment . coredata . compiler_options [ optname ] . value
except KeyError :
pass
if optname not in coredata . builtin_options and self . is_subproject ( ) :
optname = self . subproject + ' : ' + optname
try :
return self . environment . coredata . user_options [ optname ] . value
except KeyError :
2013-10-17 03:33:33 +08:00
raise InterpreterException ( ' Tried to access unknown option " %s " . ' % optname )
2015-04-22 23:03:18 +08:00
@noKwargs
2013-05-25 03:21:48 +08:00
def func_configuration_data ( self , node , args , kwargs ) :
if len ( args ) != 0 :
raise InterpreterException ( ' configuration_data takes no arguments ' )
2013-09-28 23:54:09 +08:00
return ConfigurationDataHolder ( )
2012-12-29 21:45:43 +08:00
2015-10-18 08:33:34 +08:00
def parse_default_options ( self , default_options ) :
if not isinstance ( default_options , list ) :
default_options = [ default_options ]
for option in default_options :
if not isinstance ( option , str ) :
mlog . debug ( option )
raise InterpreterException ( ' Default options must be strings ' )
if ' = ' not in option :
raise InterpreterException ( ' All default options must be of type key=value. ' )
key , value = option . split ( ' = ' , 1 )
2015-11-03 09:03:54 +08:00
builtin_options = self . coredata . builtin_options
if key in builtin_options :
2015-10-18 08:33:34 +08:00
if not hasattr ( self . environment . cmd_line_options , value ) :
2015-11-03 09:03:54 +08:00
self . coredata . set_builtin_option ( key , value )
2015-10-18 08:33:34 +08:00
# If this was set on the command line, do not override.
else :
2015-10-23 03:33:58 +08:00
newoptions = [ option ] + self . environment . cmd_line_options . projectoptions
self . environment . cmd_line_options . projectoptions = newoptions
2015-10-18 08:33:34 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2013-02-10 07:12:00 +08:00
def func_project ( self , node , args , kwargs ) :
2015-07-26 03:50:35 +08:00
if len ( args ) < 2 :
2013-01-12 05:13:49 +08:00
raise InvalidArguments ( ' Not enough arguments to project(). Needs at least the project name and one language ' )
2015-05-16 01:01:21 +08:00
if not self . is_subproject ( ) :
2014-03-18 04:09:28 +08:00
self . build . project_name = args [ 0 ]
2015-10-18 08:33:34 +08:00
if self . environment . first_invocation and ' default_options ' in kwargs :
self . parse_default_options ( kwargs [ ' default_options ' ] )
2015-08-22 01:50:40 +08:00
self . active_projectname = args [ 0 ]
2015-10-16 05:03:51 +08:00
self . project_version = kwargs . get ( ' version ' , ' undefined ' )
2015-12-10 00:00:06 +08:00
proj_license = mesonlib . stringlistify ( kwargs . get ( ' license ' , ' unknown ' ) )
2015-11-30 03:30:14 +08:00
self . build . dep_manifest [ args [ 0 ] ] = { ' version ' : self . project_version ,
2015-12-10 00:00:06 +08:00
' license ' : proj_license }
2013-12-09 08:43:28 +08:00
if self . subproject in self . build . projects :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( ' Second call to project(). ' )
2015-05-16 01:01:21 +08:00
if not self . is_subproject ( ) and ' subproject_dir ' in kwargs :
self . subproject_dir = kwargs [ ' subproject_dir ' ]
2015-10-16 02:18:39 +08:00
if ' meson_version ' in kwargs :
cv = coredata . version
pv = kwargs [ ' meson_version ' ]
if not mesonlib . version_compare ( cv , pv ) :
raise InterpreterException ( ' Meson version is %s but project requires %s . ' % ( cv , pv ) )
2013-12-09 08:43:28 +08:00
self . build . projects [ self . subproject ] = args [ 0 ]
2014-06-23 03:06:16 +08:00
mlog . log ( ' Project name: ' , mlog . bold ( args [ 0 ] ) , sep = ' ' )
2013-01-12 05:13:49 +08:00
self . add_languages ( node , args [ 1 : ] )
2014-05-10 06:14:52 +08:00
langs = self . coredata . compilers . keys ( )
if ' vala ' in langs :
if not ' c ' in langs :
2015-12-02 06:07:56 +08:00
raise InterpreterException ( ' Compiling Vala requires C. Add C to your project languages and rerun Meson. ' )
2012-12-27 05:37:41 +08:00
2015-07-26 04:20:37 +08:00
@noKwargs
@stringArgs
def func_add_languages ( self , node , args , kwargs ) :
self . add_languages ( node , args )
2015-04-22 23:03:18 +08:00
@noKwargs
2013-04-22 05:51:25 +08:00
def func_message ( self , node , args , kwargs ) :
2015-05-08 04:40:50 +08:00
# reduce arguments again to avoid flattening posargs
2015-10-18 08:33:34 +08:00
( posargs , _ ) = self . reduce_arguments ( node . args )
2015-05-08 04:40:50 +08:00
if len ( posargs ) != 1 :
raise InvalidArguments ( ' Expected 1 argument, got %d ' % len ( posargs ) )
arg = posargs [ 0 ]
if isinstance ( arg , list ) :
2015-07-26 03:50:35 +08:00
argstr = stringifyUserArguments ( arg )
2015-05-08 04:40:50 +08:00
elif isinstance ( arg , str ) :
argstr = arg
elif isinstance ( arg , int ) :
argstr = str ( arg )
else :
raise InvalidArguments ( ' Function accepts only strings, integers, lists and lists thereof. ' )
mlog . log ( mlog . bold ( ' Message: ' ) , argstr )
return
2013-01-01 23:10:55 +08:00
2015-04-22 23:03:18 +08:00
@noKwargs
2013-07-09 01:51:10 +08:00
def func_error ( self , node , args , kwargs ) :
self . validate_arguments ( args , 1 , [ str ] )
raise InterpreterException ( ' Error encountered: ' + args [ 0 ] )
2013-01-12 05:13:49 +08:00
def add_languages ( self , node , args ) :
2015-07-27 04:50:04 +08:00
need_cross_compiler = self . environment . is_cross_build ( ) and self . environment . cross_info . need_cross_compiler ( )
2013-01-02 02:45:11 +08:00
for lang in args :
2014-05-10 06:14:52 +08:00
lang = lang . lower ( )
2013-03-02 05:13:17 +08:00
if lang in self . coredata . compilers :
2013-03-02 05:38:51 +08:00
comp = self . coredata . compilers [ lang ]
2013-08-31 03:20:10 +08:00
cross_comp = self . coredata . cross_compilers . get ( lang , None )
2013-01-02 02:45:11 +08:00
else :
2013-08-31 03:20:10 +08:00
cross_comp = None
2014-05-10 06:14:52 +08:00
if lang == ' c ' :
2013-08-31 03:20:10 +08:00
comp = self . environment . detect_c_compiler ( False )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2013-08-31 03:20:10 +08:00
cross_comp = self . environment . detect_c_compiler ( True )
2014-05-10 06:14:52 +08:00
elif lang == ' cpp ' :
2013-08-31 03:20:10 +08:00
comp = self . environment . detect_cpp_compiler ( False )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2013-08-31 03:20:10 +08:00
cross_comp = self . environment . detect_cpp_compiler ( True )
2014-05-10 06:14:52 +08:00
elif lang == ' objc ' :
2013-08-31 03:20:10 +08:00
comp = self . environment . detect_objc_compiler ( False )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2013-08-31 03:20:10 +08:00
cross_comp = self . environment . detect_objc_compiler ( True )
2014-05-10 06:14:52 +08:00
elif lang == ' objcpp ' :
2013-08-31 03:20:10 +08:00
comp = self . environment . detect_objcpp_compiler ( False )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2013-08-31 03:20:10 +08:00
cross_comp = self . environment . detect_objcpp_compiler ( True )
2014-05-10 06:14:52 +08:00
elif lang == ' java ' :
2014-03-11 04:49:29 +08:00
comp = self . environment . detect_java_compiler ( )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2015-07-28 06:12:38 +08:00
cross_comp = comp # Java is platform independent.
2014-07-19 02:49:14 +08:00
elif lang == ' cs ' :
comp = self . environment . detect_cs_compiler ( )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2015-07-28 06:12:38 +08:00
cross_comp = comp # C# is platform independent.
2014-05-10 06:14:52 +08:00
elif lang == ' vala ' :
comp = self . environment . detect_vala_compiler ( )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2015-07-28 06:12:38 +08:00
cross_comp = comp # Vala is too (I think).
2014-06-18 06:22:55 +08:00
elif lang == ' rust ' :
comp = self . environment . detect_rust_compiler ( )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2015-07-28 06:10:54 +08:00
cross_comp = comp # FIXME, probably not correct.
2014-08-01 21:25:29 +08:00
elif lang == ' fortran ' :
comp = self . environment . detect_fortran_compiler ( False )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2014-08-01 21:25:29 +08:00
cross_comp = self . environment . detect_fortran_compiler ( True )
2015-12-08 03:12:23 +08:00
elif lang == ' swift ' :
comp = self . environment . detect_swift_compiler ( )
if need_cross_compiler :
raise InterpreterException ( ' Cross compilation with Swift is not working yet. ' )
#cross_comp = self.environment.detect_fortran_compiler(True)
2013-02-25 05:11:14 +08:00
else :
raise InvalidCode ( ' Tried to use unknown language " %s " . ' % lang )
comp . sanity_check ( self . environment . get_scratch_dir ( ) )
2013-03-02 05:13:17 +08:00
self . coredata . compilers [ lang ] = comp
2013-08-31 03:20:10 +08:00
if cross_comp is not None :
2015-08-25 06:19:58 +08:00
cross_comp . sanity_check ( self . environment . get_scratch_dir ( ) )
2013-08-31 03:20:10 +08:00
self . coredata . cross_compilers [ lang ] = cross_comp
2015-10-04 08:41:38 +08:00
new_options = comp . get_options ( )
optprefix = lang + ' _ '
for i in new_options :
if not i . startswith ( optprefix ) :
raise InterpreterException ( ' Internal error, %s has incorrect prefix. ' % i )
2015-10-18 08:33:34 +08:00
cmd_prefix = i + ' = '
for cmd_arg in self . environment . cmd_line_options . projectoptions :
if cmd_arg . startswith ( cmd_prefix ) :
value = cmd_arg . split ( ' = ' , 1 ) [ 1 ]
2015-12-28 01:10:45 +08:00
new_options [ i ] . set_value ( value )
2015-10-04 08:41:38 +08:00
new_options . update ( self . coredata . compiler_options )
self . coredata . compiler_options = new_options
2014-06-23 03:06:16 +08:00
mlog . log ( ' Native %s compiler: ' % lang , mlog . bold ( ' ' . join ( comp . get_exelist ( ) ) ) , ' ( %s %s ) ' % ( comp . id , comp . version ) , sep = ' ' )
2014-06-08 04:39:59 +08:00
if not comp . get_language ( ) in self . coredata . external_args :
2014-06-22 22:10:00 +08:00
( ext_compile_args , ext_link_args ) = environment . get_args_from_envvars ( comp . get_language ( ) )
self . coredata . external_args [ comp . get_language ( ) ] = ext_compile_args
self . coredata . external_link_args [ comp . get_language ( ) ] = ext_link_args
2013-04-20 04:59:06 +08:00
self . build . add_compiler ( comp )
2015-07-27 04:50:04 +08:00
if need_cross_compiler :
2014-06-23 03:06:16 +08:00
mlog . log ( ' Cross %s compiler: ' % lang , mlog . bold ( ' ' . join ( cross_comp . get_exelist ( ) ) ) , ' ( %s %s ) ' % ( cross_comp . id , cross_comp . version ) , sep = ' ' )
2013-08-31 03:20:10 +08:00
self . build . add_cross_compiler ( cross_comp )
2015-07-27 04:50:04 +08:00
if self . environment . is_cross_build ( ) and not need_cross_compiler :
self . build . add_cross_compiler ( comp )
2012-12-29 21:51:51 +08:00
2013-03-10 03:12:03 +08:00
def func_find_program ( self , node , args , kwargs ) :
self . validate_arguments ( args , 1 , [ str ] )
2013-06-01 19:09:16 +08:00
required = kwargs . get ( ' required ' , True )
2013-03-10 03:12:03 +08:00
if not isinstance ( required , bool ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' " required " argument must be a boolean. ' )
2013-03-10 03:12:03 +08:00
exename = args [ 0 ]
2013-03-10 03:20:58 +08:00
if exename in self . coredata . ext_progs and \
self . coredata . ext_progs [ exename ] . found ( ) :
2013-03-10 05:08:22 +08:00
return ExternalProgramHolder ( self . coredata . ext_progs [ exename ] )
2014-04-20 18:58:20 +08:00
# Search for scripts relative to current subdir.
search_dir = os . path . join ( self . environment . get_source_dir ( ) , self . subdir )
extprog = dependencies . ExternalProgram ( exename , search_dir = search_dir )
2013-03-10 05:08:22 +08:00
progobj = ExternalProgramHolder ( extprog )
self . coredata . ext_progs [ exename ] = extprog
2013-03-10 03:12:03 +08:00
if required and not progobj . found ( ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Program " %s " not found. ' % exename )
2013-03-10 03:12:03 +08:00
return progobj
2013-03-10 04:42:01 +08:00
def func_find_library ( self , node , args , kwargs ) :
self . validate_arguments ( args , 1 , [ str ] )
2013-06-01 19:12:24 +08:00
required = kwargs . get ( ' required ' , True )
2013-03-10 04:42:01 +08:00
if not isinstance ( required , bool ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' " required " argument must be a boolean. ' )
2013-03-10 04:42:01 +08:00
libname = args [ 0 ]
2015-11-24 23:49:12 +08:00
# We do not cache found libraries because they can come
# and go between invocations wildly. As an example we
# may find the 64 bit version but need instead the 32 bit
# one that is not installed. If we cache the found path
# then we will never found the new one if it get installed.
# This causes a bit of a slowdown as libraries are rechecked
# on every regen, but since it is a fast operation it should be
# ok.
2015-05-17 05:58:38 +08:00
if ' dirs ' in kwargs :
search_dirs = kwargs [ ' dirs ' ]
if not isinstance ( search_dirs , list ) :
search_dirs = [ search_dirs ]
for i in search_dirs :
if not isinstance ( i , str ) :
raise InvalidCode ( ' Directory entry is not a string. ' )
if not os . path . isabs ( i ) :
raise InvalidCode ( ' Search directory %s is not an absolute path. ' % i )
else :
search_dirs = None
result = self . environment . find_library ( libname , search_dirs )
2013-04-01 19:08:54 +08:00
extlib = dependencies . ExternalLibrary ( libname , result )
2013-03-10 05:08:22 +08:00
libobj = ExternalLibraryHolder ( extlib )
2013-03-10 04:42:01 +08:00
if required and not libobj . found ( ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' External library " %s " not found. ' % libname )
2013-03-10 04:42:01 +08:00
return libobj
2013-06-02 19:06:43 +08:00
def func_dependency ( self , node , args , kwargs ) :
2013-01-01 23:10:55 +08:00
self . validate_arguments ( args , 1 , [ str ] )
name = args [ 0 ]
2013-04-01 19:58:22 +08:00
identifier = dependencies . get_dep_identifier ( name , kwargs )
if identifier in self . coredata . deps :
dep = self . coredata . deps [ identifier ]
2013-02-25 05:11:14 +08:00
else :
2015-07-28 06:10:54 +08:00
dep = dependencies . Dependency ( ) # Returns always false for dep.found()
2013-03-02 05:13:17 +08:00
if not dep . found ( ) :
2015-10-28 06:29:06 +08:00
try :
dep = dependencies . find_external_dependency ( name , self . environment , kwargs )
except dependencies . DependencyException :
if ' fallback ' in kwargs :
return self . dependency_fallback ( kwargs )
raise
2013-04-01 19:58:22 +08:00
self . coredata . deps [ identifier ] = dep
2015-02-21 09:52:16 +08:00
return DependencyHolder ( dep )
2013-01-06 03:08:08 +08:00
2015-10-28 06:29:06 +08:00
def dependency_fallback ( self , kwargs ) :
fbinfo = kwargs [ ' fallback ' ]
check_stringlist ( fbinfo )
if len ( fbinfo ) != 2 :
raise InterpreterException ( ' Fallback info must have exactly two items. ' )
dirname , varname = fbinfo
self . do_subproject ( dirname , kwargs )
return self . subprojects [ dirname ] . get_variable_method ( [ varname ] , { } )
2013-02-10 07:12:00 +08:00
def func_executable ( self , node , args , kwargs ) :
2013-09-24 03:34:41 +08:00
return self . build_target ( node , args , kwargs , ExecutableHolder )
2013-01-06 03:08:08 +08:00
2013-02-10 07:51:39 +08:00
def func_static_lib ( self , node , args , kwargs ) :
2013-09-24 03:34:41 +08:00
return self . build_target ( node , args , kwargs , StaticLibraryHolder )
2013-02-10 07:51:39 +08:00
def func_shared_lib ( self , node , args , kwargs ) :
2013-09-24 03:34:41 +08:00
return self . build_target ( node , args , kwargs , SharedLibraryHolder )
2013-01-06 03:08:08 +08:00
2015-11-03 23:26:09 +08:00
def func_library ( self , node , args , kwargs ) :
2015-11-03 09:03:54 +08:00
if self . coredata . get_builtin_option ( ' default_library ' ) == ' shared ' :
return self . func_shared_lib ( node , args , kwargs )
return self . func_static_lib ( node , args , kwargs )
2014-03-11 05:33:24 +08:00
def func_jar ( self , node , args , kwargs ) :
return self . build_target ( node , args , kwargs , JarHolder )
2014-06-12 03:38:36 +08:00
2015-06-07 03:15:30 +08:00
def func_build_target ( self , node , args , kwargs ) :
if ' target_type ' not in kwargs :
raise InterpreterException ( ' Missing target_type keyword argument ' )
target_type = kwargs . pop ( ' target_type ' )
if target_type == ' executable ' :
return self . func_executable ( node , args , kwargs )
elif target_type == ' shared_library ' :
return self . func_shared_lib ( node , args , kwargs )
elif target_type == ' static_library ' :
return self . func_static_lib ( node , args , kwargs )
2015-11-03 23:26:09 +08:00
elif target_type == ' library ' :
return self . func_library ( node , args , kwargs )
2015-06-07 03:15:30 +08:00
elif target_type == ' jar ' :
return self . func_jar ( node , args , kwargs )
else :
raise InterpreterException ( ' Unknown target_type. ' )
2015-02-09 02:34:33 +08:00
def func_vcs_tag ( self , node , args , kwargs ) :
2015-02-11 10:27:40 +08:00
fallback = kwargs . pop ( ' fallback ' , None )
2015-02-09 02:34:33 +08:00
if not isinstance ( fallback , str ) :
2015-12-29 06:47:52 +08:00
raise InterpreterException ( ' Keyword argument fallback must exist and be a string. ' )
2015-02-11 10:27:40 +08:00
replace_string = kwargs . pop ( ' replace_string ' , ' @VCS_TAG@ ' )
2015-07-28 06:10:54 +08:00
regex_selector = ' (.*) ' # default regex selector for custom command: use complete output
2015-02-11 10:27:40 +08:00
vcs_cmd = kwargs . get ( ' command ' , None )
if vcs_cmd and not isinstance ( vcs_cmd , list ) :
vcs_cmd = [ vcs_cmd ]
2015-03-28 00:38:55 +08:00
source_dir = os . path . normpath ( os . path . join ( self . environment . get_source_dir ( ) , self . subdir ) )
2015-02-11 10:27:40 +08:00
if vcs_cmd :
# Is the command an executable in path or maybe a script in the source tree?
vcs_cmd [ 0 ] = shutil . which ( vcs_cmd [ 0 ] ) or os . path . join ( source_dir , vcs_cmd [ 0 ] )
else :
2015-02-14 08:56:27 +08:00
vcs = mesonlib . detect_vcs ( source_dir )
2015-02-11 10:27:40 +08:00
if vcs :
mlog . log ( ' Found %s repository at %s ' % ( vcs [ ' name ' ] , vcs [ ' wc_dir ' ] ) )
vcs_cmd = vcs [ ' get_rev ' ] . split ( )
regex_selector = vcs [ ' rev_regex ' ]
else :
2015-07-28 06:10:54 +08:00
vcs_cmd = [ ' ' ] # executing this cmd will fail in vcstagger.py and force to use the fallback string
2015-02-11 10:27:40 +08:00
scriptfile = os . path . join ( self . environment . get_script_dir ( ) , ' vcstagger.py ' )
# vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command...
kwargs [ ' command ' ] = [ sys . executable , scriptfile , ' @INPUT0@ ' , ' @OUTPUT0@ ' , fallback , source_dir , replace_string , regex_selector ] + vcs_cmd
kwargs . setdefault ( ' build_always ' , True )
return self . func_custom_target ( node , [ kwargs [ ' output ' ] ] , kwargs )
2015-02-09 02:34:33 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2014-05-19 05:59:35 +08:00
def func_custom_target ( self , node , args , kwargs ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Incorrect number of arguments ' )
name = args [ 0 ]
2015-03-06 23:36:43 +08:00
tg = CustomTargetHolder ( build . CustomTarget ( name , self . subdir , kwargs ) )
2015-07-05 06:47:34 +08:00
self . add_target ( name , tg . held_object )
2014-05-19 05:59:35 +08:00
return tg
2014-03-11 05:33:24 +08:00
2015-04-22 23:03:18 +08:00
@noKwargs
2014-06-12 03:38:36 +08:00
def func_run_target ( self , node , args , kwargs ) :
if len ( args ) < 2 :
raise InterpreterException ( ' Incorrect number of arguments ' )
2015-09-28 23:09:54 +08:00
cleaned_args = [ ]
2015-09-11 05:22:56 +08:00
for i in args :
try :
i = i . held_object
except AttributeError :
pass
2015-10-18 05:04:45 +08:00
if not isinstance ( i , ( str , build . BuildTarget , build . CustomTarget ) ) :
2015-09-11 05:22:56 +08:00
mlog . debug ( ' Wrong type: ' , str ( i ) )
raise InterpreterException ( ' Invalid argument to run_target. ' )
2015-09-28 23:09:54 +08:00
cleaned_args . append ( i )
name = cleaned_args [ 0 ]
command = cleaned_args [ 1 ]
cmd_args = cleaned_args [ 2 : ]
2014-06-12 03:38:36 +08:00
tg = RunTargetHolder ( name , command , cmd_args , self . subdir )
2015-07-05 06:47:34 +08:00
self . add_target ( name , tg . held_object )
2014-06-12 03:38:36 +08:00
return tg
2013-02-24 02:37:33 +08:00
def func_generator ( self , node , args , kwargs ) :
2014-07-26 22:46:40 +08:00
gen = GeneratorHolder ( self , args , kwargs )
2013-02-24 02:37:33 +08:00
self . generators . append ( gen )
return gen
2015-11-26 05:29:06 +08:00
def func_benchmark ( self , node , args , kwargs ) :
self . add_test ( node , args , kwargs , False )
2013-06-02 18:18:15 +08:00
def func_test ( self , node , args , kwargs ) :
2015-11-26 05:29:06 +08:00
self . add_test ( node , args , kwargs , True )
def add_test ( self , node , args , kwargs , is_base_test ) :
2014-03-11 05:33:24 +08:00
if len ( args ) != 2 :
raise InterpreterException ( ' Incorrect number of arguments ' )
if not isinstance ( args [ 0 ] , str ) :
raise InterpreterException ( ' First argument of test must be a string. ' )
2015-03-28 01:09:26 +08:00
if not isinstance ( args [ 1 ] , ( ExecutableHolder , JarHolder , ExternalProgramHolder ) ) :
2014-03-11 05:33:24 +08:00
raise InterpreterException ( ' Second argument must be executable. ' )
2013-09-13 05:50:45 +08:00
par = kwargs . get ( ' is_parallel ' , True )
if not isinstance ( par , bool ) :
raise InterpreterException ( ' Keyword argument is_parallel must be a boolean. ' )
2013-10-19 03:04:07 +08:00
cmd_args = kwargs . get ( ' args ' , [ ] )
if not isinstance ( cmd_args , list ) :
cmd_args = [ cmd_args ]
for i in cmd_args :
2015-08-22 03:11:26 +08:00
if not isinstance ( i , ( str , mesonlib . File ) ) :
2013-10-19 03:04:07 +08:00
raise InterpreterException ( ' Command line arguments must be strings ' )
envlist = kwargs . get ( ' env ' , [ ] )
if not isinstance ( envlist , list ) :
envlist = [ envlist ]
env = { }
for e in envlist :
if ' = ' not in e :
raise InterpreterException ( ' Env var definition must be of type key=val. ' )
( k , val ) = e . split ( ' = ' , 1 )
k = k . strip ( )
val = val . strip ( )
if ' ' in k :
raise InterpreterException ( ' Env var key must not have spaces in it. ' )
env [ k ] = val
2014-08-24 06:41:12 +08:00
valgrind_args = kwargs . get ( ' valgrind_args ' , [ ] )
if not isinstance ( valgrind_args , list ) :
valgrind_args = [ valgrind_args ]
for a in valgrind_args :
if not isinstance ( a , str ) :
raise InterpreterException ( ' Valgrind_arg not a string. ' )
2015-03-24 05:11:04 +08:00
should_fail = kwargs . get ( ' should_fail ' , False )
if not isinstance ( should_fail , bool ) :
raise InterpreterException ( ' Keyword argument should_fail must be a boolean. ' )
2015-07-23 04:57:00 +08:00
timeout = kwargs . get ( ' timeout ' , 30 )
2015-12-08 21:45:51 +08:00
if ' workdir ' in kwargs :
workdir = kwargs [ ' workdir ' ]
if not isinstance ( workdir , str ) :
raise InterpreterException ( ' Workdir keyword argument must be a string. ' )
if not os . path . isabs ( workdir ) :
raise InterpreterException ( ' Workdir keyword argument must be an absolute path. ' )
else :
workdir = None
2015-07-23 04:57:00 +08:00
if not isinstance ( timeout , int ) :
raise InterpreterException ( ' Timeout must be an integer. ' )
2015-12-11 04:22:42 +08:00
suite = mesonlib . stringlistify ( kwargs . get ( ' suite ' , ' ' ) )
2015-12-10 00:00:06 +08:00
if self . is_subproject ( ) :
2015-12-11 04:22:42 +08:00
newsuite = [ ]
for s in suite :
2015-12-12 03:48:47 +08:00
newsuite . append ( self . subproject . replace ( ' ' , ' _ ' ) . replace ( ' . ' , ' _ ' ) + ' . ' + s )
2015-12-11 04:22:42 +08:00
suite = newsuite
2015-12-10 00:00:06 +08:00
t = Test ( args [ 0 ] , suite , args [ 1 ] . held_object , par , cmd_args , env , should_fail , valgrind_args , timeout , workdir )
2015-11-26 05:29:06 +08:00
if is_base_test :
self . build . tests . append ( t )
mlog . debug ( ' Adding test " ' , mlog . bold ( args [ 0 ] ) , ' " . ' , sep = ' ' )
else :
self . build . benchmarks . append ( t )
mlog . debug ( ' Adding benchmark " ' , mlog . bold ( args [ 0 ] ) , ' " . ' , sep = ' ' )
2013-02-10 06:50:46 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2014-10-12 01:41:57 +08:00
def func_install_headers ( self , node , args , kwargs ) :
2014-11-04 00:23:29 +08:00
h = Headers ( self . subdir , args , kwargs )
2013-01-12 19:53:19 +08:00
self . build . headers . append ( h )
return h
2014-08-07 17:34:35 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2014-10-12 01:48:05 +08:00
def func_install_man ( self , node , args , kwargs ) :
2014-11-04 00:30:24 +08:00
m = Man ( self . subdir , args , kwargs )
2013-01-12 20:31:43 +08:00
self . build . man . append ( m )
return m
2014-08-07 17:34:35 +08:00
2015-04-22 23:03:18 +08:00
@noKwargs
2013-02-10 18:59:05 +08:00
def func_subdir ( self , node , args , kwargs ) :
2013-01-13 23:41:47 +08:00
self . validate_arguments ( args , 1 , [ str ] )
2014-02-24 04:30:41 +08:00
if ' .. ' in args [ 0 ] :
raise InvalidArguments ( ' Subdir contains .. ' )
2015-05-16 01:01:21 +08:00
if self . subdir == ' ' and args [ 0 ] == self . subproject_dir :
2014-02-24 04:30:41 +08:00
raise InvalidArguments ( ' Must not go into subprojects dir with subdir(), use subproject() instead. ' )
2013-01-13 23:41:47 +08:00
prev_subdir = self . subdir
2013-03-16 04:27:03 +08:00
subdir = os . path . join ( prev_subdir , args [ 0 ] )
if subdir in self . visited_subdirs :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Tried to enter directory " %s " , which has already been visited. ' \
% subdir )
2013-03-16 04:27:03 +08:00
self . visited_subdirs [ subdir ] = True
self . subdir = subdir
2014-05-13 06:06:27 +08:00
try :
2015-08-28 01:29:20 +08:00
os . makedirs ( os . path . join ( self . environment . build_dir , subdir ) )
2014-05-13 06:06:27 +08:00
except FileExistsError :
pass
2013-02-23 19:24:41 +08:00
buildfilename = os . path . join ( self . subdir , environment . build_filename )
2013-02-17 03:14:04 +08:00
self . build_def_files . append ( buildfilename )
2013-08-12 03:55:40 +08:00
absname = os . path . join ( self . environment . get_source_dir ( ) , buildfilename )
if not os . path . isfile ( absname ) :
raise InterpreterException ( ' Nonexistant build def file %s . ' % buildfilename )
code = open ( absname ) . read ( )
2013-01-13 23:41:47 +08:00
assert ( isinstance ( code , str ) )
2013-06-02 19:25:35 +08:00
try :
2014-03-17 06:37:47 +08:00
codeblock = mparser . Parser ( code ) . parse ( )
2013-06-02 19:25:35 +08:00
except coredata . MesonException as me :
me . file = buildfilename
raise me
2013-01-13 23:59:34 +08:00
self . evaluate_codeblock ( codeblock )
2013-01-13 23:41:47 +08:00
self . subdir = prev_subdir
2013-01-06 03:08:08 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2014-10-12 01:56:32 +08:00
def func_install_data ( self , node , args , kwargs ) :
2015-12-23 21:10:27 +08:00
data = DataHolder ( True , self . subdir , args , kwargs )
self . build . data . append ( data . held_object )
2013-01-14 01:25:54 +08:00
return data
2014-08-07 17:34:35 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2014-11-04 05:28:47 +08:00
def func_install_subdir ( self , node , args , kwargs ) :
2015-07-26 03:50:35 +08:00
if len ( args ) != 1 :
2014-11-04 05:28:47 +08:00
raise InvalidArguments ( ' Install_subdir requires exactly one argument. ' )
if not ' install_dir ' in kwargs :
raise InvalidArguments ( ' Missing keyword argument install_dir ' )
install_dir = kwargs [ ' install_dir ' ]
if not isinstance ( install_dir , str ) :
raise InvalidArguments ( ' Keyword argument install_dir not a string. ' )
idir = InstallDir ( self . subdir , args [ 0 ] , install_dir )
self . build . install_dirs . append ( idir )
return idir
2013-02-10 18:59:05 +08:00
def func_configure_file ( self , node , args , kwargs ) :
2013-05-25 03:21:48 +08:00
if len ( args ) > 0 :
raise InterpreterException ( " configure_file takes only keyword arguments. " )
if not ' input ' in kwargs :
raise InterpreterException ( ' Required keyword argument " input " not defined. ' )
if not ' output ' in kwargs :
raise InterpreterException ( ' Required keyword argument " output " not defined. ' )
2015-02-16 01:35:53 +08:00
inputfile = kwargs [ ' input ' ]
output = kwargs [ ' output ' ]
2015-03-27 00:01:14 +08:00
if not isinstance ( inputfile , str ) :
raise InterpreterException ( ' Input must be a string. ' )
if not isinstance ( output , str ) :
raise InterpreterException ( ' Output must be a string. ' )
2014-04-28 05:34:12 +08:00
if ' configuration ' in kwargs :
conf = kwargs [ ' configuration ' ]
if not isinstance ( conf , ConfigurationDataHolder ) :
raise InterpreterException ( ' Argument " configuration " is not of type configuration_data ' )
conffile = os . path . join ( self . subdir , inputfile )
2015-08-14 06:24:11 +08:00
if conffile not in self . build_def_files :
self . build_def_files . append ( conffile )
2015-03-28 05:41:28 +08:00
os . makedirs ( os . path . join ( self . environment . build_dir , self . subdir ) , exist_ok = True )
ifile_abs = os . path . join ( self . environment . source_dir , self . subdir , inputfile )
ofile_abs = os . path . join ( self . environment . build_dir , self . subdir , output )
mesonlib . do_conf_file ( ifile_abs , ofile_abs , conf . held_object )
2014-04-28 05:34:12 +08:00
conf . mark_used ( )
elif ' command ' in kwargs :
res = self . func_run_command ( node , kwargs [ ' command ' ] , { } )
if res . returncode != 0 :
2015-07-27 05:25:45 +08:00
raise InterpreterException ( ' Running configure command failed. \n %s \n %s ' %
2014-05-13 04:04:54 +08:00
( res . stdout , res . stderr ) )
2014-04-28 05:34:12 +08:00
else :
raise InterpreterException ( ' Configure_file must have either " configuration " or " command " . ' )
2015-02-16 01:35:53 +08:00
if isinstance ( kwargs . get ( ' install_dir ' , None ) , str ) :
2015-12-23 21:10:27 +08:00
self . build . data . append ( DataHolder ( False , self . subdir , [ output ] , kwargs ) . held_object )
2015-08-14 21:34:24 +08:00
return mesonlib . File . from_built_file ( self . subdir , output )
2013-01-14 01:25:54 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2013-02-10 19:08:47 +08:00
def func_include_directories ( self , node , args , kwargs ) :
2014-03-09 05:13:49 +08:00
absbase = os . path . join ( self . environment . get_source_dir ( ) , self . subdir )
2013-01-26 06:28:13 +08:00
for a in args :
2014-01-19 05:11:59 +08:00
absdir = os . path . join ( absbase , a )
if not os . path . isdir ( absdir ) :
raise InvalidArguments ( ' Include dir %s does not exist. ' % a )
2016-01-03 03:34:39 +08:00
is_system = kwargs . get ( ' is_system ' , False )
if not isinstance ( is_system , bool ) :
raise InvalidArguments ( ' Is_system must be boolean. ' )
i = IncludeDirsHolder ( build . IncludeDirs ( self . subdir , args , is_system ) )
2013-01-26 06:28:13 +08:00
return i
2015-04-22 23:27:34 +08:00
@stringArgs
2013-02-10 19:13:28 +08:00
def func_add_global_arguments ( self , node , args , kwargs ) :
2013-12-10 02:43:40 +08:00
if self . subproject != ' ' :
2014-06-22 22:10:00 +08:00
raise InvalidCode ( ' Global arguments can not be set in subprojects because there is no way to make that reliable. ' )
if self . global_args_frozen :
2015-03-30 19:46:09 +08:00
raise InvalidCode ( ' Tried to set global arguments after a build target has been declared. \n This is not permitted. Please declare all global arguments before your targets. ' )
2013-02-10 19:13:28 +08:00
if not ' language ' in kwargs :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( ' Missing language definition in add_global_arguments ' )
2013-02-10 19:13:28 +08:00
lang = kwargs [ ' language ' ] . lower ( )
2013-01-26 07:44:56 +08:00
if lang in self . build . global_args :
2013-02-10 19:13:28 +08:00
self . build . global_args [ lang ] + = args
2013-01-26 07:44:56 +08:00
else :
2013-02-10 19:13:28 +08:00
self . build . global_args [ lang ] = args
2013-01-26 07:44:56 +08:00
2013-01-26 04:42:11 +08:00
def flatten ( self , args ) :
2014-03-17 06:37:47 +08:00
if isinstance ( args , mparser . StringNode ) :
2014-03-17 06:34:31 +08:00
return args . value
2013-07-31 03:40:45 +08:00
if isinstance ( args , str ) :
return args
2013-11-05 07:47:09 +08:00
if isinstance ( args , InterpreterObject ) :
return args
2015-03-09 23:16:32 +08:00
if isinstance ( args , int ) :
return args
2013-01-26 04:42:11 +08:00
result = [ ]
for a in args :
if isinstance ( a , list ) :
2013-07-25 18:20:51 +08:00
rest = self . flatten ( a )
result = result + rest
2014-03-17 06:37:47 +08:00
elif isinstance ( a , mparser . StringNode ) :
2014-03-17 06:34:31 +08:00
result . append ( a . value )
2013-01-26 04:42:11 +08:00
else :
result . append ( a )
return result
2015-04-22 20:53:46 +08:00
def source_strings_to_files ( self , sources ) :
results = [ ]
for s in sources :
2015-06-15 05:26:19 +08:00
if isinstance ( s , mesonlib . File ) or isinstance ( s , GeneratedListHolder ) or \
2015-04-22 20:53:46 +08:00
isinstance ( s , CustomTargetHolder ) :
pass
2015-04-26 06:56:02 +08:00
elif isinstance ( s , str ) :
2015-06-15 05:26:19 +08:00
s = mesonlib . File . from_source_file ( self . environment . source_dir , self . subdir , s )
2015-04-22 20:53:46 +08:00
else :
2015-06-15 05:26:19 +08:00
raise InterpreterException ( " Source item is not string or File-type object. " )
2015-04-22 20:53:46 +08:00
results . append ( s )
return results
2015-07-05 06:47:34 +08:00
def add_target ( self , name , tobj ) :
if name in coredata . forbidden_target_names :
raise InvalidArguments ( ' Target name " %s " is reserved for Meson \' s internal use. Please rename. ' \
% name )
# To permit an executable and a shared library to have the
# same name, such as "foo.exe" and "libfoo.a".
2015-08-12 19:04:41 +08:00
idname = tobj . get_id ( )
2015-07-05 06:47:34 +08:00
if idname in self . build . targets :
raise InvalidCode ( ' Tried to create target " %s " , but a target of that name already exists. ' % name )
self . build . targets [ idname ] = tobj
if idname not in self . coredata . target_guids :
self . coredata . target_guids [ idname ] = str ( uuid . uuid4 ( ) ) . upper ( )
2015-03-09 23:16:32 +08:00
def build_target ( self , node , args , kwargs , targetholder ) :
2013-01-26 07:12:39 +08:00
name = args [ 0 ]
2013-03-02 02:49:46 +08:00
sources = args [ 1 : ]
2013-08-31 03:20:10 +08:00
if self . environment . is_cross_build ( ) :
if kwargs . get ( ' native ' , False ) :
is_cross = False
else :
is_cross = True
else :
is_cross = False
2013-02-10 07:51:39 +08:00
try :
kw_src = self . flatten ( kwargs [ ' sources ' ] )
2013-03-02 02:49:46 +08:00
if not isinstance ( kw_src , list ) :
kw_src = [ kw_src ]
2013-02-10 07:51:39 +08:00
except KeyError :
kw_src = [ ]
2013-03-02 02:49:46 +08:00
sources + = kw_src
2015-04-22 20:53:46 +08:00
sources = self . source_strings_to_files ( sources )
2013-11-05 06:16:17 +08:00
objs = self . flatten ( kwargs . get ( ' objects ' , [ ] ) )
2015-06-16 01:06:21 +08:00
kwargs [ ' dependencies ' ] = self . flatten ( kwargs . get ( ' dependencies ' , [ ] ) )
2013-11-05 06:16:17 +08:00
if not isinstance ( objs , list ) :
objs = [ objs ]
2013-12-09 08:59:15 +08:00
self . check_sources_exist ( os . path . join ( self . source_root , self . subdir ) , sources )
2015-03-10 01:48:43 +08:00
if targetholder is ExecutableHolder :
2015-03-09 23:16:32 +08:00
targetclass = build . Executable
2015-03-10 01:48:43 +08:00
elif targetholder is SharedLibraryHolder :
2015-03-09 23:16:32 +08:00
targetclass = build . SharedLibrary
2015-03-10 01:48:43 +08:00
elif targetholder is StaticLibraryHolder :
2015-03-09 23:16:32 +08:00
targetclass = build . StaticLibrary
2015-03-10 01:48:43 +08:00
elif targetholder is JarHolder :
targetclass = build . Jar
2015-03-09 23:16:32 +08:00
else :
2015-06-18 01:16:28 +08:00
mlog . debug ( ' Unknown target type: ' , str ( targetholder ) )
2015-03-09 23:16:32 +08:00
raise RuntimeError ( ' Unreachable code ' )
2015-08-12 19:04:41 +08:00
target = targetclass ( name , self . subdir , self . subproject , is_cross , sources , objs , self . environment , kwargs )
2015-09-17 23:48:26 +08:00
l = targetholder ( target , self )
2015-07-05 06:47:34 +08:00
self . add_target ( name , l . held_object )
2014-06-22 22:10:00 +08:00
self . global_args_frozen = True
2013-01-06 00:13:38 +08:00
return l
2012-12-30 00:18:41 +08:00
2013-08-11 04:17:11 +08:00
def check_sources_exist ( self , subdir , sources ) :
for s in sources :
if not isinstance ( s , str ) :
2015-07-27 05:25:45 +08:00
continue # This means a generated source and they always exist.
2014-03-09 05:13:49 +08:00
fname = os . path . join ( subdir , s )
2013-08-11 04:17:11 +08:00
if not os . path . isfile ( fname ) :
raise InterpreterException ( ' Tried to add non-existing source %s . ' % s )
2013-10-17 02:50:07 +08:00
2012-12-27 05:37:41 +08:00
def function_call ( self , node ) :
2014-03-17 04:55:22 +08:00
func_name = node . func_name
( posargs , kwargs ) = self . reduce_arguments ( node . args )
2013-01-07 00:48:16 +08:00
if func_name in self . funcs :
2015-04-22 23:27:34 +08:00
return self . funcs [ func_name ] ( node , self . flatten ( posargs ) , kwargs )
2012-12-27 06:04:28 +08:00
else :
raise InvalidCode ( ' Unknown function " %s " . ' % func_name )
2013-01-06 00:13:38 +08:00
2012-12-30 08:06:51 +08:00
def is_assignable ( self , value ) :
if isinstance ( value , InterpreterObject ) or \
2013-04-01 19:08:54 +08:00
isinstance ( value , dependencies . Dependency ) or \
2013-04-22 05:51:25 +08:00
isinstance ( value , str ) or \
2013-06-01 05:35:11 +08:00
isinstance ( value , int ) or \
2015-04-21 21:27:58 +08:00
isinstance ( value , list ) or \
2015-06-19 15:39:22 +08:00
isinstance ( value , mesonlib . File ) :
2012-12-30 08:06:51 +08:00
return True
return False
2014-08-07 17:34:35 +08:00
2012-12-30 07:31:39 +08:00
def assignment ( self , node ) :
2014-03-17 06:37:47 +08:00
assert ( isinstance ( node , mparser . AssignmentNode ) )
2012-12-30 07:31:39 +08:00
var_name = node . var_name
2014-03-17 04:55:22 +08:00
if not isinstance ( var_name , str ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Tried to assign value to a non-variable. ' )
2012-12-30 08:06:51 +08:00
value = self . evaluate_statement ( node . value )
2013-07-31 03:40:45 +08:00
value = self . to_native ( value )
2012-12-30 08:06:51 +08:00
if not self . is_assignable ( value ) :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( ' Tried to assign an invalid value to variable. ' )
2013-01-28 03:45:02 +08:00
self . set_variable ( var_name , value )
2012-12-30 07:31:39 +08:00
return value
2013-02-10 06:50:46 +08:00
2013-01-01 23:01:49 +08:00
def reduce_arguments ( self , args ) :
2014-03-17 06:37:47 +08:00
assert ( isinstance ( args , mparser . ArgumentNode ) )
2013-02-10 08:01:41 +08:00
if args . incorrect_order ( ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' All keyword arguments must be after positional arguments. ' )
2014-11-08 09:41:05 +08:00
reduced_pos = [ self . evaluate_statement ( arg ) for arg in args . arguments ]
2013-02-10 07:12:00 +08:00
reduced_kw = { }
2013-02-10 06:50:46 +08:00
for key in args . kwargs . keys ( ) :
if not isinstance ( key , str ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Keyword argument name is not a string. ' )
2013-02-10 07:12:00 +08:00
a = args . kwargs [ key ]
2014-11-08 09:41:05 +08:00
reduced_kw [ key ] = self . evaluate_statement ( a )
2015-04-22 23:27:34 +08:00
if not isinstance ( reduced_pos , list ) :
reduced_pos = [ reduced_pos ]
2013-02-10 06:50:46 +08:00
return ( reduced_pos , reduced_kw )
2013-10-17 02:50:07 +08:00
2013-07-28 01:09:30 +08:00
def string_method_call ( self , obj , method_name , args ) :
2014-04-17 00:09:19 +08:00
obj = self . to_native ( obj )
2015-10-15 23:40:00 +08:00
( posargs , _ ) = self . reduce_arguments ( args )
2013-06-30 06:36:17 +08:00
if method_name == ' strip ' :
2014-04-17 00:09:19 +08:00
return obj . strip ( )
elif method_name == ' format ' :
2013-07-28 01:09:30 +08:00
return self . format_string ( obj , args )
2014-04-17 00:09:19 +08:00
elif method_name == ' split ' :
if len ( posargs ) > 1 :
raise InterpreterException ( ' Split() must have at most one argument. ' )
elif len ( posargs ) == 1 :
s = posargs [ 0 ]
if not isinstance ( s , str ) :
raise InterpreterException ( ' Split() argument must be a string ' )
return obj . split ( s )
else :
return obj . split ( )
2015-10-15 23:40:00 +08:00
elif method_name == ' startswith ' or method_name == ' endswith ' :
s = posargs [ 0 ]
if not isinstance ( s , str ) :
raise InterpreterException ( ' Argument must be a string. ' )
if method_name == ' startswith ' :
return obj . startswith ( s )
return obj . endswith ( s )
2013-06-30 06:36:17 +08:00
raise InterpreterException ( ' Unknown method " %s " for a string. ' % method_name )
2013-01-01 23:01:49 +08:00
2013-07-28 01:09:30 +08:00
def to_native ( self , arg ) :
2014-03-17 06:37:47 +08:00
if isinstance ( arg , mparser . StringNode ) or \
isinstance ( arg , mparser . NumberNode ) or \
isinstance ( arg , mparser . BooleanNode ) :
2014-03-17 04:55:22 +08:00
return arg . value
2013-07-28 01:09:30 +08:00
return arg
def format_string ( self , templ , args ) :
templ = self . to_native ( templ )
2014-03-17 06:37:47 +08:00
if isinstance ( args , mparser . ArgumentNode ) :
2013-07-28 01:09:30 +08:00
args = args . arguments
for ( i , arg ) in enumerate ( args ) :
2014-11-08 09:41:05 +08:00
arg = self . to_native ( self . evaluate_statement ( arg ) )
2015-07-27 05:25:45 +08:00
if isinstance ( arg , bool ) : # Python boolean is upper case.
2013-07-28 01:09:30 +08:00
arg = str ( arg ) . lower ( )
templ = templ . replace ( ' @ {} @ ' . format ( i ) , str ( arg ) )
return templ
2012-12-30 09:20:53 +08:00
def method_call ( self , node ) :
2014-03-17 05:44:32 +08:00
invokable = node . source_object
2014-03-17 06:37:47 +08:00
if isinstance ( invokable , mparser . IdNode ) :
2014-03-17 05:07:00 +08:00
object_name = invokable . value
2013-06-30 06:53:37 +08:00
obj = self . get_variable ( object_name )
else :
obj = self . evaluate_statement ( invokable )
2014-03-17 05:44:32 +08:00
method_name = node . name
2015-11-03 09:03:54 +08:00
if method_name == ' extract_objects ' and self . environment . coredata . get_builtin_option ( ' unity ' ) :
2013-12-27 06:25:45 +08:00
raise InterpreterException ( ' Single object files can not be extracted in Unity builds. ' )
2014-03-17 05:44:32 +08:00
args = node . args
2014-03-17 06:37:47 +08:00
if isinstance ( obj , mparser . StringNode ) :
2013-07-28 01:09:30 +08:00
obj = obj . get_value ( )
2013-06-30 06:36:17 +08:00
if isinstance ( obj , str ) :
2013-07-28 01:09:30 +08:00
return self . string_method_call ( obj , method_name , args )
2014-09-18 23:49:36 +08:00
if isinstance ( obj , list ) :
return self . array_method_call ( obj , method_name , self . reduce_arguments ( args ) [ 0 ] )
2012-12-30 09:20:53 +08:00
if not isinstance ( obj , InterpreterObject ) :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Variable " %s " is not callable. ' % object_name )
2013-02-10 07:51:39 +08:00
( args , kwargs ) = self . reduce_arguments ( args )
2015-06-18 01:16:28 +08:00
if method_name == ' extract_objects ' :
self . validate_extraction ( obj . held_object )
2015-10-03 03:06:26 +08:00
return obj . method_call ( method_name , self . flatten ( args ) , kwargs )
2014-08-07 17:34:35 +08:00
2015-06-18 01:50:03 +08:00
# Only permit object extraction from the same subproject
2015-06-18 01:16:28 +08:00
def validate_extraction ( self , buildtarget ) :
2015-06-18 01:50:03 +08:00
if not self . subdir . startswith ( self . subproject_dir ) :
2015-06-18 01:16:28 +08:00
if buildtarget . subdir . startswith ( self . subproject_dir ) :
raise InterpreterException ( ' Tried to extract objects from a subproject target. ' )
else :
2015-06-18 02:28:42 +08:00
if not buildtarget . subdir . startswith ( self . subproject_dir ) :
2015-06-18 01:50:03 +08:00
raise InterpreterException ( ' Tried to extract objects from the main project from a subproject. ' )
if self . subdir . split ( ' / ' ) [ 1 ] != buildtarget . subdir . split ( ' / ' ) [ 1 ] :
raise InterpreterException ( ' Tried to extract objects from a different subproject. ' )
2015-06-18 01:16:28 +08:00
2014-09-18 23:49:36 +08:00
def array_method_call ( self , obj , method_name , args ) :
if method_name == ' contains ' :
return self . check_contains ( obj , args )
2015-08-14 21:05:58 +08:00
elif method_name == ' length ' :
return len ( obj )
2014-11-06 02:38:35 +08:00
elif method_name == ' get ' :
index = args [ 0 ]
if not isinstance ( index , int ) :
raise InvalidArguments ( ' Array index must be a number. ' )
2015-05-09 21:17:20 +08:00
if index < - len ( obj ) or index > = len ( obj ) :
2014-11-06 02:38:35 +08:00
raise InvalidArguments ( ' Array index %s is out of bounds for array of size %d . ' % ( index , len ( obj ) ) )
return obj [ index ]
2014-09-18 23:49:36 +08:00
raise InterpreterException ( ' Arrays do not have a method called " %s " . ' % method_name )
def check_contains ( self , obj , args ) :
if len ( args ) != 1 :
raise InterpreterException ( ' Contains method takes exactly one argument. ' )
item = args [ 0 ]
for element in obj :
if isinstance ( element , list ) :
found = self . check_contains ( element , args )
if found :
return True
try :
if element == item :
return True
except Exception :
pass
return False
2013-01-26 03:06:08 +08:00
def evaluate_if ( self , node ) :
2014-03-17 06:37:47 +08:00
assert ( isinstance ( node , mparser . IfClauseNode ) )
2014-03-17 06:00:13 +08:00
for i in node . ifs :
result = self . evaluate_statement ( i . condition )
if not ( isinstance ( result , bool ) ) :
2014-05-27 03:56:12 +08:00
print ( result )
2014-03-17 06:00:13 +08:00
raise InvalidCode ( ' If clause does not evaluate to true or false. ' )
if result :
self . evaluate_codeblock ( i . block )
return
2014-03-17 06:37:47 +08:00
if not isinstance ( node . elseblock , mparser . EmptyNode ) :
2014-03-17 06:00:13 +08:00
self . evaluate_codeblock ( node . elseblock )
2013-07-27 22:55:17 +08:00
2014-11-06 02:38:35 +08:00
def evaluate_foreach ( self , node ) :
assert ( isinstance ( node , mparser . ForeachClauseNode ) )
varname = node . varname . value
items = self . evaluate_statement ( node . items )
if not isinstance ( items , list ) :
raise InvalidArguments ( ' Items of foreach loop is not an array ' )
for item in items :
self . set_variable ( varname , item )
self . evaluate_codeblock ( node . block )
2015-08-14 21:05:58 +08:00
def evaluate_plusassign ( self , node ) :
assert ( isinstance ( node , mparser . PlusAssignmentNode ) )
varname = node . var_name
addition = self . evaluate_statement ( node . value )
# Remember that all variables are immutable. We must always create a
# full new variable and then assign it.
old_variable = self . get_variable ( varname )
if not isinstance ( old_variable , list ) :
raise InvalidArguments ( ' The += operator currently only works with arrays. ' )
# Add other data types here.
else :
if isinstance ( addition , list ) :
new_value = old_variable + addition
else :
new_value = old_variable + [ addition ]
self . set_variable ( varname , new_value )
2015-08-20 04:34:49 +08:00
def evaluate_indexing ( self , node ) :
assert ( isinstance ( node , mparser . IndexNode ) )
iobject = self . evaluate_statement ( node . iobject )
if not isinstance ( iobject , list ) :
raise InterpreterException ( ' Tried to index a non-array object. ' )
index = self . evaluate_statement ( node . index )
if not isinstance ( index , int ) :
raise InterpreterException ( ' Index value is not an integer. ' )
if index < - len ( iobject ) or index > = len ( iobject ) :
raise InterpreterException ( ' Index %d out of bounds of array of size %d . ' % ( index , len ( iobject ) ) )
return iobject [ index ]
2013-04-11 03:41:46 +08:00
def is_elementary_type ( self , v ) :
2014-11-08 09:41:05 +08:00
if isinstance ( v , ( int , float , str , bool , list ) ) :
2013-04-11 03:41:46 +08:00
return True
return False
2013-01-26 03:59:53 +08:00
def evaluate_comparison ( self , node ) :
2014-03-17 06:14:36 +08:00
v1 = self . evaluate_statement ( node . left )
v2 = self . evaluate_statement ( node . right )
2013-04-11 03:41:46 +08:00
if self . is_elementary_type ( v1 ) :
2013-01-28 04:18:40 +08:00
val1 = v1
else :
2014-03-17 06:18:30 +08:00
val1 = v1 . value
2013-04-11 03:41:46 +08:00
if self . is_elementary_type ( v2 ) :
2013-01-28 04:18:40 +08:00
val2 = v2
else :
2014-03-17 06:18:30 +08:00
val2 = v2 . value
2014-03-17 06:14:36 +08:00
if node . ctype == ' == ' :
2013-01-26 03:59:53 +08:00
return val1 == val2
2014-03-17 06:14:36 +08:00
elif node . ctype == ' != ' :
2013-01-26 03:59:53 +08:00
return val1 != val2
else :
raise InvalidCode ( ' You broke me. ' )
2013-07-27 22:06:37 +08:00
def evaluate_andstatement ( self , cur ) :
l = self . evaluate_statement ( cur . left )
2014-03-17 06:37:47 +08:00
if isinstance ( l , mparser . BooleanNode ) :
2014-03-17 06:18:30 +08:00
l = l . value
2013-07-27 22:06:37 +08:00
if not isinstance ( l , bool ) :
raise InterpreterException ( ' First argument to " and " is not a boolean. ' )
if not l :
return False
r = self . evaluate_statement ( cur . right )
2014-03-17 06:37:47 +08:00
if isinstance ( r , mparser . BooleanNode ) :
2014-03-17 06:18:30 +08:00
r = r . value
2013-07-27 22:06:37 +08:00
if not isinstance ( r , bool ) :
raise InterpreterException ( ' Second argument to " and " is not a boolean. ' )
return r
2013-07-27 22:15:22 +08:00
def evaluate_orstatement ( self , cur ) :
l = self . evaluate_statement ( cur . left )
2014-03-17 06:37:47 +08:00
if isinstance ( l , mparser . BooleanNode ) :
2013-07-27 22:15:22 +08:00
l = l . get_value ( )
if not isinstance ( l , bool ) :
raise InterpreterException ( ' First argument to " or " is not a boolean. ' )
if l :
return True
r = self . evaluate_statement ( cur . right )
2014-03-17 06:37:47 +08:00
if isinstance ( r , mparser . BooleanNode ) :
2013-07-27 22:15:22 +08:00
r = r . get_value ( )
if not isinstance ( r , bool ) :
raise InterpreterException ( ' Second argument to " or " is not a boolean. ' )
return r
2014-08-07 17:34:35 +08:00
2013-07-27 22:21:59 +08:00
def evaluate_notstatement ( self , cur ) :
2014-03-17 06:22:39 +08:00
v = self . evaluate_statement ( cur . value )
2014-03-17 06:37:47 +08:00
if isinstance ( v , mparser . BooleanNode ) :
2014-03-17 06:22:39 +08:00
v = v . value
2013-07-27 22:21:59 +08:00
if not isinstance ( v , bool ) :
2013-07-27 22:31:40 +08:00
raise InterpreterException ( ' Argument to " not " is not a boolean. ' )
2013-07-27 22:21:59 +08:00
return not v
2013-07-27 22:15:22 +08:00
2015-05-10 00:52:10 +08:00
def evaluate_uminusstatement ( self , cur ) :
v = self . evaluate_statement ( cur . value )
if isinstance ( v , mparser . NumberNode ) :
v = v . value
if not isinstance ( v , int ) :
raise InterpreterException ( ' Argument to negation is not an integer. ' )
return - v
2014-11-08 09:41:05 +08:00
def evaluate_arithmeticstatement ( self , cur ) :
l = self . to_native ( self . evaluate_statement ( cur . left ) )
r = self . to_native ( self . evaluate_statement ( cur . right ) )
if cur . operation == ' add ' :
2014-11-17 01:56:22 +08:00
try :
return l + r
except Exception as e :
raise InvalidCode ( ' Invalid use of addition: ' + str ( e ) )
2014-11-08 09:41:05 +08:00
elif cur . operation == ' sub ' :
2014-11-17 01:56:22 +08:00
if not isinstance ( l , int ) or not isinstance ( r , int ) :
raise InvalidCode ( ' Subtraction works only with integers. ' )
2014-11-08 09:41:05 +08:00
return l - r
elif cur . operation == ' mul ' :
2014-11-17 01:56:22 +08:00
if not isinstance ( l , int ) or not isinstance ( r , int ) :
raise InvalidCode ( ' Multiplication works only with integers. ' )
2014-11-08 09:41:05 +08:00
return l * r
elif cur . operation == ' div ' :
2014-11-17 01:56:22 +08:00
if not isinstance ( l , int ) or not isinstance ( r , int ) :
raise InvalidCode ( ' Division works only with integers. ' )
2014-11-08 09:41:05 +08:00
return l / / r
else :
raise InvalidCode ( ' You broke me. ' )
2013-01-26 04:42:11 +08:00
def evaluate_arraystatement ( self , cur ) :
2014-03-17 06:18:30 +08:00
( arguments , kwargs ) = self . reduce_arguments ( cur . args )
2013-02-10 08:45:15 +08:00
if len ( kwargs ) > 0 :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( ' Keyword arguments are invalid in array construction. ' )
2013-01-26 04:42:11 +08:00
return arguments
2015-05-16 01:01:21 +08:00
def is_subproject ( self ) :
return self . subproject != ' '