diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2017-04-09 21:57:46 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-09 21:57:46 +0300 |
commit | 1652dccea2c1c4729f74ae66c7af5e3decf3dc5b (patch) | |
tree | 70e8aec9bcc1037ea406ab422c196cbbd792aaba /mesonbuild | |
parent | 0e8eba7f644571ea0beb40334d2a3d0b150ac4ef (diff) | |
parent | aa3480dabaaf8fe164ae9fa5115cc092277245f5 (diff) | |
download | meson-1652dccea2c1c4729f74ae66c7af5e3decf3dc5b.zip meson-1652dccea2c1c4729f74ae66c7af5e3decf3dc5b.tar.gz meson-1652dccea2c1c4729f74ae66c7af5e3decf3dc5b.tar.bz2 |
Merge pull request #1469 from centricular/install-secondary-outputs
Support multiple install dirs for built/custom targets
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 4 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 96 | ||||
-rw-r--r-- | mesonbuild/build.py | 50 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 23 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 4 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 5 |
7 files changed, 120 insertions, 64 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index efc5bff..2e630bd 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -601,7 +601,7 @@ class Backend: for t in target.get_generated_sources(): if not isinstance(t, build.CustomTarget): continue - for f in t.output: + for f in t.get_outputs(): if self.environment.is_library(f): libs.append(os.path.join(self.get_target_dir(t), f)) return libs @@ -642,7 +642,7 @@ class Backend: build_root = self.environment.get_source_dir() outdir = os.path.join(self.environment.get_build_dir(), outdir) outputs = [] - for i in target.output: + for i in target.get_outputs(): outputs.append(os.path.join(outdir, i)) inputs = self.get_custom_target_sources(target) # Evaluate the command list diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 5a9462f..4c87951 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -633,40 +633,86 @@ int dummy; def generate_target_install(self, d): for t in self.build.get_targets().values(): - if t.should_install(): + if not t.should_install(): + continue + # Find the installation directory. + outdirs = t.get_custom_install_dir() + custom_install_dir = False + if outdirs[0] is not None and outdirs[0] is not True: + # Either the value is set, or is set to False which means + # we want this specific output out of many outputs to not + # be installed. + custom_install_dir = True + elif isinstance(t, build.SharedLibrary): + outdirs[0] = self.environment.get_shared_lib_dir() + elif isinstance(t, build.StaticLibrary): + outdirs[0] = self.environment.get_static_lib_dir() + elif isinstance(t, build.Executable): + outdirs[0] = self.environment.get_bindir() + else: + assert(isinstance(t, build.BuildTarget)) + # XXX: Add BuildTarget-specific install dir cases here + outdirs[0] = self.environment.get_libdir() + # Sanity-check the outputs and install_dirs + num_outdirs, num_out = len(outdirs), len(t.get_outputs()) + if num_outdirs != 1 and num_outdirs != num_out: + m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \ + "Pass 'false' for outputs that should not be installed and 'true' for\n" \ + 'using the default installation directory for an output.' + raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs)) + # Install the target output(s) + if isinstance(t, build.BuildTarget): should_strip = self.get_option_for_target('strip', t) - # Find the installation directory. FIXME: Currently only one - # installation directory is supported for each target - outdir = t.get_custom_install_dir() - if outdir is not None: - pass - elif isinstance(t, build.SharedLibrary): - # For toolchains/platforms that need an import library for + # Install primary build output (library/executable/jar, etc) + # Done separately because of strip/aliases/rpath + if outdirs[0] is not False: + i = [self.get_target_filename(t), outdirs[0], + t.get_aliases(), should_strip, t.install_rpath] + d.targets.append(i) + # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the - # code), we need to install the import library (dll.a/.lib) - if t.get_import_filename(): + # code), we need to install that too (dll.a/.lib). + if isinstance(t, build.SharedLibrary) and t.get_import_filename(): + if custom_install_dir: + # If the DLL is installed into a custom directory, + # install the import library into the same place so + # it doesn't go into a surprising place + implib_install_dir = outdirs[0] + else: + implib_install_dir = self.environment.get_import_lib_dir() # Install the import library. i = [self.get_target_filename_for_linking(t), - self.environment.get_import_lib_dir(), + implib_install_dir, # It has no aliases, should not be stripped, and # doesn't have an install_rpath {}, False, ''] d.targets.append(i) - outdir = self.environment.get_shared_lib_dir() - elif isinstance(t, build.StaticLibrary): - outdir = self.environment.get_static_lib_dir() - elif isinstance(t, build.Executable): - outdir = self.environment.get_bindir() - else: - # XXX: Add BuildTarget-specific install dir cases here - outdir = self.environment.get_libdir() - if isinstance(t, build.BuildTarget): - i = [self.get_target_filename(t), outdir, t.get_aliases(), - should_strip, t.install_rpath] - d.targets.append(i) - elif isinstance(t, build.CustomTarget): + # Install secondary outputs. Only used for Vala right now. + if num_outdirs > 1: + for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]): + # User requested that we not install this output + if outdir is False: + continue + f = os.path.join(self.get_target_dir(t), output) + d.targets.append([f, outdir, {}, False, None]) + elif isinstance(t, build.CustomTarget): + # If only one install_dir is specified, assume that all + # outputs will be installed into it. This is for + # backwards-compatibility and because it makes sense to + # avoid repetition since this is a common use-case. + # + # To selectively install only some outputs, pass `false` as + # the install_dir for the corresponding output by index + if num_outdirs == 1 and num_out > 1: for output in t.get_outputs(): f = os.path.join(self.get_target_dir(t), output) + d.targets.append([f, outdirs[0], {}, False, None]) + else: + for output, outdir in zip(t.get_outputs(), outdirs): + # User requested that we not install this output + if outdir is False: + continue + f = os.path.join(self.get_target_dir(t), output) d.targets.append([f, outdir, {}, False, None]) def generate_custom_install_script(self, d): @@ -1032,10 +1078,12 @@ int dummy; # Without this, it will write it inside c_out_dir args += ['--vapi', os.path.join('..', target.vala_vapi)] valac_outputs.append(vapiname) + target.outputs += [target.vala_header, target.vala_vapi] if isinstance(target.vala_gir, str): girname = os.path.join(self.get_target_dir(target), target.vala_gir) args += ['--gir', os.path.join('..', target.vala_gir)] valac_outputs.append(girname) + target.outputs.append(target.vala_gir) if self.get_option_for_target('werror', target): args += valac.get_werror_args() for d in target.get_external_deps(): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 537c91b..df3f37b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -19,7 +19,7 @@ from . import environment from . import dependencies from . import mlog from .mesonlib import File, MesonException -from .mesonlib import flatten, stringlistify, classify_unity_sources +from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources from .mesonlib import get_filenames_templates_dict, substitute_values from .environment import for_windows, for_darwin, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes @@ -318,6 +318,9 @@ class BuildTarget(Target): self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' + # The list of all files outputted by this target. Useful in cases such + # as Vala which generates .vapi and .h besides the compiled output. + self.outputs = [self.filename] self.need_install = False self.pch = {} self.extra_args = {} @@ -544,7 +547,7 @@ class BuildTarget(Target): return result def get_custom_install_dir(self): - return self.custom_install_dir + return self.install_dir def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs) @@ -591,7 +594,7 @@ class BuildTarget(Target): 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') - self.vala_gir = kwargs.get('vala_gir', None) + self.vala_gir = kwargs.get('vala_gir', None) dlist = stringlistify(kwargs.get('d_args', [])) self.add_compiler_args('d', dlist) self.link_args = kwargs.get('link_args', []) @@ -617,10 +620,10 @@ class BuildTarget(Target): if not isinstance(deplist, list): deplist = [deplist] self.add_deps(deplist) - 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') + # If an item in this list is False, the output corresponding to + # the list index of that item will not be installed + self.install_dir = typeslistify(kwargs.get('install_dir', [None]), + (str, bool)) main_class = kwargs.get('main_class', '') if not isinstance(main_class, str): raise InvalidArguments('Main class must be a string') @@ -691,7 +694,7 @@ class BuildTarget(Target): return self.filename def get_outputs(self): - return [self.filename] + return self.outputs def get_extra_args(self, language): return self.extra_args.get(language, []) @@ -1005,6 +1008,7 @@ class Executable(BuildTarget): self.filename = self.name if self.suffix: self.filename += '.' + self.suffix + self.outputs = [self.filename] def type_suffix(self): return "@exe" @@ -1032,6 +1036,7 @@ class StaticLibrary(BuildTarget): else: self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix + self.outputs = [self.filename] def type_suffix(self): return "@sta" @@ -1160,6 +1165,7 @@ class SharedLibrary(BuildTarget): if self.suffix is None: self.suffix = suffix self.filename = self.filename_tpl.format(self) + self.outputs = [self.filename] def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs, environment) @@ -1253,6 +1259,7 @@ class SharedModule(SharedLibrary): if 'soversion' in kwargs: raise MesonException('Shared modules must not specify the soversion kwarg.') super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) + self.import_filename = None class CustomTarget(Target): known_kwargs = {'input': True, @@ -1334,13 +1341,13 @@ class CustomTarget(Target): self.sources = [self.sources] if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') - self.output = kwargs['output'] - if not isinstance(self.output, list): - self.output = [self.output] + self.outputs = kwargs['output'] + if not isinstance(self.outputs, list): + self.outputs = [self.outputs] # This will substitute values from the input into output and return it. inputs = get_sources_string_names(self.sources) values = get_filenames_templates_dict(inputs, []) - for i in self.output: + for i in self.outputs: if not(isinstance(i, str)): raise InvalidArguments('Output argument not a string.') if '/' in i: @@ -1355,9 +1362,9 @@ class CustomTarget(Target): m = "Output cannot contain @PLAINNAME@ or @BASENAME@ when " \ "there is more than one input (we can't know which to use)" raise InvalidArguments(m) - self.output = substitute_values(self.output, values) + self.outputs = substitute_values(self.outputs, values) self.capture = kwargs.get('capture', False) - if self.capture and len(self.output) != 1: + if self.capture and len(self.outputs) != 1: raise InvalidArguments('Capturing can only output to a single file.') if 'command' not in kwargs: raise InvalidArguments('Missing keyword argument "command".') @@ -1379,12 +1386,14 @@ class CustomTarget(Target): raise InvalidArguments('"install" must be boolean.') 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.') + raise InvalidArguments('"install_dir" must be specified ' + 'when installing a target') + # If an item in this list is False, the output corresponding to + # the list index of that item will not be installed + self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) else: self.install = False + self.install_dir = [None] self.build_always = kwargs.get('build_always', False) if not isinstance(self.build_always, bool): raise InvalidArguments('Argument build_always must be a boolean.') @@ -1417,10 +1426,10 @@ class CustomTarget(Target): return self.install_dir def get_outputs(self): - return self.output + return self.outputs def get_filename(self): - return self.output[0] + return self.outputs[0] def get_sources(self): return self.sources @@ -1479,6 +1488,7 @@ class Jar(BuildTarget): if not s.endswith('.java'): raise InvalidArguments('Jar source %s is not a java file.' % s) self.filename = self.name + '.jar' + self.outputs = [self.filename] self.java_args = kwargs.get('java_args', []) def get_main_class(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 8c8000c..2f8e5f6 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2243,7 +2243,7 @@ class Interpreter(InterpreterBase): if 'install_mode' not in kwargs: return None install_mode = [] - mode = mesonlib.stringintlistify(kwargs.get('install_mode', [])) + mode = mesonlib.typeslistify(kwargs.get('install_mode', []), (str, int)) for m in mode: # We skip any arguments that are set to `false` if m is False: diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index a2ab484..5377d8e 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -467,25 +467,22 @@ def replace_if_different(dst, dst_tmp): else: os.unlink(dst_tmp) -def stringintlistify(item): - if isinstance(item, (str, int)): +def typeslistify(item, types): + ''' + Ensure that type(@item) is one of @types or a + list of items all of which are of type @types + ''' + if isinstance(item, types): item = [item] if not isinstance(item, list): - raise MesonException('Item must be a list, a string, or an int') + raise MesonException('Item must be a list or one of {!r}'.format(types)) for i in item: - if not isinstance(i, (str, int, type(None))): - raise MesonException('List item must be a string or an int') + if i is not None and not isinstance(i, types): + raise MesonException('List item must be one of {!r}'.format(types)) return item def stringlistify(item): - if isinstance(item, str): - item = [item] - if not isinstance(item, list): - raise MesonException('Item is not a list') - for i in item: - if not isinstance(i, str): - raise MesonException('List item not a string.') - return item + return typeslistify(item, str) def expand_arguments(args): expended_args = [] diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 55f1de0..adb6fa8 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1001,7 +1001,7 @@ class GnomeModule(ExtensionModule): target.get_subdir()) outdir = os.path.join(state.environment.get_build_dir(), target.get_subdir()) - outfile = target.output[0][:-5] # Strip .vapi + outfile = target.get_outputs()[0][:-5] # Strip .vapi ret.append('--vapidir=' + outdir) ret.append('--girdir=' + outdir) ret.append('--pkg=' + outfile) @@ -1068,7 +1068,7 @@ class GnomeModule(ExtensionModule): link_with += self._get_vapi_link_with(i.held_object) subdir = os.path.join(state.environment.get_build_dir(), i.held_object.get_subdir()) - gir_file = os.path.join(subdir, i.held_object.output[0]) + gir_file = os.path.join(subdir, i.held_object.get_outputs()[0]) cmd.append(gir_file) else: raise MesonException('Input must be a str or GirTarget') diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index e46c239..e79371f 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -76,8 +76,9 @@ class PkgConfigModule(ExtensionModule): if isinstance(l, str): yield l else: - if l.custom_install_dir: - yield '-L${prefix}/%s ' % l.custom_install_dir + install_dir = l.get_custom_install_dir()[0] + if install_dir: + yield '-L${prefix}/%s ' % install_dir else: yield '-L${libdir}' lname = self._get_lname(l, msg, pcfile) |