Skip to content

Commit

Permalink
add support for vs_module_defs to Executables
Browse files Browse the repository at this point in the history
fixes: #9254
  • Loading branch information
dcbaker committed Sep 27, 2023
1 parent 5a8c3f1 commit e9ca4b4
Show file tree
Hide file tree
Showing 10 changed files with 54 additions and 22 deletions.
4 changes: 4 additions & 0 deletions docs/markdown/snippets/executable_vs_module_defs.md
Original file line number Diff line number Diff line change
@@ -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]].
10 changes: 10 additions & 0 deletions docs/yaml/functions/executable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 2 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3248,6 +3248,8 @@ def get_target_type_link_args(self, target, linker):
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())
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/backend/vs2010backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,7 @@ def add_non_makefile_vcxproj_elements(
# 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))
Expand Down
46 changes: 27 additions & 19 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
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'}
Expand Down Expand Up @@ -1702,6 +1702,28 @@ def check_module_linking(self):
'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'.
Expand Down Expand Up @@ -1925,6 +1947,9 @@ def __init__(
# 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]
Expand Down Expand Up @@ -2323,24 +2348,7 @@ def process_kwargs(self, kwargs):
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')
Expand Down
1 change: 1 addition & 0 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]


Expand Down
1 change: 1 addition & 0 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ def _convert_darwin_versions(val: T.List[T.Union[str, int]]) -> T.Optional[T.Tup
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
Expand Down
2 changes: 2 additions & 0 deletions test cases/windows/9 vs module defs generated/exe.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
EXPORTS
exefunc
2 changes: 1 addition & 1 deletion test cases/windows/9 vs module defs generated/meson.build
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 5 additions & 1 deletion test cases/windows/9 vs module defs generated/prog.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit e9ca4b4

Please sign in to comment.