diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2022-03-31 16:26:22 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-31 16:26:22 +0300 |
commit | efc7604ca268666cf40b1efc69b62ebfca986344 (patch) | |
tree | 08a718955e5777491cccb15189cc990054a8d2f7 | |
parent | 4b97c6065043e4268425bebec35f5c3722f73c2e (diff) | |
parent | 34ea8fdf981b5e10c702e9adfcab7f9e316a129b (diff) | |
download | meson-efc7604ca268666cf40b1efc69b62ebfca986344.zip meson-efc7604ca268666cf40b1efc69b62ebfca986344.tar.gz meson-efc7604ca268666cf40b1efc69b62ebfca986344.tar.bz2 |
Merge pull request #9989 from ePirat/epirat-fix-uscore-prefix-detection
Fix underscore detection
-rw-r--r-- | mesonbuild/compilers/mixins/clike.py | 81 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/visualstudio.py | 17 | ||||
-rwxr-xr-x | run_tests.py | 13 | ||||
-rw-r--r-- | unittests/allplatformstests.py | 28 |
4 files changed, 130 insertions, 9 deletions
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 269ce5c..162005f 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -900,9 +900,10 @@ class CLikeCompiler(Compiler): return self.compiles(t, env, extra_args=extra_args, dependencies=dependencies) - def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: + def _symbols_have_underscore_prefix_searchbin(self, env: 'Environment') -> bool: ''' - Check if the compiler prefixes an underscore to global C symbols + Check if symbols have underscore prefix by compiling a small test binary + and then searching the binary for the string, ''' symbol_name = b'meson_uscore_prefix' code = '''#ifdef __cplusplus @@ -914,10 +915,10 @@ class CLikeCompiler(Compiler): #endif ''' args = self.get_compiler_check_args(CompileCheckMode.COMPILE) - n = 'symbols_have_underscore_prefix' + n = '_symbols_have_underscore_prefix_searchbin' with self._build_wrapper(code, env, extra_args=args, mode='compile', want_output=True, temp_dir=env.scratch_dir) as p: if p.returncode != 0: - raise RuntimeError(f'BUG: Unable to compile {n!r} check: {p.stdout}') + raise RuntimeError(f'BUG: Unable to compile {n!r} check: {p.stderr}') if not os.path.isfile(p.output_name): raise RuntimeError(f'BUG: Can\'t find compiled test code for {n!r} check') with open(p.output_name, 'rb') as o: @@ -925,13 +926,79 @@ class CLikeCompiler(Compiler): # Check if the underscore form of the symbol is somewhere # in the output file. if b'_' + symbol_name in line: - mlog.debug("Symbols have underscore prefix: YES") + mlog.debug("Underscore prefix check found prefixed function in binary") return True # Else, check if the non-underscored form is present elif symbol_name in line: - mlog.debug("Symbols have underscore prefix: NO") + mlog.debug("Underscore prefix check found non-prefixed function in binary") return False - raise RuntimeError(f'BUG: {n!r} check failed unexpectedly') + raise RuntimeError(f'BUG: {n!r} check did not find symbol string in binary') + + def _symbols_have_underscore_prefix_define(self, env: 'Environment') -> T.Optional[bool]: + ''' + Check if symbols have underscore prefix by querying the + __USER_LABEL_PREFIX__ define that most compilers provide + for this. Return if functions have underscore prefix or None + if it was not possible to determine, like when the compiler + does not set the define or the define has an unexpected value. + ''' + delim = '"MESON_HAVE_UNDERSCORE_DELIMITER" ' + code = f''' + #ifndef __USER_LABEL_PREFIX__ + #define MESON_UNDERSCORE_PREFIX unsupported + #else + #define MESON_UNDERSCORE_PREFIX __USER_LABEL_PREFIX__ + #endif + {delim}MESON_UNDERSCORE_PREFIX + ''' + with self._build_wrapper(code, env, mode='preprocess', want_output=False, temp_dir=env.scratch_dir) as p: + if p.returncode != 0: + raise RuntimeError(f'BUG: Unable to preprocess _symbols_have_underscore_prefix_define check: {p.stdout}') + symbol_prefix = p.stdout.partition(delim)[-1].rstrip() + + mlog.debug(f'Queried compiler for function prefix: __USER_LABEL_PREFIX__ is "{symbol_prefix!s}"') + if symbol_prefix == '_': + return True + elif symbol_prefix == '': + return False + else: + return None + + def _symbols_have_underscore_prefix_list(self, env: 'Environment') -> T.Optional[bool]: + ''' + Check if symbols have underscore prefix by consulting a hardcoded + list of cases where we know the results. + Return if functions have underscore prefix or None if unknown. + ''' + m = env.machines[self.for_machine] + # Darwin always uses the underscore prefix, not matter what + if m.is_darwin(): + return True + # Windows uses the underscore prefix on x86 (32bit) only + if m.is_windows() or m.is_cygwin(): + return m.cpu_family == 'x86' + return None + + + def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: + ''' + Check if the compiler prefixes an underscore to global C symbols + ''' + # First, try to query the compiler directly + result = self._symbols_have_underscore_prefix_define(env) + if result is not None: + return result + + # Else, try to consult a hardcoded list of cases we know + # absolutely have an underscore prefix + result = self._symbols_have_underscore_prefix_list(env) + if result is not None: + return result + + # As a last resort, try search in a compiled binary, which is the + # most unreliable way of checking this, see #5482 + return self._symbols_have_underscore_prefix_searchbin(env) + def _get_patterns(self, env: 'Environment', prefixes: T.List[str], suffixes: T.List[str], shared: bool = False) -> T.List[str]: patterns = [] # type: T.List[str] diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 5118e41..2f26453 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -383,6 +383,23 @@ class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta): def get_argument_syntax(self) -> str: return 'msvc' + def symbols_have_underscore_prefix(self, env: 'Environment') -> bool: + ''' + Check if the compiler prefixes an underscore to global C symbols. + + This overrides the Clike method, as for MSVC checking the + underscore prefix based on the compiler define never works, + so do not even try. + ''' + # Try to consult a hardcoded list of cases we know + # absolutely have an underscore prefix + result = self._symbols_have_underscore_prefix_list(env) + if result is not None: + return result + + # As a last resort, try search in a compiled binary + return self._symbols_have_underscore_prefix_searchbin(env) + class MSVCCompiler(VisualStudioLikeCompiler): diff --git a/run_tests.py b/run_tests.py index dc7a8f9..fcd9337 100755 --- a/run_tests.py +++ b/run_tests.py @@ -40,7 +40,7 @@ from mesonbuild import mesonlib from mesonbuild import mesonmain from mesonbuild import mtest from mesonbuild import mlog -from mesonbuild.environment import Environment, detect_ninja +from mesonbuild.environment import Environment, detect_ninja, detect_machine_info from mesonbuild.coredata import backendlist, version as meson_version from mesonbuild.mesonlib import OptionKey, setup_vsenv @@ -153,6 +153,17 @@ def get_fake_env(sdir='', bdir=None, prefix='', opts=None): env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library return env +def get_convincing_fake_env_and_cc(bdir, prefix): + ''' + Return a fake env and C compiler with the fake env + machine info properly detected using that compiler. + Useful for running compiler checks in the unit tests. + ''' + env = get_fake_env('', bdir, prefix) + cc = compilers.detect_c_compiler(env, mesonlib.MachineChoice.HOST) + # Detect machine info + env.machines.host = detect_machine_info({'c':cc}) + return (env, cc) Backend = Enum('Backend', 'ninja vs xcode') diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 8a7fcd7..67c50e7 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -60,7 +60,7 @@ from mesonbuild.scripts import destdir_join from mesonbuild.wrap.wrap import PackageDefinition, WrapException from run_tests import ( - Backend, exe_suffix, get_fake_env + Backend, exe_suffix, get_fake_env, get_convincing_fake_env_and_cc ) from .baseplatformtests import BasePlatformTests @@ -1546,6 +1546,32 @@ class AllPlatformTests(BasePlatformTests): self.build() self.run_tests() + def test_underscore_prefix_detection_list(self) -> None: + ''' + Test the underscore detection hardcoded lookup list + against what was detected in the binary. + ''' + env, cc = get_convincing_fake_env_and_cc(self.builddir, self.prefix) + expected_uscore = cc._symbols_have_underscore_prefix_searchbin(env) + list_uscore = cc._symbols_have_underscore_prefix_list(env) + if list_uscore is not None: + self.assertEqual(list_uscore, expected_uscore) + else: + raise SkipTest('No match in underscore prefix list for this platform.') + + def test_underscore_prefix_detection_define(self) -> None: + ''' + Test the underscore detection based on compiler-defined preprocessor macro + against what was detected in the binary. + ''' + env, cc = get_convincing_fake_env_and_cc(self.builddir, self.prefix) + expected_uscore = cc._symbols_have_underscore_prefix_searchbin(env) + define_uscore = cc._symbols_have_underscore_prefix_define(env) + if define_uscore is not None: + self.assertEqual(define_uscore, expected_uscore) + else: + raise SkipTest('Did not find the underscore prefix define __USER_LABEL_PREFIX__') + @skipIfNoPkgconfig def test_pkgconfig_static(self): ''' |