From e43e3e3ff780d130a1e1402ed9eabf0aa54c5c1d Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:54:54 +0530 Subject: fix(xcode.application): use the correct framework rpath for iOS apps Use @executable_path/Frameworks for iphoneos application bundles when embedding dependent frameworks. The existing @executable_path/../Frameworks rpath is correct for macOS app layout, but incorrect for iOS where the executable lives directly in MyApp.app and embedded frameworks live in MyApp.app/Frameworks. Add a regression test that builds an iOS simulator app with an embedded framework and verifies the generated LC_RPATH. --- .../objc/iosapp_framework_rpath/src/app/Info.plist | 20 +++++++++++++++ .../objc/iosapp_framework_rpath/src/app/main.m | 13 ++++++++++ .../src/framework/Info.plist | 18 +++++++++++++ .../iosapp_framework_rpath/src/framework/test.h | 3 +++ .../iosapp_framework_rpath/src/framework/test.m | 3 +++ .../projects/objc/iosapp_framework_rpath/test.lua | 30 ++++++++++++++++++++++ .../projects/objc/iosapp_framework_rpath/xmake.lua | 13 ++++++++++ xmake/rules/xcode/application/build.lua | 4 +-- 8 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 tests/projects/objc/iosapp_framework_rpath/src/app/Info.plist create mode 100644 tests/projects/objc/iosapp_framework_rpath/src/app/main.m create mode 100644 tests/projects/objc/iosapp_framework_rpath/src/framework/Info.plist create mode 100644 tests/projects/objc/iosapp_framework_rpath/src/framework/test.h create mode 100644 tests/projects/objc/iosapp_framework_rpath/src/framework/test.m create mode 100644 tests/projects/objc/iosapp_framework_rpath/test.lua create mode 100644 tests/projects/objc/iosapp_framework_rpath/xmake.lua diff --git a/tests/projects/objc/iosapp_framework_rpath/src/app/Info.plist b/tests/projects/objc/iosapp_framework_rpath/src/app/Info.plist new file mode 100644 index 000000000..64e1f01a8 --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/src/app/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + demo + CFBundleIdentifier + io.xmake.demo.ios + CFBundleName + demo + CFBundlePackageType + APPL + CFBundleVersion + 1 + CFBundleShortVersionString + 1.0 + UIApplicationSceneManifest + + + diff --git a/tests/projects/objc/iosapp_framework_rpath/src/app/main.m b/tests/projects/objc/iosapp_framework_rpath/src/app/main.m new file mode 100644 index 000000000..44183e7aa --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/src/app/main.m @@ -0,0 +1,13 @@ +#import +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end + +@implementation AppDelegate +@end + +int main(int argc, char *argv[]) { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])) + test_value(); +} diff --git a/tests/projects/objc/iosapp_framework_rpath/src/framework/Info.plist b/tests/projects/objc/iosapp_framework_rpath/src/framework/Info.plist new file mode 100644 index 000000000..0f3689457 --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/src/framework/Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleExecutable + test + CFBundleIdentifier + io.xmake.test.framework + CFBundleName + test + CFBundlePackageType + FMWK + CFBundleVersion + 1 + CFBundleShortVersionString + 1.0 + + diff --git a/tests/projects/objc/iosapp_framework_rpath/src/framework/test.h b/tests/projects/objc/iosapp_framework_rpath/src/framework/test.h new file mode 100644 index 000000000..91434eb54 --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/src/framework/test.h @@ -0,0 +1,3 @@ +#import + +FOUNDATION_EXPORT int test_value(void); diff --git a/tests/projects/objc/iosapp_framework_rpath/src/framework/test.m b/tests/projects/objc/iosapp_framework_rpath/src/framework/test.m new file mode 100644 index 000000000..7b8c414be --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/src/framework/test.m @@ -0,0 +1,3 @@ +int test_value(void) { + return 7; +} diff --git a/tests/projects/objc/iosapp_framework_rpath/test.lua b/tests/projects/objc/iosapp_framework_rpath/test.lua new file mode 100644 index 000000000..41e770e68 --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/test.lua @@ -0,0 +1,30 @@ +function main(t) + if not is_host("macosx") then + return t:skip("wrong host platform") + end + + os.execv("xmake", {"f", "-p", "iphoneos", "-a", "arm64", "--appledev=simulator", "-c"}) + os.execv("xmake", {"-vD"}) + + import("utils.binary.rpath") + local appfile = "build/iphoneos/arm64/release/demo.app/demo" + local rpaths = rpath.list(appfile) + local found_ios = false + local found_macos = false + if rpaths then + for _, p in ipairs(rpaths) do + if p == "@executable_path/Frameworks" then + found_ios = true + end + if p == "@executable_path/../Frameworks" then + found_macos = true + end + end + end + if not found_ios then + raise("missing iOS framework rpath @executable_path/Frameworks") + end + if found_macos then + raise("found macOS-style framework rpath in iOS app") + end +end diff --git a/tests/projects/objc/iosapp_framework_rpath/xmake.lua b/tests/projects/objc/iosapp_framework_rpath/xmake.lua new file mode 100644 index 000000000..68d0d7db1 --- /dev/null +++ b/tests/projects/objc/iosapp_framework_rpath/xmake.lua @@ -0,0 +1,13 @@ +add_rules("mode.release", "mode.debug") + +target("test") + add_rules("xcode.framework") + add_files("src/framework/test.m") + add_files("src/framework/Info.plist") + add_headerfiles("src/framework/test.h") + +target("demo") + add_rules("xcode.application") + add_deps("test") + add_files("src/app/*.m") + add_files("src/app/Info.plist") diff --git a/xmake/rules/xcode/application/build.lua b/xmake/rules/xcode/application/build.lua index 8ea734d28..7d1c836fa 100644 --- a/xmake/rules/xcode/application/build.lua +++ b/xmake/rules/xcode/application/build.lua @@ -49,7 +49,8 @@ function main (target, opt) -- @see https://github.com/xmake-io/xmake/issues/2679#issuecomment-1221839215 local targetfile = path.join(binarydir, path.filename(target:targetfile())) try { function () os.vrunv("install_name_tool", {"-delete_rpath", "@loader_path", targetfile}) end } - os.vrunv("install_name_tool", {"-add_rpath", "@executable_path/../Frameworks", targetfile}) + local rpath = target:is_plat("macosx") and "@executable_path/../Frameworks" or "@executable_path/Frameworks" + os.vrunv("install_name_tool", {"-add_rpath", rpath, targetfile}) -- copy dependent dynamic libraries and frameworks for _, dep in ipairs(target:orderdeps()) do @@ -109,4 +110,3 @@ function main (target, opt) end, {dependfile = target:dependfile(bundledir), files = {bundledir, target:targetfile()}, changed = target:is_rebuilt()}) end - -- cgit v1.3.1 From 84061455bdc813d3072afa8a998c8d049840b748 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sun, 5 Apr 2026 10:27:42 +0530 Subject: fix(test): move import to top of test.lua per review comment Co-authored-by: Qwen-Coder --- tests/projects/objc/iosapp_framework_rpath/test.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/projects/objc/iosapp_framework_rpath/test.lua b/tests/projects/objc/iosapp_framework_rpath/test.lua index 41e770e68..efc69dbea 100644 --- a/tests/projects/objc/iosapp_framework_rpath/test.lua +++ b/tests/projects/objc/iosapp_framework_rpath/test.lua @@ -1,3 +1,5 @@ +import("utils.binary.rpath") + function main(t) if not is_host("macosx") then return t:skip("wrong host platform") @@ -5,8 +7,6 @@ function main(t) os.execv("xmake", {"f", "-p", "iphoneos", "-a", "arm64", "--appledev=simulator", "-c"}) os.execv("xmake", {"-vD"}) - - import("utils.binary.rpath") local appfile = "build/iphoneos/arm64/release/demo.app/demo" local rpaths = rpath.list(appfile) local found_ios = false -- cgit v1.3.1 From d0f83e55778e37afc767cf8fa382e16d6e5dc001 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sun, 5 Apr 2026 10:38:00 +0530 Subject: fix(xcode.application): resolve merge conflict with upstream dev - add rpath duplicate guard Co-authored-by: Qwen-Coder --- xmake/rules/xcode/application/build.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xmake/rules/xcode/application/build.lua b/xmake/rules/xcode/application/build.lua index 7d1c836fa..d55d71a9c 100644 --- a/xmake/rules/xcode/application/build.lua +++ b/xmake/rules/xcode/application/build.lua @@ -23,6 +23,7 @@ import("core.base.option") import("core.theme.theme") import("core.project.depend") import("private.tools.codesign") +import("utils.binary.rpath", {alias = "rpath_utils"}) import("utils.progress") function main (target, opt) @@ -49,8 +50,13 @@ function main (target, opt) -- @see https://github.com/xmake-io/xmake/issues/2679#issuecomment-1221839215 local targetfile = path.join(binarydir, path.filename(target:targetfile())) try { function () os.vrunv("install_name_tool", {"-delete_rpath", "@loader_path", targetfile}) end } + -- macOS uses @executable_path/../Frameworks due to Contents/MacOS/ layout + -- iOS/watchOS/tvOS/visionOS use flat bundle layout where frameworks are in the same directory as the executable local rpath = target:is_plat("macosx") and "@executable_path/../Frameworks" or "@executable_path/Frameworks" - os.vrunv("install_name_tool", {"-add_rpath", rpath, targetfile}) + local rpathdirs = rpath_utils.list(targetfile, {plat = target:plat(), arch = target:arch()}) or {} + if not table.contains(rpathdirs, rpath) then + os.vrunv("install_name_tool", {"-add_rpath", rpath, targetfile}) + end -- copy dependent dynamic libraries and frameworks for _, dep in ipairs(target:orderdeps()) do -- cgit v1.3.1