summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorL. E. Segovia <amy@amyspark.me>2023-08-30 20:16:08 -0300
committerJussi Pakkanen <jpakkane@gmail.com>2024-02-25 01:59:39 +0200
commit05f4e0d6c5e74d5dfc1f1b32ac2ee26af664c950 (patch)
tree63966dfb09d0b2ea8e6270ec3602575db2a6d6d6
parent6a119256a1b87f22a6afe59b494ac50e52e24f07 (diff)
downloadmeson-05f4e0d6c5e74d5dfc1f1b32ac2ee26af664c950.tar.gz
cmake: Allow recasting a CMake dependency into an Apple framework
Fixes #12160
-rw-r--r--mesonbuild/cmake/tracetargets.py50
-rw-r--r--mesonbuild/dependencies/framework.py2
-rw-r--r--test cases/osx/9 framework recasting/main.cpp1
-rw-r--r--test cases/osx/9 framework recasting/meson.build5
4 files changed, 51 insertions, 7 deletions
diff --git a/mesonbuild/cmake/tracetargets.py b/mesonbuild/cmake/tracetargets.py
index 69d88a88c..aee67ea59 100644
--- a/mesonbuild/cmake/tracetargets.py
+++ b/mesonbuild/cmake/tracetargets.py
@@ -4,6 +4,7 @@ from __future__ import annotations
from .common import cmake_is_debug
from .. import mlog
+from ..mesonlib import Version
from pathlib import Path
import re
@@ -15,6 +16,28 @@ if T.TYPE_CHECKING:
from ..compilers import Compiler
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:
def __init__(self) -> None:
self.include_directories: T.List[str] = []
@@ -46,10 +69,25 @@ def resolve_cmake_trace_targets(target_name: str,
continue
if curr not in trace.targets:
+ curr_path = Path(curr)
if reg_is_lib.match(curr):
res.libraries += [curr]
- elif Path(curr).is_absolute() and Path(curr).exists():
- res.libraries += [curr]
+ elif curr_path.is_absolute() and curr_path.exists():
+ 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:
# CMake library dependencies can be passed as bare library names,
# 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]
- res.include_directories = sorted(set(res.include_directories))
- res.link_flags = sorted(set(res.link_flags))
- res.public_compile_opts = sorted(set(res.public_compile_opts))
- res.libraries = sorted(set(res.libraries))
+ # Do not sort flags here -- this breaks
+ # semantics of eg. `-framework CoreAudio`
+ # or `-Lpath/to/root -llibrary`
+ # see eg. #11113
return res
diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py
index cd53ff718..3c880c743 100644
--- a/mesonbuild/dependencies/framework.py
+++ b/mesonbuild/dependencies/framework.py
@@ -79,7 +79,7 @@ class ExtraFrameworkDependency(ExternalDependency):
return None
def _get_framework_latest_version(self, path: Path) -> str:
- versions = []
+ versions: T.List[Version] = []
for each in path.glob('Versions/*'):
# macOS filesystems are usually case-insensitive
if each.name.lower() == 'current':
diff --git a/test cases/osx/9 framework recasting/main.cpp b/test cases/osx/9 framework recasting/main.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/test cases/osx/9 framework recasting/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/test cases/osx/9 framework recasting/meson.build b/test cases/osx/9 framework recasting/meson.build
new file mode 100644
index 000000000..f139485ac
--- /dev/null
+++ b/test cases/osx/9 framework recasting/meson.build
@@ -0,0 +1,5 @@
+project('framework recasting', 'c', 'cpp')
+
+x = dependency('openal')
+
+y = executable('tt', files('main.cpp'), dependencies: x)