From a656febccf6614008086bf124858826615924df7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 18 Jun 2021 18:06:03 +0200 Subject: [PATCH 1/2] extract_objects: test and document using the result in a custom_target QEMU would like to use the result of extract_objects in a custom_target; examples are using objcopy, or using the object files as the key to look up command line arguments in compile_commands.json. This is slightly peculiar and not covered by the test suite, but it works; in order to avoid regressions, add a test case and document it. --- docs/markdown/Reference-manual.md | 4 +++- .../common/22 object extraction/check-obj.py | 21 +++++++++++++++++++ .../common/22 object extraction/meson.build | 6 ++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test cases/common/22 object extraction/check-obj.py diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 18f30b32d..f3f87cce2 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -2552,7 +2552,9 @@ module](#shared_module). object files generated for those source files. This is typically used to take single object files and link them to unit tests or to compile some source files with custom flags. To use the object file(s) - in another build target, use the `objects:` keyword argument. + in another build target, use the [`objects:`](#executable) keyword + argument or include them in the command line of a + [`custom_target`](#custom_target)`. - `full_path()`: returns a full path pointing to the result target file. NOTE: In most cases using the object itself will do the same job as diff --git a/test cases/common/22 object extraction/check-obj.py b/test cases/common/22 object extraction/check-obj.py new file mode 100644 index 000000000..99c2cc546 --- /dev/null +++ b/test cases/common/22 object extraction/check-obj.py @@ -0,0 +1,21 @@ +#! /usr/bin/env python3 + +import json +import sys +import os + +cc = None +output = None + +# Only the ninja backend produces compile_commands.json +if sys.argv[1] == 'ninja': + with open('compile_commands.json', 'r') as f: + cc = json.load(f) + output = set((x['output'] for x in cc)) + +for obj in sys.argv[2:]: + if not os.path.exists(obj): + sys.exit(1) + if sys.argv[1] == 'ninja' and obj not in output: + sys.exit(1) + print('Verified', obj) diff --git a/test cases/common/22 object extraction/meson.build b/test cases/common/22 object extraction/meson.build index 18be1dbeb..407c5e83b 100644 --- a/test cases/common/22 object extraction/meson.build +++ b/test cases/common/22 object extraction/meson.build @@ -16,6 +16,12 @@ else e3 = executable('main3', 'main.c', objects : obj3) e4 = executable('main4', 'main.c', objects : obj4) + custom_target('custom_target with object inputs', output: 'objs', + input: [obj1, obj2, obj3], + build_by_default: true, + command: [find_program('check-obj.py'), meson.backend(), '@INPUT@'], + capture: true) + test('extraction test 1', e1) test('extraction test 2', e2) test('extraction test 3', e3) From bd75e0398fc66a71ecab297fefe68d0066c38a81 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jun 2021 15:56:34 +0200 Subject: [PATCH 2/2] extract_objects: skip headers when building custom_target command line As seen in the testcase, passing objects to custom_target does not work if headers are passed extract_objects(), or if extract_all_objects() is used and the sources include any header files. To fix this, use the code that already exists for unity build to filter out the nonexistent ".h.o" files. This already gives for free the handling of genlist, which was mentioned in a TODO comment. --- mesonbuild/build.py | 10 ++++++---- test cases/common/22 object extraction/header.h | 1 + test cases/common/22 object extraction/meson.build | 10 ++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 test cases/common/22 object extraction/header.h diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 436a55d37..0a792fc1f 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -375,7 +375,8 @@ class ExtractedObjects: r = '<{0} {1!r}: {2}>' return r.format(self.__class__.__name__, self.target.name, self.srclist) - def classify_all_sources(self, sources, generated_sources): + @staticmethod + def get_sources(sources, generated_sources): # Merge sources and generated sources sources = list(sources) for gensrc in generated_sources: @@ -386,8 +387,10 @@ class ExtractedObjects: sources.append(s) # Filter out headers and all non-source files - sources = [s for s in sources if environment.is_source(s) and not environment.is_header(s)] + return [s for s in sources if environment.is_source(s) and not environment.is_header(s)] + def classify_all_sources(self, sources, generated_sources): + sources = self.get_sources(sources, generated_sources) return classify_unity_sources(self.target.compilers.values(), sources) def check_unity_compatible(self): @@ -407,10 +410,9 @@ class ExtractedObjects: 'the object files for each compiler at once.') def get_outputs(self, backend): - # TODO: Consider if we need to handle genlist here return [ backend.object_filename_from_source(self.target, source) - for source in self.srclist + for source in self.get_sources(self.srclist, self.genlist) ] class EnvironmentVariables: diff --git a/test cases/common/22 object extraction/header.h b/test cases/common/22 object extraction/header.h new file mode 100644 index 000000000..50403ce3c --- /dev/null +++ b/test cases/common/22 object extraction/header.h @@ -0,0 +1 @@ +/* Check that extract_all_objects works with headers. */ diff --git a/test cases/common/22 object extraction/meson.build b/test cases/common/22 object extraction/meson.build index 407c5e83b..fd4af8c60 100644 --- a/test cases/common/22 object extraction/meson.build +++ b/test cases/common/22 object extraction/meson.build @@ -4,20 +4,24 @@ if meson.is_unity() message('Skipping extraction test because this is a Unity build.') else lib1 = shared_library('somelib', 'src/lib.c') - lib2 = shared_library('somelib2', 'lib.c', 'lib2.c') + lib2 = shared_library('somelib2', 'lib.c', 'header.h', 'lib2.c') obj1 = lib1.extract_objects('src/lib.c') obj2 = lib2.extract_objects(['lib.c']) obj3 = lib2.extract_objects(files('lib.c')) obj4 = lib2.extract_objects(['lib.c', 'lib.c']) + obj5 = lib2.extract_objects(['lib.c', 'header.h']) + obj6 = lib2.extract_all_objects(recursive: true) e1 = executable('main1', 'main.c', objects : obj1) e2 = executable('main2', 'main.c', objects : obj2) e3 = executable('main3', 'main.c', objects : obj3) e4 = executable('main4', 'main.c', objects : obj4) + e5 = executable('main5', 'main.c', objects : obj5) + e6 = executable('main6', 'main.c', objects : obj6) custom_target('custom_target with object inputs', output: 'objs', - input: [obj1, obj2, obj3], + input: [obj1, obj2, obj3, obj5, obj6], build_by_default: true, command: [find_program('check-obj.py'), meson.backend(), '@INPUT@'], capture: true) @@ -26,4 +30,6 @@ else test('extraction test 2', e2) test('extraction test 3', e3) test('extraction test 4', e4) + test('extraction test 5', e5) + test('extraction test 6', e6) endif