From 6a0e6740432dfd22c54976ae3fe2fc1c9fea0b3d Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Tue, 3 Jul 2018 23:16:33 +0300 Subject: [PATCH 1/4] Add kwarg for specifying symbol visibility. --- mesonbuild/backend/ninjabackend.py | 2 ++ mesonbuild/build.py | 9 +++++++++ mesonbuild/compilers/compilers.py | 15 +++++++++++++++ mesonbuild/interpreter.py | 1 + test cases/failing build/2 hidden symbol/bob.c | 5 +++++ test cases/failing build/2 hidden symbol/bob.h | 3 +++ .../failing build/2 hidden symbol/bobuser.c | 5 +++++ .../failing build/2 hidden symbol/meson.build | 14 ++++++++++++++ 8 files changed, 54 insertions(+) create mode 100644 test cases/failing build/2 hidden symbol/bob.c create mode 100644 test cases/failing build/2 hidden symbol/bob.h create mode 100644 test cases/failing build/2 hidden symbol/bobuser.c create mode 100644 test cases/failing build/2 hidden symbol/meson.build diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 913830f8a..f88c589df 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1951,6 +1951,8 @@ rule FORTRAN_DEP_HACK%s # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other commands = CompilerArgs(compiler) + # Start with symbol visibility. + commands += compiler.symbol_visibility_args(target.symbol_visibility) # Add compiler args for compiling this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a3cd9933d..3d43c8968 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -71,6 +71,7 @@ buildtarget_kwargs = set([ 'objects', 'override_options', 'sources', + 'symbol_visibility', ]) known_build_target_kwargs = ( @@ -817,6 +818,14 @@ This will become a hard error in a future Meson release.''') self.implicit_include_directories = kwargs.get('implicit_include_directories', True) if not isinstance(self.implicit_include_directories, bool): raise InvalidArguments('Implicit_include_directories must be a boolean.') + self.symbol_visibility = kwargs.get('symbol_visibility', '') + if not isinstance(self.symbol_visibility, str): + raise InvalidArguments('Symbol visibility must be a string.') + if self.symbol_visibility != '': + permitted = ['default', 'internal', 'hidden', 'protected', 'inlineshidden'] + if self.symbol_visibility not in permitted: + raise InvalidArguments('Symbol visibility arg %s not one of: %s', + self.symbol_visibility, ', '.join(permitted)) def get_filename(self): return self.filename diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 25835a32d..3668a7996 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -311,6 +311,14 @@ vs64_instruction_set_args = {'mmx': ['/arch:AVX'], 'neon': None, } +common_symbol_visibility_args = {'': [], + 'default': ['-fvisibility=default'], + 'internal': ['-fvisibility=internal'], + 'hidden': ['-fvisibility=hidden'], + 'protected': ['-fvisibility=protected'], + 'inlineshidden': ['-fvisibility=hidden', '-fvisibility-inlines-hidden'], + } + def sanitizer_compile_args(value): if value == 'none': return [] @@ -1062,6 +1070,9 @@ class Compiler: # building fails with undefined symbols. return [] + def symbol_visibility_args(self, vistype): + return [] + GCC_STANDARD = 0 GCC_OSX = 1 GCC_MINGW = 2 @@ -1277,6 +1288,8 @@ class GnuCompiler: def openmp_flags(self): return ['-fopenmp'] + def symbol_visibility_args(self, vistype): + return common_symbol_visibility_args[vistype] class ElbrusCompiler(GnuCompiler): # Elbrus compiler is nearly like GCC, but does not support @@ -1419,6 +1432,8 @@ class ClangCompiler: # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. return [] + def symbol_visibility_args(self, vistype): + return common_symbol_visibility_args[vistype] class ArmclangCompiler: def __init__(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index fd0385d74..c84ed96c5 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3850,6 +3850,7 @@ Try setting b_lundef to false instead.''') @FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories']) @FeatureNewKwargs('build target', '0.41.0', ['rust_args']) @FeatureNewKwargs('build target', '0.40.0', ['build_by_default']) + @FeatureNewKwargs('build target', '0.48.0', ['symbol_visibility']) def build_target_decorator_caller(self, node, args, kwargs): return True diff --git a/test cases/failing build/2 hidden symbol/bob.c b/test cases/failing build/2 hidden symbol/bob.c new file mode 100644 index 000000000..9a3325a81 --- /dev/null +++ b/test cases/failing build/2 hidden symbol/bob.c @@ -0,0 +1,5 @@ +#include"bob.h" + +int hidden_function() { + return 7; +} diff --git a/test cases/failing build/2 hidden symbol/bob.h b/test cases/failing build/2 hidden symbol/bob.h new file mode 100644 index 000000000..947f6eec4 --- /dev/null +++ b/test cases/failing build/2 hidden symbol/bob.h @@ -0,0 +1,3 @@ +#pragma once + +int hidden_function(); diff --git a/test cases/failing build/2 hidden symbol/bobuser.c b/test cases/failing build/2 hidden symbol/bobuser.c new file mode 100644 index 000000000..89272ed6c --- /dev/null +++ b/test cases/failing build/2 hidden symbol/bobuser.c @@ -0,0 +1,5 @@ +#include"bob.h" + +int main(int argc, char **argv) { + return hidden_function(); +} diff --git a/test cases/failing build/2 hidden symbol/meson.build b/test cases/failing build/2 hidden symbol/meson.build new file mode 100644 index 000000000..d88838505 --- /dev/null +++ b/test cases/failing build/2 hidden symbol/meson.build @@ -0,0 +1,14 @@ +project('hidden symbol', 'c') + +if host_machine.system() == 'windows' + cc = meson.get_compiler('c') + if cc.get_id() == 'gcc' + error('MESON_SKIP_TEST -fvisibility=hidden does not work on MinGW.') + endif +endif + +l = shared_library('bob', 'bob.c', + symbol_visibility: 'hidden') + +executable('bobuser', 'bobuser.c', + link_with: l) From 3c62eaa9ff25b25f34bd42f79031bfc333ff67e2 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Tue, 3 Jul 2018 23:24:09 +0300 Subject: [PATCH 2/4] Updated sample projects to use visibility kwarg. --- mesonbuild/minit.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index 1a83ed223..7dd482bbd 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -72,16 +72,10 @@ lib_c_meson_template = '''project('{project_name}', 'c', # not the executables that use the library. lib_args = ['-DBUILDING_{utoken}'] -# Hiding symbols that are not explicitly marked as exported -# requires a compiler flag on all compilers except VS. -cc = meson.get_compiler('c') -if cc.get_id() != 'msvc' - lib_args += ['-fvisibility=hidden'] -endif - shlib = shared_library('{lib_name}', '{source_file}', install : true, c_args : lib_args, + symbol_visibility : 'hidden', ) test_exe = executable('{test_exe_name}', '{test_source_file}', @@ -226,16 +220,10 @@ lib_cpp_meson_template = '''project('{project_name}', 'cpp', # not the executables that use the library. lib_args = ['-DBUILDING_{utoken}'] -# Hiding symbols that are not explicitly marked as exported -# requires a compiler flag on all compilers except VS. -cpp = meson.get_compiler('cpp') -if cpp.get_id() != 'msvc' - lib_args += ['-fvisibility=hidden'] -endif - shlib = shared_library('{lib_name}', '{source_file}', install : true, cpp_args : lib_args, + symbol_visibility : 'hidden', ) test_exe = executable('{test_exe_name}', '{test_source_file}', From d7d948db0d9b8801afdde4f8867e4e3b94363af2 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Tue, 3 Jul 2018 23:28:38 +0300 Subject: [PATCH 3/4] Update documentation for symbol visibility. --- docs/markdown/Reference-manual.md | 16 ++++++++++++---- docs/markdown/snippets/visibility.md | 13 +++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 docs/markdown/snippets/visibility.md diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 12018fca7..d14f639e3 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -511,6 +511,13 @@ be passed to [shared and static libraries](#library). - `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 +- `symbol_visibility` specifies how symbols should be exported, see + e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more + information. This value can either be an empty string or one of + `default`, `internal`, `hidden`, `protected` or `inlineshidden`, which + is the same as `hidden` but also includes things like C++ implicit + constructors as specified in the GCC manual. Available since + 0.48.0. - `d_import_dirs` list of directories to look in for string imports used in the D programming language - `d_unittest`, when set to true, the D modules are compiled in debug mode @@ -976,15 +983,16 @@ dropped. That means that `join_paths('foo', '/bar')` returns `/bar`. buildtarget library(library_name, list_of_sources, ...) ``` -Builds a library that is either static, shared or both depending on the value of -`default_library` user option. You should use this instead of -[`shared_library`](#shared_library), +Builds a library that is either static, shared or both depending on +the value of `default_library` user option. You should use this +instead of [`shared_library`](#shared_library), [`static_library`](#static_library) or [`both_libraries`](#both_libraries) most of the time. This allows you to toggle your entire project (including subprojects) from shared to static with only one option. -The keyword arguments for this are the same as for [`executable`](#executable) with the following additions: +The keyword arguments for this are the same as for +[`executable`](#executable) with the following additions: - `name_prefix` the string that will be used as the prefix for the target output filename by overriding the default (only used for diff --git a/docs/markdown/snippets/visibility.md b/docs/markdown/snippets/visibility.md new file mode 100644 index 000000000..f55a48f4b --- /dev/null +++ b/docs/markdown/snippets/visibility.md @@ -0,0 +1,13 @@ +## Keyword argument for symbol visibility + +Build targets got a new keyword, `symbol_visibility` that controls how +symbols are exported from shared libraries. This is most commonly used +to hide implementation symbols like this: + +```meson +shared_library('mylib', ... + symbol_visibility: 'hidden') +``` + +In this case only symbols explicitly marked as visible in the source +files get exported. From fb2cdd0fe2797b30e1fd4c118407302402739a3b Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Thu, 9 Aug 2018 19:46:45 +0300 Subject: [PATCH 4/4] Call it gnu_symbol_visibility instead. --- docs/markdown/Reference-manual.md | 6 ++--- docs/markdown/snippets/visibility.md | 4 ++-- mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/build.py | 14 +++++------ mesonbuild/compilers/compilers.py | 24 +++++++++---------- mesonbuild/interpreter.py | 2 +- mesonbuild/minit.py | 4 ++-- .../failing build/2 hidden symbol/meson.build | 6 ++--- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index d14f639e3..a7b8a2b06 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -511,13 +511,13 @@ be passed to [shared and static libraries](#library). - `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 -- `symbol_visibility` specifies how symbols should be exported, see +- `gnu_symbol_visibility` specifies how symbols should be exported, see e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more information. This value can either be an empty string or one of `default`, `internal`, `hidden`, `protected` or `inlineshidden`, which is the same as `hidden` but also includes things like C++ implicit - constructors as specified in the GCC manual. Available since - 0.48.0. + constructors as specified in the GCC manual. Ignored on compilers that + do not support GNU visibility arguments. Available since 0.48.0. - `d_import_dirs` list of directories to look in for string imports used in the D programming language - `d_unittest`, when set to true, the D modules are compiled in debug mode diff --git a/docs/markdown/snippets/visibility.md b/docs/markdown/snippets/visibility.md index f55a48f4b..4b671053e 100644 --- a/docs/markdown/snippets/visibility.md +++ b/docs/markdown/snippets/visibility.md @@ -1,4 +1,4 @@ -## Keyword argument for symbol visibility +## Keyword argument for GNU symbol visibility Build targets got a new keyword, `symbol_visibility` that controls how symbols are exported from shared libraries. This is most commonly used @@ -6,7 +6,7 @@ to hide implementation symbols like this: ```meson shared_library('mylib', ... - symbol_visibility: 'hidden') + gnu_symbol_visibility: 'hidden') ``` In this case only symbols explicitly marked as visible in the source diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index f88c589df..9dcf0fa4c 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1952,7 +1952,7 @@ rule FORTRAN_DEP_HACK%s # various sources in the order in which they must override each other commands = CompilerArgs(compiler) # Start with symbol visibility. - commands += compiler.symbol_visibility_args(target.symbol_visibility) + commands += compiler.gnu_symbol_visibility_args(target.gnu_symbol_visibility) # Add compiler args for compiling this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 3d43c8968..c1cb8a824 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -71,7 +71,7 @@ buildtarget_kwargs = set([ 'objects', 'override_options', 'sources', - 'symbol_visibility', + 'gnu_symbol_visibility', ]) known_build_target_kwargs = ( @@ -818,13 +818,13 @@ This will become a hard error in a future Meson release.''') self.implicit_include_directories = kwargs.get('implicit_include_directories', True) if not isinstance(self.implicit_include_directories, bool): raise InvalidArguments('Implicit_include_directories must be a boolean.') - self.symbol_visibility = kwargs.get('symbol_visibility', '') - if not isinstance(self.symbol_visibility, str): - raise InvalidArguments('Symbol visibility must be a string.') - if self.symbol_visibility != '': + self.gnu_symbol_visibility = kwargs.get('gnu_symbol_visibility', '') + if not isinstance(self.gnu_symbol_visibility, str): + raise InvalidArguments('GNU symbol visibility must be a string.') + if self.gnu_symbol_visibility != '': permitted = ['default', 'internal', 'hidden', 'protected', 'inlineshidden'] - if self.symbol_visibility not in permitted: - raise InvalidArguments('Symbol visibility arg %s not one of: %s', + if self.gnu_symbol_visibility not in permitted: + raise InvalidArguments('GNU symbol visibility arg %s not one of: %s', self.symbol_visibility, ', '.join(permitted)) def get_filename(self): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3668a7996..b62bc4a7b 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -311,13 +311,13 @@ vs64_instruction_set_args = {'mmx': ['/arch:AVX'], 'neon': None, } -common_symbol_visibility_args = {'': [], - 'default': ['-fvisibility=default'], - 'internal': ['-fvisibility=internal'], - 'hidden': ['-fvisibility=hidden'], - 'protected': ['-fvisibility=protected'], - 'inlineshidden': ['-fvisibility=hidden', '-fvisibility-inlines-hidden'], - } +gnu_symbol_visibility_args = {'': [], + 'default': ['-fvisibility=default'], + 'internal': ['-fvisibility=internal'], + 'hidden': ['-fvisibility=hidden'], + 'protected': ['-fvisibility=protected'], + 'inlineshidden': ['-fvisibility=hidden', '-fvisibility-inlines-hidden'], + } def sanitizer_compile_args(value): if value == 'none': @@ -1070,7 +1070,7 @@ class Compiler: # building fails with undefined symbols. return [] - def symbol_visibility_args(self, vistype): + def gnu_symbol_visibility_args(self, vistype): return [] GCC_STANDARD = 0 @@ -1288,8 +1288,8 @@ class GnuCompiler: def openmp_flags(self): return ['-fopenmp'] - def symbol_visibility_args(self, vistype): - return common_symbol_visibility_args[vistype] + def gnu_symbol_visibility_args(self, vistype): + return gnu_symbol_visibility_args[vistype] class ElbrusCompiler(GnuCompiler): # Elbrus compiler is nearly like GCC, but does not support @@ -1432,8 +1432,8 @@ class ClangCompiler: # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. return [] - def symbol_visibility_args(self, vistype): - return common_symbol_visibility_args[vistype] + def gnu_symbol_visibility_args(self, vistype): + return gnu_symbol_visibility_args[vistype] class ArmclangCompiler: def __init__(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c84ed96c5..c02201e7a 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3850,7 +3850,7 @@ Try setting b_lundef to false instead.''') @FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories']) @FeatureNewKwargs('build target', '0.41.0', ['rust_args']) @FeatureNewKwargs('build target', '0.40.0', ['build_by_default']) - @FeatureNewKwargs('build target', '0.48.0', ['symbol_visibility']) + @FeatureNewKwargs('build target', '0.48.0', ['gnu_symbol_visibility']) def build_target_decorator_caller(self, node, args, kwargs): return True diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index 7dd482bbd..a66361f8e 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -75,7 +75,7 @@ lib_args = ['-DBUILDING_{utoken}'] shlib = shared_library('{lib_name}', '{source_file}', install : true, c_args : lib_args, - symbol_visibility : 'hidden', + gnu_symbol_visibility : 'hidden', ) test_exe = executable('{test_exe_name}', '{test_source_file}', @@ -223,7 +223,7 @@ lib_args = ['-DBUILDING_{utoken}'] shlib = shared_library('{lib_name}', '{source_file}', install : true, cpp_args : lib_args, - symbol_visibility : 'hidden', + gnu_symbol_visibility : 'hidden', ) test_exe = executable('{test_exe_name}', '{test_source_file}', diff --git a/test cases/failing build/2 hidden symbol/meson.build b/test cases/failing build/2 hidden symbol/meson.build index d88838505..052734779 100644 --- a/test cases/failing build/2 hidden symbol/meson.build +++ b/test cases/failing build/2 hidden symbol/meson.build @@ -1,14 +1,14 @@ project('hidden symbol', 'c') -if host_machine.system() == 'windows' +if host_machine.system() == 'windows' or host_machine.system() == 'cygwin' cc = meson.get_compiler('c') if cc.get_id() == 'gcc' - error('MESON_SKIP_TEST -fvisibility=hidden does not work on MinGW.') + error('MESON_SKIP_TEST -fvisibility=hidden does not work on MinGW or Cygwin.') endif endif l = shared_library('bob', 'bob.c', - symbol_visibility: 'hidden') + gnu_symbol_visibility: 'hidden') executable('bobuser', 'bobuser.c', link_with: l)