Merge pull request #9989 from ePirat/epirat-fix-uscore-prefix-detection

Fix underscore detection
pull/10216/head
Jussi Pakkanen 3 years ago committed by GitHub
commit efc7604ca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 81
      mesonbuild/compilers/mixins/clike.py
  2. 17
      mesonbuild/compilers/mixins/visualstudio.py
  3. 13
      run_tests.py
  4. 28
      unittests/allplatformstests.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]

@ -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):

@ -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')

@ -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):
'''

Loading…
Cancel
Save