From 737b4fd7cd286d360f155df1ea68324aaa8b7317 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:40:27 +0800 Subject: add symbols.depend --- xmake/modules/utils/symbols/depend.lua | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 xmake/modules/utils/symbols/depend.lua diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua new file mode 100644 index 000000000..33cc821e5 --- /dev/null +++ b/xmake/modules/utils/symbols/depend.lua @@ -0,0 +1,38 @@ +--!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 depend.lua +-- + +-- imports +import("core.base.option") +import("lib.detect.find_tool") + +function _get_all_depends_by_dumpbin(binaryfile, opt) + local dumpbin = find_tool("dumpbin") + if dumpbin then + local depends = try { function () return os.iorunv(dumpbin.program, {"/dependent", "/nologo", objectfile}) end } + end +end + +function main(binaryfile, opt) + local depends + if is_host("windows") then + depends = _get_all_depends_by_dumpbin(binaryfile, opt) + end + return depends +end -- cgit v1.3.1 From b29871ae1036ac77e35c2eb84d32b5fbda314572 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:45:05 +0800 Subject: use dumpbin to dump windows bin deps --- xmake/modules/utils/symbols/depend.lua | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 33cc821e5..08381c419 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -20,19 +20,47 @@ -- imports import("core.base.option") +import("core.tool.toolchain") import("lib.detect.find_tool") function _get_all_depends_by_dumpbin(binaryfile, opt) - local dumpbin = find_tool("dumpbin") - if dumpbin then - local depends = try { function () return os.iorunv(dumpbin.program, {"/dependent", "/nologo", objectfile}) end } + local depends + local plat = opt.plat or os.host() + local arch = opt.arch or os.arch() + local msvc = toolchain.load("msvc", {plat = plat, arch = arch}) + if msvc:check() then + local dumpbin = find_tool("dumpbin", {cachekey = "utils.symbols.depend", envs = msvc:runenvs()}) + if dumpbin then + local binarydir = path.directory(binaryfile) + local result = try { function () return os.iorunv(dumpbin.program, {"/dependents", "/nologo", binaryfile}) end } + if result then + 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 + end + end + end + end end + return depends end function main(binaryfile, opt) + opt = opt or {} local depends if is_host("windows") then depends = _get_all_depends_by_dumpbin(binaryfile, opt) end return depends end + -- cgit v1.3.1 From caf06e43fb5931197b18b853462b9f40c6acff84 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:48:29 +0800 Subject: dump deps by objdump --- xmake/modules/utils/symbols/depend.lua | 44 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 08381c419..ab317f5d5 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -55,12 +55,50 @@ function _get_all_depends_by_dumpbin(binaryfile, opt) return depends end +function _get_all_depends_by_objdump(binaryfile, opt) + local depends + local cachekey = "utils.symbols.depend" + local objdump = find_tool("llvm-objdump", {cachekey = cachekey}) or find_tool("objdump", {cachekey = cachekey}) + if objdump then + local binarydir = path.directory(binaryfile) + local result = try { function () return os.iorunv(objdump.program, {"-p", binaryfile}) end } + if result then + for _, line in ipairs(result:split("\n")) do + line = line:trim() + 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 = line + 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 + end + end + end + end + end + return depends +end + function main(binaryfile, opt) opt = opt or {} - local depends + local dumpers = { + _get_all_depends_by_objdump + } if is_host("windows") then - depends = _get_all_depends_by_dumpbin(binaryfile, opt) + table.insert(dumpers, _get_all_depends_by_dumpbin) + end + for _, dump in ipairs(dumpers) do + local depends = dump(binaryfile, opt) + if depends then + return depends + end end - return depends end -- cgit v1.3.1 From b908a2200db75057f59a047a4d60d2c49e70a63d Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:52:14 +0800 Subject: improve objdump for macos and linux --- xmake/modules/utils/symbols/depend.lua | 53 ++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index ab317f5d5..a2e44817e 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -57,28 +57,71 @@ end 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 objdump = find_tool("llvm-objdump", {cachekey = cachekey}) or find_tool("objdump", {cachekey = cachekey}) if objdump then local binarydir = path.directory(binaryfile) - local result = try { function () return os.iorunv(objdump.program, {"-p", binaryfile}) end } + local argv = {"-p", binaryfile} + if plat == "macosx" then + argv = {"--macho", "--dylibs-used", binaryfile} + end + local result = try { function () return os.iorunv(objdump.program, argv) end } if result then for _, line in ipairs(result:split("\n")) do line = line:trim() - if line:startswith("DLL Name:") then - local filename = line:split(":")[2]:trim() - if filename:endswith(".dll") then + if plat == "windows" or plat == "mingw" then + 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 + end + end + elseif plat == "macosx" then + local filename = line:match(".-%.dylib") + if filename then local dependfile if os.isfile(filename) then - dependfile = line + dependfile = filename elseif os.isfile(path.join(binarydir, filename)) then dependfile = path.join(binarydir, filename) + elseif filename:startswith("@rpath/") then -- TODO + filename = filename:sub(8) + if os.isfile(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 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 + end + end end end end -- cgit v1.3.1 From 425be3c4ca8ccb3cd68692fcce0150f06bfa2ce3 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:54:13 +0800 Subject: dump deps by otool --- xmake/modules/utils/symbols/depend.lua | 61 ++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index a2e44817e..7c63aa957 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -27,9 +27,10 @@ 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 msvc = toolchain.load("msvc", {plat = plat, arch = arch}) if msvc:check() then - local dumpbin = find_tool("dumpbin", {cachekey = "utils.symbols.depend", envs = msvc:runenvs()}) + local dumpbin = find_tool("dumpbin", {cachekey = cachekey, envs = msvc:runenvs()}) if dumpbin then local binarydir = path.directory(binaryfile) local result = try { function () return os.iorunv(dumpbin.program, {"/dependents", "/nologo", binaryfile}) end } @@ -64,7 +65,7 @@ function _get_all_depends_by_objdump(binaryfile, opt) if objdump then local binarydir = path.directory(binaryfile) local argv = {"-p", binaryfile} - if plat == "macosx" then + if plat == "macosx" or plat == "iphoneos" or plat == "appletvos" or plat == "watchos" then argv = {"--macho", "--dylibs-used", binaryfile} end local result = try { function () return os.iorunv(objdump.program, argv) end } @@ -87,17 +88,17 @@ function _get_all_depends_by_objdump(binaryfile, opt) end end end - elseif plat == "macosx" then - local filename = line:match(".-%.dylib") + 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.isfile(filename) then + if os.exists(filename) then dependfile = filename - elseif os.isfile(path.join(binarydir, filename)) then + 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.isfile(path.join(binarydir, filename)) then + if os.exists(path.join(binarydir, filename)) then dependfile = path.join(binarydir, filename) end end @@ -129,6 +130,48 @@ function _get_all_depends_by_objdump(binaryfile, opt) return depends end +function _get_all_depends_by_ldd(binaryfile, opt) +end + +function _get_all_depends_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 depends + local cachekey = "utils.symbols.depend" + 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 + for _, line in ipairs(result:split("\n")) do + line = line:trim() + 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 + end + end + end + end + return depends +end + function main(binaryfile, opt) opt = opt or {} local dumpers = { @@ -136,6 +179,10 @@ function main(binaryfile, opt) } if is_host("windows") then table.insert(dumpers, _get_all_depends_by_dumpbin) + elseif is_host("ldd") then + table.insert(dumpers, _get_all_depends_by_ldd) + elseif is_host("macosx") then + table.insert(dumpers, _get_all_depends_by_otool) end for _, dump in ipairs(dumpers) do local depends = dump(binaryfile, opt) -- cgit v1.3.1 From d6a92163ffb2cb29d04e3a5e2c8b2a4d0f41a046 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:56:58 +0800 Subject: dump deps by ldd --- xmake/modules/utils/symbols/depend.lua | 56 ++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 7c63aa957..83b5b2f37 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -130,9 +130,59 @@ function _get_all_depends_by_objdump(binaryfile, opt) return depends end +-- $ldd ./build/linux/x86_64/release/test +-- linux-vdso.so.1 (0x00007ffc51fdd000) +-- libfoo.so => /mnt/xmake/tests/projects/c/shared_library/./build/linux/x86_64/release/libfoo.so (0x00007fe241233000) +-- libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fe240fca000) +-- libm.so.6 => /lib64/libm.so.6 (0x00007fe240ee7000) +-- libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fe240eba000) +-- libc.so.6 => /lib64/libc.so.6 (0x00007fe240ccd000) +-- /lib64/ld-linux-x86-64.so.2 (0x00007fe24123a000) +-- function _get_all_depends_by_ldd(binaryfile, opt) + local plat = opt.plat or os.host() + local arch = opt.arch or os.arch() + if plat ~= "linux" then + return + end + local depends + local cachekey = "utils.symbols.depend" + 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 + 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 + end + end + end + end + return depends end +-- $ otool -L build/iphoneos/arm64/release/test +-- build/iphoneos/arm64/release/test: +-- @rpath/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0) +-- /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 2048.1.101) +-- /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) +-- /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1600.151.0) +-- /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0) +-- function _get_all_depends_by_otool(binaryfile, opt) local plat = opt.plat or os.host() local arch = opt.arch or os.arch() @@ -147,9 +197,9 @@ function _get_all_depends_by_otool(binaryfile, opt) local result = try { function () return os.iorunv(otool.program, {"-L", binaryfile}) end } if result then for _, line in ipairs(result:split("\n")) do - line = line:trim() local filename = line:match(".-%.dylib") or line:match(".-%.framework") if filename then + filename = filename:trim() local dependfile if os.exists(filename) then dependfile = filename @@ -175,11 +225,11 @@ end function main(binaryfile, opt) opt = opt or {} local dumpers = { - _get_all_depends_by_objdump +-- _get_all_depends_by_objdump } if is_host("windows") then table.insert(dumpers, _get_all_depends_by_dumpbin) - elseif is_host("ldd") then + elseif is_host("linux") then table.insert(dumpers, _get_all_depends_by_ldd) elseif is_host("macosx") then table.insert(dumpers, _get_all_depends_by_otool) -- cgit v1.3.1 From 50045e2822068e7904a73884fe92486f2bed651f Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:57:12 +0800 Subject: enable objdump --- xmake/modules/utils/symbols/depend.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 83b5b2f37..3072e4964 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -225,7 +225,7 @@ end function main(binaryfile, opt) opt = opt or {} local dumpers = { --- _get_all_depends_by_objdump + _get_all_depends_by_objdump } if is_host("windows") then table.insert(dumpers, _get_all_depends_by_dumpbin) -- cgit v1.3.1 From 0caf8853dfb45801c1fe71bab742c9a8379e4ff5 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 22:58:21 +0800 Subject: enable ldd for bsd --- xmake/modules/utils/symbols/depend.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 3072e4964..3a5985859 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -142,7 +142,7 @@ end function _get_all_depends_by_ldd(binaryfile, opt) local plat = opt.plat or os.host() local arch = opt.arch or os.arch() - if plat ~= "linux" then + if plat ~= "linux" and plat ~= "bsd" then return end local depends @@ -229,7 +229,7 @@ function main(binaryfile, opt) } if is_host("windows") then table.insert(dumpers, _get_all_depends_by_dumpbin) - elseif is_host("linux") then + elseif is_host("linux", "bsd") then table.insert(dumpers, _get_all_depends_by_ldd) elseif is_host("macosx") then table.insert(dumpers, _get_all_depends_by_otool) -- cgit v1.3.1 From 88dd154fc31c88a390b5addd5a89d5486a4f69e2 Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 11 Jul 2024 23:00:03 +0800 Subject: dump deps by readelf --- xmake/modules/utils/symbols/depend.lua | 55 +++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/xmake/modules/utils/symbols/depend.lua b/xmake/modules/utils/symbols/depend.lua index 3a5985859..94ca4c7e1 100644 --- a/xmake/modules/utils/symbols/depend.lua +++ b/xmake/modules/utils/symbols/depend.lua @@ -175,6 +175,52 @@ function _get_all_depends_by_ldd(binaryfile, opt) return depends 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] +function _get_all_depends_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 depends + local cachekey = "utils.symbols.depend" + 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("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 + end + end + end + end + end + return depends +end + -- $ otool -L build/iphoneos/arm64/release/test -- build/iphoneos/arm64/release/test: -- @rpath/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0) @@ -225,14 +271,15 @@ end function main(binaryfile, opt) opt = opt or {} local dumpers = { - _get_all_depends_by_objdump + _get_all_depends_by_objdump, + _get_all_depends_by_readelf } if is_host("windows") then - table.insert(dumpers, _get_all_depends_by_dumpbin) + table.insert(dumpers, 2, _get_all_depends_by_dumpbin) elseif is_host("linux", "bsd") then - table.insert(dumpers, _get_all_depends_by_ldd) + table.insert(dumpers, 1, _get_all_depends_by_ldd) elseif is_host("macosx") then - table.insert(dumpers, _get_all_depends_by_otool) + table.insert(dumpers, 1, _get_all_depends_by_otool) end for _, dump in ipairs(dumpers) do local depends = dump(binaryfile, opt) -- cgit v1.3.1