diff options
| author | ruki <[email protected]> | 2025-12-12 09:54:46 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-12 09:54:46 +0800 |
| commit | 7544d22a944cb4702534a8fe54924d74a71d3178 (patch) | |
| tree | 2df690db9f7ead09afde33fd321864c4d56b042a /xmake/modules | |
| parent | 2427bd350baa6331c5dfd62b2ab291737c7e5f49 (diff) | |
| parent | e08e654aad4f829fcf1990dae32a14394055d96c (diff) | |
Merge pull request #7120 from xmake-io/ar
Add extractlib support in binutils
Diffstat (limited to 'xmake/modules')
| -rw-r--r-- | xmake/modules/cli/binutils/bin2c.lua | 49 | ||||
| -rw-r--r-- | xmake/modules/cli/binutils/bin2obj.lua | 54 | ||||
| -rw-r--r-- | xmake/modules/utils/archive/merge_staticlib.lua | 55 | ||||
| -rw-r--r-- | xmake/modules/utils/binary/bin2c.lua | 22 | ||||
| -rw-r--r-- | xmake/modules/utils/binary/bin2obj.lua | 27 | ||||
| -rw-r--r-- | xmake/modules/utils/binary/extractlib.lua | 51 | ||||
| -rw-r--r-- | xmake/modules/utils/binary/readsyms.lua | 93 |
7 files changed, 209 insertions, 142 deletions
diff --git a/xmake/modules/cli/binutils/bin2c.lua b/xmake/modules/cli/binutils/bin2c.lua new file mode 100644 index 000000000..83e0a88c1 --- /dev/null +++ b/xmake/modules/cli/binutils/bin2c.lua @@ -0,0 +1,49 @@ +--!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, Xmake Open Source Community. +-- +-- @author ruki +-- @file bin2c.lua +-- + +-- imports +import("core.base.option") +import("utils.binary.bin2c") + +local options = { + {'w', "linewidth", "kv", nil, "Set the line width"}, + {nil, "nozeroend", "k", false, "Disable to patch zero terminating character"}, + {'i', "binarypath", "kv", nil, "Set the binary file path."}, + {'o', "outputpath", "kv", nil, "Set the output file path."} +} + +function main(...) + + -- parse arguments + local argv = {...} + local opt = option.parse(argv, options, "Print c/c++ code files from the given binary file." + , "" + , "Usage: xmake l cli.binutils.bin2c [options]") + + -- check arguments + if not opt.binarypath or not opt.outputpath then + cprint("${bright}Usage: $${clear}xmake l cli.binutils.bin2c [options]") + option.show_options(options, "bin2c") + return + end + + -- do bin2c + bin2c.main(opt.binarypath, opt.outputpath, opt) +end diff --git a/xmake/modules/cli/binutils/bin2obj.lua b/xmake/modules/cli/binutils/bin2obj.lua new file mode 100644 index 000000000..6ee6c2158 --- /dev/null +++ b/xmake/modules/cli/binutils/bin2obj.lua @@ -0,0 +1,54 @@ +--!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, Xmake Open Source Community. +-- +-- @author ruki +-- @file bin2obj.lua +-- + +-- imports +import("core.base.option") +import("utils.binary.bin2obj") + +local options = { + {'i', "binarypath", "kv", nil, "Set the binary file path."}, + {'o', "outputpath", "kv", nil, "Set the output object file path."}, + {'f', "format", "kv", nil, "Set the object file format (coff, elf, macho)."}, + {nil, "symbol_prefix", "kv", nil, "Set the symbol prefix (default: _binary_)."}, + {'a', "arch", "kv", nil, "Set the target architecture."}, + {'p', "plat", "kv", nil, "Set the target platform (macosx, iphoneos, etc.)."}, + {nil, "target_minver", "kv", nil, "Set the target minimum version (e.g., 10.0, 18.2)."}, + {nil, "xcode_sdkver", "kv", nil, "Set the Xcode SDK version (e.g., 10.0, 18.2)."}, + {nil, "zeroend", "k", nil, "Append a null terminator ('\\0') at the end of data."} +} + +function main(...) + + -- parse arguments + local argv = {...} + local opt = option.parse(argv, options, "Convert binary file to object file for direct linking." + , "" + , "Usage: xmake l cli.binutils.bin2obj [options]") + + -- check arguments + if not opt.binarypath or not opt.outputpath then + cprint("${bright}Usage: $${clear}xmake l cli.binutils.bin2obj [options]") + option.show_options(options, "bin2obj") + return + end + + -- do bin2obj + bin2obj.main(opt.binarypath, opt.outputpath, opt) +end diff --git a/xmake/modules/utils/archive/merge_staticlib.lua b/xmake/modules/utils/archive/merge_staticlib.lua index f75aa64f6..2246a926e 100644 --- a/xmake/modules/utils/archive/merge_staticlib.lua +++ b/xmake/modules/utils/archive/merge_staticlib.lua @@ -20,6 +20,7 @@ -- imports import("core.base.option") +import("core.base.binutils") import("private.tools.vstool") -- merge *.a archive libraries using libtool @@ -30,56 +31,20 @@ end -- merge *.a archive libraries using fallback method (extract and repack) -- Used for platforms where ar does not support -M option (e.g., Solaris) function _merge_for_ar_fallback(target, program, outputfile, libraryfiles, opt) - -- we need to handle duplicate object file names by adding prefixes - -- convert all library files to absolute paths before changing directory - local libraryfiles_abs = {} - for _, libraryfile in ipairs(libraryfiles) do - if os.isfile(libraryfile) then - table.insert(libraryfiles_abs, path.absolute(libraryfile)) - end - end - if #libraryfiles_abs == 0 then - return - end + + -- extract all archives to the temporary directory local tmpdir = os.tmpfile() .. ".dir" os.mkdir(tmpdir) - -- check for duplicate object file names and warn - for idx, libraryfile_abs in ipairs(libraryfiles_abs) do - local list = os.iorunv(program, {"-t", libraryfile_abs}, {curdir = tmpdir}) - if list then - local seen_files = {} - local duplicates = {} - for _, line in ipairs(list:split("\n")) do - line = line:trim() - if line:endswith(".o") then - if seen_files[line] then - if not duplicates[line] then - duplicates[line] = {} - end - table.insert(duplicates[line], libraryfile_abs) - else - seen_files[line] = true - end - end - end - if not table.empty(duplicates) then - local dup_names = table.keys(duplicates) - wprint("duplicate object file names found in %s: %s (some files may be lost during merge)", - path.filename(libraryfile_abs), table.concat(dup_names, ", ")) - end - end + for _, libraryfile in ipairs(libraryfiles) do + binutils.extractlib(libraryfile, tmpdir) end - -- extract and merge all archives + + -- collect all object files local objectfiles = {} - for idx, libraryfile_abs in ipairs(libraryfiles_abs) do - -- extract all files from this archive - os.vrunv(program, {"-x", libraryfile_abs}, {curdir = tmpdir}) - -- collect extracted object files (duplicate names will be overwritten) - for _, objfile in ipairs(os.files(path.join(tmpdir, "*.o"))) do - -- use relative path (filename only) since ar will run with curdir = tmpdir - table.insert(objectfiles, path.filename(objfile)) - end + for _, objectfile in ipairs(os.files(path.join(tmpdir, "*.o"))) do + table.insert(objectfiles, path.filename(objectfile)) end + -- create new archive with all object files if #objectfiles > 0 then os.mkdir(path.directory(outputfile)) diff --git a/xmake/modules/utils/binary/bin2c.lua b/xmake/modules/utils/binary/bin2c.lua index 34d9c4e02..7bbc797a4 100644 --- a/xmake/modules/utils/binary/bin2c.lua +++ b/xmake/modules/utils/binary/bin2c.lua @@ -20,16 +20,8 @@ -- imports import("core.base.bytes") -import("core.base.option") import("core.base.binutils") -local options = { - {'w', "linewidth", "kv", nil, "Set the line width"}, - {nil, "nozeroend", "k", false, "Disable to patch zero terminating character"}, - {'i', "binarypath", "kv", nil, "Set the binary file path."}, - {'o', "outputpath", "kv", nil, "Set the output file path."} -} - function _do_dump(binarydata, outputfile, opt) local i = 0 local n = 147 @@ -71,7 +63,7 @@ function _do_dump(binarydata, outputfile, opt) end end -function _do_bin2c(binarypath, outputpath, opt) +function main(binarypath, outputpath, opt) -- init source directory and options opt = opt or {} @@ -117,15 +109,3 @@ function _do_bin2c(binarypath, outputpath, opt) cprint("${bright}%s generated!", outputpath) end -function main(...) - - -- parse arguments - local argv = {...} - local opt = option.parse(argv, options, "Print c/c++ code files from the given binary file." - , "" - , "Usage: xmake l utils.binary.bin2c [options]") - - -- do bin2c - _do_bin2c(opt.binarypath, opt.outputpath, opt) -end - diff --git a/xmake/modules/utils/binary/bin2obj.lua b/xmake/modules/utils/binary/bin2obj.lua index 95e705ca6..13ff633e1 100644 --- a/xmake/modules/utils/binary/bin2obj.lua +++ b/xmake/modules/utils/binary/bin2obj.lua @@ -19,22 +19,9 @@ -- -- imports -import("core.base.option") import("core.base.binutils") -local options = { - {'i', "binarypath", "kv", nil, "Set the binary file path."}, - {'o', "outputpath", "kv", nil, "Set the output object file path."}, - {'f', "format", "kv", nil, "Set the object file format (coff, elf, macho)."}, - {nil, "symbol_prefix", "kv", nil, "Set the symbol prefix (default: _binary_)."}, - {'a', "arch", "kv", nil, "Set the target architecture."}, - {'p', "plat", "kv", nil, "Set the target platform (macosx, iphoneos, etc.)."}, - {nil, "target_minver", "kv", nil, "Set the target minimum version (e.g., 10.0, 18.2)."}, - {nil, "xcode_sdkver", "kv", nil, "Set the Xcode SDK version (e.g., 10.0, 18.2)."}, - {nil, "zeroend", "k", nil, "Append a null terminator ('\\0') at the end of data."} -} - -function _do_bin2obj(binarypath, outputpath, opt) +function main(binarypath, outputpath, opt) -- init source directory and options opt = opt or {} binarypath = path.absolute(binarypath) @@ -66,15 +53,3 @@ function _do_bin2obj(binarypath, outputpath, opt) cprint("${bright}%s generated!", outputpath) end -function main(...) - - -- parse arguments - local argv = {...} - local opt = option.parse(argv, options, "Convert binary file to object file for direct linking." - , "" - , "Usage: xmake l utils.binary.bin2obj [options]") - - -- do bin2obj - _do_bin2obj(opt.binarypath, opt.outputpath, opt) -end - diff --git a/xmake/modules/utils/binary/extractlib.lua b/xmake/modules/utils/binary/extractlib.lua new file mode 100644 index 000000000..818d343bc --- /dev/null +++ b/xmake/modules/utils/binary/extractlib.lua @@ -0,0 +1,51 @@ +--!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, Xmake Open Source Community. +-- +-- @author ruki +-- @file extractlib.lua +-- + +-- imports +import("core.base.binutils") + +-- extract static library to directory +-- +-- @param libraryfile the static library file path (.a or .lib) +-- @param outputdir the output directory to extract object files +-- @param opt the options (optional) +-- - plain: extract all object files to the same directory (default: true) +-- +function main(libraryfile, outputdir, opt) + -- init paths + libraryfile = path.absolute(libraryfile) + outputdir = path.absolute(outputdir) + assert(os.isfile(libraryfile), "%s not found!", libraryfile) + + -- ensure output directory exists + if not os.isdir(outputdir) then + os.mkdir(outputdir) + end + + -- trace + print("extracting static library %s to %s ..", libraryfile, outputdir) + + -- do extraction + binutils.extractlib(libraryfile, outputdir, opt) + + -- trace + cprint("${bright}extraction completed!") +end + diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 6058e8121..d8aa8674a 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -38,69 +38,62 @@ end -- -- @param binaryfile the object file path (required) function dump(binaryfile) - local symbols = _get_symbols(binaryfile) - if symbols and #symbols > 0 then - -- calculate column widths for alignment - local max_name_len = 0 - local max_type_len = 0 + local objects = _get_symbols(binaryfile) + if objects and #objects > 0 then + for _, obj in ipairs(objects) do + local symbols = obj.symbols + if symbols and #symbols > 0 then + -- print object file + print("") + cprint("${bright}Object: %s", obj.objectfile) + print(string.rep("-", 80)) - for i, sym in ipairs(symbols) do - if sym.name then - max_name_len = math.max(max_name_len, #sym.name) - end - if sym.type then - max_type_len = math.max(max_type_len, #sym.type) - end - end + -- calculate column widths for alignment + local max_name_len = 0 + local max_type_len = 0 - -- calculate column widths - local type_width = math.max(max_type_len, 4) - local name_width = math.max(max_name_len, 4) + for i, sym in ipairs(symbols) do + if sym.name then + max_name_len = math.max(max_name_len, #sym.name) + end + if sym.type then + max_type_len = math.max(max_type_len, #sym.type) + end + end - -- print header - print("") - print("Symbols:") - local header_format = " %-" .. type_width .. "s %s" - print(string.format(header_format, "TYPE", "NAME")) - print(string.rep("-", 80)) + -- calculate column widths + local type_width = math.max(max_type_len, 4) + local name_width = math.max(max_name_len, 4) - -- print symbols - local format_str = " %-" .. type_width .. "s %s" + -- print header + local header_format = " %-" .. type_width .. "s %s" + print(string.format(header_format, "TYPE", "NAME")) - for i, sym in ipairs(symbols) do - local type_str = sym.type or "unknown" - local name_str = sym.name or "" + -- print symbols + local format_str = " %-" .. type_width .. "s %s" - print(string.format(format_str, type_str, name_str)) + for i, sym in ipairs(symbols) do + local type_str = sym.type or "unknown" + local name_str = sym.name or "" + + print(string.format(format_str, type_str, name_str)) + end + print("") + cprint("${bright}%d symbols found!", #symbols) + end end - print("") - cprint("${bright}%d symbols found!", #symbols) else print("") cprint("${bright}No symbols found!") end end --- read symbols from object file(s) (auto-detect format: ELF, COFF, Mach-O) +-- read symbols from object file (auto-detect format: ELF, COFF, Mach-O) -- --- @param binaryfiles the object file path or table of object files (required) --- @return the symbols table (all symbols from all files if table is provided) -function main(binaryfiles) - assert(binaryfiles, "usage: xmake l utils.binary.readsyms <binaryfile> or readsyms(binaryfiles)") - - local all_symbols = {} - if type(binaryfiles) == "string" then - return _get_symbols(binaryfiles) - else - for _, binaryfile in ipairs(binaryfiles) do - local symbols = _get_symbols(binaryfile) - if symbols then - for _, sym in ipairs(symbols) do - table.insert(all_symbols, sym) - end - end - end - return all_symbols - end +-- @param binaryfile the object file path (required) +-- @return the symbols table +function main(binaryfile) + assert(binaryfile, "usage: xmake l utils.binary.readsyms <binaryfile>") + return _get_symbols(binaryfile) end |
