android: Added android_exe_type kwargs to executable

By setting android_exe_type to `application`, the executable gets
actually built as a shared library instead of an executable. This makes
it possible to use an application within an android application process.

mesonbuild#13758
https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/7555/
This commit is contained in:
Florian "sp1rit"​ 2025-04-16 22:11:38 +02:00 committed by Jussi Pakkanen
parent da28caa63d
commit 855cf199fc
8 changed files with 56 additions and 2 deletions

View File

@ -21,6 +21,17 @@ varargs_inherit: _build_target_base
kwargs_inherit: _build_target_base
kwargs:
android_exe_type:
type: str
default: "'executable'"
since: 1.8.0
description: |
Specifies the intended target of the executable. This can either be
`executable`, if the intended usecase is to run the executable using
fork + exec, or `application` if the executable is supposed to be
loaded as shared object by the android runtime.
export_dynamic:
type: bool
since: 0.45.0

View File

@ -112,7 +112,7 @@ known_build_target_kwargs = (
rust_kwargs |
cs_kwargs)
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs'}
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs', 'android_exe_type'}
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'}
@ -1996,6 +1996,7 @@ class Executable(BuildTarget):
super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects,
environment, compilers, kwargs)
self.win_subsystem = kwargs.get('win_subsystem') or 'console'
assert kwargs.get('android_exe_type') is None or kwargs.get('android_exe_type') in {'application', 'executable'}
# Check for export_dynamic
self.export_dynamic = kwargs.get('export_dynamic', False)
if not isinstance(self.export_dynamic, bool):

View File

@ -54,6 +54,7 @@ from .type_checking import (
CT_BUILD_BY_DEFAULT,
CT_INPUT_KW,
CT_INSTALL_DIR_KW,
_EXCLUSIVE_EXECUTABLE_KWS,
EXECUTABLE_KWS,
JAR_KWS,
LIBRARY_KWS,
@ -1816,12 +1817,24 @@ class Interpreter(InterpreterBase, HoldableObject):
def func_disabler(self, node, args, kwargs):
return Disabler()
def _strip_exe_specific_kwargs(self, kwargs: kwtypes.Executable) -> kwtypes._BuildTarget:
kwargs = kwargs.copy()
for exe_kwarg in _EXCLUSIVE_EXECUTABLE_KWS:
del kwargs[exe_kwarg.name]
return kwargs
@permittedKwargs(build.known_exe_kwargs)
@typed_pos_args('executable', str, varargs=SOURCES_VARARGS)
@typed_kwargs('executable', *EXECUTABLE_KWS, allow_unknown=True)
def func_executable(self, node: mparser.BaseNode,
args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.Executable) -> build.Executable:
for_machine = kwargs['native']
m = self.environment.machines[for_machine]
if m.is_android() and kwargs.get('android_exe_type') == 'application':
holder = self.build_target(node, args, self._strip_exe_specific_kwargs(kwargs), build.SharedLibrary)
holder.shared_library_only = True
return holder
return self.build_target(node, args, kwargs, build.Executable)
@permittedKwargs(build.known_stlib_kwargs)

View File

@ -393,6 +393,7 @@ class Executable(_BuildTarget):
pie: T.Optional[bool]
vs_module_defs: T.Optional[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex]]
win_subsystem: T.Optional[str]
android_exe_type: T.Optional[Literal['application', 'executable']]
class _StaticLibMixin(TypedDict):

View File

@ -701,6 +701,12 @@ _EXCLUSIVE_EXECUTABLE_KWS: T.List[KwargInfo] = [
convertor=lambda x: x.lower() if isinstance(x, str) else None,
validator=_validate_win_subsystem,
),
KwargInfo(
'android_exe_type',
(str, NoneType),
validator=in_set_validator({'application', 'executable'}),
since='1.8.0'
),
]
# The total list of arguments used by Executable

View File

@ -76,7 +76,7 @@ if T.TYPE_CHECKING:
v: bool
ALL_TESTS = ['cmake', 'common', 'native', 'warning-meson', 'failing-meson', 'failing-build', 'failing-test',
'keyval', 'platform-osx', 'platform-windows', 'platform-linux',
'keyval', 'platform-osx', 'platform-windows', 'platform-linux', 'platform-android',
'java', 'C#', 'vala', 'cython', 'rust', 'd', 'objective c', 'objective c++',
'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm', 'wayland',
'format',
@ -1123,6 +1123,8 @@ def detect_tests_to_run(only: T.Dict[str, T.List[str]], use_tmp: bool) -> T.List
TestCategory('platform-osx', 'osx', not mesonlib.is_osx()),
TestCategory('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()),
TestCategory('platform-linux', 'linuxlike', mesonlib.is_osx() or mesonlib.is_windows()),
# FIXME, does not actually run in CI, change to run the test if an Android cross toolchain is detected.
TestCategory('platform-android', 'android', not mesonlib.is_android()),
TestCategory('java', 'java', backend is not Backend.ninja or not have_java()),
TestCategory('C#', 'csharp', skip_csharp(backend)),
TestCategory('vala', 'vala', backend is not Backend.ninja or not shutil.which(os.environ.get('VALAC', 'valac'))),

View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(void) {
return 0;
}

View File

@ -0,0 +1,15 @@
project('android exe type', 'c')
fs = import('fs')
e = executable('executable', 'exe_type.c',
android_exe_type : 'executable')
a = executable('application', 'exe_type.c',
android_exe_type : 'application')
if fs.name(e.full_path()).contains('.')
error('Executable with exe_type `executable` did have expected filename')
endif
if not fs.name(a.full_path()).startswith('lib') or not fs.name(a.full_path()).endswith('.so')
error('Executable with exe_type `application` did not have expected filename')
endif