Skip to content

Commit

Permalink
Add build_args() that can be passed as extra_args to build targets
Browse files Browse the repository at this point in the history
The principal use-case is to pass different compiler flags to library()
depending if it's building the static or shared library.

Closes: mesonbuild#3304
  • Loading branch information
xclaesse committed Mar 26, 2018
1 parent 5dcd724 commit 762a80b
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
36 changes: 34 additions & 2 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
'native': True,
'build_by_default': True,
'override_options': True,
'extra_args': True,
}

# These contain kwargs supported by both static and shared libraries. These are
Expand Down Expand Up @@ -667,9 +668,9 @@ def process_kwargs(self, kwargs, environment):
for linktarget in lwhole:
self.link_whole(linktarget)

c_pchlist, cpp_pchlist, clist, cpplist, cslist, valalist, objclist, objcpplist, fortranlist, rustlist \
c_pchlist, cpp_pchlist, clist, cpplist, cslist, valalist, objclist, objcpplist, fortranlist, rustlist, extra_args \
= extract_as_list(kwargs, 'c_pch', 'cpp_pch', 'c_args', 'cpp_args', 'cs_args', 'vala_args', 'objc_args',
'objcpp_args', 'fortran_args', 'rust_args')
'objcpp_args', 'fortran_args', 'rust_args', 'extra_args')

self.add_pch('c', c_pchlist)
self.add_pch('cpp', cpp_pchlist)
Expand All @@ -679,6 +680,15 @@ def process_kwargs(self, kwargs, environment):
for key, value in compiler_args.items():
self.add_compiler_args(key, value)

for obj in extra_args:
obj = obj.held_object
if not isinstance(obj, BuildArgs):
raise InvalidArguments('extra_args must be a list of build_args objects.')
for target_type in self.target_types:
compiler_args = obj.compiler_args.get(target_type, {})
for key, value in compiler_args.items():
self.add_compiler_args(key, value)

if not isinstance(self, Executable):
self.vala_header = kwargs.get('vala_header', self.name + '.h')
self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi')
Expand Down Expand Up @@ -1174,6 +1184,8 @@ def get_extra_args(self):
return self.extra_args

class Executable(BuildTarget):
target_types = ['executable']

def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
# Unless overridden, executables have no suffix or prefix. Except on
Expand Down Expand Up @@ -1249,6 +1261,8 @@ def is_linkable_target(self):
return self.is_linkwithable

class StaticLibrary(BuildTarget):
target_types = ['library', 'static_library']

def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options:
kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value
Expand Down Expand Up @@ -1303,6 +1317,8 @@ def is_linkable_target(self):
return True

class SharedLibrary(BuildTarget):
target_types = ['library', 'shared_library']

def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
self.soversion = None
self.ltversion = None
Expand Down Expand Up @@ -1804,6 +1820,8 @@ def type_suffix(self):
return "@run"

class Jar(BuildTarget):
target_type = ['jar']

def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
for s in self.sources:
Expand Down Expand Up @@ -1927,6 +1945,20 @@ def __init__(self, *, exe_wrapper=None, gdb=None, timeout_multiplier=None, env=N
self.timeout_multiplier = timeout_multiplier
self.env = env

class BuildArgs:
def __init__(self):
self.compiler_args = {}

def __repr__(self):
return repr(self.compiler_args)

def add_compiler_args(self, compiler_args, target_type, language):
if target_type not in self.compiler_args:
self.compiler_args[target_type] = {}
if language not in self.compiler_args[target_type]:
self.compiler_args[target_type][language] = []
self.compiler_args[target_type][language] += compiler_args

def get_sources_string_names(sources):
'''
For the specified list of @sources which can be strings, Files, or targets,
Expand Down
47 changes: 47 additions & 0 deletions mesonbuild/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,41 @@ def first_supported_argument_method(self, args, kwargs):
mlog.log('First supported argument:', mlog.red('None'))
return []

class BuildArgsHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self):
InterpreterObject.__init__(self)
ObjectHolder.__init__(self, build.BuildArgs())
self.used = False # These objects become immutable after use.
self.methods.update({'add_compiler_args': self.add_compiler_args,
})

def is_used(self):
return self.used

def mark_used(self):
self.used = True

@permittedMethodKwargs({'target_type', 'language'})
def add_compiler_args(self, args, kwargs):
if self.used:
raise InterpreterException("Can not set values on build_args object that has been used.")

check_stringlist(args)

if 'target_type' not in kwargs:
raise InterpreterException('Missing target_type keyword argument')
target_type = kwargs['target_type']
if not isinstance(target_type, str):
raise InterpreterException('target_type keyword argument must be a string')

if 'language' not in kwargs:
raise InterpreterException('Missing language keyword argument')
language = kwargs['language']
if not isinstance(language, str):
raise InterpreterException('language keyword argument must be a string')

self.held_object.add_compiler_args(args, target_type, language)

ModuleState = namedtuple('ModuleState', [
'build_to_src', 'subproject', 'subdir', 'current_lineno', 'environment',
'project_name', 'project_version', 'backend', 'compilers', 'targets',
Expand Down Expand Up @@ -1444,6 +1479,7 @@ def get_cross_property_method(self, args, kwargs):
'build_by_default',
'build_rpath',
'dependencies',
'extra_args',
'extra_files',
'gui_app',
'link_with',
Expand Down Expand Up @@ -1575,6 +1611,7 @@ def build_func_dict(self):
'assert': self.func_assert,
'benchmark': self.func_benchmark,
'build_target': self.func_build_target,
'build_args': self.func_build_args,
'configuration_data': self.func_configuration_data,
'configure_file': self.func_configure_file,
'custom_target': self.func_custom_target,
Expand Down Expand Up @@ -2573,6 +2610,11 @@ def func_build_target(self, node, args, kwargs):
else:
raise InterpreterException('Unknown target_type.')

@noKwargs
@noPosargs
def func_build_args(self, node, args, kwargs):
return BuildArgsHolder()

@permittedKwargs(permitted_kwargs['vcs_tag'])
def func_vcs_tag(self, node, args, kwargs):
if 'input' not in kwargs or 'output' not in kwargs:
Expand Down Expand Up @@ -3234,6 +3276,11 @@ def build_target(self, node, args, kwargs, targetholder):
if 'extra_files' in kwargs:
ef = extract_as_list(kwargs, 'extra_files')
kwargs['extra_files'] = self.source_strings_to_files(ef)
extra_args = extract_as_list(kwargs, 'extra_args')
for item in extra_args:
if not isinstance(item, BuildArgsHolder):
raise InterpreterException('Argument "extra_args" is not a list of build_args')
item.mark_used()
self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
if targetholder is ExecutableHolder:
targetclass = build.Executable
Expand Down

0 comments on commit 762a80b

Please sign in to comment.