2016-01-25 00:56:04 +08:00
# Copyright 2012-2016 The Meson development team
2013-02-25 04:30:02 +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-18 04:09:28 +08:00
import pickle , os , uuid
2016-02-29 04:20:07 +08:00
from . mesonlib import MesonException , default_libdir , default_libexecdir , default_prefix
2013-02-25 04:44:01 +08:00
2016-12-21 04:26:13 +08:00
version = ' 0.38.0.dev1 '
2016-05-26 06:03:02 +08:00
backendlist = [ ' ninja ' , ' vs2010 ' , ' vs2015 ' , ' xcode ' ]
2013-03-02 04:21:02 +08:00
2015-11-03 09:31:56 +08:00
class UserOption :
2015-11-10 06:45:05 +08:00
def __init__ ( self , name , description , choices ) :
2015-11-03 09:31:56 +08:00
super ( ) . __init__ ( )
self . name = name
2015-11-10 06:45:05 +08:00
self . choices = choices
2015-11-03 09:31:56 +08:00
self . description = description
def parse_string ( self , valuestring ) :
return valuestring
class UserStringOption ( UserOption ) :
2015-11-10 06:45:05 +08:00
def __init__ ( self , name , description , value , choices = None ) :
super ( ) . __init__ ( name , description , choices )
2015-11-03 09:31:56 +08:00
self . set_value ( value )
2015-11-04 06:32:09 +08:00
def validate ( self , value ) :
if not isinstance ( value , str ) :
2016-02-21 19:14:25 +08:00
raise MesonException ( ' Value " %s " for string option " %s " is not a string. ' % ( str ( value ) , self . name ) )
2015-11-04 06:32:09 +08:00
def set_value ( self , newvalue ) :
self . validate ( newvalue )
2015-11-03 09:31:56 +08:00
self . value = newvalue
class UserBooleanOption ( UserOption ) :
def __init__ ( self , name , description , value ) :
2016-02-29 04:20:07 +08:00
super ( ) . __init__ ( name , description , [ True , False ] )
2015-11-03 09:31:56 +08:00
self . set_value ( value )
def tobool ( self , thing ) :
if isinstance ( thing , bool ) :
return thing
if thing . lower ( ) == ' true ' :
return True
if thing . lower ( ) == ' false ' :
return False
raise MesonException ( ' Value %s is not boolean (true or false). ' % thing )
def set_value ( self , newvalue ) :
self . value = self . tobool ( newvalue )
def parse_string ( self , valuestring ) :
if valuestring == ' false ' :
return False
if valuestring == ' true ' :
return True
raise MesonException ( ' Value " %s " for boolean option " %s " is not a boolean. ' % ( valuestring , self . name ) )
2016-05-31 01:11:18 +08:00
def __bool__ ( self ) :
return self . value
2015-11-03 09:31:56 +08:00
class UserComboOption ( UserOption ) :
def __init__ ( self , name , description , choices , value ) :
2015-11-10 06:45:05 +08:00
super ( ) . __init__ ( name , description , choices )
2015-11-03 09:31:56 +08:00
if not isinstance ( self . choices , list ) :
raise MesonException ( ' Combo choices must be an array. ' )
for i in self . choices :
if not isinstance ( i , str ) :
raise MesonException ( ' Combo choice elements must be strings. ' )
self . set_value ( value )
def set_value ( self , newvalue ) :
if newvalue not in self . choices :
optionsstring = ' , ' . join ( [ ' " %s " ' % ( item , ) for item in self . choices ] )
raise MesonException ( ' Value " %s " for combo option " %s " is not one of the choices. Possible choices are: %s . ' % ( newvalue , self . name , optionsstring ) )
self . value = newvalue
class UserStringArrayOption ( UserOption ) :
2015-11-10 06:45:05 +08:00
def __init__ ( self , name , description , value , * * kwargs ) :
super ( ) . __init__ ( name , description , kwargs . get ( ' choices ' , [ ] ) )
2015-11-03 09:31:56 +08:00
self . set_value ( value )
def set_value ( self , newvalue ) :
if isinstance ( newvalue , str ) :
if not newvalue . startswith ( ' [ ' ) :
raise MesonException ( ' Valuestring does not define an array: ' + newvalue )
newvalue = eval ( newvalue , { } , { } ) # Yes, it is unsafe.
if not isinstance ( newvalue , list ) :
2016-07-18 04:57:32 +08:00
raise MesonException ( ' " {0} " should be a string array, but it is not ' . format ( str ( newvalue ) ) )
2015-11-03 09:31:56 +08:00
for i in newvalue :
if not isinstance ( i , str ) :
2016-07-18 04:57:32 +08:00
raise MesonException ( ' String array element " {0} " is not a string. ' . format ( str ( newvalue ) ) )
2015-11-03 09:31:56 +08:00
self . value = newvalue
2013-04-01 19:08:54 +08:00
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.
2013-02-25 04:30:02 +08:00
class CoreData ( ) :
2013-06-20 23:07:03 +08:00
2013-02-25 04:30:02 +08:00
def __init__ ( self , options ) :
2014-03-18 06:43:04 +08:00
self . guid = str ( uuid . uuid4 ( ) ) . upper ( )
2014-03-19 05:54:03 +08:00
self . test_guid = str ( uuid . uuid4 ( ) ) . upper ( )
2015-11-05 02:00:04 +08:00
self . regen_guid = str ( uuid . uuid4 ( ) ) . upper ( )
2014-03-18 04:09:28 +08:00
self . target_guids = { }
2013-03-02 04:21:02 +08:00
self . version = version
2015-11-03 09:03:54 +08:00
self . init_builtins ( options )
2013-10-19 01:55:10 +08:00
self . user_options = { }
2015-10-04 08:41:38 +08:00
self . compiler_options = { }
2016-03-17 03:55:03 +08:00
self . base_options = { }
2014-06-08 04:39:59 +08:00
self . external_args = { } # These are set from "the outside" with e.g. mesonconf
self . external_link_args = { }
2013-08-24 07:24:29 +08:00
if options . cross_file is not None :
self . cross_file = os . path . join ( os . getcwd ( ) , options . cross_file )
else :
self . cross_file = None
2013-02-25 04:44:01 +08:00
2013-03-10 03:20:58 +08:00
self . compilers = { }
2013-08-31 03:20:10 +08:00
self . cross_compilers = { }
2013-02-25 05:27:52 +08:00
self . deps = { }
2015-03-14 01:55:09 +08:00
self . modules = { }
2016-07-03 23:31:46 +08:00
# Only to print a warning if it changes between Meson invocations.
self . pkgconf_envvar = os . environ . get ( ' PKG_CONFIG_PATH ' , ' ' )
2013-02-25 05:11:14 +08:00
2015-11-03 09:03:54 +08:00
def init_builtins ( self , options ) :
2016-02-29 04:20:07 +08:00
self . builtins = { }
for key in get_builtin_options ( ) :
args = [ key ] + builtin_options [ key ] [ 1 : - 1 ] + [ getattr ( options , key , get_builtin_option_default ( key ) ) ]
self . builtins [ key ] = builtin_options [ key ] [ 0 ] ( * args )
2015-11-03 09:03:54 +08:00
2014-11-17 00:30:38 +08:00
def get_builtin_option ( self , optname ) :
2016-02-29 04:20:07 +08:00
if optname in self . builtins :
return self . builtins [ optname ] . value
raise RuntimeError ( ' Tried to get unknown builtin option %s . ' % optname )
2014-11-17 00:30:38 +08:00
2015-11-03 09:03:54 +08:00
def set_builtin_option ( self , optname , value ) :
2016-02-29 04:20:07 +08:00
if optname in self . builtins :
self . builtins [ optname ] . set_value ( value )
2015-11-03 09:03:54 +08:00
else :
2016-02-29 04:20:07 +08:00
raise RuntimeError ( ' Tried to set unknown builtin option %s . ' % optname )
2015-11-04 06:32:09 +08:00
2013-02-25 04:44:01 +08:00
def load ( filename ) :
2016-10-13 05:09:17 +08:00
load_fail_msg = ' Coredata file {!r} is corrupted. Try with a fresh build tree. ' . format ( filename )
try :
with open ( filename , ' rb ' ) as f :
obj = pickle . load ( f )
except pickle . UnpicklingError :
raise MesonException ( load_fail_msg )
2013-02-25 04:44:01 +08:00
if not isinstance ( obj , CoreData ) :
2016-10-13 05:09:17 +08:00
raise MesonException ( load_fail_msg )
2013-03-02 04:21:02 +08:00
if obj . version != version :
2017-01-01 02:50:15 +08:00
raise MesonException ( ' Build directory has been generated with Meson version %s , which is incompatible with current version %s . \n Please delete this build directory AND create a new one. ' %
2017-01-01 03:19:38 +08:00
( obj . version , version ) )
2013-02-25 04:44:01 +08:00
return obj
def save ( obj , filename ) :
2013-03-02 04:21:02 +08:00
if obj . version != version :
2016-10-13 05:09:17 +08:00
raise MesonException ( ' Fatal version mismatch corruption. ' )
2016-08-25 07:29:11 +08:00
with open ( filename , ' wb ' ) as f :
pickle . dump ( obj , f )
2013-03-10 05:53:02 +08:00
2016-02-29 04:20:07 +08:00
def get_builtin_options ( ) :
return list ( builtin_options . keys ( ) )
def is_builtin_option ( optname ) :
return optname in get_builtin_options ( )
def get_builtin_option_choices ( optname ) :
if is_builtin_option ( optname ) :
if builtin_options [ optname ] [ 0 ] == UserStringOption :
return None
elif builtin_options [ optname ] [ 0 ] == UserBooleanOption :
return [ True , False ]
else :
return builtin_options [ optname ] [ 2 ]
else :
raise RuntimeError ( ' Tried to get the supported values for an unknown builtin option \' %s \' . ' % optname )
def get_builtin_option_description ( optname ) :
if is_builtin_option ( optname ) :
return builtin_options [ optname ] [ 1 ]
else :
raise RuntimeError ( ' Tried to get the description for an unknown builtin option \' %s \' . ' % optname )
def get_builtin_option_default ( optname ) :
if is_builtin_option ( optname ) :
o = builtin_options [ optname ]
if o [ 0 ] == UserComboOption :
return o [ 3 ]
return o [ 2 ]
else :
raise RuntimeError ( ' Tried to get the default value for an unknown builtin option \' %s \' . ' % optname )
builtin_options = {
2016-12-31 20:33:42 +08:00
' buildtype ' : [ UserComboOption , ' Build type to use. ' , [ ' plain ' , ' debug ' , ' debugoptimized ' , ' release ' , ' minsize ' ] , ' debug ' ] ,
' strip ' : [ UserBooleanOption , ' Strip targets on install. ' , False ] ,
' unity ' : [ UserBooleanOption , ' Unity build. ' , False ] ,
' prefix ' : [ UserStringOption , ' Installation prefix. ' , default_prefix ( ) ] ,
' libdir ' : [ UserStringOption , ' Library directory. ' , default_libdir ( ) ] ,
' libexecdir ' : [ UserStringOption , ' Library executable directory. ' , default_libexecdir ( ) ] ,
' bindir ' : [ UserStringOption , ' Executable directory. ' , ' bin ' ] ,
' sbindir ' : [ UserStringOption , ' System executable directory. ' , ' sbin ' ] ,
' includedir ' : [ UserStringOption , ' Header file directory. ' , ' include ' ] ,
' datadir ' : [ UserStringOption , ' Data file directory. ' , ' share ' ] ,
' mandir ' : [ UserStringOption , ' Manual page directory. ' , ' share/man ' ] ,
' infodir ' : [ UserStringOption , ' Info page directory. ' , ' share/info ' ] ,
' localedir ' : [ UserStringOption , ' Locale data directory. ' , ' share/locale ' ] ,
2016-12-18 07:08:45 +08:00
# sysconfdir, localstatedir and sharedstatedir are a bit special. These defaults to ${prefix}/etc,
# ${prefix}/var and ${prefix}/com but nobody uses that. Instead they always set it
# manually to /etc, /var and /var/lib. This default values is thus pointless and not really used
# but we set it to this for consistency with other systems.
2016-11-01 06:11:35 +08:00
#
2016-12-18 07:08:45 +08:00
# Projects installing to sysconfdir, localstatedir or sharedstatedir probably want
2016-12-05 21:27:05 +08:00
# to set the following in project():
2016-11-01 06:11:35 +08:00
#
2016-12-18 07:08:45 +08:00
# default_options : ['sysconfdir=/etc', 'localstatedir=/var', 'sharedstatedir=/var/lib']
2016-12-31 20:33:42 +08:00
' sysconfdir ' : [ UserStringOption , ' Sysconf data directory. ' , ' etc ' ] ,
' localstatedir ' : [ UserStringOption , ' Localstate data directory. ' , ' var ' ] ,
' sharedstatedir ' : [ UserStringOption , ' Architecture-independent data directory. ' , ' com ' ] ,
' werror ' : [ UserBooleanOption , ' Treat warnings as errors. ' , False ] ,
' warning_level ' : [ UserComboOption , ' Compiler warning level to use. ' , [ ' 1 ' , ' 2 ' , ' 3 ' ] , ' 1 ' ] ,
' layout ' : [ UserComboOption , ' Build directory layout. ' , [ ' mirror ' , ' flat ' ] , ' mirror ' ] ,
' default_library ' : [ UserComboOption , ' Default library type. ' , [ ' shared ' , ' static ' ] , ' shared ' ] ,
' backend ' : [ UserComboOption , ' Backend to use. ' , backendlist , ' ninja ' ] ,
' stdsplit ' : [ UserBooleanOption , ' Split stdout and stderr in test logs. ' , True ] ,
' errorlogs ' : [ UserBooleanOption , " Whether to print the logs from failing tests. " , True ] ,
2016-02-29 04:20:07 +08:00
}
2013-03-10 05:53:02 +08:00
forbidden_target_names = { ' clean ' : None ,
2016-12-20 04:40:54 +08:00
' clean-ctlist ' : None ,
2013-03-25 03:28:59 +08:00
' clean-gcno ' : None ,
' clean-gcda ' : None ,
2013-03-10 05:53:02 +08:00
' coverage-text ' : None ,
' coverage-xml ' : None ,
' coverage-html ' : None ,
' phony ' : None ,
2014-11-24 07:33:26 +08:00
' PHONY ' : None ,
2013-03-10 05:53:02 +08:00
' all ' : None ,
' test ' : None ,
2016-06-04 02:17:57 +08:00
' test: ' : None ,
2015-11-26 05:29:06 +08:00
' benchmark ' : None ,
2013-03-10 05:53:02 +08:00
' install ' : None ,
2016-12-29 05:16:19 +08:00
' uninstall ' : None ,
2013-03-23 04:37:34 +08:00
' build.ninja ' : None ,
2016-05-23 00:24:59 +08:00
' scan-build ' : None ,
2016-11-03 05:14:54 +08:00
' reconfigure ' : None ,
2015-06-19 15:26:20 +08:00
}