diff options
| author | ruki <[email protected]> | 2026-01-24 08:02:15 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-24 08:02:15 +0800 |
| commit | 63b0d1fd45189858622b010fcac151efb8841025 (patch) | |
| tree | 3f269e815f0edba25e885cf5d3c1691c5c7eecd7 | |
| parent | 91724398015b16fb6377c0f3a7bdd2686d281853 (diff) | |
| parent | 86600e3d53105c12f6c1d28cb8b69b0b4d0053c3 (diff) | |
Merge pull request #7258 from xmake-io/qt
improve qt xpack
| -rw-r--r-- | tests/plugins/pack/qtapp/src/main.cpp | 3 | ||||
| -rw-r--r-- | tests/plugins/pack/qtapp/xmake.lua | 3 | ||||
| -rw-r--r-- | xmake/modules/private/utils/target.lua | 57 | ||||
| -rw-r--r-- | xmake/modules/target/action/install/main.lua | 59 | ||||
| -rw-r--r-- | xmake/modules/target/action/uninstall/main.lua | 57 | ||||
| -rw-r--r-- | xmake/plugins/pack/batchcmds.lua | 136 | ||||
| -rw-r--r-- | xmake/rules/qt/deploy/macosx.lua | 42 | ||||
| -rw-r--r-- | xmake/rules/qt/installcmd.lua | 19 |
8 files changed, 172 insertions, 204 deletions
diff --git a/tests/plugins/pack/qtapp/src/main.cpp b/tests/plugins/pack/qtapp/src/main.cpp index a1cfd8dea..452328225 100644 --- a/tests/plugins/pack/qtapp/src/main.cpp +++ b/tests/plugins/pack/qtapp/src/main.cpp @@ -1,8 +1,11 @@ #include "mainwindow.h" #include <QApplication> +#include <QDebug> +#include <zlib.h> int main(int argc, char *argv[]) { QApplication a(argc, argv); + qDebug() << "zlib version:" << zlibVersion(); MainWindow w; w.show(); return a.exec(); diff --git a/tests/plugins/pack/qtapp/xmake.lua b/tests/plugins/pack/qtapp/xmake.lua index fb10ae741..d4c9c9f4d 100644 --- a/tests/plugins/pack/qtapp/xmake.lua +++ b/tests/plugins/pack/qtapp/xmake.lua @@ -3,12 +3,15 @@ add_rules("mode.debug", "mode.release") includes("@builtin/xpack") +add_requires("zlib", {configs = {shared = true}, system = false}) + target("qtapp") add_rules("qt.widgetapp") add_headerfiles("src/*.h") add_files("src/*.cpp") add_files("src/mainwindow.ui") add_files("src/mainwindow.h") + add_packages("zlib") xpack("qtapp") set_formats("nsis", "dmg", "appimage", "zip", "targz") diff --git a/xmake/modules/private/utils/target.lua b/xmake/modules/private/utils/target.lua index 728bd6016..56fb6faeb 100644 --- a/xmake/modules/private/utils/target.lua +++ b/xmake/modules/private/utils/target.lua @@ -23,6 +23,7 @@ import("core.base.option") import("core.base.hashset") import("core.project.config") import("core.project.project") +import("utils.binary.deplibs", {alias = "get_depend_libraries"}) -- Is this target has these tools? function has_tool(toolname, tools) @@ -204,3 +205,59 @@ function config_targets(opt) end end end + +function get_target_package_libfiles(target, opt) + opt = opt or {} + local libfiles = {} + for _, pkg in ipairs(target:orderpkgs(opt)) do + if pkg:enabled() and pkg:get("libfiles") then + for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do + local filename = path.filename(libfile) + if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so[%.%d+]+$") or filename:endswith(".dylib") then + table.insert(libfiles, libfile) + end + end + end + end + -- we can only reserve used libraries + if project.policy("install.strip_packagelibs") then + if target:is_binary() or target:is_shared() or opt.binaryfile then + -- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ... + -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732 + local deplibs = get_depend_libraries(opt.binaryfile or target:targetfile(), { + plat = target:plat(), arch = target:arch(), + recursive = true, resolve_path = true, resolve_hint_paths = libfiles}) + if deplibs then + local depends = hashset.from(deplibs) + table.remove_if(libfiles, function (_, libfile) return not depends:has(libfile) end) + end + end + end + return libfiles +end + +-- get target libraries +function get_target_libfiles(target, libfiles, binaryfile, refs, opt) + if not refs[target] then + local plaindeps = target:get("deps") + if plaindeps then + for _, depname in ipairs(plaindeps) do + local dep = target:dep(depname) + if dep then + if dep:is_shared() then + local depfile = dep:targetfile() + if os.isfile(depfile) then + table.insert(libfiles, depfile) + end + get_target_libfiles(dep, libfiles, dep:targetfile(), refs, opt) + elseif dep:is_library() then + get_target_libfiles(dep, libfiles, binaryfile, refs, opt) + end + end + end + end + table.join2(libfiles, get_target_package_libfiles(target, table.join({binaryfile = binaryfile}, opt))) + refs[target] = true + end +end + diff --git a/xmake/modules/target/action/install/main.lua b/xmake/modules/target/action/install/main.lua index e4f48ddfa..2e92122e8 100644 --- a/xmake/modules/target/action/install/main.lua +++ b/xmake/modules/target/action/install/main.lua @@ -23,6 +23,7 @@ import("core.base.hashset") import("core.project.project") import("utils.binary.deplibs", {alias = "get_depend_libraries"}) import("utils.binary.rpath", {alias = "rpath_utils"}) +import("private.utils.target", {alias = "target_utils"}) function _get_target_libdir(target, opt) if not opt.installdir then @@ -48,63 +49,7 @@ function _get_target_includedir(target, opt) return path.join(opt.installdir, opt.includedir) end -function _get_target_package_libfiles(target, opt) - opt = opt or {} - if not opt.packages then - return {} - end - local libfiles = {} - for _, pkg in ipairs(target:orderpkgs(opt)) do - if pkg:enabled() and pkg:get("libfiles") then - for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do - local filename = path.filename(libfile) - if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so[%.%d+]+$") or filename:endswith(".dylib") then - table.insert(libfiles, libfile) - end - end - end - end - -- we can only reserve used libraries - if project.policy("install.strip_packagelibs") then - if target:is_binary() or target:is_shared() or opt.binaryfile then - -- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ... - -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732 - local deplibs = get_depend_libraries(opt.binaryfile or target:targetfile(), { - plat = target:plat(), arch = target:arch(), - recursive = true, resolve_path = true, resolve_hint_paths = libfiles}) - if deplibs then - local depends = hashset.from(deplibs) - table.remove_if(libfiles, function (_, libfile) return not depends:has(libfile) end) - end - end - end - return libfiles -end --- get target libraries -function _get_target_libfiles(target, libfiles, binaryfile, refs, opt) - if not refs[target] then - local plaindeps = target:get("deps") - if plaindeps then - for _, depname in ipairs(plaindeps) do - local dep = target:dep(depname) - if dep then - if dep:is_shared() then - local depfile = dep:targetfile() - if os.isfile(depfile) then - table.insert(libfiles, depfile) - end - _get_target_libfiles(dep, libfiles, dep:targetfile(), refs, opt) - elseif dep:is_library() then - _get_target_libfiles(dep, libfiles, binaryfile, refs, opt) - end - end - end - end - table.join2(libfiles, _get_target_package_libfiles(target, table.join({binaryfile = binaryfile}, opt))) - refs[target] = true - end -end -- copy file with symlinks function _copy_file_with_symlinks(srcfile, outputdir) @@ -162,7 +107,7 @@ function _install_shared_libraries(target, opt) -- get all dependent shared libraries local libfiles = {} - _get_target_libfiles(target, libfiles, target:targetfile(), {}, opt) + target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}, opt) libfiles = table.unique(libfiles) -- do install diff --git a/xmake/modules/target/action/uninstall/main.lua b/xmake/modules/target/action/uninstall/main.lua index 26ea33530..a81aa63d8 100644 --- a/xmake/modules/target/action/uninstall/main.lua +++ b/xmake/modules/target/action/uninstall/main.lua @@ -22,8 +22,8 @@ import("core.base.option") import("core.base.hashset") import("core.project.project") -import("utils.binary.deplibs", {alias = "get_depend_libraries"}) import("private.action.clean.remove_files") +import("private.utils.target", {alias = "target_utils"}) function _get_target_libdir(target, opt) if not opt.installdir then @@ -49,60 +49,7 @@ function _get_target_includedir(target, opt) return path.join(opt.installdir, opt.includedir) end -function _get_target_package_libfiles(target, opt) - opt = opt or {} - local libfiles = {} - for _, pkg in ipairs(target:orderpkgs(opt)) do - if pkg:enabled() and pkg:get("libfiles") then - for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do - local filename = path.filename(libfile) - if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so[%.%d+]+$") or filename:endswith(".dylib") then - table.insert(libfiles, libfile) - end - end - end - end - -- we can only reserve used libraries - if project.policy("install.strip_packagelibs") then - if target:is_binary() or target:is_shared() or opt.binaryfile then - -- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ... - -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732 - local deplibs = get_depend_libraries(opt.binaryfile or target:targetfile(), { - plat = target:plat(), arch = target:arch(), - recursive = true, resolve_path = true, resolve_hint_paths = libfiles}) - if deplibs then - local depends = hashset.from(deplibs) - table.remove_if(libfiles, function (_, libfile) return not depends:has(libfile) end) - end - end - end - return libfiles -end --- get target libraries -function _get_target_libfiles(target, libfiles, binaryfile, refs) - if not refs[target] then - local plaindeps = target:get("deps") - if plaindeps then - for _, depname in ipairs(plaindeps) do - local dep = target:dep(depname) - if dep then - if dep:is_shared() then - local depfile = dep:targetfile() - if os.isfile(depfile) then - table.insert(libfiles, depfile) - end - _get_target_libfiles(dep, libfiles, dep:targetfile(), refs) - elseif dep:is_library() then - _get_target_libfiles(dep, libfiles, binaryfile, refs) - end - end - end - end - table.join2(libfiles, _get_target_package_libfiles(target, {binaryfile = binaryfile})) - refs[target] = true - end -end -- remove file with symbols function _remove_file_with_symbols(filepath) @@ -150,7 +97,7 @@ function _uninstall_shared_libraries(target, opt) -- get all dependent shared libraries local libfiles = {} - _get_target_libfiles(target, libfiles, target:targetfile(), {}) + target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}) libfiles = table.unique(libfiles) -- do uninstall diff --git a/xmake/plugins/pack/batchcmds.lua b/xmake/plugins/pack/batchcmds.lua index 09b42d7c9..8fe0c08ed 100644 --- a/xmake/plugins/pack/batchcmds.lua +++ b/xmake/plugins/pack/batchcmds.lua @@ -25,7 +25,9 @@ import("core.project.project") import("utils.archive") import("utils.binary.deplibs", {alias = "get_depend_libraries"}) import("private.utils.batchcmds") +import("private.utils.target", {alias = "target_utils"}) +-- get target bindir function _get_target_bindir(package, target) local bindir = package:bindir() local prefixdir = target:prefixdir() @@ -35,6 +37,7 @@ function _get_target_bindir(package, target) return path.normalize(bindir) end +-- get target libdir function _get_target_libdir(package, target) local libdir = package:libdir() local prefixdir = target:prefixdir() @@ -44,6 +47,7 @@ function _get_target_libdir(package, target) return path.normalize(libdir) end +-- get target includedir function _get_target_includedir(package, target) local includedir = package:includedir() local prefixdir = target:prefixdir() @@ -53,6 +57,7 @@ function _get_target_includedir(package, target) return path.normalize(includedir) end +-- get target installdir function _get_target_installdir(package, target) local installdir = package:installdir() local prefixdir = target:prefixdir() @@ -62,60 +67,9 @@ function _get_target_installdir(package, target) return path.normalize(installdir) end -function _get_target_package_libfiles(target, opt) - opt = opt or {} - local libfiles = {} - for _, pkg in ipairs(target:orderpkgs(opt)) do - if pkg:enabled() and pkg:get("libfiles") then - for _, libfile in ipairs(table.wrap(pkg:get("libfiles"))) do - local filename = path.filename(libfile) - if filename:endswith(".dll") or filename:endswith(".so") or filename:find("%.so[%.%d+]+$") or filename:endswith(".dylib") then - table.insert(libfiles, libfile) - end - end - end - end - -- we can only reserve used libraries - if project.policy("install.strip_packagelibs") then - if target:is_binary() or target:is_shared() or opt.binaryfile then - -- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ... - -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732 - local deplibs = get_depend_libraries(opt.binaryfile or target:targetfile(), { - plat = target:plat(), arch = target:arch(), - recursive = true, resolve_path = true, resolve_hint_paths = libfiles}) - if deplibs then - local depends = hashset.from(deplibs) - table.remove_if(libfiles, function (_, libfile) return not depends:has(libfile) end) - end - end - end - return libfiles -end --- get target libraries -function _get_target_libfiles(target, libfiles, binaryfile, refs) - if not refs[target] then - local plaindeps = target:get("deps") - if plaindeps then - for _, depname in ipairs(plaindeps) do - local dep = target:dep(depname) - if dep then - if dep:is_shared() then - local depfile = dep:targetfile() - if os.isfile(depfile) then - table.insert(libfiles, depfile) - end - _get_target_libfiles(dep, libfiles, dep:targetfile(), refs) - elseif dep:is_library() then - _get_target_libfiles(dep, libfiles, binaryfile, refs) - end - end - end - end - table.join2(libfiles, _get_target_package_libfiles(target, {binaryfile = binaryfile})) - refs[target] = true - end -end + + -- copy file with symlinks function _copy_file_with_symlinks(batchcmds_, srcfile, outputdir) @@ -131,37 +85,10 @@ function _copy_file_with_symlinks(batchcmds_, srcfile, outputdir) end end --- update install rpath, we can only get and update rpathdirs with `{installonly = true}` --- e.g. add_rpathdirs("@loader_path/../lib", {installonly = true}) -function _update_target_install_rpath(target, batchcmds_, opt) - if target:is_plat("windows", "mingw") then - return - end - local package = opt.package - local bindir = _get_target_bindir(package, target) - local targetfile = path.join(bindir, target:filename()) - if target:policy("install.rpath") then - batchcmds_:clean_rpath(targetfile, {plat = target:plat(), arch = target:arch()}) - local result, sources = target:get_from("rpathdirs", "*") - if result and sources then - for idx, rpathdirs in ipairs(result) do - local source = sources[idx] - local extraconf = target:extraconf_from("rpathdirs", source) - if extraconf then - for _, rpathdir in ipairs(rpathdirs) do - local extra = extraconf[rpathdir] - if extra and extra.installonly then - batchcmds_:insert_rpath(targetfile, rpathdir, {plat = target:plat(), arch = target:arch()}) - end - end - end - end - end - end -end + -- install target files -function _install_target_files(target, batchcmds_, opt) +function install_target_files(target, batchcmds_, opt) local package = opt.package local srcfiles, dstfiles = target:installfiles(_get_target_installdir(package, target)) if srcfiles and dstfiles then @@ -199,13 +126,13 @@ function _install_target_headers(target, batchcmds_, opt) end -- install target shared libraries -function _install_target_shared_libraries(target, batchcmds_, opt) +function install_target_shared_libraries(target, batchcmds_, opt) local package = opt.package - local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target) + local bindir = opt.bindir or (target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target)) -- get all dependent shared libraries local libfiles = {} - _get_target_libfiles(target, libfiles, target:targetfile(), {}) + target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}) libfiles = table.unique(libfiles) -- do install @@ -251,7 +178,7 @@ function _uninstall_target_shared_libraries(target, batchcmds_, opt) -- get all dependent shared libraries local libfiles = {} - _get_target_libfiles(target, libfiles, target:targetfile(), {}) + target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}) libfiles = table.unique(libfiles) -- do uninstall @@ -261,6 +188,35 @@ function _uninstall_target_shared_libraries(target, batchcmds_, opt) end end +-- update install rpath, we can only get and update rpathdirs with `{installonly = true}` +-- e.g. add_rpathdirs("@loader_path/../lib", {installonly = true}) +function update_target_install_rpath(target, batchcmds, opt) + if target:is_plat("windows", "mingw") then + return + end + local package = opt.package + local bindir = _get_target_bindir(package, target) + local targetfile = path.join(bindir, target:filename()) + if target:policy("install.rpath") then + batchcmds:clean_rpath(targetfile, {plat = target:plat(), arch = target:arch()}) + local result, sources = target:get_from("rpathdirs", "*") + if result and sources then + for idx, rpathdirs in ipairs(result) do + local source = sources[idx] + local extraconf = target:extraconf_from("rpathdirs", source) + if extraconf then + for _, rpathdir in ipairs(rpathdirs) do + local extra = extraconf[rpathdir] + if extra and extra.installonly then + batchcmds:insert_rpath(targetfile, rpathdir, {plat = target:plat(), arch = target:arch()}) + end + end + end + end + end + end +end + -- on install binary target command function _on_target_installcmd_binary(target, batchcmds_, opt) local package = opt.package @@ -269,8 +225,8 @@ function _on_target_installcmd_binary(target, batchcmds_, opt) if os.isfile(target:symbolfile()) then batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile()))) end - _install_target_shared_libraries(target, batchcmds_, opt) - _update_target_install_rpath(target, batchcmds_, opt) + install_target_shared_libraries(target, batchcmds_, opt) + update_target_install_rpath(target, batchcmds_, opt) end -- on install shared target command @@ -293,7 +249,7 @@ function _on_target_installcmd_shared(target, batchcmds_, opt) end _install_target_headers(target, batchcmds_, opt) - _install_target_shared_libraries(target, batchcmds_, opt) + install_target_shared_libraries(target, batchcmds_, opt) end -- on install static target command @@ -358,7 +314,7 @@ function _on_target_installcmd(target, batchcmds_, opt) end -- install target files - _install_target_files(target, batchcmds_, opt) + install_target_files(target, batchcmds_, opt) end -- on uninstall binary target command diff --git a/xmake/rules/qt/deploy/macosx.lua b/xmake/rules/qt/deploy/macosx.lua index 6507d7032..deeafb11f 100644 --- a/xmake/rules/qt/deploy/macosx.lua +++ b/xmake/rules/qt/deploy/macosx.lua @@ -29,6 +29,7 @@ import("lib.detect.find_path") import("detect.sdks.find_qt") import("utils.progress") import("private.tools.codesign") +import("private.utils.target", {alias = "target_utils"}) -- save Info.plist function _save_info_plist(target, info_plist_file) @@ -74,6 +75,38 @@ function _save_info_plist(target, info_plist_file) </plist>]], name, name, name, name, target_minver or (macos.version():major() .. "." .. macos.version():minor()))) end +-- copy install files to Contents/Resources +function _install_target_files(target, target_contents) + local srcfiles, dstfiles = target:installfiles(path.join(target_contents, "Resources")) + if srcfiles and dstfiles then + for idx, srcfile in ipairs(srcfiles) do + os.cp(srcfile, dstfiles[idx]) + end + end + for _, dep in ipairs(target:orderdeps()) do + local srcfiles, dstfiles = dep:installfiles(path.join(target_contents, "Resources"), {interface = true}) + if srcfiles and dstfiles then + for idx, srcfile in ipairs(srcfiles) do + os.cp(srcfile, dstfiles[idx]) + end + end + end +end + +-- copy package libraries to Contents/Frameworks +function _install_target_frameworks(target, target_contents) + local libfiles = {} + target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}) + libfiles = table.unique(libfiles) + if #libfiles > 0 then + local frameworks_dir = path.join(target_contents, "Frameworks") + os.mkdir(frameworks_dir) + for _, libfile in ipairs(libfiles) do + os.cp(libfile, path.join(frameworks_dir, path.filename(libfile))) + end + end +end + -- deploy application package for macosx function main(target, opt) @@ -102,12 +135,19 @@ function main(target, opt) -- generate target app local target_contents = path.join(target_app, "Contents") os.tryrm(target_app) - os.cp(target:targetfile(), path.join(target_contents, "MacOS", target:basename())) + local target_binary = path.join(target_contents, "MacOS", target:basename()) + os.cp(target:targetfile(), target_binary) os.cp(path.join(os.programdir(), "scripts", "PkgInfo"), target_contents) -- generate Info.plist _save_info_plist(target, path.join(target_contents, "Info.plist")) + -- copy install files to Contents/Resources + _install_target_files(target, target_contents) + + -- copy package libraries to Contents/Frameworks + _install_target_frameworks(target, target_contents) + -- find qml directory local qmldir = target:values("qt.deploy.qmldir") if not qmldir then diff --git a/xmake/rules/qt/installcmd.lua b/xmake/rules/qt/installcmd.lua index 705ca9843..563e4b9c6 100644 --- a/xmake/rules/qt/installcmd.lua +++ b/xmake/rules/qt/installcmd.lua @@ -19,7 +19,11 @@ -- -- imports +import("core.project.project") +import("core.base.hashset") +import("utils.binary.deplibs", {alias = "get_depend_libraries"}) import("rules.qt.install.windeployqt", {rootdir = os.programdir()}) +import("plugins.pack.batchcmds", {alias = "pack_batchcmds", rootdir = os.programdir()}) -- install application for xpack function main(target, batchcmds, opt) @@ -73,6 +77,9 @@ function main(target, batchcmds, opt) -- copy all deployed files and directories from deploydir to root install directory via batchcmds local installdir = package:installdir() batchcmds:cp(path.join(deploydir, "*"), installdir, {rootdir = deploydir}) + + -- install other shared libraries (e.g. from packages) + pack_batchcmds.install_target_shared_libraries(target, batchcmds, {bindir = installdir, package = package}) else -- Linux: copy all files from bindir (plugins, translations, etc. should be handled separately) local bindir = target:bindir() @@ -80,7 +87,17 @@ function main(target, batchcmds, opt) local package_bindir = package:installdir("bin") -- copy all files and directories from bindir batchcmds:cp(path.join(bindir, "*"), package_bindir, {rootdir = bindir}) + + -- install shared libraries + local package_libdir = package:installdir("lib") + pack_batchcmds.install_target_shared_libraries(target, batchcmds, {bindir = package_libdir, package = package}) end end -end + -- install target files (resources, etc.) + -- for macosx, we have already installed them in deploy rule + if not target:is_plat("macosx") then + pack_batchcmds.install_target_files(target, batchcmds, opt) + pack_batchcmds.update_target_install_rpath(target, batchcmds, opt) + end +end |
