diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 16962a4b1163..a548bc3f1546 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2448,6 +2448,20 @@ def guess_external_link_dependencies(self, linker, target, commands, internal): return guessed_dependencies + absolute_libs + def get_export_symbol_file_args(self, linker, target): + args = [] + dep_files = [] + for f in target.symbol_export_files: + if isinstance(f, File): + relpath = f.rel_to_builddir(self.build_to_src) + elif isinstance(f, build.CustomTarget): + relpath = self.get_target_filename(f) + else: + raise RuntimeError('Broken, please file a bug.') + args += linker.get_symbol_export_file_args(relpath) + dep_files.append(relpath) + return (args, dep_files) + def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[], stdlib_args=[]): if isinstance(target, build.StaticLibrary): linker_base = 'STATIC' @@ -2481,6 +2495,8 @@ def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[ commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target)) + export_file_commands, export_file_deps = self.get_export_symbol_file_args(linker, target) + commands += export_file_commands # Add /DEBUG and the pdb filename when using MSVC if self.get_option_for_target('debug', target): commands += self.get_link_debugfile_args(linker, target, outname) @@ -2586,6 +2602,7 @@ def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[ dep_targets.extend([self.get_dependency_filename(t) for t in dependencies]) dep_targets.extend([self.get_dependency_filename(t) for t in target.link_depends]) + dep_targets += export_file_deps elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list) elem.add_dep(dep_targets + custom_target_libraries) elem.add_item('LINK_ARGS', commands) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 702b338daffe..cdeab253a548 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -77,6 +77,7 @@ 'objects', 'override_options', 'sources', + 'symbol_export_file', 'gnu_symbol_visibility', ]) @@ -448,6 +449,7 @@ def __init__(self, name, subdir, subproject, is_cross, sources, objects, environ self.link_targets = [] self.link_whole_targets = [] self.link_depends = [] + self.symbol_export_files = [] self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' @@ -936,6 +938,16 @@ def process_kwargs(self, kwargs, environment): if self.gnu_symbol_visibility not in permitted: raise InvalidArguments('GNU symbol visibility arg %s not one of: %s', self.symbol_visibility, ', '.join(permitted)) + for i in listify(kwargs.get('symbol_export_file', []), unholder=True): + if isinstance(i, str): + f = File(False, self.subdir, i) + if not os.path.exists(f.absolute_path(self.environment.source_dir, + self.environment.build_dir)): + raise InvalidArguments('Nonexisting file {}.'.format(i)) + i = f + if not isinstance(i, (File, CustomTarget)): + raise InvalidArguments('Symbol_export_file must be a string, file or a custom target.') + self.symbol_export_files.append(i) def _extract_pic_pie(self, kwargs, arg): # Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index a1a8fb95004c..3f70d4a3b92e 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1497,6 +1497,9 @@ def gen_vs_module_defs_args(self, defsfile): # so if a module defs file is specified, we use that to export symbols return ['/DEF:' + defsfile] + def get_symbol_export_file_args(self, path): + return ['/DEF:' + path] + def gen_pch_args(self, header, source, pchname): objname = os.path.splitext(pchname)[0] + '.obj' return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname] diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3d4cce810cb0..db8ba7beea7a 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1271,6 +1271,9 @@ def language_stdlib_only_link_flags(self): def gnu_symbol_visibility_args(self, vistype): return [] + def get_symbol_export_file_args(self, path): + raise EnvironmentException('Compiler {} does not support symbol exports.'.format(self.get_id())) + def get_gui_app_args(self, value): return [] @@ -1547,6 +1550,9 @@ def openmp_flags(self): def gnu_symbol_visibility_args(self, vistype): return gnu_symbol_visibility_args[vistype] + def get_symbol_export_file_args(self, path): + return ['-Wl,--version-script=' + path] + def gen_vs_module_defs_args(self, defsfile): if not isinstance(defsfile, str): raise RuntimeError('Module definitions file should be str') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e33cb7fe1f93..212d07e07be7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3950,6 +3950,7 @@ def build_target(self, node, args, kwargs, targetholder): @FeatureNewKwargs('build target', '0.41.0', ['rust_args']) @FeatureNewKwargs('build target', '0.40.0', ['build_by_default']) @FeatureNewKwargs('build target', '0.48.0', ['gnu_symbol_visibility']) + @FeatureNewKwargs('build target', '0.50.0', ['symbol_export_file']) def build_target_decorator_caller(self, node, args, kwargs): return True diff --git a/test cases/linuxlike/3 linker script/bob.c b/test cases/common/213 version file/bob.c similarity index 100% rename from test cases/linuxlike/3 linker script/bob.c rename to test cases/common/213 version file/bob.c diff --git a/test cases/linuxlike/3 linker script/bob.h b/test cases/common/213 version file/bob.h similarity index 100% rename from test cases/linuxlike/3 linker script/bob.h rename to test cases/common/213 version file/bob.h diff --git a/test cases/linuxlike/3 linker script/bob.map b/test cases/common/213 version file/bob.map similarity index 100% rename from test cases/linuxlike/3 linker script/bob.map rename to test cases/common/213 version file/bob.map diff --git a/test cases/linuxlike/3 linker script/bob.map.in b/test cases/common/213 version file/bob.map.in similarity index 100% rename from test cases/linuxlike/3 linker script/bob.map.in rename to test cases/common/213 version file/bob.map.in diff --git a/test cases/common/213 version file/bob.sym b/test cases/common/213 version file/bob.sym new file mode 100644 index 000000000000..5a3f0299b6b4 --- /dev/null +++ b/test cases/common/213 version file/bob.sym @@ -0,0 +1,2 @@ +EXPORTS + bobMcBob diff --git a/test cases/common/213 version file/bob.sym.in b/test cases/common/213 version file/bob.sym.in new file mode 100644 index 000000000000..6aeb511bb31c --- /dev/null +++ b/test cases/common/213 version file/bob.sym.in @@ -0,0 +1,2 @@ +EXPORTS + @in@ diff --git a/test cases/linuxlike/3 linker script/copy.py b/test cases/common/213 version file/copy.py similarity index 100% rename from test cases/linuxlike/3 linker script/copy.py rename to test cases/common/213 version file/copy.py diff --git a/test cases/common/213 version file/meson.build b/test cases/common/213 version file/meson.build new file mode 100644 index 000000000000..49bd7ded37a5 --- /dev/null +++ b/test cases/common/213 version file/meson.build @@ -0,0 +1,70 @@ +project('linker script', 'c') + +cc = meson.get_compiler('c') + +if build_machine.system() == 'cygwin' + error('MESON_SKIP_TEST does not work on cygwin for some reason.') +endif + +if cc.get_id() == 'clang-cl' + error('MESON_SKIP_TEST uses lld which is not supported yet. Patches welcome.') +endif + + +# Static map file +if cc.get_id() == 'msvc' + suffix = '.sym' +else + suffix = '.map' +endif + +mapfile = 'bob' + suffix + +l = shared_library('bob', 'bob.c', symbol_export_file: mapfile) +e = executable('prog', 'prog.c', link_with : l) +test('core', e) + +# configure_file +conf = configuration_data() +conf.set('in', 'bobMcBob') +m = configure_file( + input : 'bob' + suffix + '.in', + output : 'bob-conf' + suffix, + configuration : conf, +) + +l = shared_library('bob-conf', 'bob.c', symbol_export_file: m) +e = executable('prog-conf', 'prog.c', link_with : l) +test('core', e) + +## custom_target +python = find_program('python3', required : false) +if not python.found() + python = find_program('python') +endif +m = custom_target( + 'bob-ct' + suffix, + command : [python, '@INPUT0@', '@INPUT1@', '@OUTPUT@'], + input : ['copy.py', 'bob' + suffix], + output : 'bob-ct' + suffix, +) + +l = shared_library('bob-ct', ['bob.c', m], symbol_export_file: m) +e = executable('prog-ct', 'prog.c', link_with : l) +test('core', e) + +# File +mapfile = files('bob' + suffix) + +l = shared_library('bob-files', 'bob.c', symbol_export_file: mapfile) +e = executable('prog-files', 'prog.c', link_with : l) +test('core', e) + +subdir('sub') + +# With map file in subdir +mapfile = files('sub/foo' + suffix) + +l = shared_library('bar', 'bob.c', symbol_export_file: mapfile) +e = executable('prog-bar', 'prog.c', link_with : l) +test('core', e) diff --git a/test cases/linuxlike/3 linker script/prog.c b/test cases/common/213 version file/prog.c similarity index 100% rename from test cases/linuxlike/3 linker script/prog.c rename to test cases/common/213 version file/prog.c diff --git a/test cases/linuxlike/3 linker script/sub/foo.map b/test cases/common/213 version file/sub/foo.map similarity index 100% rename from test cases/linuxlike/3 linker script/sub/foo.map rename to test cases/common/213 version file/sub/foo.map diff --git a/test cases/common/213 version file/sub/foo.sym b/test cases/common/213 version file/sub/foo.sym new file mode 100644 index 000000000000..5a3f0299b6b4 --- /dev/null +++ b/test cases/common/213 version file/sub/foo.sym @@ -0,0 +1,2 @@ +EXPORTS + bobMcBob diff --git a/test cases/common/213 version file/sub/meson.build b/test cases/common/213 version file/sub/meson.build new file mode 100644 index 000000000000..7ec590a18274 --- /dev/null +++ b/test cases/common/213 version file/sub/meson.build @@ -0,0 +1,5 @@ +mapfile = 'foo' + suffix + +l = shared_library('foo', '../bob.c', symbol_export_file: mapfile) +e = executable('prog-foo', '../prog.c', link_with : l) +test('core', e) diff --git a/test cases/linuxlike/13 cmake dependency/incdir/myinc.h b/test cases/linuxlike/3 cmake dependency/incdir/myinc.h similarity index 100% rename from test cases/linuxlike/13 cmake dependency/incdir/myinc.h rename to test cases/linuxlike/3 cmake dependency/incdir/myinc.h diff --git a/test cases/linuxlike/13 cmake dependency/meson.build b/test cases/linuxlike/3 cmake dependency/meson.build similarity index 100% rename from test cases/linuxlike/13 cmake dependency/meson.build rename to test cases/linuxlike/3 cmake dependency/meson.build diff --git a/test cases/linuxlike/13 cmake dependency/prog-checkver.c b/test cases/linuxlike/3 cmake dependency/prog-checkver.c similarity index 100% rename from test cases/linuxlike/13 cmake dependency/prog-checkver.c rename to test cases/linuxlike/3 cmake dependency/prog-checkver.c diff --git a/test cases/linuxlike/13 cmake dependency/prog.c b/test cases/linuxlike/3 cmake dependency/prog.c similarity index 100% rename from test cases/linuxlike/13 cmake dependency/prog.c rename to test cases/linuxlike/3 cmake dependency/prog.c diff --git a/test cases/linuxlike/3 linker script/meson.build b/test cases/linuxlike/3 linker script/meson.build deleted file mode 100644 index 63765e7ca602..000000000000 --- a/test cases/linuxlike/3 linker script/meson.build +++ /dev/null @@ -1,56 +0,0 @@ -project('linker script', 'c') - -# Static map file -mapfile = 'bob.map' -vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) - -l = shared_library('bob', 'bob.c', link_args : vflag, link_depends : mapfile) -e = executable('prog', 'prog.c', link_with : l) -test('core', e) - -# configure_file -conf = configuration_data() -conf.set('in', 'bobMcBob') -m = configure_file( - input : 'bob.map.in', - output : 'bob-conf.map', - configuration : conf, -) -vflag = '-Wl,--version-script,@0@'.format(m) - -l = shared_library('bob-conf', 'bob.c', link_args : vflag, link_depends : m) -e = executable('prog-conf', 'prog.c', link_with : l) -test('core', e) - -# custom_target -python = find_program('python3') -m = custom_target( - 'bob-ct.map', - command : [python, '@INPUT0@', '@INPUT1@', 'bob-ct.map'], - input : ['copy.py', 'bob.map'], - output : 'bob-ct.map', - depend_files : 'bob.map', -) -vflag = '-Wl,--version-script,@0@'.format(m.full_path()) - -l = shared_library('bob-ct', ['bob.c', m], link_args : vflag, link_depends : m) -e = executable('prog-ct', 'prog.c', link_with : l) -test('core', e) - -# File -mapfile = files('bob.map') -vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile[0]) - -l = shared_library('bob-files', 'bob.c', link_args : vflag, link_depends : mapfile) -e = executable('prog-files', 'prog.c', link_with : l) -test('core', e) - -subdir('sub') - -# With map file in subdir -mapfile = 'sub/foo.map' -vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) - -l = shared_library('bar', 'bob.c', link_args : vflag, link_depends : mapfile) -e = executable('prog-bar', 'prog.c', link_with : l) -test('core', e) diff --git a/test cases/linuxlike/3 linker script/sub/meson.build b/test cases/linuxlike/3 linker script/sub/meson.build deleted file mode 100644 index 93199f3927a0..000000000000 --- a/test cases/linuxlike/3 linker script/sub/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -mapfile = 'foo.map' -vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) - -l = shared_library('foo', '../bob.c', link_args : vflag, link_depends : mapfile) -e = executable('prog-foo', '../prog.c', link_with : l) -test('core', e)