From a5cf8c2bb716632c27f75aff173d1684ea5c679b Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 22:28:21 +0800 Subject: improve to export symbols --- .../rules/utils/symbols/export_all/export_all.lua | 81 ++++++++++++---------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index 14ea99211..b67a415c8 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -26,6 +26,44 @@ import("core.base.hashset") import("core.project.depend") import("utils.progress") +-- use dumpbin to get all symbols from object files +function _get_allsymbols_by_dumpbin(target, dumpbin, opt) + opt = opt or {} + local allsymbols = hashset.new() + local export_classes = opt.export_classes + for _, objectfile in ipairs(target:objectfiles()) do + local objectsymbols = try { function () return os.iorunv(dumpbin, {"/symbols", "/nologo", objectfile}) end } + if objectsymbols then + for _, line in ipairs(objectsymbols:split('\n', {plain = true})) do + -- https://docs.microsoft.com/en-us/cpp/build/reference/symbols + -- 008 00000000 SECT3 notype () External | add + if line:find("External") and not line:find("UNDEF") then + local symbol = line:match(".*External%s+| (.*)") + if symbol then + symbol = symbol:split('%s')[1] + if not symbol:startswith("__") then + -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 + if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("_DllMain@") then + symbol = symbol:sub(2) + end + if export_classes or not symbol:startswith("?") then + if export_classes then + if not symbol:startswith("??_G") and not symbol:startswith("??_E") then + allsymbols:insert(symbol) + end + else + allsymbols:insert(symbol) + end + end + end + end + end + end + end + end + return allsymbols +end + -- export all symbols for dynamic library function main(target, opt) @@ -43,48 +81,19 @@ function main(target, opt) -- trace progress info progress.show(opt.progress, "${color.build.target}exporting.$(mode) %s", path.filename(target:targetfile())) - -- get dumpbin - local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) - local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") - -- export c++ class? local export_classes = target:extraconf("rules", "utils.symbols.export_all", "export_classes") - -- get all symbols from object files - local allsymbols = hashset.new() - for _, objectfile in ipairs(target:objectfiles()) do - local objectsymbols = try { function () return os.iorunv(dumpbin.program, {"/symbols", "/nologo", objectfile}) end } - if objectsymbols then - for _, line in ipairs(objectsymbols:split('\n', {plain = true})) do - -- https://docs.microsoft.com/en-us/cpp/build/reference/symbols - -- 008 00000000 SECT3 notype () External | add - if line:find("External") and not line:find("UNDEF") then - local symbol = line:match(".*External%s+| (.*)") - if symbol then - symbol = symbol:split('%s')[1] - if not symbol:startswith("__") then - -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 - if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("_DllMain@") then - symbol = symbol:sub(2) - end - if export_classes or not symbol:startswith("?") then - if export_classes then - if not symbol:startswith("??_G") and not symbol:startswith("??_E") then - allsymbols:insert(symbol) - end - else - allsymbols:insert(symbol) - end - end - end - end - end - end - end + -- get all symbols + local allsymbols + local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) + if msvc:check() then + local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") + allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) end -- export all symbols - if allsymbols:size() > 0 then + if allsymbols and allsymbols:size() > 0 then local allsymbols_file = io.open(allsymbols_filepath, 'w') allsymbols_file:print("EXPORTS") for _, symbol in allsymbols:keys() do -- cgit v1.3.1 From 582e9e5e8c6215f01818bf767c5379e2cdbe861a Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 22:35:52 +0800 Subject: use objdump to dump symbols --- xmake/rules/utils/symbols/export_all/export_all.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index b67a415c8..e172b56cb 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -64,6 +64,22 @@ function _get_allsymbols_by_dumpbin(target, dumpbin, opt) return allsymbols end +-- use objdump to get all symbols from object files +function _get_allsymbols_by_objdump(target, objdump, opt) + opt = opt or {} + local allsymbols = hashset.new() + local export_classes = opt.export_classes + for _, objectfile in ipairs(target:objectfiles()) do + local objectsymbols = try { function () return os.iorunv(objdump, {"--syms", objectfile}) end } + if objectsymbols then + for _, line in ipairs(objectsymbols:split('\n', {plain = true})) do + print(line) + end + end + end + return allsymbols +end + -- export all symbols for dynamic library function main(target, opt) @@ -90,6 +106,9 @@ function main(target, opt) if msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) + elseif target:has_tool("cc", "clang", "clang_cl", "clangxx") then + local objdump = assert(find_tool("llvm-objdump") or find_tool("objdump"), "objdump not found!") + allsymbols = _get_allsymbols_by_dumpbin(target, objdump.program, {export_classes = export_classes}) end -- export all symbols -- cgit v1.3.1 From 3bb68cf977aa087d781fef792a262fd1a8f4d48b Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 22:46:17 +0800 Subject: dump symbols by objdump --- .../rules/utils/symbols/export_all/export_all.lua | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index e172b56cb..62d9d07dc 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -73,7 +73,27 @@ function _get_allsymbols_by_objdump(target, objdump, opt) local objectsymbols = try { function () return os.iorunv(objdump, {"--syms", objectfile}) end } if objectsymbols then for _, line in ipairs(objectsymbols:split('\n', {plain = true})) do - print(line) + if line:find("(scl 2)", 1, true) then + local splitinfo = line:split("%s") + local symbol = splitinfo[#splitinfo] + if symbol then + if not symbol:startswith("__") then + -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 + if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("_DllMain@") then + symbol = symbol:sub(2) + end + if export_classes or not symbol:startswith("?") then + if export_classes then + if not symbol:startswith("??_G") and not symbol:startswith("??_E") then + allsymbols:insert(symbol) + end + else + allsymbols:insert(symbol) + end + end + end + end + end end end end @@ -103,12 +123,12 @@ function main(target, opt) -- get all symbols local allsymbols local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) - if msvc:check() then + if false then--msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) elseif target:has_tool("cc", "clang", "clang_cl", "clangxx") then local objdump = assert(find_tool("llvm-objdump") or find_tool("objdump"), "objdump not found!") - allsymbols = _get_allsymbols_by_dumpbin(target, objdump.program, {export_classes = export_classes}) + allsymbols = _get_allsymbols_by_objdump(target, objdump.program, {export_classes = export_classes}) end -- export all symbols @@ -125,3 +145,4 @@ function main(target, opt) end, {dependfile = dependfile, files = target:objectfiles(), changed = target:is_rebuilt()}) end + -- cgit v1.3.1 From c3d9a8dfc63f2f8e054cc5f140830dc02b6332a0 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 22:46:43 +0800 Subject: enable msvc check --- xmake/rules/utils/symbols/export_all/export_all.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index 62d9d07dc..d3d326105 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -123,7 +123,7 @@ function main(target, opt) -- get all symbols local allsymbols local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) - if false then--msvc:check() then + if msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) elseif target:has_tool("cc", "clang", "clang_cl", "clangxx") then -- cgit v1.3.1 From 1dee088e701ace1ea4cdfe904a152caddfc55f42 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 22:51:06 +0800 Subject: add gcc check --- xmake/rules/utils/symbols/export_all/export_all.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index d3d326105..4842546f3 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -126,7 +126,7 @@ function main(target, opt) if msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) - elseif target:has_tool("cc", "clang", "clang_cl", "clangxx") then + elseif target:has_tool("cc", "clang", "clang_cl", "clangxx", "gcc", "gxx") then local objdump = assert(find_tool("llvm-objdump") or find_tool("objdump"), "objdump not found!") allsymbols = _get_allsymbols_by_objdump(target, objdump.program, {export_classes = export_classes}) end -- cgit v1.3.1 From dad8fe9b2acda84bfbead2a05a8b0d4b504d6479 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 19 May 2024 23:15:53 +0800 Subject: add export filter --- .../c++/shared_library_export_all/src/bar.cpp | 5 +++++ .../c++/shared_library_export_all/src/bar.h | 4 ++++ .../c++/shared_library_export_all/src/foo.cpp | 3 +-- .../c++/shared_library_export_all/src/foo.h | 3 +-- .../c++/shared_library_export_all/src/main.cpp | 9 ++++---- .../c++/shared_library_export_all/xmake.lua | 11 +++++++++- .../rules/utils/symbols/export_all/export_all.lua | 25 ++++++++++++++++++---- 7 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 tests/projects/c++/shared_library_export_all/src/bar.cpp create mode 100644 tests/projects/c++/shared_library_export_all/src/bar.h diff --git a/tests/projects/c++/shared_library_export_all/src/bar.cpp b/tests/projects/c++/shared_library_export_all/src/bar.cpp new file mode 100644 index 000000000..a3065ed8b --- /dev/null +++ b/tests/projects/c++/shared_library_export_all/src/bar.cpp @@ -0,0 +1,5 @@ +#include "bar.h" + +int bar::add(int a, int b) { + return a + b; +} diff --git a/tests/projects/c++/shared_library_export_all/src/bar.h b/tests/projects/c++/shared_library_export_all/src/bar.h new file mode 100644 index 000000000..687386e0a --- /dev/null +++ b/tests/projects/c++/shared_library_export_all/src/bar.h @@ -0,0 +1,4 @@ +class bar { +public: + static int add(int a, int b); +}; diff --git a/tests/projects/c++/shared_library_export_all/src/foo.cpp b/tests/projects/c++/shared_library_export_all/src/foo.cpp index 3ab50856c..46635f458 100644 --- a/tests/projects/c++/shared_library_export_all/src/foo.cpp +++ b/tests/projects/c++/shared_library_export_all/src/foo.cpp @@ -1,6 +1,5 @@ #include "foo.h" -int test::add(int a, int b) -{ +int foo::add(int a, int b) { return a + b; } diff --git a/tests/projects/c++/shared_library_export_all/src/foo.h b/tests/projects/c++/shared_library_export_all/src/foo.h index f671c7d32..e27636b94 100644 --- a/tests/projects/c++/shared_library_export_all/src/foo.h +++ b/tests/projects/c++/shared_library_export_all/src/foo.h @@ -1,5 +1,4 @@ -class test -{ +class foo { public: static int add(int a, int b); }; diff --git a/tests/projects/c++/shared_library_export_all/src/main.cpp b/tests/projects/c++/shared_library_export_all/src/main.cpp index e48f4730e..cc95897ee 100644 --- a/tests/projects/c++/shared_library_export_all/src/main.cpp +++ b/tests/projects/c++/shared_library_export_all/src/main.cpp @@ -1,10 +1,9 @@ #include "foo.h" +#include "bar.h" #include -using namespace std; - -int main(int argc, char** argv) -{ - cout << "add(1, 2) = " << test::add(1, 2) << endl; +int main(int argc, char** argv) { + std::cout << "foo::add(1, 2) = " << foo::add(1, 2) << std::endl; + std::cout << "bar::add(1, 2) = " << bar::add(1, 2) << std::endl; return 0; } diff --git a/tests/projects/c++/shared_library_export_all/xmake.lua b/tests/projects/c++/shared_library_export_all/xmake.lua index fa25fac50..73159d4b5 100644 --- a/tests/projects/c++/shared_library_export_all/xmake.lua +++ b/tests/projects/c++/shared_library_export_all/xmake.lua @@ -5,9 +5,18 @@ target("foo") add_files("src/foo.cpp") add_rules("utils.symbols.export_all", {export_classes = true}) +target("bar") + set_kind("shared") + add_files("src/bar.cpp") + add_rules("utils.symbols.export_all", {export_filter = function (symbol) + if symbol:find("add", 1, true) then + return true + end + end}) + target("demo") set_kind("binary") - add_deps("foo") + add_deps("foo", "bar") add_files("src/main.cpp") diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index 4842546f3..9376e557e 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -31,6 +31,7 @@ function _get_allsymbols_by_dumpbin(target, dumpbin, opt) opt = opt or {} local allsymbols = hashset.new() local export_classes = opt.export_classes + local export_filter = opt.export_filter for _, objectfile in ipairs(target:objectfiles()) do local objectsymbols = try { function () return os.iorunv(dumpbin, {"/symbols", "/nologo", objectfile}) end } if objectsymbols then @@ -41,7 +42,11 @@ function _get_allsymbols_by_dumpbin(target, dumpbin, opt) local symbol = line:match(".*External%s+| (.*)") if symbol then symbol = symbol:split('%s')[1] - if not symbol:startswith("__") then + if export_filter then + if export_filter(symbol) then + allsymbols:insert(symbol) + end + elseif not symbol:startswith("__") then -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("_DllMain@") then symbol = symbol:sub(2) @@ -69,6 +74,7 @@ function _get_allsymbols_by_objdump(target, objdump, opt) opt = opt or {} local allsymbols = hashset.new() local export_classes = opt.export_classes + local export_filter = opt.export_filter for _, objectfile in ipairs(target:objectfiles()) do local objectsymbols = try { function () return os.iorunv(objdump, {"--syms", objectfile}) end } if objectsymbols then @@ -77,7 +83,11 @@ function _get_allsymbols_by_objdump(target, objdump, opt) local splitinfo = line:split("%s") local symbol = splitinfo[#splitinfo] if symbol then - if not symbol:startswith("__") then + if export_filter then + if export_filter(symbol) then + allsymbols:insert(symbol) + end + elseif not symbol:startswith("__") then -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("_DllMain@") then symbol = symbol:sub(2) @@ -120,15 +130,22 @@ function main(target, opt) -- export c++ class? local export_classes = target:extraconf("rules", "utils.symbols.export_all", "export_classes") + -- the export filter + local export_filter = target:extraconf("rules", "utils.symbols.export_all", "export_filter") + -- get all symbols local allsymbols local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) if msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") - allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {export_classes = export_classes}) + allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, { + export_classes = export_classes, + export_filter = export_filter}) elseif target:has_tool("cc", "clang", "clang_cl", "clangxx", "gcc", "gxx") then local objdump = assert(find_tool("llvm-objdump") or find_tool("objdump"), "objdump not found!") - allsymbols = _get_allsymbols_by_objdump(target, objdump.program, {export_classes = export_classes}) + allsymbols = _get_allsymbols_by_objdump(target, objdump.program, { + export_classes = export_classes, + export_filter = export_filter}) end -- export all symbols -- cgit v1.3.1