add support for vs_module_defs to Executables

fixes: #9254
pull/12302/head
Dylan Baker 1 year ago committed by Eli Schwartz
parent 5421c24ea0
commit 32be9bd6de
  1. 4
      docs/markdown/snippets/executable_vs_module_defs.md
  2. 10
      docs/yaml/functions/executable.yaml
  3. 2
      mesonbuild/backend/ninjabackend.py
  4. 2
      mesonbuild/backend/vs2010backend.py
  5. 46
      mesonbuild/build.py
  6. 1
      mesonbuild/interpreter/kwargs.py
  7. 1
      mesonbuild/interpreter/type_checking.py
  8. 2
      test cases/windows/9 vs module defs generated/exe.def
  9. 2
      test cases/windows/9 vs module defs generated/meson.build
  10. 6
      test cases/windows/9 vs module defs generated/prog.c

@ -0,0 +1,4 @@
## Executable gains vs_module_defs keyword
This allows using a .def file to control which functions an [[executable]] will
expose to a [[shared_module]].

@ -44,3 +44,13 @@ kwargs:
type: bool
since: 0.49.0
description: Build a position-independent executable.
vs_module_defs:
type: str | file | custom_tgt | custom_idx
since: 1.3.0
description: |
Specify a Microsoft module definition file for controlling symbol exports,
etc., on platforms where that is possible (e.g. Windows).
This can be used to expose which functions a shared_module loaded by an
executable will be allowed to use.

@ -3248,6 +3248,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
commands += linker.gen_import_library_args(self.get_import_filename(target))
if target.pie:
commands += linker.get_pie_link_args()
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
elif isinstance(target, build.SharedLibrary):
if isinstance(target, build.SharedModule):
commands += linker.get_std_shared_module_link_args(target.get_options())

@ -1530,7 +1530,7 @@ class Vs2010Backend(backends.Backend):
# DLLs built with MSVC always have an import library except when
# they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
if isinstance(target, build.SharedLibrary):
if isinstance(target, (build.SharedLibrary, build.Executable)):
# Add module definitions file, if provided
if target.vs_module_defs:
relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src))

@ -114,7 +114,7 @@ known_build_target_kwargs = (
rust_kwargs |
cs_kwargs)
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs', 'rust_abi'}
known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink', 'rust_abi'}
@ -1702,6 +1702,28 @@ class BuildTarget(Target):
'use shared_library() with `override_options: [\'b_lundef=false\']` instead.')
link_target.force_soname = True
def process_vs_module_defs_kw(self, kwargs: T.Dict[str, T.Any]) -> None:
if kwargs.get('vs_module_defs') is None:
return
path: T.Union[str, File, CustomTarget, CustomTargetIndex] = kwargs['vs_module_defs']
if isinstance(path, str):
if os.path.isabs(path):
self.vs_module_defs = File.from_absolute_file(path)
else:
self.vs_module_defs = File.from_source_file(self.environment.source_dir, self.subdir, path)
elif isinstance(path, File):
# When passing a generated file.
self.vs_module_defs = path
elif isinstance(path, (CustomTarget, CustomTargetIndex)):
# When passing output of a Custom Target
self.vs_module_defs = File.from_built_file(path.get_subdir(), path.get_filename())
else:
raise InvalidArguments(
'vs_module_defs must be either a string, '
'a file object, a Custom Target, or a Custom Target Index')
self.process_link_depends(path)
class FileInTargetPrivateDir:
"""Represents a file with the path '/path/to/build/target_private_dir/fname'.
target_private_dir is the return value of get_target_private_dir which is e.g. 'subdir/target.p'.
@ -1925,6 +1947,9 @@ class Executable(BuildTarget):
# Remember that this exe was returned by `find_program()` through an override
self.was_returned_by_find_program = False
self.vs_module_defs: T.Optional[File] = None
self.process_vs_module_defs_kw(kwargs)
def post_init(self) -> None:
super().post_init()
machine = self.environment.machines[self.for_machine]
@ -2321,24 +2346,7 @@ class SharedLibrary(BuildTarget):
self.darwin_versions = (self.soversion, self.soversion)
# Visual Studio module-definitions file
if kwargs.get('vs_module_defs') is not None:
path = kwargs['vs_module_defs']
if isinstance(path, str):
if os.path.isabs(path):
self.vs_module_defs = File.from_absolute_file(path)
else:
self.vs_module_defs = File.from_source_file(self.environment.source_dir, self.subdir, path)
elif isinstance(path, File):
# When passing a generated file.
self.vs_module_defs = path
elif isinstance(path, (CustomTarget, CustomTargetIndex)):
# When passing output of a Custom Target
self.vs_module_defs = File.from_built_file(path.get_subdir(), path.get_filename())
else:
raise InvalidArguments(
'Shared library vs_module_defs must be either a string, '
'a file object, a Custom Target, or a Custom Target Index')
self.process_link_depends(path)
self.process_vs_module_defs_kw(kwargs)
rust_abi = kwargs.get('rust_abi')
rust_crate_type = kwargs.get('rust_crate_type')

@ -341,6 +341,7 @@ class _LibraryMixin(TypedDict):
class Executable(_BuildTarget):
gui_app: T.Optional[bool]
vs_module_defs: T.Optional[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex]]
win_subsystem: T.Optional[str]

@ -601,6 +601,7 @@ _EXCLUSIVE_EXECUTABLE_KWS: T.List[KwargInfo] = [
EXECUTABLE_KWS = [
*_BUILD_TARGET_KWS,
*_EXCLUSIVE_EXECUTABLE_KWS,
_VS_MODULE_DEFS_KW.evolve(since='1.3.0', since_values=None),
]
# Arguments exclusive to library types

@ -1,5 +1,5 @@
project('generated_dll_module_defs', 'c')
subdir('subdir')
exe = executable('prog', 'prog.c', link_with : shlib)
exe = executable('prog', 'prog.c', link_with : shlib, vs_module_defs : 'exe.def')
test('runtest', exe)

@ -1,5 +1,9 @@
int somedllfunc(void);
int exefunc(void) {
return 42;
}
int main(void) {
return somedllfunc() == 42 ? 0 : 1;
return somedllfunc() == exefunc() ? 0 : 1;
}

Loading…
Cancel
Save