diff options
13 files changed, 175 insertions, 74 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a3c36c2..fa537ad 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -264,7 +264,6 @@ int dummy; if isinstance(target, build.RunTarget): self.generate_run_target(target, outfile) name = target.get_id() - vala_gen_sources = [] if name in self.processed_targets: return self.processed_targets[name] = True @@ -285,14 +284,22 @@ int dummy; self.generate_swift_target(target, outfile) return - # Pre-existing target C/C++ sources to be built - target_sources = [] - # GeneratedList and CustomTarget sources to be built - generated_sources = [] + # Pre-existing target C/C++ sources to be built; dict of full path to + # source relative to build root and the original File object. + target_sources = {} + # GeneratedList and CustomTarget sources to be built; dict of the full + # path to source relative to build root and the generating target/list + generated_sources = {} + # Array of sources generated by valac that have to be compiled + vala_generated_sources = [] if 'vala' in target.compilers: - vala_gen_sources = self.generate_vala_compile(target, outfile) - target_sources = self.get_target_sources(target) - generated_sources = self.get_target_generated_sources(target) + # Sources consumed by valac are filtered out. These only contain + # C/C++ sources, objects, generated libs, and unknown sources now. + target_sources, generated_sources, \ + vala_generated_sources = self.generate_vala_compile(target, outfile) + else: + target_sources = self.get_target_sources(target) + generated_sources = self.get_target_generated_sources(target) self.scan_fortran_module_outputs(target) # Generate rules for GeneratedLists self.generate_generator_list_rules(target, outfile) @@ -347,8 +354,8 @@ int dummy; header_deps=header_deps)) # Generate compilation targets for C sources generated from Vala # sources. This can be extended to other $LANG->C compilers later if - # necessary. - for src in vala_gen_sources: + # necessary. This needs to be separate for at least Vala + for src in vala_generated_sources: src_list.append(src) if is_unity: unity_src.append(os.path.join(self.environment.get_build_dir(), src)) @@ -368,8 +375,6 @@ int dummy; obj_list.append(self.generate_single_compile(target, outfile, src, 'vala', [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for f, src in target_sources.items(): - if src.endswith('.vala'): - continue if not self.environment.is_header(src): src_list.append(src) if is_unity: @@ -871,17 +876,13 @@ int dummy; outfile.write(description) outfile.write('\n') - def split_vala_sources(self, sources): - other_src = [] - vapi_src = [] - for s in sources: - if s.endswith('.vapi'): - vapi_src.append(s) - else: - other_src.append(s) - return (other_src, vapi_src) - def determine_dep_vapis(self, target): + """ + Peek into the sources of BuildTargets we're linking with, and if any of + them was built with Vala, assume that it also generated a .vapi file of + the same name as the BuildTarget and return the path to it relative to + the build directory. + """ result = [] for dep in target.link_targets: for i in dep.sources: @@ -894,57 +895,119 @@ int dummy; break return result + def split_vala_sources(self, t): + """ + Splits the target's sources into .vala, .vapi, and other sources. + Handles both pre-existing and generated sources. + + Returns a tuple (vala, vapi, others) each of which is a dictionary with + the keys being the path to the file (relative to the build directory) + and the value being the object that generated or represents the file. + """ + vala = {} + vapi = {} + others = {} + othersgen = {} + # Split pre-existing sources + for s in t.get_sources(): + # BuildTarget sources are always mesonlib.File files which are + # either in the source root, or generated with configure_file and + # in the build root + if not isinstance(s, File): + msg = 'All sources in target {!r} must be of type ' \ + 'mesonlib.File, not {!r}'.format(t, s) + raise InvalidArguments(msg) + f = s.rel_to_builddir(self.build_to_src) + if s.endswith('.vala'): + srctype = vala + elif s.endswith('.vapi'): + srctype = vapi + else: + srctype = others + srctype[f] = s + # Split generated sources + for gensrc in t.get_generated_sources(): + for s in gensrc.get_outputs(): + f = self.get_target_generated_dir(t, gensrc, s) + if s.endswith('.vala'): + srctype = vala + elif s.endswith('.vapi'): + srctype = vapi + # Generated non-Vala (C/C++) sources. Won't be used for + # generating the Vala compile rule below. + else: + srctype = othersgen + # Duplicate outputs are disastrous + if f in srctype: + msg = 'Duplicate output {0!r} from {1!r} {2!r}; ' \ + 'conflicts with {0!r} from {4!r} {3!r}' \ + ''.format(f, type(gensrc).__name__, gensrc.name, + srctype[f].name, type(srctype[f]).__name__) + raise InvalidArguments(msg) + # Store 'somefile.vala': GeneratedList (or CustomTarget) + srctype[f] = gensrc + return (vala, vapi, (others, othersgen)) + def generate_vala_compile(self, target, outfile): """Vala is compiled into C. Set up all necessary build steps here.""" - valac = target.compilers['vala'] - (other_src, vapi_src) = self.split_vala_sources(target.get_sources()) - vapi_src = [x.rel_to_builddir(self.build_to_src) for x in vapi_src] + (vala_src, vapi_src, other_src) = self.split_vala_sources(target) extra_dep_files = [] - if len(other_src) == 0: + if len(vala_src) == 0: raise InvalidArguments('Vala library has no Vala source files.') - namebase = target.name - base_h = namebase + '.h' - base_vapi = namebase + '.vapi' - hname = os.path.normpath(os.path.join(self.get_target_dir(target), base_h)) - vapiname = os.path.normpath(os.path.join(self.get_target_dir(target), base_vapi)) - - generated_c_files = [] - outputs = [vapiname] - args = [] - args += self.build.get_global_args(valac) - args += valac.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype')) - args += ['-d', self.get_target_private_dir(target)] - args += ['-C']#, '-o', cname] - if not isinstance(target, build.Executable): - outputs.append(hname) - args += ['-H', hname] - args += ['--library=' + target.name] - args += ['--vapi=' + os.path.join('..', base_vapi)] - vala_src = [] - for s in other_src: - if not s.endswith('.vala'): - continue - vala_file = s.rel_to_builddir(self.build_to_src) - vala_src.append(vala_file) + + valac = target.compilers['vala'] + c_out_dir = self.get_target_private_dir(target) + # C files generated by valac + vala_c_src = [] + # Files generated by valac + valac_outputs = [] + # All sources that are passed to valac on the commandline + all_files = list(vapi_src.keys()) + for (vala_file, gensrc) in vala_src.items(): + all_files.append(vala_file) # Figure out where the Vala compiler will write the compiled C file - dirname, basename = os.path.split(vala_file) # If the Vala file is in a subdir of the build dir (in our case # because it was generated/built by something else), the subdir path # components will be preserved in the output path. But if the Vala # file is outside the build directory, the path components will be # stripped and just the basename will be used. - c_file = os.path.splitext(basename)[0] + '.c' - if s.is_built: - c_file = os.path.join(dirname, c_file) - full_c = os.path.join(self.get_target_private_dir(target), c_file) - generated_c_files.append(full_c) - outputs.append(full_c) + if isinstance(gensrc, (build.CustomTarget, build.GeneratedList)) or gensrc.is_built: + vala_c_file = os.path.splitext(vala_file)[0] + '.c' + else: + vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c' + # All this will be placed inside the c_out_dir + vala_c_file = os.path.join(c_out_dir, vala_c_file) + vala_c_src.append(vala_c_file) + valac_outputs.append(vala_c_file) + + args = [] + args += self.build.get_global_args(valac) + args += valac.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype')) + # Tell Valac to output everything in our private directory. Sadly this + # means it will also preserve the directory components of Vala sources + # found inside the build tree (generated sources). + args += ['-d', c_out_dir] + args += ['-C'] + if not isinstance(target, build.Executable): + # Library name + args += ['--library=' + target.name] + # Outputted header + hname = os.path.join(self.get_target_dir(target), target.name + '.h') + args += ['-H', hname] + valac_outputs.append(hname) + # Outputted vapi file + base_vapi = target.name + '.vapi' + vapiname = os.path.join(self.get_target_dir(target), base_vapi) + # Force valac to write the vapi file in the target build dir. + # Without this, it will write it inside c_out_dir + args += ['--vapi=../' + base_vapi] + valac_outputs.append(vapiname) if self.environment.coredata.get_builtin_option('werror'): args += valac.get_werror_args() - for d in target.external_deps: + for d in target.get_external_deps(): if isinstance(d, dependencies.PkgConfigDependency): if d.name == 'glib-2.0' and d.version_requirement is not None \ - and d.version_requirement.startswith(('>=', '==')): + and d.version_requirement.startswith(('>=', '==')): args += ['--target-glib', d.version_requirement[2:]] args += ['--pkg', d.name] extra_args = [] @@ -959,14 +1022,13 @@ int dummy; dependency_vapis = self.determine_dep_vapis(target) extra_dep_files += dependency_vapis args += extra_args - args += dependency_vapis - element = NinjaBuildElement(self.all_outputs, outputs, + element = NinjaBuildElement(self.all_outputs, valac_outputs, valac.get_language() + '_COMPILER', - vala_src + vapi_src) + all_files + dependency_vapis) element.add_item('ARGS', args) element.add_dep(extra_dep_files) element.write(outfile) - return generated_c_files + return other_src[0], other_src[1], vala_c_src def generate_rust_target(self, target, outfile): rustc = target.compilers['rust'] @@ -1664,7 +1726,7 @@ rule FORTRAN_DEP_HACK if isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) else: - raise build.InvalidArguments('Invalid source type.') + raise InvalidArguments('Invalid source type: {!r}'.format(src)) abs_src = os.path.join(self.environment.get_build_dir(), rel_src) if isinstance(src, (RawFilename, File)): src_filename = src.fname @@ -1791,7 +1853,10 @@ rule FORTRAN_DEP_HACK if len(pch) == 0: continue if '/' not in pch[0] or '/' not in pch[-1]: - raise build.InvalidArguments('Precompiled header of "%s" must not be in the same directory as source, please put it in a subdirectory.' % target.get_basename()) + msg = 'Precompiled header of {!r} must not be in the same ' \ + 'directory as source, please put it in a subdirectory.' \ + ''.format(target.get_basename()) + raise InvalidArguments(msg) compiler = self.get_compiler_for_lang(lang) if compiler.id == 'msvc': src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1]) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index e500410..e16f118 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -776,6 +776,7 @@ class GeneratedList(): if hasattr(generator, 'held_object'): generator = generator.held_object self.generator = generator + self.name = self.generator.exe self.infilelist = [] self.outfilelist = [] self.outmap = {} diff --git a/test cases/vala/8 generated source/src/meson.build b/test cases/vala/8 generated source/src/meson.build deleted file mode 100644 index 9096c67..0000000 --- a/test cases/vala/8 generated source/src/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -config = configure_file(input: 'config.vala.in', - output: 'config.vala', - configuration: cd) - -src = files('test.vala') diff --git a/test cases/vala/8 generated source/src/test.vala b/test cases/vala/8 generated source/src/test.vala deleted file mode 100644 index 98d6821..0000000 --- a/test cases/vala/8 generated source/src/test.vala +++ /dev/null @@ -1,3 +0,0 @@ -void main() { - print (Config.x); -} diff --git a/test cases/vala/8 generated source/installed_files.txt b/test cases/vala/8 generated sources/installed_files.txt index a4c37f6..a4c37f6 100644 --- a/test cases/vala/8 generated source/installed_files.txt +++ b/test cases/vala/8 generated sources/installed_files.txt diff --git a/test cases/vala/8 generated source/meson.build b/test cases/vala/8 generated sources/meson.build index 7271821..7271821 100644 --- a/test cases/vala/8 generated source/meson.build +++ b/test cases/vala/8 generated sources/meson.build diff --git a/test cases/vala/8 generated source/src/config.vala.in b/test cases/vala/8 generated sources/src/config.vala.in index a5196fd..a5196fd 100644 --- a/test cases/vala/8 generated source/src/config.vala.in +++ b/test cases/vala/8 generated sources/src/config.vala.in diff --git a/test cases/vala/8 generated sources/src/copy_file.py b/test cases/vala/8 generated sources/src/copy_file.py new file mode 100644 index 0000000..b90d91f --- /dev/null +++ b/test cases/vala/8 generated sources/src/copy_file.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import os +import sys +import shutil + +shutil.copyfile(sys.argv[1], sys.argv[2]) diff --git a/test cases/vala/8 generated sources/src/meson.build b/test cases/vala/8 generated sources/src/meson.build new file mode 100644 index 0000000..06515c1 --- /dev/null +++ b/test cases/vala/8 generated sources/src/meson.build @@ -0,0 +1,17 @@ +config = configure_file(input: 'config.vala.in', + output: 'config.vala', + configuration: cd) + +print = find_program('write_wrapper.py') +wrapper = custom_target('wrapper', + output : 'print_wrapper.vala', + command : [print, '@OUTPUT@']) + +copy = find_program('copy_file.py') +gen = generator(copy, + output : '@BASENAME@.vala', + arguments : ['@INPUT@', '@OUTPUT@']) + +returncode = gen.process('returncode.in') + +src = files('test.vala') diff --git a/test cases/vala/8 generated sources/src/returncode.in b/test cases/vala/8 generated sources/src/returncode.in new file mode 100644 index 0000000..e3d3ea6 --- /dev/null +++ b/test cases/vala/8 generated sources/src/returncode.in @@ -0,0 +1,3 @@ +int return_code() { + return 0; +} diff --git a/test cases/vala/8 generated sources/src/test.vala b/test cases/vala/8 generated sources/src/test.vala new file mode 100644 index 0000000..ca27676 --- /dev/null +++ b/test cases/vala/8 generated sources/src/test.vala @@ -0,0 +1,4 @@ +int main() { + print_wrapper (Config.x); + return return_code (); +} diff --git a/test cases/vala/8 generated sources/src/write_wrapper.py b/test cases/vala/8 generated sources/src/write_wrapper.py new file mode 100644 index 0000000..b5608f7 --- /dev/null +++ b/test cases/vala/8 generated sources/src/write_wrapper.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import sys + +contents = ''' +void print_wrapper(string arg) { + print (arg); +} +''' + +with open(sys.argv[1], 'w') as f: + f.write(contents) diff --git a/test cases/vala/8 generated source/tools/meson.build b/test cases/vala/8 generated sources/tools/meson.build index 834ec1a..303468e 100644 --- a/test cases/vala/8 generated source/tools/meson.build +++ b/test cases/vala/8 generated sources/tools/meson.build @@ -1,3 +1,3 @@ -executable('generatedtest', [src, config], +executable('generatedtest', [src, config, returncode, wrapper], install : true, dependencies: [dependency('glib-2.0'), dependency('gobject-2.0')]) |