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-21 21:27:58 +08:00
from mesonlib import File
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 ) :
raise InvalidArguments ( ' Argument not a list. ' )
2015-05-08 04:40:50 +08:00
if not all ( isinstance ( s , str ) for s in a ) :
raise InvalidArguments ( msg )
2015-04-23 00:40:09 +08:00
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 ,
} )
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 ,
} )
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__ ( )
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 ,
} )
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
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 ( )
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 ) :
2013-02-24 03:13:01 +08:00
if len ( kwargs ) > 0 :
raise InvalidArguments ( ' Process does not take keyword arguments. ' )
2015-04-23 00:40:09 +08:00
check_stringlist ( args )
2013-09-24 04:08:50 +08:00
gl = GeneratedListHolder ( self )
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-03-14 01:38:53 +08:00
def __init__ ( self , arg1 ) :
2013-09-24 04:08:50 +08:00
super ( ) . __init__ ( )
2015-03-14 01:59:12 +08:00
if isinstance ( arg1 , GeneratorHolder ) :
self . held_object = build . GeneratedList ( arg1 . held_object )
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
2013-08-24 06:46:36 +08:00
class Build ( InterpreterObject ) :
def __init__ ( self ) :
InterpreterObject . __init__ ( self )
self . methods . update ( { ' name ' : self . get_name_method ,
} )
def get_name_method ( self , args , kwargs ) :
return platform . system ( ) . lower ( )
2013-01-28 03:45:02 +08:00
# This currently returns data for the current environment.
# It should return info for the target host.
class Host ( InterpreterObject ) :
2013-08-24 06:46:36 +08:00
def __init__ ( self , envir ) :
2013-01-28 03:45:02 +08:00
InterpreterObject . __init__ ( self )
2013-08-24 06:46:36 +08:00
self . environment = envir
2013-10-21 04:28:16 +08:00
self . methods . update ( { ' name ' : self . get_name_method ,
2013-01-28 04:28:19 +08:00
' is_big_endian ' : self . is_big_endian_method ,
2013-01-28 04:18:40 +08:00
} )
2013-01-28 03:45:02 +08:00
2013-02-10 19:15:33 +08:00
def get_name_method ( self , args , kwargs ) :
2013-08-24 06:46:36 +08:00
if self . environment . is_cross_build ( ) :
return self . environment . cross_info . get ( ' name ' )
2013-01-28 03:45:02 +08:00
return platform . system ( ) . lower ( )
2014-08-07 17:34:35 +08:00
2013-02-10 19:15:33 +08:00
def is_big_endian_method ( self , args , kwargs ) :
2013-01-28 04:28:19 +08:00
return sys . byteorder != ' little '
2013-01-28 03:45:02 +08:00
2013-09-24 04:08:50 +08:00
class IncludeDirsHolder ( InterpreterObject ) :
2015-04-22 23:03:18 +08:00
def __init__ ( self , curdir , dirs ) :
2013-09-24 04:08:50 +08:00
super ( ) . __init__ ( )
2015-04-22 23:03:18 +08:00
self . held_object = build . IncludeDirs ( curdir , dirs )
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
2013-01-14 01:25:54 +08:00
class Data ( InterpreterObject ) :
2015-02-16 01:35:53 +08:00
def __init__ ( self , in_sourcetree , source_subdir , sources , kwargs ) :
2013-01-14 01:25:54 +08:00
InterpreterObject . __init__ ( self )
2015-02-16 01:35:53 +08:00
self . in_sourcetree = in_sourcetree
2014-11-04 00:37:23 +08:00
self . source_subdir = source_subdir
2013-01-14 01:25:54 +08:00
self . sources = sources
2013-02-10 08:31:21 +08:00
kwsource = kwargs . get ( ' sources ' , [ ] )
if not isinstance ( kwsource , list ) :
kwsource = [ kwsource ]
self . sources + = kwsource
2015-04-23 00:40:09 +08:00
check_stringlist ( self . sources )
2015-02-16 01:13:21 +08:00
self . install_dir = kwargs . get ( ' install_dir ' , None )
if not isinstance ( self . install_dir , str ) :
2014-02-13 04:50:45 +08:00
raise InterpreterException ( ' Custom_install_dir must be a string. ' )
2013-01-14 01:25:54 +08:00
2014-11-04 00:37:23 +08:00
def get_install_subdir ( self ) :
return self . install_subdir
def get_source_subdir ( self ) :
return self . source_subdir
2013-01-14 01:25:54 +08:00
def get_sources ( self ) :
return self . sources
2015-02-16 01:13:21 +08:00
def get_install_dir ( self ) :
return self . 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-03-09 23:16:32 +08:00
def __init__ ( self , target ) :
2013-11-05 07:47:09 +08:00
super ( ) . __init__ ( )
2015-03-09 23:16:32 +08:00
self . held_object = target
2013-11-05 07:47:09 +08:00
self . methods . update ( { ' extract_objects ' : self . extract_objects_method } )
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 ( )
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
2013-09-24 03:34:41 +08:00
class ExecutableHolder ( BuildTargetHolder ) :
2015-03-09 23:16:32 +08:00
def __init__ ( self , target ) :
super ( ) . __init__ ( target )
2012-12-30 00:18:41 +08:00
2013-09-24 03:34:41 +08:00
class StaticLibraryHolder ( BuildTargetHolder ) :
2015-03-09 23:16:32 +08:00
def __init__ ( self , target ) :
super ( ) . __init__ ( target )
2013-01-06 00:13:38 +08:00
2013-09-24 03:34:41 +08:00
class SharedLibraryHolder ( BuildTargetHolder ) :
2015-03-09 23:16:32 +08:00
def __init__ ( self , target ) :
super ( ) . __init__ ( target )
2013-01-12 08:25:06 +08:00
2014-03-11 05:33:24 +08:00
class JarHolder ( BuildTargetHolder ) :
2015-03-10 01:48:43 +08:00
def __init__ ( self , target ) :
super ( ) . __init__ ( target )
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-03-24 05:11:04 +08:00
def __init__ ( self , name , exe , is_parallel , cmd_args , env , should_fail , valgrind_args ) :
2013-01-07 01:13:30 +08:00
InterpreterObject . __init__ ( self )
self . name = name
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
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
self . methods . update ( {
' get_variable ' : self . get_variable_method ,
} )
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 ,
' 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 ,
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 ,
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
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 ]
2013-08-25 04:40:11 +08:00
result = self . compiler . alignment ( typename , self . environment )
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. ' )
2013-07-27 21:06:39 +08:00
result = self . compiler . run ( code )
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. ' )
had = self . compiler . has_member ( typename , membername , prefix )
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. ' )
2013-08-25 04:32:13 +08:00
had = self . compiler . has_function ( funcname , prefix , self . environment )
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 = ' ' )
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. ' )
2013-08-25 04:10:44 +08:00
esize = self . compiler . sizeof ( element , prefix , self . environment )
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 )
2013-04-21 22:46:58 +08:00
string = 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. ' )
result = self . compiler . compiles ( string )
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
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 ]
2013-06-05 23:22:51 +08:00
haz = self . compiler . has_header ( string )
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 ( ) ,
self . interpreter . environment . get_build_dir ( ) )
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-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-21 19:57:53 +08:00
state . pkgconfig_gens = self . interpreter . build . pkgconfig_gens
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 ,
2014-07-09 21:30:58 +08:00
' set_install_script ' : self . set_install_script_method ,
2013-08-31 04:43:27 +08:00
} )
2014-07-09 21:30:58 +08:00
def set_install_script_method ( self , args , kwargs ) :
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 )
self . build . install_script = scriptfile
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 )
2013-08-31 04:56:09 +08:00
def has_exe_wrapper_method ( self , args , kwargs ) :
if self . is_cross_build_method ( None , None ) :
return ' exe_wrap ' in self . build . environment . cross_info
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 ) :
return self . build . environment . coredata . unity
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
2012-12-27 02:58:48 +08:00
class Interpreter ( ) :
2013-01-02 02:13:46 +08:00
2015-05-16 01:01:21 +08:00
def __init__ ( self , build , subproject = ' ' , subdir = ' ' , subproject_dir = ' subprojects ' ) :
2013-01-12 04:59:49 +08:00
self . build = build
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 ) :
2014-08-07 02:40:09 +08:00
oi = optinterpreter . OptionInterpreter ( self . subproject , \
self . build . environment . cmd_line_options )
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 = { }
2013-08-24 06:46:36 +08:00
self . builtin [ ' build ' ] = Build ( )
self . builtin [ ' host ' ] = Host ( build . environment )
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 ,
2014-03-11 05:33:24 +08:00
' jar ' : self . func_jar ,
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 ,
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 ,
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 ,
2014-02-06 06:16:23 +08:00
' pkgconfig_gen ' : self . func_pkgconfig_gen ,
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-03-05 05:53:35 +08:00
' import ' : self . func_import ,
2015-05-02 20:47:03 +08:00
' files ' : self . func_files ,
2013-01-07 00:48:16 +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-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
2012-12-30 07:31:39 +08:00
i + = 1 # In THE FUTURE jump over blocks and stuff.
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-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 ) :
return [ File . from_source_file ( self . environment . source_dir , self . subdir , fname ) for fname in args ]
2015-04-21 21:27:58 +08:00
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-02-21 08:48:32 +08:00
if re . fullmatch ( ' [_a-zA-Z][_0-9a-zA-Z]* ' , varname ) is None :
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 )
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 ) :
raise InvalidArguments ( ' Expected %d arguments, got %d ' ,
argcount , len ( args ) )
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. ' )
2014-02-06 06:16:23 +08:00
def func_pkgconfig_gen ( self , nodes , args , kwargs ) :
if len ( args ) > 0 :
raise InterpreterException ( ' Pkgconfig_gen takes no positional arguments. ' )
libs = kwargs . get ( ' libraries ' , [ ] )
if not isinstance ( libs , list ) :
libs = [ libs ]
for l in libs :
if not ( isinstance ( l , SharedLibraryHolder ) or isinstance ( l , StaticLibraryHolder ) ) :
raise InterpreterException ( ' Library argument not a library object. ' )
2014-02-10 03:47:36 +08:00
subdirs = kwargs . get ( ' subdirs ' , [ ' . ' ] )
if not isinstance ( subdirs , list ) :
subdirs = [ subdirs ]
for h in subdirs :
if not isinstance ( h , str ) :
raise InterpreterException ( ' Header argument not string. ' )
2014-02-06 06:16:23 +08:00
version = kwargs . get ( ' version ' , ' ' )
if not isinstance ( version , str ) :
raise InterpreterException ( ' Version must be a string. ' )
name = kwargs . get ( ' name ' , None )
if not isinstance ( name , str ) :
raise InterpreterException ( ' Name not specified. ' )
2014-02-06 06:47:47 +08:00
filebase = kwargs . get ( ' filebase ' , name )
2014-02-06 06:16:23 +08:00
if not isinstance ( filebase , str ) :
2014-02-06 06:47:47 +08:00
raise InterpreterException ( ' Filebase must be a string. ' )
2014-02-06 06:16:23 +08:00
description = kwargs . get ( ' description ' , None )
if not isinstance ( description , str ) :
raise InterpreterException ( ' Description is not a string. ' )
2014-02-10 03:47:36 +08:00
p = build . PkgConfigGenerator ( libs , subdirs , name , description , version , filebase )
2014-02-06 06:16:23 +08:00
self . build . pkgconfig_gens . append ( p )
2015-04-22 23:27:34 +08:00
@stringArgs
2015-04-22 23:03:18 +08:00
@noKwargs
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 ]
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
subdir = os . path . join ( self . subproject_dir , dirname )
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-05-16 01:01:21 +08:00
subi = Interpreter ( self . build , 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 ]
2013-12-09 08:43:28 +08:00
subi . run ( )
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 ]
2015-05-16 01:01:21 +08:00
if self . is_subproject ( ) :
2014-12-22 03:34:26 +08:00
optname = self . subproject + ' : ' + optname
2014-11-17 00:30:38 +08:00
try :
return self . environment . get_coredata ( ) . get_builtin_option ( optname )
except RuntimeError :
pass
2013-10-19 01:55:10 +08:00
if optname not in self . environment . coredata . user_options :
2013-10-17 03:33:33 +08:00
raise InterpreterException ( ' Tried to access unknown option " %s " . ' % optname )
2013-10-19 01:55:10 +08:00
return self . environment . coredata . user_options [ optname ] . value
2013-10-17 03:33:33 +08:00
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-04-22 23:27:34 +08:00
@stringArgs
2013-02-10 07:12:00 +08:00
def func_project ( self , node , args , kwargs ) :
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 list ( kwargs . keys ( ) ) != [ ' subproject_dir ' ] and len ( kwargs ) != 0 :
raise InvalidArguments ( ' project() only accepts the keyword argument " subproject_dir " ' )
if not self . is_subproject ( ) :
2014-03-18 04:09:28 +08:00
self . build . project_name = args [ 0 ]
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 ' ]
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 :
raise InterpreterException ( ' Compiling Vala requires a C compiler ' )
2012-12-27 05:37:41 +08:00
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
( posargs , kwargs ) = self . reduce_arguments ( node . args )
if len ( posargs ) != 1 :
raise InvalidArguments ( ' Expected 1 argument, got %d ' % len ( posargs ) )
arg = posargs [ 0 ]
if isinstance ( arg , list ) :
argstr = stringifyUserArguments ( arg )
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 ) :
2013-08-31 03:20:10 +08:00
is_cross = self . environment . is_cross_build ( )
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 )
if is_cross :
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 )
if is_cross :
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 )
if is_cross :
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 )
if is_cross :
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 ( )
if is_cross :
cross_comp = comp # Java is platform independent.
2014-07-19 02:49:14 +08:00
elif lang == ' cs ' :
comp = self . environment . detect_cs_compiler ( )
if is_cross :
cross_comp = comp # C# is platform independent.
2014-05-10 06:14:52 +08:00
elif lang == ' vala ' :
comp = self . environment . detect_vala_compiler ( )
if is_cross :
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 ( )
if is_cross :
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 )
if is_cross :
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 :
self . coredata . cross_compilers [ lang ] = cross_comp
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 )
2013-08-31 03:20:10 +08:00
if is_cross :
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 )
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 ]
if libname in self . coredata . ext_libs and \
self . coredata . ext_libs [ libname ] . found ( ) :
2013-03-10 05:53:02 +08:00
return ExternalLibraryHolder ( self . coredata . ext_libs [ libname ] )
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 )
self . coredata . ext_libs [ libname ] = 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 :
2013-04-01 19:08:54 +08:00
dep = dependencies . Dependency ( ) # Returns always false for dep.found()
2013-03-02 05:13:17 +08:00
if not dep . found ( ) :
2013-04-01 19:08:54 +08:00
dep = dependencies . find_external_dependency ( name , kwargs )
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
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
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-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 ) :
raise InterpreterException ( ' Keyword argument must exist and be a string. ' )
2015-02-11 10:27:40 +08:00
replace_string = kwargs . pop ( ' replace_string ' , ' @VCS_TAG@ ' )
regex_selector = ' (.*) ' # default regex selector for custom command: use complete output
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 :
vcs_cmd = [ ' ' ] # executing this cmd will fail in vcstagger.py and force to use the fallback string
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 ]
if name in coredata . forbidden_target_names :
raise InvalidArguments ( ' Target name " %s " is reserved for Meson \' s internal use. Please rename. ' \
% name )
if name in self . build . targets :
raise InvalidCode ( ' Tried to create target " %s " , but a target of that name already exists. ' % name )
2015-03-06 23:36:43 +08:00
tg = CustomTargetHolder ( build . CustomTarget ( name , self . subdir , kwargs ) )
2014-05-19 05:59:35 +08:00
self . build . targets [ name ] = tg . held_object
return tg
2014-03-11 05:33:24 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
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 ' )
name = args [ 0 ]
if name in coredata . forbidden_target_names :
raise InvalidArguments ( ' Target name " %s " is reserved for Meson \' s internal use. Please rename. ' \
% name )
if name in self . build . targets :
raise InvalidCode ( ' Tried to create target " %s " , but a target of that name already exists. ' % name )
command = args [ 1 ]
cmd_args = args [ 2 : ]
tg = RunTargetHolder ( name , command , cmd_args , self . subdir )
self . build . targets [ name ] = tg . held_object
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
2013-06-02 18:18:15 +08:00
def func_test ( self , node , args , kwargs ) :
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 :
if not isinstance ( i , str ) :
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. ' )
t = Test ( args [ 0 ] , args [ 1 ] . held_object , par , cmd_args , env , should_fail , valgrind_args )
2013-01-12 04:59:49 +08:00
self . build . tests . append ( t )
2013-08-11 19:38:32 +08:00
mlog . debug ( ' Adding test " ' , 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 :
os . mkdir ( os . path . join ( self . environment . build_dir , subdir ) )
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-02-16 01:35:53 +08:00
data = Data ( True , self . subdir , args , kwargs )
2013-01-14 01:25:54 +08:00
self . build . data . append ( data )
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 ) :
if len ( args ) != 1 :
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 )
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 :
2014-05-13 04:04:54 +08:00
raise InterpreterException ( ' Running configure command failed. \n %s \n %s ' %
( 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 ) :
self . build . data . append ( Data ( False , self . subdir , [ output ] , kwargs ) )
2015-03-27 00:01:14 +08:00
# FIXME, HORROR, this is a massive hack to get this working. The correct
# solution is to finally do the refactoring where source files are no
# longer strings but actual objects. This is a major undertaking
# and will only be done after the next release.
outputfile = os . path . join ( self . environment . build_dir , self . subdir , output )
return outputfile
2013-01-14 01:25:54 +08:00
2015-04-22 23:27:34 +08:00
@stringArgs
2015-04-22 23:03:18 +08:00
@noKwargs
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 )
2015-04-22 23:03:18 +08:00
i = IncludeDirsHolder ( self . subdir , args )
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 :
if isinstance ( s , File ) or isinstance ( s , GeneratedListHolder ) or \
isinstance ( s , CustomTargetHolder ) :
pass
2015-04-26 06:56:02 +08:00
elif isinstance ( s , str ) :
2015-04-22 20:53:46 +08:00
s = File . from_source_file ( self . environment . source_dir , self . subdir , s )
else :
raise RuntimeError ( " Unreachable code " )
results . append ( s )
return results
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-03-10 05:53:02 +08:00
if name in coredata . forbidden_target_names :
2013-05-27 03:42:39 +08:00
raise InvalidArguments ( ' Target name " %s " is reserved for Meson \' s internal use. Please rename. ' \
% name )
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 ' , [ ] ) )
if not isinstance ( objs , list ) :
objs = [ objs ]
2013-01-12 04:59:49 +08:00
if name in self . build . targets :
2013-05-27 03:42:39 +08:00
raise InvalidCode ( ' Tried to create target " %s " , but a target of that name already exists. ' % name )
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-03-10 01:48:43 +08:00
print ( targetholder )
2015-03-09 23:16:32 +08:00
raise RuntimeError ( ' Unreachable code ' )
target = targetclass ( name , self . subdir , is_cross , sources , objs , self . environment , kwargs )
l = targetholder ( target )
2013-11-05 07:47:09 +08:00
self . build . targets [ name ] = l . held_object
2014-03-18 04:09:28 +08:00
if name not in self . coredata . target_guids :
2014-03-18 06:43:04 +08:00
self . coredata . target_guids [ name ] = str ( uuid . uuid4 ( ) ) . upper ( )
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 ) :
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 \
isinstance ( value , 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 )
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 ' :
( posargs , _ ) = self . reduce_arguments ( args )
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 ( )
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 ) )
2013-07-28 01:09:30 +08:00
if isinstance ( arg , bool ) : # Python boolean is upper case.
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
2013-12-27 06:25:45 +08:00
if method_name == ' extract_objects ' and self . environment . coredata . unity :
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 )
return obj . method_call ( method_name , args , kwargs )
2014-08-07 17:34:35 +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 )
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 )
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 != ' '