Skip to content

Commit

Permalink
Both variants
Browse files Browse the repository at this point in the history
  • Loading branch information
2xsaiko committed Feb 18, 2025
2 parents 95858d7 + 460c1f7 commit 7f0a58a
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 3 deletions.
2 changes: 2 additions & 0 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ def get_target_filename(self, t: T.Union[build.Target, build.CustomTargetIndex],
filename = t.get_outputs()[0]
elif isinstance(t, build.CustomTargetIndex):
filename = t.get_outputs()[0]
elif isinstance(t, build.BundleTarget):
filename = t.get_filename()
else:
assert isinstance(t, build.BuildTarget), t
filename = t.get_filename()
Expand Down
6 changes: 6 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,8 @@ def generate_target(self, target) -> None:
self.generate_custom_target(target)
if isinstance(target, build.RunTarget):
self.generate_run_target(target)
if isinstance(target, build.BundleTarget):
return self.generate_bundle_target3(target)
compiled_sources: T.List[str] = []
source2object: T.Dict[str, str] = {}
name = target.get_id()
Expand Down Expand Up @@ -1594,6 +1596,10 @@ def make_relative_link(src: PurePath, dst: PurePath):

self.add_build(elem)

def generate_bundle_target3(self, target: build.BundleTarget) -> None:
main_exe = os.path.join(self.get_target_dir(target.main_exe), target.main_exe.get_filename())
self.generate_bundle_target(target, main_exe)

def generate_cs_resource_tasks(self, target) -> T.Tuple[T.List[str], T.List[str]]:
args = []
deps = []
Expand Down
69 changes: 69 additions & 0 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3109,6 +3109,75 @@ def get_default_install_dir(self) -> T.Union[T.Tuple[str, str], T.Tuple[None, No
return self.environment.get_framework_dir(), '{frameworkdir}'


class BundleTarget(BundleTargetBase):
def __init__(self, name: str, subdir: str, subproject: str, environment: environment.Environment, main_exe: T.Union[Executable, SharedLibrary], bundle_type: BundleType):
super().__init__(name, subdir, subproject, True, main_exe.for_machine, environment)

self.main_exe: T.Union[Executable, SharedLibrary] = main_exe
self.bundle_type: BundleType = bundle_type
self.install_dir: T.Optional[str] = None

self.bundle_info: BundleInfo = BundleInfo(self)

if bundle_type == BundleType.APPLICATION:
assert isinstance(main_exe, Executable)
elif bundle_type == BundleType.FRAMEWORK:
assert isinstance(main_exe, SharedLibrary)

def __repr__(self):
repr_str = "<{0} {1}: {2}>"
return repr_str.format(self.__class__.__name__, self.get_id(), self.get_filename())

def __str__(self):
return f"{self.name}"

def get_default_install_dir(self) -> T.Union[T.Tuple[str, str], T.Tuple[None, None]]:
if self.bundle_type == BundleType.APPLICATION:
return self.environment.get_app_dir(), '{appdir}'
elif self.bundle_type == BundleType.FRAMEWORK:
return self.environment.get_framework_dir(), '{frameworkdir}'
else:
return (None, None)

def get_custom_install_dir(self) -> T.List[T.Union[str, Literal[False]]]:
return self.install_dir

def type_suffix(self) -> str:
if self.bundle_type == BundleType.APPLICATION:
return '@nsapp'
elif self.bundle_type == BundleType.FRAMEWORK:
return '@nsframework'
else:
return '@nsbundle'

@property
def typename(self) -> str:
if self.bundle_type == BundleType.APPLICATION:
return 'nsapp'
elif self.bundle_type == BundleType.FRAMEWORK:
return 'nsframework'
else:
return 'nsbundle'

def get_bundle_info(self) -> BundleInfo:
return self.bundle_info

def get_bundle_type(self) -> BundleType:
return self.bundle_type

def get_executable_name(self) -> str:
return self.main_exe.get_filename()

def get_filename(self) -> str:
return self.bundle_info.get_wrapper_name()

def can_output_be_directory(self, output: str) -> bool:
return output == self.get_filename()

def get_outputs(self) -> T.List[str]:
return [self.get_filename()]


@dataclass(eq=False)
class CustomTargetIndex(CustomTargetBase, HoldableObject):

Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ def build_holder_map(self) -> None:
build.Jar: OBJ.JarHolder,
build.AppBundle: OBJ.AppBundleHolder,
build.FrameworkBundle: OBJ.FrameworkBundleHolder,
build.BundleTarget: OBJ.BundleTargetHolder,
build.CustomTarget: OBJ.CustomTargetHolder,
build.CustomTargetIndex: OBJ.CustomTargetIndexHolder,
build.Generator: OBJ.GeneratorHolder,
Expand Down Expand Up @@ -489,7 +490,7 @@ def process_new_values(self, invalues: T.List[T.Union[TYPE_var, ExecutableSerial
for v in invalues:
if isinstance(v, ObjectHolder):
raise InterpreterException('Modules must not return ObjectHolders')
if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)):
if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget, build.BundleTarget)):
self.add_target(v.name, v)
elif isinstance(v, list):
self.process_new_values(v)
Expand Down
3 changes: 3 additions & 0 deletions mesonbuild/interpreter/interpreterobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,9 @@ class AppBundleHolder(BuildTargetHolder[build.AppBundle]):
class FrameworkBundleHolder(BuildTargetHolder[build.FrameworkBundle]):
pass

class BundleTargetHolder(ObjectHolder[build.BundleTarget]):
pass

class CustomTargetIndexHolder(ObjectHolder[build.CustomTargetIndex]):
def __init__(self, target: build.CustomTargetIndex, interp: 'Interpreter'):
super().__init__(target, interp)
Expand Down
75 changes: 73 additions & 2 deletions mesonbuild/modules/nsbundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,52 @@
import typing as T

from . import NewExtensionModule, ModuleInfo, ModuleReturnValue
from mesonbuild import build, dependencies
from mesonbuild.build import AppBundle, FrameworkBundle
from mesonbuild.interpreter.type_checking import NSAPP_KWS, NSFRAMEWORK_KWS, SOURCES_VARARGS
from mesonbuild.interpreterbase.decorators import FeatureNew, typed_kwargs, typed_pos_args
from mesonbuild.interpreter.type_checking import KwargInfo, NoneType, NSAPP_KWS, NSFRAMEWORK_KWS, SOURCES_VARARGS
from mesonbuild.interpreterbase.decorators import ContainerTypeInfo, FeatureNew, typed_kwargs, typed_pos_args
from mesonbuild.nsbundle import BundleType

if T.TYPE_CHECKING:
from typing_extensions import TypedDict

from . import ModuleState
from mesonbuild.interpreter.type_checking import SourcesVarargsType
from mesonbuild.interpreter import Interpreter, kwargs as kwtypes

class CommonKws(TypedDict):
contents: T.Optional[build.StructuredSources]
resources: T.Optional[build.StructuredSources]
extra_binaries: T.List[T.Union[str, build.File, build.Executable, build.CustomTarget, build.CustomTargetIndex]]
info_plist: T.Optional[T.Union[str, build.File, build.CustomTarget, build.CustomTargetIndex]]

class ApplicationKws(CommonKws):
layout: T.Optional[str]
executable_folder_name: T.Optional[str]

class FrameworkKws(CommonKws):
headers: T.Optional[build.StructuredSources]


COMMON_KWS: T.List[KwargInfo] = [
KwargInfo('contents', (NoneType, build.StructuredSources)),
KwargInfo('resources', (NoneType, build.StructuredSources)),
KwargInfo('extra_binaries', ContainerTypeInfo(list, (str, build.File, build.Executable, build.CustomTarget,
build.CustomTargetIndex)), default=[], listify=True),
KwargInfo('info_plist', (NoneType, str, build.File, build.CustomTarget, build.CustomTargetIndex))
]

APPLICATION_KWS: T.List[KwargInfo] = [
*COMMON_KWS,
KwargInfo('layout', (NoneType, str)),
KwargInfo('executable_folder_name', (NoneType, str)),
]

FRAMEWORK_KWS: T.List[KwargInfo] = [
*COMMON_KWS,
KwargInfo('headers', (NoneType, build.StructuredSources)),
]


def initialize(*args: T.Any, **kwargs: T.Any) -> NSBundleModule:
return NSBundleModule(*args, **kwargs)
Expand All @@ -28,6 +65,8 @@ def __init__(self, interpreter: Interpreter):
self.methods.update({
'application': self.application,
'framework': self.framework,
'wrap_application': self.wrap_application,
'wrap_framework': self.wrap_framework,
})

@FeatureNew('nsbundle.application', '1.7.99')
Expand All @@ -45,3 +84,35 @@ def framework(self, state: ModuleState, args: T.Tuple[str, SourcesVarargsType],
) -> ModuleReturnValue:
tgt = state.create_build_target(FrameworkBundle, args, kwargs)
return ModuleReturnValue(tgt, [tgt])

@FeatureNew('nsbundle.wrap_application', '1.7.99')
@typed_pos_args('nsbundle.wrap_application', build.Executable)
@typed_kwargs('nsbundle.wrap_application', *APPLICATION_KWS)
def wrap_application(self, state: ModuleState, args: T.Tuple[build.Executable], kwargs: ApplicationKws
) -> ModuleReturnValue:
(main_exe,) = args

tgt = build.BundleTarget(main_exe.name, state.subdir, state.subproject, state.environment, main_exe, BundleType.APPLICATION)
tgt.bundle_info.resources = kwargs['resources']
tgt.bundle_info.contents = kwargs['contents']
tgt.bundle_info.extra_binaries = kwargs['extra_binaries']

if kwargs['info_plist'] is not None:
tgt.bundle_info.info_dict_file = build._source_input_to_file(tgt, 'info_plist', kwargs['info_plist'])

return ModuleReturnValue(tgt, [tgt])

@FeatureNew('nsbundle.wrap_framework', '1.7.99')
@typed_pos_args('nsbundle.wrap_framework', (build.SharedLibrary, dependencies.InternalDependency))
@typed_kwargs('nsbundle.wrap_framework', *FRAMEWORK_KWS)
def wrap_framework(self, state: ModuleState,
args: T.Tuple[T.Union[build.SharedLibrary, dependencies.InternalDependency]],
kwargs: FrameworkKws) -> ModuleReturnValue:
(main_lib,) = args

# TODO
if not isinstance(main_lib, dependencies.InternalDependency):
main_lib = dependencies.InternalDependency(state.project_version, [], [], [], [main_lib], [], [], [], [],
{}, [], [], [])

return ModuleReturnValue(main_lib, [])

0 comments on commit 7f0a58a

Please sign in to comment.