summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2024-07-23 12:50:50 +0800
committerGitHub <[email protected]>2024-07-23 12:50:50 +0800
commitd4364efee8f1906288ac5c650ae7bd101066240a (patch)
tree72baca766710b28ca154f4b0f0983d7e9d8abc00
parent45852e6ffcd3f043d961574e72f40d287a2898ab (diff)
parent56ca5adad669d45f400198b0c99a1d20f546970c (diff)
Merge pull request #5335 from xmake-io/install
Improve installation
-rw-r--r--tests/actions/install/.gitignore8
-rw-r--r--tests/actions/install/src/foo.cpp5
-rw-r--r--tests/actions/install/src/foo.h17
-rw-r--r--tests/actions/install/src/foo.txt0
-rw-r--r--tests/actions/install/src/main.cpp7
-rw-r--r--tests/actions/install/test.lua10
-rw-r--r--tests/actions/install/xmake.lua27
-rw-r--r--xmake/actions/clean/main.lua12
-rw-r--r--xmake/actions/install/install.lua2
-rw-r--r--xmake/actions/install/install_admin.lua21
-rw-r--r--xmake/actions/install/main.lua5
-rw-r--r--xmake/actions/uninstall/main.lua5
-rw-r--r--xmake/actions/uninstall/uninstall.lua2
-rw-r--r--xmake/actions/uninstall/uninstall_admin.lua18
-rw-r--r--xmake/core/base/os.lua2
-rw-r--r--xmake/core/project/policy.lua4
-rw-r--r--xmake/core/project/target.lua63
-rw-r--r--xmake/core/sandbox/modules/os.lua16
-rw-r--r--xmake/modules/package/manager/xmake/find_package.lua7
-rw-r--r--xmake/modules/private/action/clean/remove_files.lua6
-rw-r--r--xmake/modules/private/utils/batchcmds.lua77
-rw-r--r--xmake/modules/target/action/install/main.lua233
-rw-r--r--xmake/modules/target/action/install/unix.lua161
-rw-r--r--xmake/modules/target/action/install/windows.lua163
-rw-r--r--xmake/modules/target/action/uninstall/main.lua191
-rw-r--r--xmake/modules/target/action/uninstall/unix.lua137
-rw-r--r--xmake/modules/target/action/uninstall/windows.lua115
-rw-r--r--xmake/modules/utils/binary/deplibs.lua (renamed from xmake/modules/utils/symbols/depend.lua)127
-rw-r--r--xmake/modules/utils/binary/rpath.lua277
-rw-r--r--xmake/plugins/pack/archive.lua1
-rw-r--r--xmake/plugins/pack/batchcmds.lua361
-rw-r--r--xmake/plugins/pack/xpack.lua6
-rw-r--r--xmake/rules/c++/modules/modules_support/compiler_support.lua2
-rw-r--r--xmake/rules/c++/modules/xmake.lua9
-rw-r--r--xmake/rules/utils/inherit_links/inherit_links.lua2
35 files changed, 1187 insertions, 912 deletions
diff --git a/tests/actions/install/.gitignore b/tests/actions/install/.gitignore
new file mode 100644
index 000000000..152105761
--- /dev/null
+++ b/tests/actions/install/.gitignore
@@ -0,0 +1,8 @@
+# Xmake cache
+.xmake/
+build/
+
+# MacOS Cache
+.DS_Store
+
+
diff --git a/tests/actions/install/src/foo.cpp b/tests/actions/install/src/foo.cpp
new file mode 100644
index 000000000..1a1fb3425
--- /dev/null
+++ b/tests/actions/install/src/foo.cpp
@@ -0,0 +1,5 @@
+#include "foo.h"
+
+int add(int a, int b) {
+ return a + b;
+}
diff --git a/tests/actions/install/src/foo.h b/tests/actions/install/src/foo.h
new file mode 100644
index 000000000..20df0baa4
--- /dev/null
+++ b/tests/actions/install/src/foo.h
@@ -0,0 +1,17 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_WIN32)
+# define __export __declspec(dllexport)
+#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+# define __export __attribute__((visibility("default")))
+#else
+# define __export
+#endif
+
+__export int add(int a, int b);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/actions/install/src/foo.txt b/tests/actions/install/src/foo.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/actions/install/src/foo.txt
diff --git a/tests/actions/install/src/main.cpp b/tests/actions/install/src/main.cpp
new file mode 100644
index 000000000..d55d4d342
--- /dev/null
+++ b/tests/actions/install/src/main.cpp
@@ -0,0 +1,7 @@
+#include "foo.h"
+#include <iostream>
+
+int main(int argc, char** argv) {
+ std::cout << "add(1, 2) = " << add(1, 2) << std::endl;
+ return 0;
+}
diff --git a/tests/actions/install/test.lua b/tests/actions/install/test.lua
new file mode 100644
index 000000000..4edc90275
--- /dev/null
+++ b/tests/actions/install/test.lua
@@ -0,0 +1,10 @@
+function main(t)
+ if is_host("windows", "linux", "macosx") and os.arch():startswith("x") then
+ os.vrun("xmake -y")
+ os.vrun("xmake run app")
+ os.vrun("xmake install -o build/usr")
+ if not is_host("linux") then -- TODO, change rpath has been not supported yet on linux.
+ os.vrun("./build/usr/app/bin/app" .. (is_host("windows") and ".exe" or ""))
+ end
+ end
+end
diff --git a/tests/actions/install/xmake.lua b/tests/actions/install/xmake.lua
new file mode 100644
index 000000000..652857116
--- /dev/null
+++ b/tests/actions/install/xmake.lua
@@ -0,0 +1,27 @@
+add_rules("mode.debug", "mode.release")
+
+set_version("1.0.1", {soname = true})
+
+add_requires("libzip", {system = false, configs = {shared = true}})
+
+target("foo")
+ set_kind("shared")
+ add_files("src/foo.cpp")
+ add_packages("libzip", {public = true})
+ add_headerfiles("src/foo.h", {public = true})
+ add_installfiles("src/foo.txt", {prefixdir = "assets", public = true})
+ set_prefixdir("/", {libdir = "foo_lib"})
+
+target("app")
+ set_kind("binary")
+ add_deps("foo")
+ add_files("src/main.cpp")
+ set_prefixdir("app", {libdir = "app_lib"})
+ add_rpathdirs("@loader_path/../app_lib", {installonly = true})
+
+includes("@builtin/xpack")
+
+xpack("test")
+ add_targets("app")
+ set_formats("zip")
+
diff --git a/xmake/actions/clean/main.lua b/xmake/actions/clean/main.lua
index 6470208d5..413a3121e 100644
--- a/xmake/actions/clean/main.lua
+++ b/xmake/actions/clean/main.lua
@@ -104,17 +104,19 @@ end
-- clean target
function _clean(targetname)
-
- -- clean the given target
if targetname then
local target = project.target(targetname)
_clean_target(target)
else
_clean_targets(project.ordertargets())
end
+end
- -- remove the configure directory if remove all
+-- clean configuration cache
+function _clean_configs()
if option.get("all") then
+ -- we need to close it first after removing file lock
+ project.filelock():close()
remove_files(config.directory())
end
end
@@ -142,7 +144,6 @@ function _try_clean()
end
end
--- main
function main()
-- try cleaning it using third-party buildsystem if xmake.lua not exists
@@ -176,6 +177,9 @@ function main()
-- unlock the whole project
project.unlock()
+ -- we must call it after unlocking project because it will remove project lockfile
+ _clean_configs()
+
-- leave project directory
os.cd(oldir)
end
diff --git a/xmake/actions/install/install.lua b/xmake/actions/install/install.lua
index ae9857ed3..95f634fe6 100644
--- a/xmake/actions/install/install.lua
+++ b/xmake/actions/install/install.lua
@@ -110,13 +110,11 @@ function main(targetname, group_pattern)
local targets = {}
if targetname and not targetname:startswith("__") then
local target = project.target(targetname)
- table.join2(targets, target:orderdeps())
table.insert(targets, target)
else
for _, target in ipairs(project.ordertargets()) do
local group = target:get("group")
if (target:is_default() and not group_pattern) or targetname == "__all" or (group_pattern and group and group:match(group_pattern)) then
- table.join2(targets, target:orderdeps())
table.insert(targets, target)
end
end
diff --git a/xmake/actions/install/install_admin.lua b/xmake/actions/install/install_admin.lua
index ba5101324..93fbf5beb 100644
--- a/xmake/actions/install/install_admin.lua
+++ b/xmake/actions/install/install_admin.lua
@@ -25,39 +25,30 @@ import("core.project.project")
import("core.platform.platform")
import("install")
--- install
function main(targetname, group_pattern, installdir, prefix)
-
local verbose = option.get("verbose")
+ if group_pattern and #group_pattern == 0 then
+ group_pattern = nil
+ end
+ if installdir and #installdir == 0 then
+ installdir = nil
+ end
- -- enter project directory
os.cd(project.directory())
-
- -- load config
config.load()
-
- -- load platform
platform.load(config.plat())
-- save the current option and push a new option context
option.save()
-
- -- preserve verbose option
option.set("verbose", verbose)
-
- -- pass installdir to option
if installdir then
option.set("installdir", installdir)
end
-
- -- pass prefix to option
if prefix then
option.set("prefix", prefix)
end
-- install target
install(targetname, group_pattern)
-
- -- restore the previous option context
option.restore()
end
diff --git a/xmake/actions/install/main.lua b/xmake/actions/install/main.lua
index 1d9f8b1c1..24081f874 100644
--- a/xmake/actions/install/main.lua
+++ b/xmake/actions/install/main.lua
@@ -116,7 +116,10 @@ function main()
if sudo.has() and option.get("admin") then
-- install target with administrator permission
- sudo.execl(path.join(os.scriptdir(), "install_admin.lua"), {targetname or (option.get("all") and "__all" or "__def"), group_pattern, option.get("installdir"), option.get("prefix")})
+ sudo.execl(path.join(os.scriptdir(), "install_admin.lua"), {
+ targetname or (option.get("all") and "__all" or "__def"),
+ group_pattern or "", option.get("installdir") or "",
+ option.get("prefix")})
cprint("${color.success}install ok!")
ok = true
end
diff --git a/xmake/actions/uninstall/main.lua b/xmake/actions/uninstall/main.lua
index 5c403b85e..f2ae59eb9 100644
--- a/xmake/actions/uninstall/main.lua
+++ b/xmake/actions/uninstall/main.lua
@@ -68,7 +68,10 @@ function main()
if sudo.has() and option.get("admin") then
-- uninstall target with administrator permission
- sudo.execl(path.join(os.scriptdir(), "uninstall_admin.lua"), {targetname or "__all", option.get("installdir"), option.get("prefix")})
+ sudo.execl(path.join(os.scriptdir(), "uninstall_admin.lua"), {
+ targetname or "__all",
+ option.get("installdir") or "",
+ option.get("prefix")})
-- trace
cprint("${color.success}uninstall ok!")
diff --git a/xmake/actions/uninstall/uninstall.lua b/xmake/actions/uninstall/uninstall.lua
index 5aade0313..76feafd56 100644
--- a/xmake/actions/uninstall/uninstall.lua
+++ b/xmake/actions/uninstall/uninstall.lua
@@ -110,13 +110,11 @@ function main(targetname)
local targets = {}
if targetname and not targetname:startswith("__") then
local target = project.target(targetname)
- table.join2(targets, target:orderdeps())
table.insert(targets, target)
else
for _, target in ipairs(project.ordertargets()) do
local group = target:get("group")
if (target:is_default() and not group_pattern) or targetname == "__all" or (group_pattern and group and group:match(group_pattern)) then
- table.join2(targets, target:orderdeps())
table.insert(targets, target)
end
end
diff --git a/xmake/actions/uninstall/uninstall_admin.lua b/xmake/actions/uninstall/uninstall_admin.lua
index f597dea11..68b496d87 100644
--- a/xmake/actions/uninstall/uninstall_admin.lua
+++ b/xmake/actions/uninstall/uninstall_admin.lua
@@ -25,39 +25,27 @@ import("core.project.project")
import("core.platform.platform")
import("uninstall")
--- uninstall
function main(targetname, installdir, prefix)
-
local verbose = option.get("verbose")
+ if installdir and #installdir == 0 then
+ installdir = nil
+ end
- -- enter project directory
os.cd(project.directory())
-
- -- load config
config.load()
-
- -- load platform
platform.load(config.plat())
-- save the current option and push a new option context
option.save()
-
- -- preserve verbose option
option.set("verbose", verbose)
-
- -- pass installdir to option
if installdir then
option.set("installdir", installdir)
end
-
- -- pass prefix to option
if prefix then
option.set("prefix", prefix)
end
-- uninstall target
uninstall(targetname ~= "__all" and targetname or nil)
-
- -- restore the previous option context
option.restore()
end
diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua
index b0545afc8..9160aa534 100644
--- a/xmake/core/base/os.lua
+++ b/xmake/core/base/os.lua
@@ -503,7 +503,7 @@ function os.rm(filepath, opt)
return false, errors
end
if opt.emptydirs then
- ok, errors = os._rm_empty_parentdirs(filepath)
+ ok, errors = os._rm_empty_parentdirs(_filepath)
if not ok then
return false, errors
end
diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua
index 7299de719..2a2195cdb 100644
--- a/xmake/core/project/policy.lua
+++ b/xmake/core/project/policy.lua
@@ -68,6 +68,8 @@ function policy.policies()
["build.sanitizer.leak"] = {description = "Enable leak sanitizer for c/c++ building.", type = "boolean"},
-- Enable undefined sanitizer for c/c++ building.
["build.sanitizer.undefined"] = {description = "Enable undefined sanitizer for c/c++ building.", type = "boolean"},
+ -- Enable build rpath
+ ["build.rpath"] = {description = "Enable build rpath.", default = true, type = "boolean"},
-- Enable C++ modules for C++ building, even if no .mpp is involved in the compilation
["build.c++.modules"] = {description = "Enable C++ modules for C++ building.", type = "boolean"},
-- Enable std module
@@ -96,6 +98,8 @@ function policy.policies()
["windows.manifest.uac.ui"] = {description = "Enable windows manifest UAC.", type = "boolean"},
-- Automatically build before running
["run.autobuild"] = {description = "Automatically build before running.", type = "boolean"},
+ -- Enable install rpath
+ ["install.rpath"] = {description = "Enable install rpath.", default = true, type = "boolean"},
-- Preprocessor configuration for ccache/distcc, we can disable linemarkers to speed up preprocess
["preprocessor.linemarkers"] = {description = "Enable linemarkers for preprocessor.", default = true, type = "boolean"},
-- Preprocessor configuration for ccache/distcc, we can disable it to avoid cache object file with __DATE__, __TIME__
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 0ed7465d4..e19ea07c5 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -1623,20 +1623,56 @@ function _instance:rundir()
return baseoption.get("workdir") or self:get("rundir") or path.directory(self:targetfile())
end
--- get install directory
-function _instance:installdir()
+-- get prefix directory
+function _instance:prefixdir()
+ return self:get("prefixdir")
+end
+
+-- get the installed binary directory
+function _instance:bindir()
+ local bindir = self:extraconf("prefixdir", self:prefixdir(), "bindir")
+ if bindir == nil then
+ bindir = "bin"
+ end
+ return self:installdir(bindir)
+end
+
+-- get the installed library directory
+function _instance:libdir()
+ local libdir = self:extraconf("prefixdir", self:prefixdir(), "libdir")
+ if libdir == nil then
+ libdir = "lib"
+ end
+ return self:installdir(libdir)
+end
- -- get it from the cache
+-- get the installed include directory
+function _instance:includedir()
+ local includedir = self:extraconf("prefixdir", self:prefixdir(), "includedir")
+ if includedir == nil then
+ includedir = "include"
+ end
+ return self:installdir(includedir)
+end
+
+-- get install directory
+function _instance:installdir(...)
+ opt = opt or {}
local installdir = baseoption.get("installdir")
if not installdir then
-
-- DESTDIR: be compatible with https://www.gnu.org/prep/standards/html_node/DESTDIR.html
installdir = self:get("installdir") or os.getenv("INSTALLDIR") or os.getenv("PREFIX") or os.getenv("DESTDIR") or platform.get("installdir")
if installdir then
installdir = installdir:trim()
end
end
- return installdir
+ if installdir then
+ local prefixdir = self:prefixdir()
+ if prefixdir then
+ installdir = path.join(installdir, prefixdir)
+ end
+ return path.normalize(path.join(installdir, ...))
+ end
end
-- get package directory
@@ -2000,7 +2036,7 @@ end
-- get the header files
function _instance:headerfiles(outputdir, opt)
opt = opt or {}
- local headerfiles = self:get("headerfiles")
+ local headerfiles = self:get("headerfiles", opt) or {}
-- add_headerfiles("src/*.h", {install = false})
-- @see https://github.com/xmake-io/xmake/issues/2577
if opt.installonly then
@@ -2016,13 +2052,12 @@ function _instance:headerfiles(outputdir, opt)
return
end
- local headerdir = outputdir
- if not headerdir then
- if self:installdir() then
- headerdir = path.join(self:installdir(), "include")
+ if not outputdir then
+ if self:includedir() then
+ outputdir = self:includedir()
end
end
- return match_copyfiles(self, "headerfiles", headerdir, {copyfiles = headerfiles})
+ return match_copyfiles(self, "headerfiles", outputdir, {copyfiles = headerfiles})
end
-- get the configuration files
@@ -2036,8 +2071,9 @@ function _instance:configfiles(outputdir)
end
-- get the install files
-function _instance:installfiles(outputdir)
- return match_copyfiles(self, "installfiles", outputdir or self:installdir())
+function _instance:installfiles(outputdir, opt)
+ local installfiles = self:get("installfiles", opt) or {}
+ return match_copyfiles(self, "installfiles", outputdir or self:installdir(), {copyfiles = installfiles})
end
-- get the extra files
@@ -2737,6 +2773,7 @@ function target.apis()
, "target.set_runargs"
, "target.set_exceptions"
, "target.set_encodings"
+ , "target.set_prefixdir"
-- target.add_xxx
, "target.add_deps"
, "target.add_rules"
diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua
index 9004f66ee..d626d0372 100644
--- a/xmake/core/sandbox/modules/os.lua
+++ b/xmake/core/sandbox/modules/os.lua
@@ -102,21 +102,21 @@ function sandbox_os.cp(srcpath, dstpath, opt)
end
-- move file or directory
-function sandbox_os.mv(srcpath, dstpath)
+function sandbox_os.mv(srcpath, dstpath, opt)
assert(srcpath and dstpath)
srcpath = tostring(srcpath)
dstpath = tostring(dstpath)
- local ok, errors = os.mv(vformat(srcpath), vformat(dstpath))
+ local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt)
if not ok then
os.raise(errors)
end
end
-- remove files or directories
-function sandbox_os.rm(filepath)
+function sandbox_os.rm(filepath, opt)
assert(filepath)
filepath = tostring(filepath)
- local ok, errors = os.rm(vformat(filepath))
+ local ok, errors = os.rm(vformat(filepath), opt)
if not ok then
os.raise(errors)
end
@@ -161,12 +161,12 @@ function sandbox_os.vrm(filepath, opt)
end
-- link file or directory with the verbose info
-function sandbox_os.vln(srcpath, dstpath)
+function sandbox_os.vln(srcpath, dstpath, opt)
assert(srcpath and dstpath)
if option.get("verbose") then
utils.cprint("${dim}> link %s to %s", srcpath, dstpath)
end
- return sandbox_os.ln(srcpath, dstpath)
+ return sandbox_os.ln(srcpath, dstpath, opt)
end
-- try to copy file or directory
@@ -176,9 +176,9 @@ function sandbox_os.trycp(srcpath, dstpath, opt)
end
-- try to move file or directory
-function sandbox_os.trymv(srcpath, dstpath)
+function sandbox_os.trymv(srcpath, dstpath, opt)
assert(srcpath and dstpath)
- return os.mv(vformat(srcpath), vformat(dstpath))
+ return os.mv(vformat(srcpath), vformat(dstpath), opt)
end
-- try to remove files or directories
diff --git a/xmake/modules/package/manager/xmake/find_package.lua b/xmake/modules/package/manager/xmake/find_package.lua
index 0d5336fe4..e3aed1294 100644
--- a/xmake/modules/package/manager/xmake/find_package.lua
+++ b/xmake/modules/package/manager/xmake/find_package.lua
@@ -167,6 +167,13 @@ function _find_package_from_repo(name, opt)
result.shared = true
table.insert(libfiles, file)
end
+ -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242513463
+ if not result.shared then
+ for _, file in ipairs(os.files(path.join(installdir, "**.dll"))) do
+ result.shared = true
+ table.insert(libfiles, file)
+ end
+ end
end
-- add root link directories
diff --git a/xmake/modules/private/action/clean/remove_files.lua b/xmake/modules/private/action/clean/remove_files.lua
index 3d62c6b78..8ec7dca77 100644
--- a/xmake/modules/private/action/clean/remove_files.lua
+++ b/xmake/modules/private/action/clean/remove_files.lua
@@ -25,6 +25,10 @@ import("core.base.option")
function main(filedirs, opt)
opt = opt or {}
for _, filedir in ipairs(filedirs) do
- os.tryrm(filedir, {emptydirs = option.get("all") or opt.emptydir})
+ -- os.exists will return false if symlink -> not found, but we need still remove this symlink
+ if os.exists(filedir) or os.islink(filedir) then
+ -- we cannot use os.tryrm, because we need raise exception if remove failed with `uninstall --admin`
+ os.rm(filedir, {emptydirs = option.get("all") or opt.emptydir})
+ end
end
end
diff --git a/xmake/modules/private/utils/batchcmds.lua b/xmake/modules/private/utils/batchcmds.lua
index 6c3742b9f..97f414c77 100644
--- a/xmake/modules/private/utils/batchcmds.lua
+++ b/xmake/modules/private/utils/batchcmds.lua
@@ -29,6 +29,7 @@ import("core.tool.linker")
import("core.tool.compiler")
import("core.language.language")
import("utils.progress", {alias = "progress_utils"})
+import("utils.binary.rpath", {alias = "rpath_utils"})
-- define module
local batchcmds = batchcmds or object { _init = {"_TARGET", "_CMDS", "_DEPINFO", "_tip"}}
@@ -173,6 +174,34 @@ function _runcmd_ln(cmd, opt)
end
end
+-- run command: clean rpath
+function _runcmd_clean_rpath(cmd, opt)
+ if not opt.dryrun then
+ rpath_utils.clean(cmd.filepath, opt.opt)
+ end
+end
+
+-- run command: insert rpath
+function _runcmd_insert_rpath(cmd, opt)
+ if not opt.dryrun then
+ rpath_utils.insert(cmd.filepath, cmd.rpath, opt.opt)
+ end
+end
+
+-- run command: remove rpath
+function _runcmd_remove_rpath(cmd, opt)
+ if not opt.dryrun then
+ rpath_utils.remove(cmd.filepath, cmd.rpath, opt.opt)
+ end
+end
+
+-- run command: change rpath
+function _runcmd_change_rpath(cmd, opt)
+ if not opt.dryrun then
+ rpath_utils.change(cmd.filepath, cmd.rpath_old, cmd.rpath_new, opt.opt)
+ end
+end
+
-- run command
function _runcmd(cmd, opt)
local kind = cmd.kind
@@ -180,18 +209,22 @@ function _runcmd(cmd, opt)
if not maps then
maps =
{
- show = _runcmd_show,
- runv = _runcmd_runv,
- vrunv = _runcmd_vrunv,
- execv = _runcmd_execv,
- vexecv = _runcmd_vexecv,
- mkdir = _runcmd_mkdir,
- rmdir = _runcmd_rmdir,
- cd = _runcmd_cd,
- rm = _runcmd_rm,
- cp = _runcmd_cp,
- mv = _runcmd_mv,
- ln = _runcmd_ln
+ show = _runcmd_show,
+ runv = _runcmd_runv,
+ vrunv = _runcmd_vrunv,
+ execv = _runcmd_execv,
+ vexecv = _runcmd_vexecv,
+ mkdir = _runcmd_mkdir,
+ rmdir = _runcmd_rmdir,
+ cd = _runcmd_cd,
+ rm = _runcmd_rm,
+ cp = _runcmd_cp,
+ mv = _runcmd_mv,
+ ln = _runcmd_ln,
+ clean_rpath = _runcmd_clean_rpath,
+ insert_rpath = _runcmd_insert_rpath,
+ remove_rpath = _runcmd_remove_rpath,
+ change_rpath = _runcmd_change_rpath
}
_g.maps = maps
end
@@ -389,6 +422,26 @@ function batchcmds:show(format, ...)
table.insert(self:cmds(), {kind = "show", showtext = showtext})
end
+-- add command: clean rpath
+function batchcmds:clean_rpath(filepath, opt)
+ table.insert(self:cmds(), {kind = "clean_rpath", filepath = filepath, opt = opt})
+end
+
+-- add command: insert rpath
+function batchcmds:insert_rpath(filepath, rpath, opt)
+ table.insert(self:cmds(), {kind = "insert_rpath", filepath = filepath, rpath = rpath, opt = opt})
+end
+
+-- add command: remove rpath
+function batchcmds:remove_rpath(filepath, rpath, opt)
+ table.insert(self:cmds(), {kind = "remove_rpath", filepath = filepath, rpath = rpath, opt = opt})
+end
+
+-- add command: change rpath
+function batchcmds:change_rpath(filepath, rpath_old, rpath_new, opt)
+ table.insert(self:cmds(), {kind = "change_rpath", filepath = filepath, rpath_old = rpath_old, rpath_new = rpath_new, opt = opt})
+end
+
-- add raw command for the specific generator or xpack format
function batchcmds:rawcmd(kind, rawstr)
table.insert(self:cmds(), {kind = kind, rawstr = rawstr})
diff --git a/xmake/modules/target/action/install/main.lua b/xmake/modules/target/action/install/main.lua
index c115e836e..6eecfaba4 100644
--- a/xmake/modules/target/action/install/main.lua
+++ b/xmake/modules/target/action/install/main.lua
@@ -18,40 +18,239 @@
-- @file main.lua
--
+-- imports
+import("core.base.option")
+import("core.base.hashset")
+import("utils.binary.deplibs", {alias = "get_depend_libraries"})
+import("utils.binary.rpath", {alias = "rpath_utils"})
+
+-- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ...
+-- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732
+function _get_target_package_deplibs(target, depends, libfiles, binaryfile)
+ local deplibs = get_depend_libraries(binaryfile, {plat = target:plat(), arch = target:arch()})
+ local depends_new = hashset.new()
+ for _, deplib in ipairs(deplibs) do
+ local libname = path.filename(deplib)
+ if not depends:has(libname) then
+ depends:insert(libname)
+ depends_new:insert(libname)
+ end
+ end
+ for _, libfile in ipairs(libfiles) do
+ local libname = path.filename(libfile)
+ if depends_new:has(libname) then
+ _get_target_package_deplibs(target, depends, libfiles, libfile)
+ end
+ end
+end
+
+function _get_target_package_libfiles(target, opt)
+ if option.get("nopkgs") 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 target:is_binary() or target:is_shared() then
+ local depends = hashset.new()
+ _get_target_package_deplibs(target, depends, libfiles, target:targetfile())
+ table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end)
+ end
+ return libfiles
+end
+
+-- copy file with symlinks
+function _copy_file_with_symlinks(srcfile, outputdir)
+ if os.islink(srcfile) then
+ local srcfile_symlink = os.readlink(srcfile)
+ if not path.is_absolute(srcfile_symlink) then
+ srcfile_symlink = path.join(path.directory(srcfile), srcfile_symlink)
+ end
+ _copy_file_with_symlinks(srcfile_symlink, outputdir)
+ os.vcp(srcfile, path.join(outputdir, path.filename(srcfile)), {symlink = true, force = true})
+ else
+ os.vcp(srcfile, path.join(outputdir, path.filename(srcfile)))
+ end
+end
+
-- install files
function _install_files(target)
local srcfiles, dstfiles = target:installfiles()
if srcfiles and dstfiles then
- local i = 1
- for _, srcfile in ipairs(srcfiles) do
- local dstfile = dstfiles[i]
- if dstfile then
- os.vcp(srcfile, dstfile)
+ for idx, srcfile in ipairs(srcfiles) do
+ os.vcp(srcfile, dstfiles[idx])
+ end
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local srcfiles, dstfiles = dep:installfiles(dep:installdir(), {interface = true})
+ if srcfiles and dstfiles then
+ for idx, srcfile in ipairs(srcfiles) do
+ os.vcp(srcfile, dstfiles[idx])
end
- i = i + 1
end
end
end
--- the builtin install main entry
-function main(target, opt)
+-- install headers
+function _install_headers(target, opt)
+ local srcheaders, dstheaders = target:headerfiles(target:includedir(), {installonly = true})
+ if srcheaders and dstheaders then
+ for idx, srcheader in ipairs(srcheaders) do
+ os.vcp(srcheader, dstheaders[idx])
+ end
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local srcfiles, dstfiles = dep:headerfiles(dep:includedir(), {installonly = true, interface = true})
+ if srcfiles and dstfiles then
+ for idx, srcfile in ipairs(srcfiles) do
+ os.vcp(srcfile, dstfiles[idx])
+ end
+ end
+ end
+end
+
+-- install shared libraries
+function _install_shared_libraries(target, opt)
+ local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir()
+
+ -- get all dependent shared libraries
+ local libfiles = {}
+ for _, dep in ipairs(target:orderdeps()) do
+ if dep:kind() == "shared" then
+ local depfile = dep:targetfile()
+ if os.isfile(depfile) then
+ table.insert(libfiles, depfile)
+ end
+ end
+ table.join2(libfiles, _get_target_package_libfiles(dep, {interface = true}))
+ end
+ table.join2(libfiles, _get_target_package_libfiles(target))
+
+ -- deduplicate libfiles, prevent packages using the same libfiles from overwriting each other
+ libfiles = table.unique(libfiles)
+
+ -- do install
+ for _, libfile in ipairs(libfiles) do
+ local filename = path.filename(libfile)
+ local filepath = path.join(bindir, filename)
+ if os.isfile(filepath) and hash.sha256(filepath) ~= hash.sha256(libfile) then
+ wprint("'%s' already exists in install dir, we are copying '%s' to overwrite it.", filepath, libfile)
+ end
+ _copy_file_with_symlinks(libfile, bindir)
+ 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_install_rpath(target, opt)
+ if target:is_plat("windows", "mingw") then
+ return
+ end
+ local bindir = target:bindir()
+ local targetfile = path.join(bindir, target:filename())
+ if target:policy("install.rpath") then
+ rpath_utils.clean(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
+ rpath_utils.insert(targetfile, rpathdir, {plat = target:plat(), arch = target:arch()})
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- install binary
+function _install_binary(target, opt)
+ local bindir = target:bindir()
+ os.mkdir(bindir)
+ os.vcp(target:targetfile(), bindir)
+ os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))
+ _install_shared_libraries(target, opt)
+ _update_install_rpath(target, opt)
+end
+
+-- install shared library
+function _install_shared(target, opt)
+ local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir()
+ os.mkdir(bindir)
+ local targetfile = target:targetfile()
+
+ if target:is_plat("windows", "mingw") then
+ -- install *.lib for shared/windows (*.dll) target
+ -- @see https://github.com/xmake-io/xmake/issues/714
+ os.vcp(target:targetfile(), bindir)
+ local libdir = target:libdir()
+ local targetfile_lib = path.join(path.directory(targetfile), path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib"))
+ if os.isfile(targetfile_lib) then
+ os.mkdir(libdir)
+ os.vcp(targetfile_lib, libdir)
+ end
+ else
+ -- install target with soname and symlink
+ _copy_file_with_symlinks(targetfile, bindir)
+ end
+ os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))
+
+ _install_headers(target, opt)
+ _install_shared_libraries(target, opt)
+end
- -- get install directory
+-- install static library
+function _install_static(target, opt)
+ local libdir = target:libdir()
+ os.mkdir(libdir)
+ os.vcp(target:targetfile(), libdir)
+ os.trycp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile())))
+ _install_headers(target, opt)
+end
+
+-- install headeronly library
+function _install_headeronly(target, opt)
+ _install_headers(target, opt)
+end
+
+-- install moduleonly library
+function _install_moduleonly(target, opt)
+ _install_headers(target, opt)
+end
+
+function main(target, opt)
local installdir = target:installdir()
if not installdir then
+ wprint("please use `xmake install -o installdir` or `set_installdir` to set install directory.")
return
end
-
- -- trace
print("installing %s to %s ..", target:name(), installdir)
- -- call script
- local install_style = target:is_plat("windows", "mingw") and "windows" or "unix"
- local script = import(install_style, {anonymous = true})["install_" .. target:kind()]
- if script then
- script(target, opt)
+ if target:is_binary() then
+ _install_binary(target, opt)
+ elseif target:is_shared() then
+ _install_shared(target, opt)
+ elseif target:is_static() then
+ _install_static(target, opt)
+ elseif target:is_headeronly() then
+ _install_headeronly(target, opt)
+ elseif target:is_moduleonly() then
+ _install_moduleonly(target, opt)
end
- -- install other files
_install_files(target)
end
diff --git a/xmake/modules/target/action/install/unix.lua b/xmake/modules/target/action/install/unix.lua
deleted file mode 100644
index 71a6df42b..000000000
--- a/xmake/modules/target/action/install/unix.lua
+++ /dev/null
@@ -1,161 +0,0 @@
---!A cross-platform build utility based on Lua
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- Copyright (C) 2015-present, TBOOX Open Source Group.
---
--- @author ruki
--- @file unix.lua
---
-
--- imports
-import("core.base.option")
-
--- install headers
-function _install_headers(target, opt)
- local includedir = path.join(target:installdir(), opt and opt.includedir or "include")
- os.mkdir(includedir)
- local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true})
- if srcheaders and dstheaders then
- local i = 1
- for _, srcheader in ipairs(srcheaders) do
- local dstheader = dstheaders[i]
- if dstheader then
- os.vcp(srcheader, dstheader)
- end
- i = i + 1
- end
- end
-end
-
--- install shared libraries for package
-function _install_shared_for_package(target, pkg, outputdir)
- _g.installed_libfiles = _g.installed_libfiles or {}
- for _, sopath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if sopath:endswith(".so") or sopath:match(".+%.so%..+$") or sopath:endswith(".dylib") then
- -- prevent packages using the same system libfiles from overwriting each other
- if not _g.installed_libfiles[sopath] then
- local soname = path.filename(sopath)
- local targetname = path.join(outputdir, soname)
- if os.isfile(targetname) then
- wprint("'%s' already exists in install dir, overwriting it from package(%s).", soname, pkg:name())
- -- rm because symlink cannot overwrite existing file
- os.rm(targetname)
- end
- -- we need to reserve symlink
- -- @see https://github.com/xmake-io/xmake/issues/1582
- os.vcp(sopath, outputdir, {symlink = true, force = true})
- _g.installed_libfiles[sopath] = true
- end
- end
- end
-end
-
--- install shared libraries for packages
-function _install_shared_for_packages(target, outputdir)
- if option.get("nopkgs") then
- return
- end
- _g.installed_packages = _g.installed_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.installed_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _install_shared_for_package(target, pkg, outputdir)
- end
- _g.installed_packages[pkg:name()] = true
- end
- end
-end
-
--- install binary
-function install_binary(target, opt)
-
- -- install binary
- local binarydir = path.join(target:installdir(), opt and opt.bindir or "bin")
- os.mkdir(binarydir)
- os.vcp(target:targetfile(), binarydir)
-
- -- install libraries
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.mkdir(librarydir)
-
- -- install the dependent shared (*.so) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- for _, dep in ipairs(target:orderdeps()) do
- if dep:kind() == "shared" then
- local depfile = dep:targetfile()
- if os.isfile(depfile) then
- os.vcp(depfile, librarydir)
- end
- end
- -- install all shared libraries in packages in all deps
- _install_shared_for_packages(dep, librarydir)
- end
-
- -- install shared libraries for all packages
- _install_shared_for_packages(target, librarydir)
-end
-
--- install shared library
-function install_shared(target, opt)
-
- -- install libraries
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.mkdir(librarydir)
- local targetfile = target:targetfile()
- if os.islink(targetfile) then
- local targetfile_with_soname = os.readlink(targetfile)
- if not path.is_absolute(targetfile_with_soname) then
- targetfile_with_soname = path.join(target:targetdir(), targetfile_with_soname)
- end
- if os.islink(targetfile_with_soname) then
- local targetfile_with_version = os.readlink(targetfile_with_soname)
- if not path.is_absolute(targetfile_with_version) then
- targetfile_with_version = path.join(target:targetdir(), targetfile_with_version)
- end
- os.vcp(targetfile_with_version, librarydir, {symlink = true, force = true})
- end
- os.vcp(targetfile_with_soname, librarydir, {symlink = true, force = true})
- os.vcp(targetfile, librarydir, {symlink = true, force = true})
- else
- os.vcp(targetfile, librarydir)
- end
-
- -- install shared libraries for all packages
- _install_shared_for_packages(target, librarydir)
-
- -- install headers
- _install_headers(target, opt)
-end
-
--- install static library
-function install_static(target, opt)
-
- -- install libraries
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.mkdir(librarydir)
- os.vcp(target:targetfile(), librarydir)
-
- -- install headers
- _install_headers(target, opt)
-end
-
--- install headeronly library
-function install_headeronly(target, opt)
- _install_headers(target, opt)
-end
-
--- install moduleonly library
-function install_moduleonly(target, opt)
- _install_headers(target, opt)
-end
diff --git a/xmake/modules/target/action/install/windows.lua b/xmake/modules/target/action/install/windows.lua
deleted file mode 100644
index d7b71387c..000000000
--- a/xmake/modules/target/action/install/windows.lua
+++ /dev/null
@@ -1,163 +0,0 @@
---!A cross-platform build utility based on Lua
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- Copyright (C) 2015-present, TBOOX Open Source Group.
---
--- @author ruki
--- @file windows.lua
---
-
--- imports
-import("core.base.option")
-import("lib.detect.find_file")
-
--- get install directory
-function _get_installdir(target)
- local installdir = assert(target:installdir(), "please use `xmake install -o installdir` or `set_installdir` to set install directory on windows.")
- return installdir
-end
-
--- install headers
-function _install_headers(target, opt)
- local installdir = _get_installdir(target)
- local includedir = path.join(installdir, opt and opt.includedir or "include")
- os.mkdir(includedir)
- local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true})
- if srcheaders and dstheaders then
- local i = 1
- for _, srcheader in ipairs(srcheaders) do
- local dstheader = dstheaders[i]
- if dstheader then
- os.vcp(srcheader, dstheader)
- end
- i = i + 1
- end
- end
-end
-
--- install shared libraries for package
-function _install_shared_for_package(target, pkg, outputdir)
- _g.installed_dllfiles = _g.installed_dllfiles or {}
- for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if dllpath:endswith(".dll") then
- -- prevent packages using the same libfiles from overwriting each other
- if not _g.installed_dllfiles[dllpath] then
- local dllname = path.filename(dllpath)
- if os.isfile(path.join(outputdir, dllname)) then
- wprint("'%s' already exists in install dir, overwriting it from package(%s).", dllname, pkg:name())
- end
- os.vcp(dllpath, outputdir)
- _g.installed_dllfiles[dllpath] = true
- end
- end
- end
-end
-
--- install shared libraries for packages
-function _install_shared_for_packages(target, outputdir)
- if option.get("nopkgs") then
- return
- end
- _g.installed_packages = _g.installed_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.installed_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _install_shared_for_package(target, pkg, outputdir)
- end
- _g.installed_packages[pkg:name()] = true
- end
- end
-end
-
--- install binary
-function install_binary(target, opt)
-
- -- install binary
- local installdir = _get_installdir(target)
- local binarydir = path.join(installdir, opt and opt.bindir or "bin")
- os.mkdir(binarydir)
- os.vcp(target:targetfile(), binarydir)
- os.trycp(target:symbolfile(), binarydir)
-
- -- install the dependent shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- _g.installed_dllfiles = _g.installed_dllfiles or {}
- for _, dep in ipairs(target:orderdeps()) do
- if dep:kind() == "shared" then
- local depfile = dep:targetfile()
- if os.isfile(depfile) then
- if not _g.installed_dllfiles[depfile] then
- os.vcp(depfile, binarydir)
- _g.installed_dllfiles[depfile] = true
- end
- end
- end
- -- install all shared libraries in packages in all deps
- _install_shared_for_packages(dep, binarydir)
- end
-
- -- install shared libraries for all packages
- _install_shared_for_packages(target, binarydir)
-end
-
--- install shared library
-function install_shared(target, opt)
-
- -- install dll library to the binary directory
- local installdir = _get_installdir(target)
- local binarydir = path.join(installdir, opt and opt.bindir or "bin")
- os.mkdir(binarydir)
- os.vcp(target:targetfile(), binarydir)
- os.trycp(target:symbolfile(), binarydir)
-
- -- install *.lib for shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/714
- local targetfile = target:targetfile()
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- local targetfile_lib = path.join(path.directory(targetfile), path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib"))
- if os.isfile(targetfile_lib) then
- os.mkdir(librarydir)
- os.vcp(targetfile_lib, librarydir)
- end
-
- -- install shared libraries for all packages
- _install_shared_for_packages(target, binarydir)
-
- -- install headers
- _install_headers(target, opt)
-end
-
--- install static library
-function install_static(target, opt)
-
- -- install library
- local installdir = _get_installdir(target)
- local librarydir = path.join(installdir, opt and opt.libdir or "lib")
- os.mkdir(librarydir)
- os.vcp(target:targetfile(), librarydir)
- os.trycp(target:symbolfile(), librarydir)
-
- -- install headers
- _install_headers(target, opt)
-end
-
--- install headeronly
-function install_headeronly(target, opt)
- _install_headers(target, opt)
-end
-
--- install moduleonly
-function install_moduleonly(target, opt)
- _install_headers(target, opt)
-end
diff --git a/xmake/modules/target/action/uninstall/main.lua b/xmake/modules/target/action/uninstall/main.lua
index daa23917c..ab2333207 100644
--- a/xmake/modules/target/action/uninstall/main.lua
+++ b/xmake/modules/target/action/uninstall/main.lua
@@ -18,45 +18,192 @@
-- @file main.lua
--
+-- imports
+import("core.base.option")
+import("core.base.hashset")
+import("utils.binary.deplibs", {alias = "get_depend_libraries"})
+import("private.action.clean.remove_files")
+
+-- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ...
+-- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732
+function _get_target_package_deplibs(target, depends, libfiles, binaryfile)
+ local deplibs = get_depend_libraries(binaryfile, {plat = target:plat(), arch = target:arch()})
+ local depends_new = hashset.new()
+ for _, deplib in ipairs(deplibs) do
+ local libname = path.filename(deplib)
+ if not depends:has(libname) then
+ depends:insert(libname)
+ depends_new:insert(libname)
+ end
+ end
+ for _, libfile in ipairs(libfiles) do
+ local libname = path.filename(libfile)
+ if depends_new:has(libname) then
+ _get_target_package_deplibs(target, depends, libfiles, libfile)
+ end
+ end
+end
+
+function _get_target_package_libfiles(target, opt)
+ if option.get("nopkgs") then
+ return {}
+ end
+ local libfiles = {}
+ local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir()
+ 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 target:is_binary() or target:is_shared() then
+ local depends = hashset.new()
+ _get_target_package_deplibs(target, depends, libfiles, target:targetfile())
+ table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end)
+ end
+ return libfiles
+end
+
+-- remove file with symbols
+function _remove_file_with_symbols(filepath)
+ if os.islink(filepath) then
+ local filepath_symlink = os.readlink(filepath)
+ if not path.is_absolute(filepath_symlink) then
+ filepath_symlink = path.join(path.directory(filepath), filepath_symlink)
+ end
+ _remove_file_with_symbols(filepath_symlink)
+ end
+ remove_files(filepath, {emptydir = true})
+end
+
-- uninstall files
function _uninstall_files(target)
local _, dstfiles = target:installfiles()
for _, dstfile in ipairs(dstfiles) do
- os.vrm(dstfile)
+ remove_files(dstfile, {emptydir = true})
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local _, dstfiles = dep:installfiles(dep:installdir(), {interface = true})
+ for _, dstfile in ipairs(dstfiles) do
+ remove_files(dstfile, {emptydir = true})
+ end
end
end
--- uninstall modules
-function _uninstall_modules(target, opt)
- local moduledir = path.join(target:installdir(), opt and opt.moduledir or "modules")
- os.vrm(moduledir)
+-- uninstall headers
+function _uninstall_headers(target, opt)
+ local _, dstheaders = target:headerfiles(target:includedir(), {installonly = true})
+ for _, dstheader in ipairs(dstheaders) do
+ remove_files(dstheader, {emptydir = true})
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local _, dstfiles = dep:headerfiles(dep:includedir(), {installonly = true, interface = true})
+ for _, dstfile in ipairs(dstfiles) do
+ remove_files(dstfile, {emptydir = true})
+ end
+ end
end
--- the builtin uninstall main entry
-function main(target, opt)
+-- uninstall shared libraries
+function _uninstall_shared_libraries(target, opt)
+ local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir()
- -- get install directory
+ -- get all dependent shared libraries
+ local libfiles = {}
+ for _, dep in ipairs(target:orderdeps()) do
+ if dep:kind() == "shared" then
+ local depfile = dep:targetfile()
+ if os.isfile(depfile) then
+ table.insert(libfiles, depfile)
+ end
+ end
+ table.join2(libfiles, _get_target_package_libfiles(dep, {interface = true}))
+ end
+ table.join2(libfiles, _get_target_package_libfiles(target))
+
+ -- deduplicate libfiles, prevent packages using the same libfiles from overwriting each other
+ libfiles = table.unique(libfiles)
+
+ -- do uninstall
+ for _, libfile in ipairs(libfiles) do
+ local filename = path.filename(libfile)
+ local filepath = path.join(bindir, filename)
+ _remove_file_with_symbols(filepath)
+ end
+end
+
+-- uninstall binary
+function _uninstall_binary(target, opt)
+ local bindir = target:bindir()
+ remove_files(path.join(bindir, path.filename(target:targetfile())), {emptydir = true})
+ remove_files(path.join(bindir, path.filename(target:symbolfile())), {emptydir = true})
+ _uninstall_shared_libraries(target, opt)
+end
+
+-- uninstall shared library
+function _uninstall_shared(target, opt)
+ local bindir = target:is_plat("windows", "mingw") and target:bindir() or target:libdir()
+
+ if target:is_plat("windows", "mingw") then
+ -- uninstall *.lib for shared/windows (*.dll) target
+ -- @see https://github.com/xmake-io/xmake/issues/714
+ local libdir = target:libdir()
+ local targetfile = target:targetfile()
+ remove_files(path.join(bindir, path.filename(targetfile)), {emptydir = true})
+ remove_files(path.join(libdir, path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")), {emptydir = true})
+ else
+ local targetfile = path.join(bindir, path.filename(target:targetfile()))
+ _remove_file_with_symbols(targetfile)
+ end
+ remove_files(path.join(bindir, path.filename(target:symbolfile())), {emptydir = true})
+
+ _uninstall_headers(target, opt)
+ _uninstall_shared_libraries(target, opt)
+end
+
+-- uninstall static library
+function _uninstall_static(target, opt)
+ local libdir = target:libdir()
+ remove_files(path.join(libdir, path.filename(target:targetfile())), {emptydir = true})
+ remove_files(path.join(libdir, path.filename(target:symbolfile())), {emptydir = true})
+ _uninstall_headers(target, opt)
+end
+
+-- uninstall headeronly library
+function _uninstall_headeronly(target, opt)
+ _uninstall_headers(target, opt)
+end
+
+-- uninstall moduleonly library
+function _uninstall_moduleonly(target, opt)
+ _uninstall_headers(target, opt)
+end
+
+function main(target, opt)
local installdir = target:installdir()
if not installdir then
+ wprint("please use `xmake install -o installdir` or `set_installdir` to set install directory.")
return
end
+ print("uninstalling %s to %s ..", target:name(), installdir)
- -- trace
- print("uninstalling %s from %s ..", target:name(), installdir)
-
- -- call script
- if not target:is_phony() then
- local install_style = target:is_plat("windows", "mingw") and "windows" or "unix"
- local script = import(install_style, {anonymous = true})["uninstall_" .. target:kind()]
- if script then
- script(target, opt)
- end
+ if target:is_binary() then
+ _uninstall_binary(target, opt)
+ elseif target:is_shared() then
+ _uninstall_shared(target, opt)
+ elseif target:is_static() then
+ _uninstall_static(target, opt)
+ elseif target:is_headeronly() then
+ _uninstall_headeronly(target, opt)
+ elseif target:is_moduleonly() then
+ _uninstall_moduleonly(target, opt)
end
- -- remove modules
- _uninstall_modules(target, opt)
-
- -- uninstall the other files
_uninstall_files(target)
end
diff --git a/xmake/modules/target/action/uninstall/unix.lua b/xmake/modules/target/action/uninstall/unix.lua
deleted file mode 100644
index ce14c2c7b..000000000
--- a/xmake/modules/target/action/uninstall/unix.lua
+++ /dev/null
@@ -1,137 +0,0 @@
---!A cross-platform build utility based on Lua
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- Copyright (C) 2015-present, TBOOX Open Source Group.
---
--- @author ruki
--- @file unix.lua
---
-
--- imports
-import("private.action.clean.remove_files")
-
--- uninstall headers
-function _uninstall_headers(target, opt)
- local includedir = path.join(target:installdir(), opt and opt.includedir or "include")
- local _, dstheaders = target:headerfiles(includedir, {installonly = true})
- for _, dstheader in ipairs(dstheaders) do
- remove_files(dstheader, {emptydir = true})
- end
-end
-
--- uninstall shared libraries for package
-function _uninstall_shared_for_package(target, pkg, outputdir)
- for _, sopath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if sopath:endswith(".so") or sopath:match(".+%.so%..+$") or sopath:endswith(".dylib") then
- local soname = path.filename(sopath)
- local filepath = path.join(outputdir, soname)
- -- https://github.com/xmake-io/xmake/issues/2665#issuecomment-1209619081
- if os.islink(filepath) then
- -- relative link? e.g. libxx.so -> libxx.4.so
- local realitem = os.readlink(filepath)
- if realitem and not path.is_absolute(realitem) then
- local realpath = path.join(outputdir, realitem)
- if os.isfile(realpath) then
- os.vrm(realpath)
- end
- end
- end
- remove_files(filepath, {emptydir = true})
- end
- end
-end
-
--- uninstall shared libraries for packages
-function _uninstall_shared_for_packages(target, outputdir)
- _g.uninstalled_packages = _g.uninstalled_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.uninstalled_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _uninstall_shared_for_package(target, pkg, outputdir)
- end
- _g.uninstalled_packages[pkg:name()] = true
- end
- end
-end
-
--- uninstall binary
-function uninstall_binary(target, opt)
-
- -- remove the target file
- local binarydir = path.join(target:installdir(), opt and opt.bindir or "bin")
- os.vrm(path.join(binarydir, path.filename(target:targetfile())))
-
- -- remove the dependent shared (*.so) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- for _, dep in ipairs(target:orderdeps()) do
- if dep:kind() == "shared" then
- os.vrm(path.join(librarydir, path.filename(dep:targetfile())))
- end
- _uninstall_shared_for_packages(dep, librarydir)
- end
-
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, librarydir)
-end
-
--- uninstall shared library
-function uninstall_shared(target, opt)
-
- -- remove the target file
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- local targetfile = path.join(librarydir, path.filename(target:targetfile()))
- if os.islink(targetfile) then
- local targetfile_with_soname = os.readlink(targetfile)
- if not path.is_absolute(targetfile_with_soname) then
- targetfile_with_soname = path.join(librarydir, targetfile_with_soname)
- end
- if os.islink(targetfile_with_soname) then
- local targetfile_with_version = os.readlink(targetfile_with_soname)
- if not path.is_absolute(targetfile_with_version) then
- targetfile_with_version = path.join(librarydir, targetfile_with_version)
- end
- os.vrm(targetfile_with_version)
- end
- os.vrm(targetfile_with_soname)
- end
- os.vrm(targetfile)
-
- -- remove headers from the include directory
- _uninstall_headers(target, opt)
-
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, librarydir)
-end
-
--- uninstall static library
-function uninstall_static(target, opt)
-
- -- remove the target file
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.vrm(path.join(librarydir, path.filename(target:targetfile())))
-
- -- remove headers from the include directory
- _uninstall_headers(target, opt)
-end
-
--- uninstall headeronly library
-function uninstall_headeronly(target, opt)
- _uninstall_headers(target, opt)
-end
-
--- uninstall moduleonly library
-function uninstall_moduleonly(target, opt)
- _uninstall_headers(target, opt)
-end
diff --git a/xmake/modules/target/action/uninstall/windows.lua b/xmake/modules/target/action/uninstall/windows.lua
deleted file mode 100644
index 338f8c707..000000000
--- a/xmake/modules/target/action/uninstall/windows.lua
+++ /dev/null
@@ -1,115 +0,0 @@
---!A cross-platform build utility based on Lua
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- Copyright (C) 2015-present, TBOOX Open Source Group.
---
--- @author ruki
--- @file windows.lua
---
-
--- uninstall headers
-function _uninstall_headers(target, opt)
- local includedir = path.join(target:installdir(), opt and opt.includedir or "include")
- local _, dstheaders = target:headerfiles(includedir, {installonly = true})
- for _, dstheader in ipairs(dstheaders) do
- os.vrm(dstheader)
- end
-end
-
--- uninstall shared libraries for package
-function _uninstall_shared_for_package(target, pkg, outputdir)
- for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if dllpath:endswith(".dll") then
- local dllname = path.filename(dllpath)
- os.vrm(path.join(outputdir, dllname))
- end
- end
-end
-
--- uninstall shared libraries for packages
-function _uninstall_shared_for_packages(target, outputdir)
- _g.uninstalled_packages = _g.uninstalled_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.uninstalled_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _uninstall_shared_for_package(target, pkg, outputdir)
- end
- _g.uninstalled_packages[pkg:name()] = true
- end
- end
-end
-
--- uninstall binary
-function uninstall_binary(target, opt)
-
- -- remove the target file
- local binarydir = path.join(target:installdir(), opt and opt.bindir or "bin")
- os.vrm(path.join(binarydir, path.filename(target:targetfile())))
- os.tryrm(path.join(binarydir, path.filename(target:symbolfile())))
-
- -- remove the dependent shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- for _, dep in ipairs(target:orderdeps()) do
- if dep:kind() == "shared" then
- os.vrm(path.join(binarydir, path.filename(dep:targetfile())))
- end
- _uninstall_shared_for_packages(dep, binarydir)
- end
-
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, binarydir)
-end
-
--- uninstall shared library
-function uninstall_shared(target, opt)
-
- -- remove the target file
- local binarydir = path.join(target:installdir(), opt and opt.bindir or "bin")
- os.vrm(path.join(binarydir, path.filename(target:targetfile())))
- os.tryrm(path.join(binarydir, path.filename(target:symbolfile())))
-
- -- remove *.lib for shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/714
- local targetfile = target:targetfile()
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.vrm(path.join(librarydir, path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")))
-
- -- remove headers from the include directory
- _uninstall_headers(target, opt)
-
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, binarydir)
-end
-
--- uninstall static library
-function uninstall_static(target, opt)
-
- -- remove the target file
- local librarydir = path.join(target:installdir(), opt and opt.libdir or "lib")
- os.vrm(path.join(librarydir, path.filename(target:targetfile())))
- os.tryrm(path.join(librarydir, path.filename(target:symbolfile())))
-
- -- remove headers from the include directory
- _uninstall_headers(target, opt)
-end
-
--- uninstall headeronly library
-function uninstall_headeronly(target, opt)
- _uninstall_headers(target, opt)
-end
-
--- uninstall moduleonly library
-function uninstall_moduleonly(target, opt)
- _uninstall_headers(target, opt)
-end
diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/binary/deplibs.lua
index 94ca4c7e1..146e79504 100644
--- a/xmake/modules/utils/symbols/depend.lua
+++ b/xmake/modules/utils/binary/deplibs.lua
@@ -15,7 +15,7 @@
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki
--- @file depend.lua
+-- @file deplibs.lua
--
-- imports
@@ -27,7 +27,7 @@ function _get_all_depends_by_dumpbin(binaryfile, opt)
local depends
local plat = opt.plat or os.host()
local arch = opt.arch or os.arch()
- local cachekey = "utils.symbols.depend"
+ local cachekey = "utils.binary.deplibs"
local msvc = toolchain.load("msvc", {plat = plat, arch = arch})
if msvc:check() then
local dumpbin = find_tool("dumpbin", {cachekey = cachekey, envs = msvc:runenvs()})
@@ -38,16 +38,8 @@ function _get_all_depends_by_dumpbin(binaryfile, opt)
for _, line in ipairs(result:split("\n")) do
line = line:trim()
if line:endswith(".dll") then
- local dependfile
- if os.isfile(line) then
- dependfile = line
- elseif os.isfile(path.join(binarydir, line)) then
- dependfile = path.join(binarydir, line)
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, line)
end
end
end
@@ -60,7 +52,7 @@ function _get_all_depends_by_objdump(binaryfile, opt)
local depends
local plat = opt.plat or os.host()
local arch = opt.arch or os.arch()
- local cachekey = "utils.symbols.depend"
+ local cachekey = "utils.binary.deplibs"
local objdump = find_tool("llvm-objdump", {cachekey = cachekey}) or find_tool("objdump", {cachekey = cachekey})
if objdump then
local binarydir = path.directory(binaryfile)
@@ -76,51 +68,22 @@ function _get_all_depends_by_objdump(binaryfile, opt)
if line:startswith("DLL Name:") then
local filename = line:split(":")[2]:trim()
if filename:endswith(".dll") then
- local dependfile
- if os.isfile(filename) then
- dependfile = filename
- elseif os.isfile(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename)
end
end
elseif plat == "macosx" or plat == "iphoneos" or plat == "appletvos" or plat == "watchos" then
local filename = line:match(".-%.dylib") or line:match(".-%.framework")
if filename then
- local dependfile
- if os.exists(filename) then
- dependfile = filename
- elseif os.exists(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- elseif filename:startswith("@rpath/") then -- TODO
- filename = filename:sub(8)
- if os.exists(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename)
end
else
if line:startswith("NEEDED") then
local filename = line:split("%s+")[2]
if filename and filename:endswith(".so") then
- local dependfile
- if os.isfile(filename) then
- dependfile = filename
- elseif os.isfile(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename)
end
end
end
@@ -146,28 +109,23 @@ function _get_all_depends_by_ldd(binaryfile, opt)
return
end
local depends
- local cachekey = "utils.symbols.depend"
+ local cachekey = "utils.binary.deplibs"
local ldd = find_tool("ldd", {cachekey = cachekey})
if ldd then
local binarydir = path.directory(binaryfile)
local result = try { function () return os.iorunv(ldd.program, {binaryfile}) end }
if result then
for _, line in ipairs(result:split("\n")) do
- line = line:split("=>")[2] or line
+ local splitinfo = line:split("=>")
+ line = splitinfo[2]
+ if not line or line:find("not found", 1, true) then
+ line = splitinfo[1]
+ end
line = line:gsub("%(.+%)", ""):trim()
local filename = line:match(".-%.so$") or line:match(".-%.so%.%d+")
if filename then
- filename = filename:trim()
- local dependfile
- if os.isfile(filename) then
- dependfile = filename
- elseif os.isfile(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename:trim())
end
end
end
@@ -192,7 +150,7 @@ function _get_all_depends_by_readelf(binaryfile, opt)
return
end
local depends
- local cachekey = "utils.symbols.depend"
+ local cachekey = "utils.binary.deplibs"
local readelf = find_tool("readelf", {cachekey = cachekey})
if readelf then
local binarydir = path.directory(binaryfile)
@@ -202,17 +160,8 @@ function _get_all_depends_by_readelf(binaryfile, opt)
if line:find("NEEDED", 1, true) then
local filename = line:match("Shared library: %[(.-)%]")
if filename then
- filename = filename:trim()
- local dependfile
- if os.isfile(filename) then
- dependfile = filename
- elseif os.isfile(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename:trim())
end
end
end
@@ -236,7 +185,7 @@ function _get_all_depends_by_otool(binaryfile, opt)
return
end
local depends
- local cachekey = "utils.symbols.depend"
+ local cachekey = "utils.binary.deplibs"
local otool = find_tool("otool", {cachekey = cachekey})
if otool then
local binarydir = path.directory(binaryfile)
@@ -245,22 +194,8 @@ function _get_all_depends_by_otool(binaryfile, opt)
for _, line in ipairs(result:split("\n")) do
local filename = line:match(".-%.dylib") or line:match(".-%.framework")
if filename then
- filename = filename:trim()
- local dependfile
- if os.exists(filename) then
- dependfile = filename
- elseif os.exists(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- elseif filename:startswith("@rpath/") then -- TODO
- filename = filename:sub(8)
- if os.exists(path.join(binarydir, filename)) then
- dependfile = path.join(binarydir, filename)
- end
- end
- if dependfile then
- depends = depends or {}
- table.insert(depends, path.absolute(dependfile))
- end
+ depends = depends or {}
+ table.insert(depends, filename:trim())
end
end
end
@@ -270,19 +205,19 @@ end
function main(binaryfile, opt)
opt = opt or {}
- local dumpers = {
+ local ops = {
_get_all_depends_by_objdump,
_get_all_depends_by_readelf
}
if is_host("windows") then
- table.insert(dumpers, 2, _get_all_depends_by_dumpbin)
+ table.insert(ops, 2, _get_all_depends_by_dumpbin)
elseif is_host("linux", "bsd") then
- table.insert(dumpers, 1, _get_all_depends_by_ldd)
+ table.insert(ops, 1, _get_all_depends_by_ldd)
elseif is_host("macosx") then
- table.insert(dumpers, 1, _get_all_depends_by_otool)
+ table.insert(ops, 1, _get_all_depends_by_otool)
end
- for _, dump in ipairs(dumpers) do
- local depends = dump(binaryfile, opt)
+ for _, op in ipairs(ops) do
+ local depends = op(binaryfile, opt)
if depends then
return depends
end
diff --git a/xmake/modules/utils/binary/rpath.lua b/xmake/modules/utils/binary/rpath.lua
new file mode 100644
index 000000000..674a9edf0
--- /dev/null
+++ b/xmake/modules/utils/binary/rpath.lua
@@ -0,0 +1,277 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file rpath.lua
+--
+
+-- imports
+import("core.base.option")
+import("lib.detect.find_tool")
+
+function _replace_rpath_vars(rpath, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat == "macosx" or plat == "iphoneos" or plat == "appletvos" or plat == "watchos" then
+ rpath = rpath:gsub("%$ORIGIN", "@loader_path")
+ else
+ rpath = rpath:gsub("@loader_path", "$ORIGIN")
+ rpath = rpath:gsub("@executable_path", "$ORIGIN")
+ end
+ return rpath
+end
+
+function _get_rpath_list_by_objdump(binaryfile, opt)
+ local list
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ local cachekey = "utils.binary.rpath"
+ local objdump = find_tool("llvm-objdump", {cachekey = cachekey}) or find_tool("objdump", {cachekey = cachekey})
+ if objdump then
+ local binarydir = path.directory(binaryfile)
+ local argv = {"-x", binaryfile}
+ if plat == "macosx" or plat == "iphoneos" or plat == "appletvos" or plat == "watchos" then
+ argv = {"--macho", "-x", binaryfile}
+ end
+ local result = try { function () return os.iorunv(objdump.program, argv) end }
+ if result then
+ local cmd = false
+ for _, line in ipairs(result:split("\n")) do
+ line = line:trim()
+ if plat == "macosx" or plat == "iphoneos" or plat == "appletvos" or plat == "watchos" then
+ if not cmd and line:find("cmd LC_RPATH", 1, true) then
+ cmd = true
+ elseif cmd and (line:find("cmd ", 1, true) or line:find("Load command", 1, true)) then
+ cmd = false
+ end
+ if cmd then
+ local p = line:match("path (.-) %(")
+ if p then
+ list = list or {}
+ table.insert(list, p:trim())
+ end
+ end
+ else
+ if line:startswith("RUNPATH") or line:startswith("RPATH") then
+ local p = line:split("%s+")[2]
+ if p then
+ list = list or {}
+ table.insert(list, p:trim())
+ end
+ end
+ end
+ end
+ end
+ end
+ return list
+end
+
+-- $ readelf -d build/linux/x86_64/release/test
+--
+-- Dynamic section at offset 0x2db8 contains 29 entries:
+-- Tag Type Name/Value
+-- 0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
+-- 0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
+-- 0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
+-- 0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
+-- 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
+-- 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN]
+-- ...
+-- 0x000000000000000f (RPATH) Library rpath: [$ORIGIN]
+function _get_rpath_list_by_readelf(binaryfile, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat ~= "linux" and plat ~= "bsd" and plat ~= "android" and plat ~= "cross" then
+ return
+ end
+ local list
+ local cachekey = "utils.binary.rpath"
+ local readelf = find_tool("readelf", {cachekey = cachekey})
+ if readelf then
+ local binarydir = path.directory(binaryfile)
+ local result = try { function () return os.iorunv(readelf.program, {"-d", binaryfile}) end }
+ if result then
+ for _, line in ipairs(result:split("\n")) do
+ if line:find("RUNPATH", 1, true) then
+ local p = line:match("Library runpath: %[(.-)%]")
+ if p then
+ list = list or {}
+ table.insert(list, p:trim())
+ end
+ elseif line:find("RPATH", 1, true) then
+ local p = line:match("Library rpath: %[(.-)%]")
+ if p then
+ list = list or {}
+ table.insert(list, p:trim())
+ end
+ end
+ end
+ end
+ end
+ return list
+end
+
+-- $ otool -l build/iphoneos/arm64/release/test
+-- build/iphoneos/arm64/release/test:
+-- cmd LC_RPATH
+-- cmdsize 32
+-- path @loader_path (offset 12)
+--
+function _get_rpath_list_by_otool(binaryfile, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat ~= "macosx" and plat ~= "iphoneos" and plat ~= "appletvos" and plat ~= "watchos" then
+ return
+ end
+ local list
+ local cachekey = "utils.binary.rpath"
+ local otool = find_tool("otool", {cachekey = cachekey})
+ if otool then
+ local binarydir = path.directory(binaryfile)
+ local result = try { function () return os.iorunv(otool.program, {"-l", binaryfile}) end }
+ if result then
+ local cmd = false
+ for _, line in ipairs(result:split("\n")) do
+ if not cmd and line:find("cmd LC_RPATH", 1, true) then
+ cmd = true
+ elseif cmd and (line:find("cmd ", 1, true) or line:find("Load command", 1, true)) then
+ cmd = false
+ end
+ if cmd then
+ local p = line:match("path (.-) %(")
+ if p then
+ list = list or {}
+ table.insert(list, p:trim())
+ end
+ end
+ end
+ end
+ end
+ return list
+end
+
+-- install_name_tool -add_rpath <rpath> binaryfile
+function _insert_rpath_by_install_name_tool(binaryfile, rpath, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat ~= "macosx" and plat ~= "iphoneos" and plat ~= "appletvos" and plat ~= "watchos" then
+ return false
+ end
+ local ok = try { function ()
+ os.vrunv("install_name_tool", {"-add_rpath", rpath, binaryfile})
+ return true
+ end }
+ return ok
+end
+
+-- install_name_tool -rpath <rpath_old> <rpath_new> binaryfile
+function _change_rpath_by_install_name_tool(binaryfile, rpath_old, rpath_new, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat ~= "macosx" and plat ~= "iphoneos" and plat ~= "appletvos" and plat ~= "watchos" then
+ return false
+ end
+ local ok = try { function ()
+ os.vrunv("install_name_tool", {"-rpath", rpath_old, rpath_new, binaryfile})
+ return true
+ end }
+ return ok
+end
+
+-- install_name_tool -delete_rpath <rpath> binaryfile
+function _remove_rpath_by_install_name_tool(binaryfile, rpath, opt)
+ local plat = opt.plat or os.host()
+ local arch = opt.arch or os.arch()
+ if plat ~= "macosx" and plat ~= "iphoneos" and plat ~= "appletvos" and plat ~= "watchos" then
+ return false
+ end
+ local ok = try { function ()
+ os.vrunv("install_name_tool", {"-delete_rpath", rpath, binaryfile})
+ return true
+ end }
+ return ok
+end
+
+-- get rpath list
+function list(binaryfile, opt)
+ opt = opt or {}
+ local ops = {
+ _get_rpath_list_by_objdump,
+ _get_rpath_list_by_readelf
+ }
+ if is_host("macosx") then
+ table.insert(ops, 1, _get_rpath_list_by_otool)
+ end
+ for _, op in ipairs(ops) do
+ local result = op(binaryfile, opt)
+ if result then
+ return result
+ end
+ end
+end
+
+-- insert rpath
+function insert(binaryfile, rpath, opt)
+ opt = opt or {}
+ local ops = {}
+ if is_host("macosx") then
+ table.insert(ops, 1, _insert_rpath_by_install_name_tool)
+ end
+ rpath = _replace_rpath_vars(rpath, opt)
+ for _, op in ipairs(ops) do
+ if op(binaryfile, rpath, opt) then
+ break
+ end
+ end
+end
+
+-- change rpath
+function change(binaryfile, rpath_old, rpath_new, opt)
+ opt = opt or {}
+ local ops = {}
+ if is_host("macosx") then
+ table.insert(ops, 1, _change_rpath_by_install_name_tool)
+ end
+ rpath_old = _replace_rpath_vars(rpath_old, opt)
+ rpath_new = _replace_rpath_vars(rpath_new, opt)
+ for _, op in ipairs(ops) do
+ if op(binaryfile, rpath_old, rpath_new, opt) then
+ break
+ end
+ end
+end
+
+-- remove rpath
+function remove(binaryfile, rpath, opt)
+ opt = opt or {}
+ local ops = {}
+ if is_host("macosx") then
+ table.insert(ops, 1, _remove_rpath_by_install_name_tool)
+ end
+ rpath = _replace_rpath_vars(rpath, opt)
+ for _, op in ipairs(ops) do
+ if op(binaryfile, rpath, opt) then
+ break
+ end
+ end
+end
+
+-- clean rpath
+function clean(binaryfile, opt)
+ for _, rpath in ipairs(list(binaryfile, opt)) do
+ remove(binaryfile, rpath, opt)
+ end
+end
diff --git a/xmake/plugins/pack/archive.lua b/xmake/plugins/pack/archive.lua
index dd1861ca4..5d59c05fb 100644
--- a/xmake/plugins/pack/archive.lua
+++ b/xmake/plugins/pack/archive.lua
@@ -55,6 +55,7 @@ function _pack_archive(package)
local oldir = os.cd(rootdir)
local archivefiles = os.files("**")
os.cd(oldir)
+ os.tryrm(package:outputfile())
archive.archive(path.absolute(package:outputfile()), archivefiles, {curdir = rootdir, compress = "best"})
end
diff --git a/xmake/plugins/pack/batchcmds.lua b/xmake/plugins/pack/batchcmds.lua
index 8091134b2..4017ed175 100644
--- a/xmake/plugins/pack/batchcmds.lua
+++ b/xmake/plugins/pack/batchcmds.lua
@@ -20,124 +20,274 @@
-- imports
import("core.base.option")
+import("core.base.hashset")
import("utils.archive")
+import("utils.binary.deplibs", {alias = "get_depend_libraries"})
import("private.utils.batchcmds")
--- install headers
-function _install_headers(target, batchcmds_, includedir)
- local srcheaders, dstheaders = target:headerfiles(includedir, {installonly = true})
- if srcheaders and dstheaders then
- local i = 1
- for _, srcheader in ipairs(srcheaders) do
- local dstheader = dstheaders[i]
- if dstheader then
- batchcmds_:cp(srcheader, dstheader)
- end
- i = i + 1
+function _get_target_bindir(package, target)
+ local bindir = package:bindir()
+ local prefixdir = target:prefixdir()
+ if prefixdir then
+ bindir = path.join(package:installdir(), prefixdir, target:extraconf("prefixdir", prefixdir, "bindir") or "bin")
+ end
+ return path.normalize(bindir)
+end
+
+function _get_target_libdir(package, target)
+ local libdir = package:libdir()
+ local prefixdir = target:prefixdir()
+ if prefixdir then
+ libdir = path.join(package:installdir(), prefixdir, target:extraconf("prefixdir", prefixdir, "libdir") or "lib")
+ end
+ return path.normalize(libdir)
+end
+
+function _get_target_includedir(package, target)
+ local includedir = package:includedir()
+ local prefixdir = target:prefixdir()
+ if prefixdir then
+ includedir = path.join(package:installdir(), prefixdir, target:extraconf("prefixdir", prefixdir, "includedir") or "include")
+ end
+ return path.normalize(includedir)
+end
+
+function _get_target_installdir(package, target)
+ local installdir = package:installdir()
+ local prefixdir = target:prefixdir()
+ if prefixdir then
+ installdir = path.join(package:installdir(), prefixdir)
+ end
+ return path.normalize(installdir)
+end
+
+-- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ...
+-- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732
+function _get_target_package_deplibs(target, depends, libfiles, binaryfile)
+ local deplibs = get_depend_libraries(binaryfile, {plat = target:plat(), arch = target:arch()})
+ local depends_new = hashset.new()
+ for _, deplib in ipairs(deplibs) do
+ local libname = path.filename(deplib)
+ if not depends:has(libname) then
+ depends:insert(libname)
+ depends_new:insert(libname)
+ end
+ end
+ for _, libfile in ipairs(libfiles) do
+ local libname = path.filename(libfile)
+ if depends_new:has(libname) then
+ _get_target_package_deplibs(target, depends, libfiles, libfile)
end
end
end
--- install shared libraries for package
-function _install_shared_for_package(target, pkg, batchcmds_, outputdir)
- _g.installed_dllfiles = _g.installed_dllfiles or {}
- for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if dllpath:endswith(".dll") then
- -- prevent packages using the same libfiles from overwriting each other
- if not _g.installed_dllfiles[dllpath] then
- local dllname = path.filename(dllpath)
- batchcmds_:cp(dllpath, path.join(outputdir, dllname))
- _g.installed_dllfiles[dllpath] = true
+function _get_target_package_libfiles(target, opt)
+ 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 target:is_binary() or target:is_shared() then
+ local depends = hashset.new()
+ _get_target_package_deplibs(target, depends, libfiles, target:targetfile())
+ table.remove_if(libfiles, function (_, libfile) return not depends:has(path.filename(libfile)) end)
+ end
+ return libfiles
+end
+
+-- copy file with symlinks
+function _copy_file_with_symlinks(batchcmds_, srcfile, outputdir)
+ if os.islink(srcfile) then
+ local srcfile_symlink = os.readlink(srcfile)
+ if not path.is_absolute(srcfile_symlink) then
+ srcfile_symlink = path.join(path.directory(srcfile), srcfile_symlink)
+ end
+ _copy_file_with_symlinks(batchcmds_, srcfile_symlink, outputdir)
+ batchcmds_:cp(srcfile, path.join(outputdir, path.filename(srcfile)), {symlink = true, force = true})
+ else
+ batchcmds_:cp(srcfile, path.join(outputdir, path.filename(srcfile)))
+ end
end
--- install shared libraries for packages
-function _install_shared_for_packages(target, batchcmds_, outputdir)
- _g.installed_packages = _g.installed_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.installed_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _install_shared_for_package(target, pkg, batchcmds_, outputdir)
+-- 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
- _g.installed_packages[pkg:name()] = true
end
end
end
--- uninstall headers
-function _uninstall_headers(target, batchcmds_, includedir)
- local _, dstheaders = target:headerfiles(includedir, {installonly = true})
- for _, dstheader in ipairs(dstheaders) do
- batchcmds_:rm(dstheader, {emptydirs = true})
+-- install target files
+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
+ for idx, srcfile in ipairs(srcfiles) do
+ batchcmds_:cp(srcfile, dstfiles[idx])
+ end
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local srcfiles, dstfiles = dep:installfiles(_get_target_installdir(package, dep), {interface = true})
+ if srcfiles and dstfiles then
+ for idx, srcfile in ipairs(srcfiles) do
+ batchcmds_:cp(srcfile, dstfiles[idx])
+ end
+ end
end
end
--- uninstall shared libraries for package
-function _uninstall_shared_for_package(target, pkg, batchcmds_, outputdir)
- for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do
- if dllpath:endswith(".dll") then
- local dllname = path.filename(dllpath)
- batchcmds_:rm(path.join(outputdir, dllname), {emptydirs = true})
+-- install target headers
+function _install_target_headers(target, batchcmds_, opt)
+ local package = opt.package
+ local srcheaders, dstheaders = target:headerfiles(_get_target_includedir(package, target), {installonly = true})
+ if srcheaders and dstheaders then
+ for idx, srcheader in ipairs(srcheaders) do
+ batchcmds_:cp(srcheader, dstheaders[idx])
+ end
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local srcheaders, dstheaders = dep:headerfiles(_get_target_includedir(package, dep), {installonly = true, interface = true})
+ if srcheaders and dstheaders then
+ for idx, srcheader in ipairs(srcheaders) do
+ batchcmds_:cp(srcheader, dstheaders[idx])
+ end
end
end
end
--- uninstall shared libraries for packages
-function _uninstall_shared_for_packages(target, batchcmds_, outputdir)
- _g.uninstalled_packages = _g.uninstalled_packages or {}
- for _, pkg in ipairs(target:orderpkgs()) do
- if not _g.uninstalled_packages[pkg:name()] then
- if pkg:enabled() and pkg:get("libfiles") then
- _uninstall_shared_for_package(target, pkg, batchcmds_, outputdir)
+-- install target shared libraries
+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)
+
+ -- get all dependent shared libraries
+ local libfiles = {}
+ for _, dep in ipairs(target:orderdeps()) do
+ if dep:kind() == "shared" then
+ local depfile = dep:targetfile()
+ if os.isfile(depfile) then
+ table.insert(libfiles, depfile)
end
- _g.uninstalled_packages[pkg:name()] = true
end
+ table.join2(libfiles, _get_target_package_libfiles(dep, {interface = true}))
+ end
+ table.join2(libfiles, _get_target_package_libfiles(target))
+
+ -- deduplicate libfiles, prevent packages using the same libfiles from overwriting each other
+ libfiles = table.unique(libfiles)
+
+ -- do install
+ for _, libfile in ipairs(libfiles) do
+ local filename = path.filename(libfile)
+ _copy_file_with_symlinks(batchcmds_, libfile, bindir)
end
end
--- on install binary target command
-function _on_target_installcmd_binary(target, batchcmds_, opt)
+-- uninstall target files
+function _uninstall_target_files(target, batchcmds_, opt)
local package = opt.package
- local bindir = package:bindir()
+ local _, dstfiles = target:installfiles(_get_target_installdir(package, target))
+ for _, dstfile in ipairs(dstfiles) do
+ batchcmds_:rm(dstfile, {emptydirs = true})
+ end
+ for _, dep in ipairs(target:orderdeps()) do
+ local _, dstfiles = dep:installfiles(_get_target_installdir(package, dep), {interface = true})
+ for _, dstfile in ipairs(dstfiles) do
+ batchcmds_:rm(dstfile, {emptydirs = true})
+ end
+ end
+end
- -- install target file
- batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename()))
- if os.isfile(target:symbolfile()) then
- batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))
+-- uninstall target headers
+function _uninstall_target_headers(target, batchcmds_, opt)
+ local package = opt.package
+ local _, dstheaders = target:headerfiles(_get_target_includedir(package, target), {installonly = true})
+ for _, dstheader in ipairs(dstheaders) do
+ batchcmds_:rm(dstheader, {emptydirs = true})
end
+ for _, dep in ipairs(target:orderdeps()) do
+ local _, dstheaders = dep:headerfiles(_get_target_includedir(package, dep), {installonly = true, interface = true})
+ for _, dstheader in ipairs(dstheaders) do
+ batchcmds_:rm(dstheader, {emptydirs = true})
+ end
+ end
+end
- -- install the dependent shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- _g.installed_dllfiles = _g.installed_dllfiles or {}
+-- uninstall target shared libraries
+function _uninstall_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)
+
+ -- get all dependent shared libraries
+ local libfiles = {}
for _, dep in ipairs(target:orderdeps()) do
if dep:kind() == "shared" then
local depfile = dep:targetfile()
if os.isfile(depfile) then
- if not _g.installed_dllfiles[depfile] then
- batchcmds_:cp(depfile, path.join(bindir, path.filename(depfile)))
- _g.installed_dllfiles[depfile] = true
- end
+ table.insert(libfiles, depfile)
end
end
- -- install all shared libraries in packages in all deps
- _install_shared_for_packages(dep, batchcmds_, bindir)
+ table.join2(libfiles, _get_target_package_libfiles(dep, {interface = true}))
end
+ table.join2(libfiles, _get_target_package_libfiles(target))
- -- install shared libraries for all packages
- _install_shared_for_packages(target, batchcmds_, bindir)
+ -- deduplicate libfiles, prevent packages using the same libfiles from overwriting each other
+ libfiles = table.unique(libfiles)
+
+ -- do uninstall
+ for _, libfile in ipairs(libfiles) do
+ local filename = path.filename(libfile)
+ batchcmds_:rm(libfile, path.join(bindir, filename), {emptydirs = true})
+ end
+end
+
+-- on install binary target command
+function _on_target_installcmd_binary(target, batchcmds_, opt)
+ local package = opt.package
+ local bindir = _get_target_bindir(package, target)
+ batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename()))
+ 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)
end
-- on install shared target command
function _on_target_installcmd_shared(target, batchcmds_, opt)
local package = opt.package
- local bindir = package:bindir()
- local libdir = package:libdir()
- local includedir = package:includedir()
+ local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target)
+ local libdir = _get_target_libdir(package, target)
- -- install target file
- batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename()))
+ _copy_file_with_symlinks(batchcmds_, target:targetfile(), bindir)
if os.isfile(target:symbolfile()) then
batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))
end
@@ -151,36 +301,26 @@ function _on_target_installcmd_shared(target, batchcmds_, opt)
batchcmds_:cp(targetfile_lib, path.join(libdir, path.filename(targetfile_lib)))
end
- -- install shared libraries for all packages
- _install_shared_for_packages(target, batchcmds_, bindir)
-
- -- install headers
- _install_headers(target, batchcmds_, includedir)
+ _install_target_headers(target, batchcmds_, opt)
+ _install_target_shared_libraries(target, batchcmds_, opt)
end
-- on install static target command
function _on_target_installcmd_static(target, batchcmds_, opt)
local package = opt.package
- local libdir = package:libdir()
- local includedir = package:includedir()
+ local libdir = _get_target_libdir(package, target)
- -- install target file
batchcmds_:cp(target:targetfile(), path.join(libdir, target:filename()))
if os.isfile(target:symbolfile()) then
batchcmds_:cp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile())))
end
- -- install headers
- _install_headers(target, batchcmds_, includedir)
+ _install_target_headers(target, batchcmds_, opt)
end
-- on install headeronly target command
function _on_target_installcmd_headeronly(target, batchcmds_, opt)
- local package = opt.package
- local includedir = package:includedir()
-
- -- install headers
- _install_headers(target, batchcmds_, includedir)
+ _install_target_headers(target, batchcmds_, opt)
end
-- on install source target command
@@ -216,76 +356,60 @@ function _on_target_installcmd(target, batchcmds_, opt)
end
-- install target files
- local srcfiles, dstfiles = target:installfiles(package:installdir())
- for idx, srcfile in ipairs(srcfiles) do
- batchcmds_:cp(srcfile, dstfiles[idx])
- end
+ _install_target_files(target, batchcmds_, opt)
end
-- on uninstall binary target command
function _on_target_uninstallcmd_binary(target, batchcmds_, opt)
local package = opt.package
- local bindir = package:bindir()
+ local bindir = _get_target_bindir(package, target)
-- uninstall target file
batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true})
batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true})
- -- remove the dependent shared/windows (*.dll) target
- -- @see https://github.com/xmake-io/xmake/issues/961
- for _, dep in ipairs(target:orderdeps()) do
- if dep:is_shared() then
- batchcmds_:rm(path.join(bindir, path.filename(dep:targetfile())), {emptydirs = true})
- end
- _uninstall_shared_for_packages(dep, batchcmds_, bindir)
- end
-
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, batchcmds_, bindir)
+ -- uninstall target shared libraries
+ _uninstall_target_shared_libraries(target, batchcmds_, opt)
end
-- on uninstall shared target command
function _on_target_uninstallcmd_shared(target, batchcmds_, opt)
local package = opt.package
- local bindir = package:bindir()
- local libdir = package:libdir()
- local includedir = package:includedir()
+ local bindir = target:is_plat("windows", "mingw") and _get_target_bindir(package, target) or _get_target_libdir(package, target)
+ local libdir = _get_target_libdir(package, target)
-- uninstall target file
batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true})
batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true})
- -- remove *.lib for shared/windows (*.dll) target
+ -- uninstall *.lib for shared/windows (*.dll) target
-- @see https://github.com/xmake-io/xmake/issues/714
local targetfile = target:targetfile()
batchcmds_:rm(path.join(libdir, path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")), {emptydirs = true})
- -- remove headers from the include directory
- _uninstall_headers(target, batchcmds_, includedir)
+ -- uninstall target headers
+ _uninstall_target_headers(target, batchcmds_, opt)
- -- uninstall shared libraries for packages
- _uninstall_shared_for_packages(target, batchcmds_, bindir)
+ -- uninstall target shared libraries
+ _uninstall_target_shared_libraries(target, batchcmds_, opt)
end
-- on uninstall static target command
function _on_target_uninstallcmd_static(target, batchcmds_, opt)
local package = opt.package
- local libdir = package:libdir()
- local includedir = package:includedir()
+ local libdir = _get_target_libdir(package, target)
-- uninstall target file
batchcmds_:rm(path.join(libdir, target:filename()), {emptydirs = true})
batchcmds_:rm(path.join(libdir, path.filename(target:symbolfile())), {emptydirs = true})
-- remove headers from the include directory
- _uninstall_headers(target, batchcmds_, includedir)
+ _uninstall_target_headers(target, batchcmds_, opt)
end
-- on uninstall headeronly target command
function _on_target_uninstallcmd_headeronly(target, batchcmds_, opt)
- local package = opt.package
- local includedir = package:includedir()
- _uninstall_headers(target, batchcmds_, includedir)
+ _uninstall_target_headers(target, batchcmds_, opt)
end
-- on uninstall source target command
@@ -314,10 +438,7 @@ function _on_target_uninstallcmd(target, batchcmds_, opt)
end
-- uninstall target files
- local _, dstfiles = target:installfiles(package:installdir())
- for _, dstfile in ipairs(dstfiles) do
- batchcmds_:rm(dstfile, {emptydirs = true})
- end
+ _uninstall_target_files(target, batchcmds_, opt)
end
-- get build commands from targets
diff --git a/xmake/plugins/pack/xpack.lua b/xmake/plugins/pack/xpack.lua
index 89ee5a54b..203fcbe6d 100644
--- a/xmake/plugins/pack/xpack.lua
+++ b/xmake/plugins/pack/xpack.lua
@@ -453,7 +453,7 @@ end
-- get the binary directory
function xpack:bindir()
- local bindir = self:get("bindir")
+ local bindir = self:get("bindir") or self:extraconf("prefixdir", self:prefixdir(), "bindir")
if bindir == nil then
bindir = "bin"
end
@@ -462,7 +462,7 @@ end
-- get the library directory
function xpack:libdir()
- local libdir = self:get("libdir")
+ local libdir = self:get("libdir") or self:extraconf("prefixdir", self:prefixdir(), "libdir")
if libdir == nil then
libdir = "lib"
end
@@ -471,7 +471,7 @@ end
-- get the include directory
function xpack:includedir()
- local includedir = self:get("includedir")
+ local includedir = self:get("includedir") or self:extraconf("prefixdir", self:prefixdir(), "includedir")
if includedir == nil then
includedir = "include"
end
diff --git a/xmake/rules/c++/modules/modules_support/compiler_support.lua b/xmake/rules/c++/modules/modules_support/compiler_support.lua
index 72e7b93fd..a005dc80d 100644
--- a/xmake/rules/c++/modules/modules_support/compiler_support.lua
+++ b/xmake/rules/c++/modules/modules_support/compiler_support.lua
@@ -293,7 +293,7 @@ function get_provided_module(module)
return name, provide, cppfile
end
-function install_module_target(target)
+function add_installfiles_for_modules(target)
local sourcebatch = target:sourcebatches()["c++.build.modules.install"]
if sourcebatch and sourcebatch.sourcefiles then
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index 90ba66c81..d658815aa 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -227,6 +227,13 @@ rule("c++.build.modules.install")
local modules = compiler_support.localcache():get2(target:name(), "c++.modules")
builder.generate_metadata(target, modules)
- compiler_support.install_module_target(target)
+ compiler_support.add_installfiles_for_modules(target)
+ end
+ end)
+
+ before_uninstall(function (target)
+ import("modules_support.compiler_support")
+ if compiler_support.contains_modules(target) then
+ compiler_support.add_installfiles_for_modules(target)
end
end)
diff --git a/xmake/rules/utils/inherit_links/inherit_links.lua b/xmake/rules/utils/inherit_links/inherit_links.lua
index b235c8bff..a128e1cb7 100644
--- a/xmake/rules/utils/inherit_links/inherit_links.lua
+++ b/xmake/rules/utils/inherit_links/inherit_links.lua
@@ -104,7 +104,7 @@ function main(target)
end
-- export rpathdirs for all shared library
- if target:is_binary() then
+ if target:is_binary() and target:policy("build.rpath") then
local targetdir = target:targetdir()
for _, dep in ipairs(target:orderdeps({inherit = true})) do
if dep:kind() == "shared" then