Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tests/projects/objc/macapp_external_dylib/ext/extfoo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int extfoo_value(void) {
return 7;
}
18 changes: 18 additions & 0 deletions tests/projects/objc/macapp_external_dylib/src/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>demo</string>
<key>CFBundleIdentifier</key>
<string>io.xmake.demo.external</string>
<key>CFBundleName</key>
<string>demo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions tests/projects/objc/macapp_external_dylib/src/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#import <AppKit/AppKit.h>

int extfoo_value(void);

int main(void) {
return extfoo_value() == 7 ? 0 : 1;
}
41 changes: 41 additions & 0 deletions tests/projects/objc/macapp_external_dylib/test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
function _build_external_dylib()
local arch = os.arch()
local sdkdir = os.iorunv("xcrun", {"--sdk", "macosx", "--show-sdk-path"}):trim()
os.execv("xcrun", {
"--sdk", "macosx", "clang",
"-dynamiclib",
"-target", arch .. "-apple-macos",
"-isysroot", sdkdir,
"-install_name", "@rpath/libextfoo.dylib",
"-o", "ext/libextfoo.dylib",
"ext/extfoo.c"
})
end

function main(t)
if not is_host("macosx") then
return t:skip("wrong host platform")
end

local homedir = path.absolute("home")
os.setenv("HOME", homedir)
os.mkdir(homedir)
os.mkdir(path.join(homedir, ".xmake"))

_build_external_dylib()
local arch = os.arch()

local xmake = path.absolute(path.join(os.projectdir(), "build", "xmake"))
local xmake_program_dir = path.absolute(path.join(os.projectdir(), "xmake"))
os.setenv("XMAKE_PROGRAM_FILE", xmake)
os.setenv("XMAKE_PROGRAM_DIR", xmake_program_dir)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here


os.execv(xmake, {"f", "-p", "macosx", "-a", arch, "-c"})
os.execv(xmake, {"-vD"})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here


local appdir = path.join("build", "macosx", arch, "release", "demo.app", "Contents", "Frameworks")
local dylibfile = path.join(appdir, "libextfoo.dylib")
if not os.isfile(dylibfile) then
raise("missing external dylib in macOS app bundle: %s", dylibfile)
end
end
10 changes: 10 additions & 0 deletions tests/projects/objc/macapp_external_dylib/xmake.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_rules("mode.release", "mode.debug")

set_languages("c11", "objc")

target("demo")
add_rules("xcode.application")
add_linkdirs("ext")
add_links("extfoo")
add_files("src/main.m")
add_files("src/Info.plist")
85 changes: 73 additions & 12 deletions xmake/rules/xcode/application/build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,42 @@
import("core.base.option")
import("core.theme.theme")
import("core.project.depend")
import("lib.detect.find_library")
import("private.tools.codesign")
import("private.utils.target", {alias = "target_utils"})
import("utils.binary.deplibs", {alias = "get_depend_libraries"})
import("utils.progress")

function _is_non_system_dylib(libfile)
return libfile and libfile:endswith(".dylib")
and not libfile:startswith("/usr/lib/")
and not libfile:startswith("/System/Library/")
end

local function _get_target_linkdirs(target)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here

local linkdirs = {}
for _, values in ipairs(table.wrap(target:get_from("linkdirs", "*"))) do
for _, linkdir in ipairs(table.wrap(values)) do
table.insert(linkdirs, path.absolute(linkdir))
end
end
return table.unique(linkdirs)
end

local function _get_target_linklibfiles(target)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here

local linkdirs = _get_target_linkdirs(target)
local libfiles = {}
for _, values in ipairs(table.wrap(target:get_from("links", "*"))) do
for _, link in ipairs(table.wrap(values)) do
local libinfo = find_library(link, linkdirs, {plat = target:plat(), kind = "shared"})
if libinfo then
table.insert(libfiles, path.join(libinfo.linkdir, libinfo.filename))
end
end
end
return table.unique(libfiles)
end

function main (target, opt)

-- get app and resources directory
Expand Down Expand Up @@ -51,18 +85,46 @@ function main (target, opt)
try { function () os.vrunv("install_name_tool", {"-delete_rpath", "@loader_path", targetfile}) end }
os.vrunv("install_name_tool", {"-add_rpath", "@executable_path/../Frameworks", targetfile})

-- copy dependent dynamic libraries and frameworks
-- copy dependent frameworks and dynamic libraries
local frameworks_to_copy = {}
local framework_targetfiles = {}
for _, dep in ipairs(target:orderdeps()) do
if dep:kind() == "shared" then
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of dependencies on non-framework dynamic libraries is also missing here.

if not os.isdir(frameworksdir) then
os.mkdir(frameworksdir)
end
local frameworkdir = dep:data("xcode.bundle.rootdir")
if dep:rule("xcode.framework") and frameworkdir then
os.cp(frameworkdir, frameworksdir, {symlink = true})
else
os.vcp(dep:targetfile(), frameworksdir)
end
local frameworkdir = dep:data("xcode.bundle.rootdir")
if dep:rule("xcode.framework") and frameworkdir then
table.insert(frameworks_to_copy, frameworkdir)
framework_targetfiles[path.absolute(dep:targetfile())] = true
end
end
local libfiles = {}
target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {})
table.join2(libfiles, _get_target_linklibfiles(target))
local dependfiles = get_depend_libraries(target:targetfile(), {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to the implementation details in the installation guide.

The get_target_libfiles function has already called get_depend_libraries internally. Then, _get_target_linklibfiles performs a very time-consuming find_library function, which then calls get_depend_libraries again.

plat = target:plat(),
arch = target:arch(),
recursive = true,
resolve_path = true,
resolve_hint_paths = libfiles
})
for _, dependfile in ipairs(table.wrap(dependfiles)) do
if _is_non_system_dylib(dependfile) then
table.insert(libfiles, dependfile)
end
end
local dylibs_to_copy = {}
for _, libfile in ipairs(table.unique(libfiles)) do
if not framework_targetfiles[path.absolute(libfile)] then
table.insert(dylibs_to_copy, libfile)
end
end
if #frameworks_to_copy > 0 or #dylibs_to_copy > 0 then
if not os.isdir(frameworksdir) then
os.mkdir(frameworksdir)
end
for _, frameworkdir in ipairs(frameworks_to_copy) do
os.cp(frameworkdir, frameworksdir, {symlink = true})
end
for _, libfile in ipairs(dylibs_to_copy) do
os.vcp(libfile, frameworksdir)
end
end

Expand Down Expand Up @@ -109,4 +171,3 @@ function main (target, opt)

end, {dependfile = target:dependfile(bundledir), files = {bundledir, target:targetfile()}, changed = target:is_rebuilt()})
end