cmake: Allow recasting a CMake dependency into an Apple framework

Fixes #12160
pull/12194/head
L. E. Segovia 1 year ago committed by Jussi Pakkanen
parent 6a119256a1
commit 05f4e0d6c5
  1. 50
      mesonbuild/cmake/tracetargets.py
  2. 2
      mesonbuild/dependencies/framework.py
  3. 1
      test cases/osx/9 framework recasting/main.cpp
  4. 5
      test cases/osx/9 framework recasting/meson.build

@ -4,6 +4,7 @@ from __future__ import annotations
from .common import cmake_is_debug from .common import cmake_is_debug
from .. import mlog from .. import mlog
from ..mesonlib import Version
from pathlib import Path from pathlib import Path
import re import re
@ -15,6 +16,28 @@ if T.TYPE_CHECKING:
from ..compilers import Compiler from ..compilers import Compiler
from ..dependencies import MissingCompiler from ..dependencies import MissingCompiler
# Small duplication of ExtraFramework to parse full
# framework paths as exposed by CMake
def _get_framework_latest_version(path: Path) -> str:
versions: list[Version] = []
for each in path.glob('Versions/*'):
# macOS filesystems are usually case-insensitive
if each.name.lower() == 'current':
continue
versions.append(Version(each.name))
if len(versions) == 0:
# most system frameworks do not have a 'Versions' directory
return 'Headers'
return 'Versions/{}/Headers'.format(sorted(versions)[-1]._s)
def _get_framework_include_path(path: Path) -> T.Optional[str]:
trials = ('Headers', 'Versions/Current/Headers', _get_framework_latest_version(path))
for each in trials:
trial = path / each
if trial.is_dir():
return trial.as_posix()
return None
class ResolvedTarget: class ResolvedTarget:
def __init__(self) -> None: def __init__(self) -> None:
self.include_directories: T.List[str] = [] self.include_directories: T.List[str] = []
@ -46,10 +69,25 @@ def resolve_cmake_trace_targets(target_name: str,
continue continue
if curr not in trace.targets: if curr not in trace.targets:
curr_path = Path(curr)
if reg_is_lib.match(curr): if reg_is_lib.match(curr):
res.libraries += [curr] res.libraries += [curr]
elif Path(curr).is_absolute() and Path(curr).exists(): elif curr_path.is_absolute() and curr_path.exists():
res.libraries += [curr] if any(x.endswith('.framework') for x in curr_path.parts):
# Frameworks detected by CMake are passed as absolute paths
# Split into -F/path/to/ and -framework name
path_to_framework = []
# Try to slice off the `Versions/X/name.tbd`
for x in curr_path.parts:
path_to_framework.append(x)
if x.endswith('.framework'):
break
curr_path = Path(*path_to_framework)
framework_path = curr_path.parent
framework_name = curr_path.stem
res.libraries += [f'-F{framework_path}', '-framework', framework_name]
else:
res.libraries += [curr]
elif reg_is_maybe_bare_lib.match(curr) and clib_compiler: elif reg_is_maybe_bare_lib.match(curr) and clib_compiler:
# CMake library dependencies can be passed as bare library names, # CMake library dependencies can be passed as bare library names,
# CMake brute-forces a combination of prefix/suffix combinations to find the # CMake brute-forces a combination of prefix/suffix combinations to find the
@ -115,9 +153,9 @@ def resolve_cmake_trace_targets(target_name: str,
processed_targets += [curr] processed_targets += [curr]
res.include_directories = sorted(set(res.include_directories)) # Do not sort flags here -- this breaks
res.link_flags = sorted(set(res.link_flags)) # semantics of eg. `-framework CoreAudio`
res.public_compile_opts = sorted(set(res.public_compile_opts)) # or `-Lpath/to/root -llibrary`
res.libraries = sorted(set(res.libraries)) # see eg. #11113
return res return res

@ -79,7 +79,7 @@ class ExtraFrameworkDependency(ExternalDependency):
return None return None
def _get_framework_latest_version(self, path: Path) -> str: def _get_framework_latest_version(self, path: Path) -> str:
versions = [] versions: T.List[Version] = []
for each in path.glob('Versions/*'): for each in path.glob('Versions/*'):
# macOS filesystems are usually case-insensitive # macOS filesystems are usually case-insensitive
if each.name.lower() == 'current': if each.name.lower() == 'current':

@ -0,0 +1,5 @@
project('framework recasting', 'c', 'cpp')
x = dependency('openal')
y = executable('tt', files('main.cpp'), dependencies: x)
Loading…
Cancel
Save