2014-11-17 02:19:12 +08:00
# Copyright 2012-2014 The Meson development team
2013-01-12 04:59:49 +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.
2016-01-16 03:12:23 +08:00
from . import coredata
from . import environment
from . import dependencies
from . import mlog
2016-07-01 17:13:51 +08:00
import copy , os , re
2016-08-21 07:40:29 +08:00
from . mesonlib import File , flatten , MesonException , stringlistify
2016-07-01 17:13:51 +08:00
from . environment import for_windows , for_darwin
2014-09-14 18:47:18 +08:00
2015-03-09 23:16:32 +08:00
known_basic_kwargs = { ' install ' : True ,
2014-09-14 18:47:18 +08:00
' c_pch ' : True ,
' cpp_pch ' : True ,
' c_args ' : True ,
' cpp_args ' : True ,
' cs_args ' : True ,
2015-07-02 17:13:23 +08:00
' vala_args ' : True ,
2016-08-18 16:42:12 +08:00
' d_args ' : True ,
2014-09-14 18:47:18 +08:00
' link_args ' : True ,
' link_depends ' : True ,
' link_with ' : True ,
' include_directories ' : True ,
' dependencies ' : True ,
' install_dir ' : True ,
' main_class ' : True ,
' gui_app ' : True ,
' extra_files ' : True ,
' install_rpath ' : True ,
' resources ' : True ,
' sources ' : True ,
' objects ' : True ,
' native ' : True ,
2015-06-19 15:28:21 +08:00
}
2014-09-14 18:47:18 +08:00
known_shlib_kwargs = known_basic_kwargs . copy ( )
known_shlib_kwargs . update ( { ' version ' : True ,
2016-02-13 03:57:31 +08:00
' soversion ' : True ,
' name_prefix ' : True ,
2016-02-21 23:12:09 +08:00
' name_suffix ' : True ,
2016-02-15 11:35:10 +08:00
' vs_module_defs ' : True } )
2014-09-14 18:47:18 +08:00
2016-07-01 17:13:51 +08:00
def sources_are_suffix ( sources , suffix ) :
2016-07-04 22:19:04 +08:00
for source in sources :
if source . endswith ( ' . ' + suffix ) :
return True
return False
2016-07-01 17:13:51 +08:00
def compiler_is_msvc ( sources , is_cross , env ) :
"""
Since each target does not currently have the compiler information attached
to it , we must do this detection manually here .
This detection is purposely incomplete and will cause bugs if other code is
extended and this piece of code is forgotten .
"""
compiler = None
if sources_are_suffix ( sources , ' c ' ) :
try :
compiler = env . detect_c_compiler ( is_cross )
except MesonException :
return False
elif sources_are_suffix ( sources , ' cxx ' ) or \
sources_are_suffix ( sources , ' cpp ' ) or \
sources_are_suffix ( sources , ' cc ' ) :
try :
compiler = env . detect_cpp_compiler ( is_cross )
except MesonException :
return False
2016-07-04 22:19:04 +08:00
if compiler and compiler . get_id ( ) == ' msvc ' :
2016-07-01 17:13:51 +08:00
return True
return False
2016-03-23 01:31:55 +08:00
class InvalidArguments ( MesonException ) :
2013-09-24 03:34:41 +08:00
pass
2013-01-12 04:59:49 +08:00
class Build :
""" A class that holds the status of one build including
all dependencies and so on .
"""
def __init__ ( self , environment ) :
2014-03-18 04:09:28 +08:00
self . project_name = ' name of master project '
2015-08-22 01:50:40 +08:00
self . project_version = None
2013-01-12 04:59:49 +08:00
self . environment = environment
2013-12-09 08:43:28 +08:00
self . projects = { }
2013-01-12 04:59:49 +08:00
self . targets = { }
self . compilers = [ ]
2013-08-31 03:20:10 +08:00
self . cross_compilers = [ ]
2013-01-26 07:44:56 +08:00
self . global_args = { }
2016-05-29 02:31:59 +08:00
self . global_link_args = { }
2013-01-12 04:59:49 +08:00
self . tests = [ ]
2015-11-26 05:29:06 +08:00
self . benchmarks = [ ]
2013-01-12 19:53:19 +08:00
self . headers = [ ]
2013-01-12 20:31:43 +08:00
self . man = [ ]
2013-01-14 01:25:54 +08:00
self . data = [ ]
2013-04-20 04:59:06 +08:00
self . static_linker = None
2013-08-31 04:07:26 +08:00
self . static_cross_linker = None
2013-12-10 02:39:53 +08:00
self . subprojects = { }
2015-07-30 07:01:47 +08:00
self . install_scripts = [ ]
2016-03-01 21:07:38 +08:00
self . postconf_scripts = [ ]
2014-11-04 05:28:47 +08:00
self . install_dirs = [ ]
2015-08-22 01:50:40 +08:00
self . dep_manifest_name = None
self . dep_manifest = { }
2016-05-22 02:46:03 +08:00
self . cross_stdlibs = { }
2013-01-12 04:59:49 +08:00
2014-03-11 04:35:00 +08:00
def has_language ( self , language ) :
for i in self . compilers :
if i . get_language ( ) == language :
return True
return False
2013-04-20 04:59:06 +08:00
def add_compiler ( self , compiler ) :
2014-06-18 06:22:55 +08:00
if self . static_linker is None and compiler . needs_static_linker ( ) :
2013-04-20 04:59:06 +08:00
self . static_linker = self . environment . detect_static_linker ( compiler )
2014-03-11 04:35:00 +08:00
if self . has_language ( compiler . get_language ( ) ) :
return
2013-04-20 04:59:06 +08:00
self . compilers . append ( compiler )
2013-08-31 03:20:10 +08:00
def add_cross_compiler ( self , compiler ) :
2013-08-31 04:07:26 +08:00
if len ( self . cross_compilers ) == 0 :
self . static_cross_linker = self . environment . detect_static_linker ( compiler )
2013-12-09 09:18:51 +08:00
for i in self . cross_compilers :
if i . get_language ( ) == compiler . get_language ( ) :
return
2013-08-31 03:20:10 +08:00
self . cross_compilers . append ( compiler )
2013-01-12 04:59:49 +08:00
def get_project ( self ) :
2013-12-09 08:59:15 +08:00
return self . projects [ ' ' ]
2013-01-12 04:59:49 +08:00
def get_targets ( self ) :
return self . targets
def get_tests ( self ) :
return self . tests
2013-01-12 19:53:19 +08:00
2015-11-26 05:29:06 +08:00
def get_benchmarks ( self ) :
return self . benchmarks
2013-01-12 19:53:19 +08:00
def get_headers ( self ) :
return self . headers
2013-01-12 20:31:43 +08:00
def get_man ( self ) :
return self . man
2013-01-14 01:25:54 +08:00
def get_data ( self ) :
return self . data
2013-01-14 07:13:55 +08:00
2014-11-04 05:28:47 +08:00
def get_install_subdirs ( self ) :
return self . install_dirs
2014-06-22 22:10:00 +08:00
def get_global_args ( self , compiler ) :
2013-01-26 07:44:56 +08:00
return self . global_args . get ( compiler . get_language ( ) , [ ] )
2013-09-24 03:34:41 +08:00
2016-05-29 02:31:59 +08:00
def get_global_link_args ( self , compiler ) :
return self . global_link_args . get ( compiler . get_language ( ) , [ ] )
2013-09-24 04:08:50 +08:00
class IncludeDirs ( ) :
2016-01-03 03:34:39 +08:00
def __init__ ( self , curdir , dirs , is_system , extra_build_dirs = None ) :
2013-09-24 04:08:50 +08:00
self . curdir = curdir
self . incdirs = dirs
2016-01-03 03:34:39 +08:00
self . is_system = is_system
2014-01-19 05:11:59 +08:00
# Interpreter has validated that all given directories
# actually exist.
2015-10-04 04:18:40 +08:00
if extra_build_dirs is None :
self . extra_build_dirs = [ ]
else :
self . extra_build_dirs = extra_build_dirs
2013-09-24 04:08:50 +08:00
def get_curdir ( self ) :
return self . curdir
def get_incdirs ( self ) :
return self . incdirs
2015-10-04 04:18:40 +08:00
def get_extra_build_dirs ( self ) :
return self . extra_build_dirs
2013-11-05 07:47:09 +08:00
class ExtractedObjects ( ) :
def __init__ ( self , target , srclist ) :
self . target = target
self . srclist = srclist
2013-09-24 03:34:41 +08:00
class BuildTarget ( ) :
2015-08-12 19:04:41 +08:00
def __init__ ( self , name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) :
2013-09-24 03:34:41 +08:00
self . name = name
self . subdir = subdir
2015-08-12 19:04:41 +08:00
self . subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project.
2013-09-24 03:34:41 +08:00
self . is_cross = is_cross
self . sources = [ ]
2013-11-05 06:16:17 +08:00
self . objects = [ ]
2013-09-24 03:34:41 +08:00
self . external_deps = [ ]
self . include_dirs = [ ]
self . link_targets = [ ]
2014-03-08 02:10:59 +08:00
self . link_depends = [ ]
2013-09-24 03:34:41 +08:00
self . filename = ' no_name '
self . need_install = False
self . pch = { }
self . extra_args = { }
self . generated = [ ]
2014-04-26 03:13:15 +08:00
self . extra_files = [ ]
2013-09-24 03:34:41 +08:00
self . process_sourcelist ( sources )
2013-11-05 06:16:17 +08:00
self . process_objectlist ( objects )
2014-04-26 03:13:15 +08:00
self . process_kwargs ( kwargs , environment )
2014-09-14 18:47:18 +08:00
self . check_unknown_kwargs ( kwargs )
2015-07-22 02:34:18 +08:00
if len ( self . sources ) == 0 and \
len ( self . generated ) == 0 and \
len ( self . objects ) == 0 :
2014-09-14 18:47:18 +08:00
raise InvalidArguments ( ' Build target %s has no sources. ' % name )
self . validate_sources ( )
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
repr_str = " < {0} {1} : {2} > "
return repr_str . format ( self . __class__ . __name__ , self . get_id ( ) , self . filename )
2015-08-12 19:04:41 +08:00
def get_id ( self ) :
2015-09-21 00:51:16 +08:00
# This ID must also be a valid file name on all OSs.
# It should also avoid shell metacharacters for obvious
# reasons.
base = self . name + self . type_suffix ( )
if self . subproject == ' ' :
return base
return self . subproject + ' @@ ' + base
2015-08-12 19:04:41 +08:00
2014-09-14 18:47:18 +08:00
def check_unknown_kwargs ( self , kwargs ) :
# Override this method in derived classes that have more
# keywords.
self . check_unknown_kwargs_int ( kwargs , known_basic_kwargs )
def check_unknown_kwargs_int ( self , kwargs , known_kwargs ) :
2014-08-13 03:44:16 +08:00
unknowns = [ ]
for k in kwargs :
2014-09-14 18:47:18 +08:00
if not k in known_kwargs :
2014-08-13 03:44:16 +08:00
unknowns . append ( k )
if len ( unknowns ) > 0 :
mlog . log ( mlog . bold ( ' Warning: ' ) , ' Unknown keyword argument(s) in target %s : %s . ' %
( self . name , ' , ' . join ( unknowns ) ) )
2013-10-05 04:04:26 +08:00
2013-11-05 06:16:17 +08:00
def process_objectlist ( self , objects ) :
assert ( isinstance ( objects , list ) )
for s in objects :
2013-11-05 07:47:09 +08:00
if hasattr ( s , ' held_object ' ) :
s = s . held_object
2016-08-27 20:47:29 +08:00
if isinstance ( s , ( str , ExtractedObjects ) ) :
2013-11-05 06:16:17 +08:00
self . objects . append ( s )
2016-08-27 20:47:29 +08:00
elif isinstance ( s , ( GeneratedList , CustomTarget ) ) :
2016-08-16 02:45:37 +08:00
msg = ' Generated files are not allowed in the \' objects \' kwarg ' + \
' for target {!r} . \n It is meant only for ' . format ( self . name ) + \
' pre-built object files that are shipped with the \n source ' + \
' tree. Try adding it in the list of sources. '
raise InvalidArguments ( msg )
2013-11-05 06:16:17 +08:00
else :
2016-08-16 02:45:37 +08:00
msg = ' Bad object of type {!r} in target {!r} . ' . format ( type ( s ) . __name__ , self . name )
raise InvalidArguments ( msg )
2013-11-05 06:16:17 +08:00
2013-09-24 03:34:41 +08:00
def process_sourcelist ( self , sources ) :
if not isinstance ( sources , list ) :
sources = [ sources ]
2015-03-14 06:49:10 +08:00
added_sources = { } # If the same source is defined multiple times, use it only once.
2013-09-24 03:34:41 +08:00
for s in sources :
2013-09-24 04:16:54 +08:00
# Holder unpacking. Ugly.
2014-07-27 07:54:23 +08:00
if hasattr ( s , ' held_object ' ) :
s = s . held_object
2015-04-25 23:11:17 +08:00
if isinstance ( s , File ) :
2015-03-14 06:49:10 +08:00
if not s in added_sources :
self . sources . append ( s )
added_sources [ s ] = True
2016-08-27 20:47:29 +08:00
elif isinstance ( s , ( GeneratedList , CustomTarget ) ) :
2013-09-24 03:34:41 +08:00
self . generated . append ( s )
else :
2016-08-16 02:45:37 +08:00
msg = ' Bad source of type {!r} in target {!r} . ' . format ( type ( s ) . __name__ , self . name )
raise InvalidArguments ( msg )
2013-09-24 03:34:41 +08:00
2014-06-23 00:38:47 +08:00
def validate_sources ( self ) :
if len ( self . sources ) > 0 :
2015-04-21 21:27:58 +08:00
firstname = self . sources [ 0 ]
if isinstance ( firstname , File ) :
firstname = firstname . fname
first = os . path . split ( firstname ) [ 1 ]
2014-06-23 00:38:47 +08:00
( base , suffix ) = os . path . splitext ( first )
if suffix == ' .rs ' :
if self . name != base :
raise InvalidArguments ( ' In Rust targets, the first source file must be named projectname.rs. ' )
2013-09-24 03:34:41 +08:00
def get_original_kwargs ( self ) :
return self . kwargs
2013-11-05 07:47:09 +08:00
def unpack_holder ( self , d ) :
if not isinstance ( d , list ) :
d = [ d ]
newd = [ ]
for i in d :
2014-11-08 01:00:57 +08:00
if hasattr ( i , ' held_object ' ) :
2013-11-05 07:47:09 +08:00
newd . append ( i . held_object )
else :
newd . append ( i )
return newd
2013-09-29 00:50:15 +08:00
def copy_kwargs ( self , kwargs ) :
2013-09-24 03:34:41 +08:00
self . kwargs = copy . copy ( kwargs )
2013-09-29 00:50:15 +08:00
# This sucks quite badly. Arguments
# are holders but they can't be pickled
# so unpack those known.
2014-06-24 23:41:24 +08:00
if ' dependencies ' in self . kwargs :
self . kwargs [ ' dependencies ' ] = self . unpack_holder ( self . kwargs [ ' dependencies ' ] )
2013-11-05 07:47:09 +08:00
if ' link_with ' in self . kwargs :
self . kwargs [ ' link_with ' ] = self . unpack_holder ( self . kwargs [ ' link_with ' ] )
2015-04-02 18:54:37 +08:00
def extract_objects ( self , srcargs ) :
2013-11-05 07:47:09 +08:00
obj_src = [ ]
2015-04-02 18:54:37 +08:00
for srclist in srcargs :
if not isinstance ( srclist , list ) :
srclist = [ srclist ]
for src in srclist :
if not isinstance ( src , str ) :
2016-03-23 01:31:55 +08:00
raise MesonException ( ' Extraction arguments must be strings. ' )
2015-04-22 20:53:46 +08:00
src = File ( False , self . subdir , src )
2015-04-02 18:54:37 +08:00
if src not in self . sources :
2016-03-23 01:31:55 +08:00
raise MesonException ( ' Tried to extract unknown source %s . ' % src )
2015-04-02 18:54:37 +08:00
obj_src . append ( src )
2013-11-05 07:47:09 +08:00
return ExtractedObjects ( self , obj_src )
2013-09-29 00:50:15 +08:00
2015-07-22 02:34:18 +08:00
def extract_all_objects ( self ) :
return ExtractedObjects ( self , self . sources )
2015-09-03 05:01:39 +08:00
def get_all_link_deps ( self ) :
return self . get_transitive_link_deps ( )
2013-10-05 04:04:26 +08:00
2015-09-03 05:01:39 +08:00
def get_transitive_link_deps ( self ) :
2013-10-05 04:04:26 +08:00
result = [ ]
for i in self . link_targets :
2015-09-03 05:01:39 +08:00
result + = i . get_all_link_deps ( )
2013-10-05 04:04:26 +08:00
return result
2014-05-22 04:47:23 +08:00
2014-02-13 04:37:25 +08:00
def get_custom_install_dir ( self ) :
return self . custom_install_dir
2013-10-05 04:04:26 +08:00
2014-04-26 03:13:15 +08:00
def process_kwargs ( self , kwargs , environment ) :
2013-09-29 00:50:15 +08:00
self . copy_kwargs ( kwargs )
2013-09-24 03:34:41 +08:00
kwargs . get ( ' modules ' , [ ] )
self . need_install = kwargs . get ( ' install ' , self . need_install )
llist = kwargs . get ( ' link_with ' , [ ] )
if not isinstance ( llist , list ) :
llist = [ llist ]
for linktarget in llist :
2013-09-24 04:08:50 +08:00
# Sorry for this hack. Keyword targets are kept in holders
# in kwargs. Unpack here without looking at the exact type.
2013-11-05 07:47:09 +08:00
if hasattr ( linktarget , " held_object " ) :
linktarget = linktarget . held_object
2013-09-24 03:34:41 +08:00
self . link ( linktarget )
c_pchlist = kwargs . get ( ' c_pch ' , [ ] )
if not isinstance ( c_pchlist , list ) :
c_pchlist = [ c_pchlist ]
self . add_pch ( ' c ' , c_pchlist )
cpp_pchlist = kwargs . get ( ' cpp_pch ' , [ ] )
if not isinstance ( cpp_pchlist , list ) :
cpp_pchlist = [ cpp_pchlist ]
self . add_pch ( ' cpp ' , cpp_pchlist )
clist = kwargs . get ( ' c_args ' , [ ] )
if not isinstance ( clist , list ) :
clist = [ clist ]
self . add_compiler_args ( ' c ' , clist )
cpplist = kwargs . get ( ' cpp_args ' , [ ] )
if not isinstance ( cpplist , list ) :
cpplist = [ cpplist ]
self . add_compiler_args ( ' cpp ' , cpplist )
2014-07-19 06:44:10 +08:00
cslist = kwargs . get ( ' cs_args ' , [ ] )
if not isinstance ( cslist , list ) :
cslist = [ cslist ]
self . add_compiler_args ( ' cs ' , cslist )
2015-07-02 17:13:23 +08:00
valalist = kwargs . get ( ' vala_args ' , [ ] )
if not isinstance ( valalist , list ) :
valalist = [ valalist ]
self . add_compiler_args ( ' vala ' , valalist )
2016-08-21 07:40:29 +08:00
dlist = stringlistify ( kwargs . get ( ' d_args ' , [ ] ) )
2016-08-18 16:42:12 +08:00
self . add_compiler_args ( ' d ' , dlist )
2014-06-22 22:10:00 +08:00
self . link_args = kwargs . get ( ' link_args ' , [ ] )
if not isinstance ( self . link_args , list ) :
self . link_args = [ self . link_args ]
for i in self . link_args :
2014-03-08 01:51:13 +08:00
if not isinstance ( i , str ) :
2014-06-22 22:10:00 +08:00
raise InvalidArguments ( ' Link_args arguments must be strings. ' )
2014-03-08 02:10:59 +08:00
self . link_depends = kwargs . get ( ' link_depends ' , [ ] )
if not isinstance ( self . link_depends , list ) :
self . link_depends = [ self . link_depends ]
for i in self . link_depends :
if not isinstance ( i , str ) :
raise InvalidArguments ( ' Link_depends arguments must be strings. ' )
2014-08-05 05:45:39 +08:00
inclist = kwargs . get ( ' include_directories ' , [ ] )
2013-09-24 03:34:41 +08:00
if not isinstance ( inclist , list ) :
inclist = [ inclist ]
self . add_include_dirs ( inclist )
2014-06-22 22:26:36 +08:00
deplist = kwargs . get ( ' dependencies ' , [ ] )
2013-09-24 03:34:41 +08:00
if not isinstance ( deplist , list ) :
deplist = [ deplist ]
self . add_external_deps ( deplist )
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 InvalidArguments ( ' Custom_install_dir must be a string ' )
2014-03-12 04:30:05 +08:00
main_class = kwargs . get ( ' main_class ' , ' ' )
if not isinstance ( main_class , str ) :
raise InvalidArguments ( ' Main class must be a string ' )
self . main_class = main_class
2014-03-23 01:25:19 +08:00
if isinstance ( self , Executable ) :
self . gui_app = kwargs . get ( ' gui_app ' , False )
if not isinstance ( self . gui_app , bool ) :
raise InvalidArguments ( ' Argument gui_app must be boolean. ' )
elif ' gui_app ' in kwargs :
raise InvalidArguments ( ' Argument gui_app can only be used on executables. ' )
2014-04-26 03:13:15 +08:00
extra_files = kwargs . get ( ' extra_files ' , [ ] )
if isinstance ( extra_files , str ) :
extra_files = [ extra_files ]
for i in extra_files :
if not isinstance ( i , str ) :
raise InvalidArguments ( ' Arguments to extra_files must be strings. ' )
trial = os . path . join ( environment . get_source_dir ( ) , self . subdir , i )
if not ( os . path . isfile ( trial ) ) :
raise InvalidArguments ( ' Tried to add non-existing extra file %s . ' % i )
self . extra_files = extra_files
2014-07-12 01:53:50 +08:00
self . install_rpath = kwargs . get ( ' install_rpath ' , ' ' )
if not isinstance ( self . install_rpath , str ) :
raise InvalidArguments ( ' Install_rpath is not a string. ' )
2014-07-30 20:49:01 +08:00
resources = kwargs . get ( ' resources ' , [ ] )
if not isinstance ( resources , list ) :
resources = [ resources ]
for r in resources :
if not isinstance ( r , str ) :
raise InvalidArguments ( ' Resource argument is not a string. ' )
trial = os . path . join ( environment . get_source_dir ( ) , self . subdir , r )
if not os . path . isfile ( trial ) :
raise InvalidArguments ( ' Tried to add non-existing resource %s . ' % r )
self . resources = resources
2016-02-13 03:57:31 +08:00
if ' name_prefix ' in kwargs :
name_prefix = kwargs [ ' name_prefix ' ]
2016-02-21 23:12:09 +08:00
if isinstance ( name_prefix , list ) :
if len ( name_prefix ) != 0 :
raise InvalidArguments ( ' Array must be empty to signify null. ' )
elif not isinstance ( name_prefix , str ) :
2016-02-13 03:57:31 +08:00
raise InvalidArguments ( ' Name prefix must be a string. ' )
self . prefix = name_prefix
2016-02-21 23:12:09 +08:00
if ' name_suffix ' in kwargs :
name_suffix = kwargs [ ' name_suffix ' ]
if isinstance ( name_suffix , list ) :
if len ( name_suffix ) != 0 :
raise InvalidArguments ( ' Array must be empty to signify null. ' )
2016-02-22 06:09:06 +08:00
else :
if not isinstance ( name_suffix , str ) :
raise InvalidArguments ( ' Name suffix must be a string. ' )
self . suffix = name_suffix
2013-09-24 03:34:41 +08:00
def get_subdir ( self ) :
return self . subdir
def get_filename ( self ) :
return self . filename
def get_extra_args ( self , language ) :
return self . extra_args . get ( language , [ ] )
def get_dependencies ( self ) :
2014-09-03 04:06:07 +08:00
transitive_deps = [ ]
for t in self . link_targets :
transitive_deps . append ( t )
if isinstance ( t , StaticLibrary ) :
transitive_deps + = t . get_dependencies ( )
return transitive_deps
2013-09-24 03:34:41 +08:00
def get_basename ( self ) :
return self . name
def get_source_subdir ( self ) :
return self . subdir
def get_sources ( self ) :
return self . sources
2013-11-05 06:16:17 +08:00
def get_objects ( self ) :
return self . objects
2013-09-24 03:34:41 +08:00
def get_generated_sources ( self ) :
return self . generated
def should_install ( self ) :
return self . need_install
def has_pch ( self ) :
return len ( self . pch ) > 0
def get_pch ( self , language ) :
try :
return self . pch [ language ]
except KeyError :
return [ ]
def get_include_dirs ( self ) :
return self . include_dirs
def add_external_deps ( self , deps ) :
2015-11-05 05:57:26 +08:00
if not isinstance ( deps , list ) :
deps = [ deps ]
2013-09-24 03:34:41 +08:00
for dep in deps :
2014-11-08 01:00:57 +08:00
if hasattr ( dep , ' held_object ' ) :
dep = dep . held_object
2015-06-15 05:26:19 +08:00
if isinstance ( dep , dependencies . InternalDependency ) :
2016-02-29 00:02:50 +08:00
# Those parts that are internal.
2015-07-01 01:58:58 +08:00
self . process_sourcelist ( dep . sources )
2015-06-15 05:26:19 +08:00
self . add_include_dirs ( dep . include_directories )
for l in dep . libraries :
self . link ( l )
2016-02-29 00:02:50 +08:00
# Those parts that are external.
2016-05-29 08:15:16 +08:00
extpart = dependencies . InternalDependency ( ' undefined ' ,
[ ] ,
2016-02-29 00:02:50 +08:00
dep . compile_args ,
dep . link_args ,
[ ] , [ ] , [ ] )
self . external_deps . append ( extpart )
# Deps of deps.
2015-11-05 05:57:26 +08:00
self . add_external_deps ( dep . ext_deps )
2015-06-15 05:26:19 +08:00
elif isinstance ( dep , dependencies . Dependency ) :
self . external_deps . append ( dep )
2013-09-24 03:34:41 +08:00
self . process_sourcelist ( dep . get_sources ( ) )
2015-06-15 05:26:19 +08:00
else :
raise InvalidArguments ( ' Argument is not an external dependency ' )
2013-09-24 03:34:41 +08:00
def get_external_deps ( self ) :
return self . external_deps
def link ( self , target ) :
2014-09-21 00:01:48 +08:00
if not isinstance ( target , list ) :
target = [ target ]
for t in target :
if hasattr ( t , ' held_object ' ) :
t = t . held_object
2016-08-27 20:47:29 +08:00
if not isinstance ( t , ( StaticLibrary , SharedLibrary ) ) :
2014-09-21 00:01:48 +08:00
raise InvalidArguments ( ' Link target is not library. ' )
2015-11-04 07:17:12 +08:00
if self . is_cross != t . is_cross :
raise InvalidArguments ( ' Tried to mix cross built and native libraries in target %s . ' % self . name )
2014-09-21 00:01:48 +08:00
self . link_targets . append ( t )
2013-09-24 03:34:41 +08:00
def set_generated ( self , genlist ) :
for g in genlist :
if not ( isinstance ( g , GeneratedList ) ) :
raise InvalidArguments ( ' Generated source argument is not the output of a generator. ' )
self . generated . append ( g )
def add_pch ( self , language , pchlist ) :
if len ( pchlist ) == 0 :
return
2014-02-24 04:07:54 +08:00
elif len ( pchlist ) == 1 :
if not environment . is_header ( pchlist [ 0 ] ) :
raise InvalidArguments ( ' Pch argument %s is not a header. ' % pchlist [ 0 ] )
elif len ( pchlist ) == 2 :
2013-09-24 03:34:41 +08:00
if environment . is_header ( pchlist [ 0 ] ) :
if not environment . is_source ( pchlist [ 1 ] ) :
2013-10-17 03:33:33 +08:00
raise InvalidArguments ( ' PCH definition must contain one header and at most one source. ' )
2013-09-24 03:34:41 +08:00
elif environment . is_source ( pchlist [ 0 ] ) :
if not environment . is_header ( pchlist [ 1 ] ) :
2013-10-17 03:33:33 +08:00
raise InvalidArguments ( ' PCH definition must contain one header and at most one source. ' )
2013-09-24 03:34:41 +08:00
pchlist = [ pchlist [ 1 ] , pchlist [ 0 ] ]
else :
2013-10-17 03:33:33 +08:00
raise InvalidArguments ( ' PCH argument %s is of unknown type. ' % pchlist [ 0 ] )
2013-09-24 03:34:41 +08:00
elif len ( pchlist ) > 2 :
2013-10-17 03:33:33 +08:00
raise InvalidArguments ( ' PCH definition may have a maximum of 2 files. ' )
2013-09-24 03:34:41 +08:00
self . pch [ language ] = pchlist
def add_include_dirs ( self , args ) :
2013-09-24 04:08:50 +08:00
ids = [ ]
2013-09-24 03:34:41 +08:00
for a in args :
2013-09-24 04:08:50 +08:00
# FIXME same hack, forcibly unpack from holder.
2014-11-08 01:05:15 +08:00
if hasattr ( a , ' held_object ' ) :
a = a . held_object
2013-09-24 03:34:41 +08:00
if not isinstance ( a , IncludeDirs ) :
raise InvalidArguments ( ' Include directory to be added is not an include directory object. ' )
2013-09-24 04:08:50 +08:00
ids . append ( a )
self . include_dirs + = ids
2013-09-24 03:34:41 +08:00
2014-06-22 22:10:00 +08:00
def add_compiler_args ( self , language , args ) :
2015-07-04 03:18:09 +08:00
args = flatten ( args )
2014-06-22 22:10:00 +08:00
for a in args :
2015-07-04 03:18:09 +08:00
if not isinstance ( a , ( str , File ) ) :
2013-09-24 03:34:41 +08:00
raise InvalidArguments ( ' A non-string passed to compiler args. ' )
if language in self . extra_args :
2014-06-22 22:10:00 +08:00
self . extra_args [ language ] + = args
2013-09-24 03:34:41 +08:00
else :
2014-06-22 22:10:00 +08:00
self . extra_args [ language ] = args
2013-09-24 03:34:41 +08:00
def get_aliaslist ( self ) :
return [ ]
2013-09-24 04:08:50 +08:00
class Generator ( ) :
def __init__ ( self , args , kwargs ) :
if len ( args ) != 1 :
raise InvalidArguments ( ' Generator requires one and only one positional argument ' )
2015-03-10 01:39:12 +08:00
exe = args [ 0 ]
if hasattr ( exe , ' held_object ' ) :
exe = exe . held_object
2016-08-27 20:47:29 +08:00
if not isinstance ( exe , ( Executable , dependencies . ExternalProgram ) ) :
2015-03-10 01:39:12 +08:00
raise InvalidArguments ( ' First generator argument must be an executable. ' )
2013-09-24 04:08:50 +08:00
self . exe = exe
2016-08-21 04:11:16 +08:00
self . depfile = None
2013-09-24 04:08:50 +08:00
self . process_kwargs ( kwargs )
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
repr_str = " < {0} : {1} > "
return repr_str . format ( self . __class__ . __name__ , self . exe )
2013-09-24 04:08:50 +08:00
def get_exe ( self ) :
return self . exe
def process_kwargs ( self , kwargs ) :
if ' arguments ' not in kwargs :
raise InvalidArguments ( ' Generator must have " arguments " keyword argument. ' )
args = kwargs [ ' arguments ' ]
if isinstance ( args , str ) :
args = [ args ]
if not isinstance ( args , list ) :
raise InvalidArguments ( ' " Arguments " keyword argument must be a string or a list of strings. ' )
for a in args :
if not isinstance ( a , str ) :
raise InvalidArguments ( ' A non-string object in " arguments " keyword argument. ' )
self . arglist = args
2014-05-24 23:26:34 +08:00
if ' output ' not in kwargs :
raise InvalidArguments ( ' Generator must have " output " keyword argument. ' )
outputs = kwargs [ ' output ' ]
2013-09-24 04:08:50 +08:00
if not isinstance ( outputs , list ) :
outputs = [ outputs ]
for rule in outputs :
if not isinstance ( rule , str ) :
2014-05-24 23:26:34 +08:00
raise InvalidArguments ( ' " output " may only contain strings. ' )
2013-09-24 04:08:50 +08:00
if not ' @BASENAME@ ' in rule and not ' @PLAINNAME@ ' in rule :
2015-10-04 04:18:40 +08:00
raise InvalidArguments ( ' Every element of " output " must contain @BASENAME@ or @PLAINNAME@. ' )
2013-09-24 04:08:50 +08:00
if ' / ' in rule or ' \\ ' in rule :
raise InvalidArguments ( ' " outputs " must not contain a directory separator. ' )
2014-03-22 22:46:38 +08:00
if len ( outputs ) > 1 :
for o in outputs :
if ' @OUTPUT@ ' in o :
raise InvalidArguments ( ' Tried to use @OUTPUT@ in a rule with more than one output. ' )
2013-09-24 04:08:50 +08:00
self . outputs = outputs
2016-08-21 04:11:16 +08:00
if ' depfile ' in kwargs :
depfile = kwargs [ ' depfile ' ]
if not isinstance ( depfile , str ) :
raise InvalidArguments ( ' Depfile must be a string. ' )
if os . path . split ( depfile ) [ 1 ] != depfile :
raise InvalidArguments ( ' Depfile must be a plain filename without a subdirectory. ' )
self . depfile = depfile
2013-09-24 04:08:50 +08:00
def get_base_outnames ( self , inname ) :
plainname = os . path . split ( inname ) [ 1 ]
basename = plainname . split ( ' . ' ) [ 0 ]
return [ x . replace ( ' @BASENAME@ ' , basename ) . replace ( ' @PLAINNAME@ ' , plainname ) for x in self . outputs ]
2016-08-21 04:11:16 +08:00
def get_dep_outname ( self , inname ) :
if self . depfile is None :
raise InvalidArguments ( ' Tried to get dep name for rule that does not have dependency file defined. ' )
plainname = os . path . split ( inname ) [ 1 ]
basename = plainname . split ( ' . ' ) [ 0 ]
return self . depfile . replace ( ' @BASENAME@ ' , basename ) . replace ( ' @PLAINNAME@ ' , plainname )
2013-09-24 04:08:50 +08:00
def get_arglist ( self ) :
return self . arglist
class GeneratedList ( ) :
2015-11-29 01:47:52 +08:00
def __init__ ( self , generator , extra_args = [ ] ) :
2014-11-08 01:05:15 +08:00
if hasattr ( generator , ' held_object ' ) :
generator = generator . held_object
2013-09-24 04:08:50 +08:00
self . generator = generator
self . infilelist = [ ]
self . outfilelist = [ ]
self . outmap = { }
2015-04-09 04:05:14 +08:00
self . extra_depends = [ ]
2015-11-29 01:47:52 +08:00
self . extra_args = extra_args
2013-09-24 04:08:50 +08:00
def add_file ( self , newfile ) :
self . infilelist . append ( newfile )
outfiles = self . generator . get_base_outnames ( newfile )
self . outfilelist + = outfiles
self . outmap [ newfile ] = outfiles
def get_infilelist ( self ) :
return self . infilelist
def get_outfilelist ( self ) :
return self . outfilelist
def get_outputs_for ( self , filename ) :
return self . outmap [ filename ]
def get_generator ( self ) :
return self . generator
2015-11-29 01:47:52 +08:00
def get_extra_args ( self ) :
return self . extra_args
2013-09-24 03:34:41 +08:00
class Executable ( BuildTarget ) :
2015-08-12 19:04:41 +08:00
def __init__ ( self , name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) :
super ( ) . __init__ ( name , subdir , subproject , is_cross , sources , objects , environment , kwargs )
2016-07-01 17:13:51 +08:00
# Unless overriden, executables have no suffix or prefix. Except on
# Windows and with C#/Mono executables where the suffix is 'exe'
if not hasattr ( self , ' prefix ' ) :
self . prefix = ' '
if not hasattr ( self , ' suffix ' ) :
# Executable for Windows or C#/Mono
if for_windows ( is_cross , environment ) or sources_are_suffix ( self . sources , ' cs ' ) :
self . suffix = ' exe '
else :
self . suffix = ' '
self . filename = self . name
if self . suffix :
self . filename + = ' . ' + self . suffix
2013-09-24 03:34:41 +08:00
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @exe "
2013-09-24 03:34:41 +08:00
class StaticLibrary ( BuildTarget ) :
2015-08-12 19:04:41 +08:00
def __init__ ( self , name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) :
super ( ) . __init__ ( name , subdir , subproject , is_cross , sources , objects , environment , kwargs )
2016-07-01 17:13:51 +08:00
if sources_are_suffix ( self . sources , ' cs ' ) :
2014-07-19 04:12:14 +08:00
raise InvalidArguments ( ' Static libraries not supported for C#. ' )
2016-07-01 17:13:51 +08:00
# By default a static library is named libfoo.a even on Windows because
# MSVC does not have a consistent convention for what static libraries
# are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses
# it and GCC only looks for static libraries called foo.lib and
# libfoo.a. However, we cannot use foo.lib because that's the same as
# the import library. Using libfoo.a is ok because people using MSVC
# always pass the library filename while linking anyway.
2016-02-13 03:57:31 +08:00
if not hasattr ( self , ' prefix ' ) :
2016-07-01 17:13:51 +08:00
self . prefix = ' lib '
if not hasattr ( self , ' suffix ' ) :
# Rust static library crates have .rlib suffix
if sources_are_suffix ( self . sources , ' rs ' ) :
self . suffix = ' rlib '
else :
self . suffix = ' a '
2014-04-01 03:07:43 +08:00
self . filename = self . prefix + self . name + ' . ' + self . suffix
2013-09-24 03:34:41 +08:00
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @sta "
2013-09-24 03:34:41 +08:00
class SharedLibrary ( BuildTarget ) :
2015-08-12 19:04:41 +08:00
def __init__ ( self , name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) :
2013-09-24 03:34:41 +08:00
self . soversion = None
2016-07-01 17:13:51 +08:00
self . ltversion = None
2016-02-15 11:35:10 +08:00
self . vs_module_defs = None
2016-07-01 17:13:51 +08:00
# The import library this target will generate
self . import_filename = None
# The import library that Visual Studio would generate (and accept)
self . vs_import_filename = None
# The import library that GCC would generate (and prefer)
self . gcc_import_filename = None
super ( ) . __init__ ( name , subdir , subproject , is_cross , sources , objects , environment , kwargs )
if not hasattr ( self , ' prefix ' ) :
self . prefix = None
if not hasattr ( self , ' suffix ' ) :
self . suffix = None
self . basic_filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
self . determine_filenames ( is_cross , environment )
def determine_filenames ( self , is_cross , env ) :
"""
See https : / / github . com / mesonbuild / meson / pull / 417 for details .
First we determine the filename template ( self . filename_tpl ) , then we
set the output filename ( self . filename ) .
The template is needed while creating aliases ( self . get_aliaslist ) ,
which are needed while generating . so shared libraries for Linux .
Besides this , there ' s also the import library name, which is only used
on Windows since on that platform the linker uses a separate library
called the " import library " during linking instead of the shared
library ( DLL ) . The toolchain will output an import library in one of
two formats : GCC or Visual Studio .
When we ' re building with Visual Studio, the import library that will be
generated by the toolchain is self . vs_import_filename , and with
MinGW / GCC , it ' s self.gcc_import_filename. self.import_filename will
always contain the import library name this target will generate .
"""
prefix = ' '
suffix = ' '
self . filename_tpl = self . basic_filename_tpl
# If the user already provided the prefix and suffix to us, we don't
# need to do any filename suffix/prefix detection.
# NOTE: manual prefix/suffix override is currently only tested for C/C++
if self . prefix != None and self . suffix != None :
pass
# C# and Mono
elif sources_are_suffix ( self . sources , ' cs ' ) :
prefix = ' '
suffix = ' dll '
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
# Rust
elif sources_are_suffix ( self . sources , ' rs ' ) :
# Currently, we always build --crate-type=rlib
2016-02-13 03:57:31 +08:00
prefix = ' lib '
2016-07-01 17:13:51 +08:00
suffix = ' rlib '
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
# C, C++, Swift, Vala
# Only Windows uses a separate import library for linking
# For all other targets/platforms import_filename stays None
elif for_windows ( is_cross , env ) :
2016-02-21 23:12:09 +08:00
suffix = ' dll '
2016-07-01 17:13:51 +08:00
self . vs_import_filename = ' {0} .lib ' . format ( self . name )
self . gcc_import_filename = ' lib {0} .dll.a ' . format ( self . name )
if compiler_is_msvc ( self . sources , is_cross , env ) :
# Shared library is of the form foo.dll
prefix = ' '
# Import library is called foo.lib
self . import_filename = self . vs_import_filename
# Assume GCC-compatible naming
else :
# Shared library is of the form libfoo.dll
prefix = ' lib '
# Import library is called libfoo.dll.a
self . import_filename = self . gcc_import_filename
# Shared library has the soversion if it is defined
if self . soversion :
self . filename_tpl = ' {0.prefix} {0.name} - {0.soversion} . {0.suffix} '
else :
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
elif for_darwin ( is_cross , env ) :
prefix = ' lib '
suffix = ' dylib '
2016-08-16 18:23:55 +08:00
# libfoo.dylib
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
# On OS X, the filename should never have the soversion
# See: https://github.com/mesonbuild/meson/pull/680
2014-07-19 04:12:14 +08:00
else :
2016-07-01 17:13:51 +08:00
prefix = ' lib '
suffix = ' so '
if self . ltversion :
# libfoo.so.X[.Y[.Z]] (.Y and .Z are optional)
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} . {0.ltversion} '
elif self . soversion :
# libfoo.so.X
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} . {0.soversion} '
2016-02-21 23:12:09 +08:00
else :
2016-07-01 17:13:51 +08:00
# No versioning, libfoo.so
self . filename_tpl = ' {0.prefix} {0.name} . {0.suffix} '
if self . prefix == None :
self . prefix = prefix
if self . suffix == None :
self . suffix = suffix
self . filename = self . filename_tpl . format ( self )
2013-09-24 03:34:41 +08:00
2015-06-20 18:45:25 +08:00
def process_kwargs ( self , kwargs , environment ) :
super ( ) . process_kwargs ( kwargs , environment )
2016-07-01 17:13:51 +08:00
# Shared library version
2015-06-20 18:45:25 +08:00
if ' version ' in kwargs :
2016-07-01 17:13:51 +08:00
self . ltversion = kwargs [ ' version ' ]
if not isinstance ( self . ltversion , str ) :
raise InvalidArguments ( ' Shared library version needs to be a string, not ' + type ( self . ltversion ) . __name__ )
if not re . fullmatch ( r ' [0-9]+( \ .[0-9]+) { 0,2} ' , self . ltversion ) :
raise InvalidArguments ( ' Invalid Shared library version " {0} " . Must be of the form X.Y.Z where all three are numbers. Y and Z are optional. ' . format ( self . ltversion ) )
# Try to extract/deduce the soversion
2015-06-20 18:45:25 +08:00
if ' soversion ' in kwargs :
2016-07-01 17:13:51 +08:00
self . soversion = kwargs [ ' soversion ' ]
if isinstance ( self . soversion , int ) :
self . soversion = str ( self . soversion )
if not isinstance ( self . soversion , str ) :
raise InvalidArguments ( ' Shared library soversion is not a string or integer. ' )
try :
int ( self . soversion )
except ValueError :
raise InvalidArguments ( ' Shared library soversion must be a valid integer ' )
elif self . ltversion :
# library version is defined, get the soversion from that
self . soversion = self . ltversion . split ( ' . ' ) [ 0 ]
# Visual Studio module-definitions file
2016-02-15 11:35:10 +08:00
if ' vs_module_defs ' in kwargs :
path = kwargs [ ' vs_module_defs ' ]
if ( os . path . isabs ( path ) ) :
self . vs_module_defs = File . from_absolute_file ( path )
else :
self . vs_module_defs = File . from_source_file ( environment . source_dir , self . subdir , path )
2016-08-18 23:22:22 +08:00
# link_depends can be an absolute path or relative to self.subdir
self . link_depends . append ( path )
2015-06-20 18:45:25 +08:00
2014-09-14 18:47:18 +08:00
def check_unknown_kwargs ( self , kwargs ) :
self . check_unknown_kwargs_int ( kwargs , known_shlib_kwargs )
2014-03-20 04:26:47 +08:00
def get_import_filename ( self ) :
2016-07-01 17:13:51 +08:00
"""
The name of the import library that will be outputted by the compiler
2014-03-20 04:26:47 +08:00
2016-07-01 17:13:51 +08:00
Returns None if there is no import library required for this platform
"""
return self . import_filename
2014-04-03 04:40:04 +08:00
2016-07-01 17:13:51 +08:00
def get_import_filenameslist ( self ) :
if self . import_filename :
return [ self . vs_import_filename , self . gcc_import_filename ]
return [ ]
2013-09-24 03:34:41 +08:00
2016-07-01 17:13:51 +08:00
def get_all_link_deps ( self ) :
return [ self ] + self . get_transitive_link_deps ( )
2013-09-24 03:34:41 +08:00
def get_aliaslist ( self ) :
2016-07-01 17:13:51 +08:00
"""
If the versioned library name is libfoo . so .0 .100 .0 , aliases are :
* libfoo . so .0 ( soversion )
* libfoo . so ( unversioned ; for linking )
"""
# Aliases are only useful with .so libraries. Also if the .so library
# ends with .so (no versioning), we don't need aliases.
if self . suffix != ' so ' or self . filename . endswith ( ' .so ' ) :
return [ ]
# Unversioned alias: libfoo.so
aliases = [ self . basic_filename_tpl . format ( self ) ]
# If ltversion != soversion we create an soversion alias: libfoo.so.X
if self . ltversion and self . ltversion != self . soversion :
if not self . soversion :
# This is done in self.process_kwargs()
raise AssertionError ( ' BUG: If library version is defined, soversion must have been defined ' )
alias_tpl = self . filename_tpl . replace ( ' ltversion ' , ' soversion ' )
aliases . append ( alias_tpl . format ( self ) )
2013-09-24 03:34:41 +08:00
return aliases
2013-09-28 23:54:09 +08:00
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @sha "
2014-05-19 05:59:35 +08:00
class CustomTarget :
2014-08-13 03:51:36 +08:00
known_kwargs = { ' input ' : True ,
' output ' : True ,
' command ' : True ,
2016-08-24 16:35:15 +08:00
' capture ' : False ,
2014-08-13 03:51:36 +08:00
' install ' : True ,
2015-02-07 20:48:38 +08:00
' install_dir ' : True ,
2015-04-02 21:43:35 +08:00
' build_always ' : True ,
2015-10-27 03:12:22 +08:00
' depends ' : True ,
' depend_files ' : True ,
2016-08-21 02:01:49 +08:00
' depfile ' : True ,
2015-10-27 03:12:22 +08:00
}
2015-04-02 21:43:35 +08:00
2014-05-19 05:59:35 +08:00
def __init__ ( self , name , subdir , kwargs ) :
self . name = name
self . subdir = subdir
2014-05-22 04:47:23 +08:00
self . dependencies = [ ]
2015-04-02 21:43:35 +08:00
self . extra_depends = [ ]
2015-10-27 03:12:22 +08:00
self . depend_files = [ ] # Files that this target depends on but are not on the command line.
2016-08-21 02:01:49 +08:00
self . depfile = None
2014-05-19 05:59:35 +08:00
self . process_kwargs ( kwargs )
2014-05-23 21:44:25 +08:00
self . extra_files = [ ]
2014-07-12 01:53:50 +08:00
self . install_rpath = ' '
2014-08-13 03:51:36 +08:00
unknowns = [ ]
for k in kwargs :
if k not in CustomTarget . known_kwargs :
unknowns . append ( k )
if len ( unknowns ) > 0 :
mlog . log ( mlog . bold ( ' Warning: ' ) , ' Unknown keyword arguments in target %s : %s ' %
( self . name , ' , ' . join ( unknowns ) ) )
2014-05-19 05:59:35 +08:00
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
repr_str = " < {0} {1} : {2} > "
return repr_str . format ( self . __class__ . __name__ , self . get_id ( ) , self . command )
2015-08-12 19:04:41 +08:00
def get_id ( self ) :
return self . name + self . type_suffix ( )
2016-03-16 07:00:39 +08:00
def get_target_dependencies ( self ) :
deps = self . dependencies [ : ]
deps + = self . extra_depends
for c in self . sources :
if hasattr ( c , ' held_object ' ) :
c = c . held_object
2016-08-27 20:47:29 +08:00
if isinstance ( c , ( BuildTarget , CustomTarget , GeneratedList ) ) :
2016-03-16 07:00:39 +08:00
deps . append ( c )
return deps
2014-05-19 05:59:35 +08:00
def process_kwargs ( self , kwargs ) :
2014-05-24 23:18:47 +08:00
self . sources = kwargs . get ( ' input ' , [ ] )
if not isinstance ( self . sources , list ) :
self . sources = [ self . sources ]
2014-05-19 05:59:35 +08:00
if ' output ' not in kwargs :
raise InvalidArguments ( ' Missing keyword argument " output " . ' )
self . output = kwargs [ ' output ' ]
2014-07-27 07:54:23 +08:00
if not isinstance ( self . output , list ) :
self . output = [ self . output ]
for i in self . output :
if not ( isinstance ( i , str ) ) :
raise InvalidArguments ( ' Output argument not a string. ' )
if ' / ' in i :
raise InvalidArguments ( ' Output must not contain a path segment. ' )
2016-08-24 16:35:15 +08:00
self . capture = kwargs . get ( ' capture ' , False )
if self . capture and len ( self . output ) != 1 :
raise InvalidArguments (
' Capturing can only output to a single file. ' )
2014-05-19 05:59:35 +08:00
if ' command ' not in kwargs :
raise InvalidArguments ( ' Missing keyword argument " command " . ' )
2016-08-21 02:01:49 +08:00
if ' depfile ' in kwargs :
depfile = kwargs [ ' depfile ' ]
if not isinstance ( depfile , str ) :
raise InvalidArguments ( ' Depfile must be a string. ' )
if os . path . split ( depfile ) [ 1 ] != depfile :
raise InvalidArguments ( ' Depfile must be a plain filename without a subdirectory. ' )
self . depfile = depfile
2014-05-19 05:59:35 +08:00
cmd = kwargs [ ' command ' ]
if not ( isinstance ( cmd , list ) ) :
cmd = [ cmd ]
final_cmd = [ ]
for i , c in enumerate ( cmd ) :
2014-05-22 04:47:23 +08:00
if hasattr ( c , ' held_object ' ) :
c = c . held_object
2016-08-27 20:47:29 +08:00
if isinstance ( c , ( str , File ) ) :
2014-05-19 05:59:35 +08:00
final_cmd . append ( c )
elif isinstance ( c , dependencies . ExternalProgram ) :
2016-03-24 03:26:55 +08:00
if not c . found ( ) :
raise InvalidArguments ( ' Tried to use not found external program in a build rule. ' )
2014-09-20 19:08:48 +08:00
final_cmd + = c . get_command ( )
2016-08-27 20:47:29 +08:00
elif isinstance ( c , ( BuildTarget , CustomTarget ) ) :
2014-05-22 04:47:23 +08:00
self . dependencies . append ( c )
2015-09-03 05:01:39 +08:00
final_cmd . append ( c )
2014-05-24 23:18:47 +08:00
elif isinstance ( c , list ) :
# Hackety hack, only supports one level of flattening. Should really
# work to arbtrary depth.
for s in c :
if not isinstance ( s , str ) :
raise InvalidArguments ( ' Array as argument %d contains a non-string. ' % i )
final_cmd . append ( s )
2014-05-19 05:59:35 +08:00
else :
raise InvalidArguments ( ' Argument %s in " command " is invalid. ' % i )
self . command = final_cmd
2016-08-27 19:41:14 +08:00
if self . capture :
for c in self . command :
if isinstance ( c , str ) and ' @OUTPUT@ ' in c :
raise InvalidArguments ( ' @OUTPUT@ is not allowed when capturing output. ' )
2014-05-19 05:59:35 +08:00
if ' install ' in kwargs :
self . install = kwargs [ ' install ' ]
if not isinstance ( self . install , bool ) :
raise InvalidArguments ( ' " install " must be boolean. ' )
2016-04-18 03:52:10 +08:00
if self . install :
if ' install_dir ' not in kwargs :
raise InvalidArguments ( ' " install_dir " not specified. ' )
self . install_dir = kwargs [ ' install_dir ' ]
if not ( isinstance ( self . install_dir , str ) ) :
raise InvalidArguments ( ' " install_dir " must be a string. ' )
2014-05-19 05:59:35 +08:00
else :
self . install = False
2015-02-08 05:59:36 +08:00
self . build_always = kwargs . get ( ' build_always ' , False )
2015-02-07 20:48:38 +08:00
if not isinstance ( self . build_always , bool ) :
raise InvalidArguments ( ' Argument build_always must be a boolean. ' )
2015-04-02 21:43:35 +08:00
extra_deps = kwargs . get ( ' depends ' , [ ] )
if not isinstance ( extra_deps , list ) :
extra_deps = [ extra_deps ]
for ed in extra_deps :
while hasattr ( ed , ' held_object ' ) :
ed = ed . held_object
2016-08-27 20:47:29 +08:00
if not isinstance ( ed , ( CustomTarget , BuildTarget ) ) :
2015-04-02 21:43:35 +08:00
raise InvalidArguments ( ' Can only depend on toplevel targets. ' )
self . extra_depends . append ( ed )
2015-10-27 03:12:22 +08:00
depend_files = kwargs . get ( ' depend_files ' , [ ] )
if not isinstance ( depend_files , list ) :
depend_files = [ depend_files ]
for i in depend_files :
if isinstance ( i , ( File , str ) ) :
self . depend_files . append ( i )
else :
mlog . debug ( i )
raise InvalidArguments ( ' Unknown type in depend_files. ' )
2014-05-19 05:59:35 +08:00
def get_basename ( self ) :
return self . name
def get_dependencies ( self ) :
2014-05-22 04:47:23 +08:00
return self . dependencies
2014-05-19 05:59:35 +08:00
def should_install ( self ) :
return self . install
def get_custom_install_dir ( self ) :
return self . install_dir
2014-05-22 04:47:23 +08:00
2014-05-19 05:59:35 +08:00
def get_subdir ( self ) :
return self . subdir
def get_filename ( self ) :
return self . output
def get_aliaslist ( self ) :
return [ ]
2014-05-23 21:44:25 +08:00
def get_sources ( self ) :
return self . sources
def get_generated_sources ( self ) :
return [ ]
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @cus "
2014-06-12 03:38:36 +08:00
class RunTarget :
2016-06-25 04:07:57 +08:00
def __init__ ( self , name , command , args , dependencies , subdir ) :
2014-06-12 03:38:36 +08:00
self . name = name
self . command = command
self . args = args
2016-06-25 04:07:57 +08:00
self . dependencies = dependencies
2014-06-12 03:38:36 +08:00
self . subdir = subdir
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
repr_str = " < {0} {1} : {2} > "
return repr_str . format ( self . __class__ . __name__ , self . get_id ( ) , self . command )
2015-08-12 19:04:41 +08:00
def get_id ( self ) :
return self . name + self . type_suffix ( )
2014-06-12 03:38:36 +08:00
def get_basename ( self ) :
return self . name
def get_dependencies ( self ) :
2016-06-25 04:07:57 +08:00
return self . dependencies
2014-06-12 03:38:36 +08:00
def get_generated_sources ( self ) :
return [ ]
2015-05-03 20:06:04 +08:00
def get_sources ( self ) :
return [ ]
2014-06-12 03:38:36 +08:00
def get_subdir ( self ) :
return self . subdir
def should_install ( self ) :
return False
def get_filename ( self ) :
return self . name
2014-08-13 03:51:36 +08:00
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @run "
2014-03-11 05:33:24 +08:00
class Jar ( BuildTarget ) :
2015-08-12 19:04:41 +08:00
def __init__ ( self , name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) :
super ( ) . __init__ ( name , subdir , subproject , is_cross , sources , objects , environment , kwargs ) ;
2014-03-11 05:33:24 +08:00
for s in self . sources :
if not s . endswith ( ' .java ' ) :
raise InvalidArguments ( ' Jar source %s is not a java file. ' % s )
2014-03-11 06:23:20 +08:00
self . filename = self . name + ' .jar '
2016-01-11 04:31:56 +08:00
incdirs = kwargs . get ( ' include_directories ' , [ ] )
2014-03-11 05:33:24 +08:00
2014-03-12 04:30:05 +08:00
def get_main_class ( self ) :
return self . main_class
2015-07-05 06:47:34 +08:00
def type_suffix ( self ) :
return " @jar "
2013-09-28 23:54:09 +08:00
class ConfigureFile ( ) :
def __init__ ( self , subdir , sourcename , targetname , configuration_data ) :
self . subdir = subdir
self . sourcename = sourcename
self . targetname = targetname
self . configuration_data = configuration_data
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
repr_str = " < {0} : {1} -> {2} > "
src = os . path . join ( self . subdir , self . sourcename )
dst = os . path . join ( self . subdir , self . targetname )
return repr_str . format ( self . __class__ . __name__ , src , dst )
2013-09-28 23:54:09 +08:00
def get_configuration_data ( self ) :
return self . configuration_data
def get_subdir ( self ) :
return self . subdir
def get_source_name ( self ) :
return self . sourcename
def get_target_name ( self ) :
return self . targetname
class ConfigurationData ( ) :
def __init__ ( self ) :
super ( ) . __init__ ( )
self . values = { }
2016-07-01 17:13:51 +08:00
def __repr__ ( self ) :
return repr ( self . values )
2013-09-28 23:54:09 +08:00
def get ( self , name ) :
return self . values [ name ]
def keys ( self ) :
return self . values . keys ( )
2014-02-06 06:16:23 +08:00
2015-12-23 21:10:27 +08:00
# A bit poorly named, but this represents plain data files to copy
# during install.
class Data ( ) :
def __init__ ( self , in_sourcetree , source_subdir , sources , install_dir ) :
self . in_sourcetree = in_sourcetree
self . source_subdir = source_subdir
self . sources = sources
self . install_dir = install_dir
2015-07-30 07:01:47 +08:00
class InstallScript :
def __init__ ( self , cmd_arr ) :
assert ( isinstance ( cmd_arr , list ) )
self . cmd_arr = cmd_arr