summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-10 00:48:15 +0800
committerruki <[email protected]>2025-12-12 09:00:43 +0800
commit094b9b26786db5960947819680ccc49985f5ed55 (patch)
treed980e4bb569b5ac8b6b0c482b09aaabd4eb63b01
parent245d472158edc782c4ee7ddb6d47be65270c5451 (diff)
add binutils extractlib
-rw-r--r--core/src/xmake/binutils/ar/extractlib.c296
-rw-r--r--core/src/xmake/binutils/extractlib.c126
-rw-r--r--core/src/xmake/binutils/mslib/extractlib.c52
-rw-r--r--core/src/xmake/binutils/mslib/prefix.h30
-rw-r--r--core/src/xmake/engine.c2
-rwxr-xr-xcore/src/xmake/xmake.sh1
-rw-r--r--xmake/core/base/binutils.lua19
-rw-r--r--xmake/core/sandbox/modules/import/core/base/binutils.lua8
-rw-r--r--xmake/modules/utils/binary/extractlib.lua64
9 files changed, 598 insertions, 0 deletions
diff --git a/core/src/xmake/binutils/ar/extractlib.c b/core/src/xmake/binutils/ar/extractlib.c
new file mode 100644
index 000000000..fb8ffa542
--- /dev/null
+++ b/core/src/xmake/binutils/ar/extractlib.c
@@ -0,0 +1,296 @@
+/*!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.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "extractlib"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+/* get member name from AR header, handling extended names (#N/L format)
+ *
+ * @param istream the input stream
+ * @param header the AR header
+ * @param name output buffer for the name
+ * @param name_size size of the name buffer
+ * @param name_len output: actual name length
+ * @return tb_true on success, tb_false on failure
+ */
+static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const *header, tb_char_t *name, tb_size_t name_size, tb_size_t *name_len) {
+ tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len, tb_false);
+
+ // check for extended name format (#N/L)
+ if (header->name[0] == '#' && header->name[1] == '/') {
+ // format: #N/L where N is name length, L is total data length (including name)
+ tb_int64_t name_length = xm_binutils_ar_parse_decimal(header->name + 2, 14);
+ if (name_length <= 0 || name_length >= (tb_int64_t)name_size) {
+ return tb_false;
+ }
+
+ // read the actual name
+ if (!tb_stream_bread(istream, (tb_byte_t*)name, (tb_size_t)name_length)) {
+ return tb_false;
+ }
+ name[name_length] = '\0';
+ *name_len = (tb_size_t)name_length;
+ return tb_true;
+ } else {
+ // regular name (null-terminated or space-padded)
+ tb_size_t i = 0;
+ for (i = 0; i < 16 && i < name_size - 1; i++) {
+ if (header->name[i] == ' ' || header->name[i] == '\0' || header->name[i] == '/') {
+ break;
+ }
+ name[i] = header->name[i];
+ }
+ name[i] = '\0';
+ *name_len = i;
+ return tb_true;
+ }
+}
+
+/* check if member is a symbol table (should be skipped)
+ *
+ * @param name the member name
+ * @return tb_true if it's a symbol table, tb_false otherwise
+ */
+static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *name) {
+ if (!name) return tb_false;
+ return (tb_strcmp(name, "__.SYMDEF") == 0 || tb_strcmp(name, "__.SYMDEF SORTED") == 0 ||
+ tb_strcmp(name, "/") == 0 || tb_strcmp(name, "//") == 0 ||
+ tb_strncmp(name, "__.SYMDEF", 9) == 0);
+}
+
+/* check if member is an object file (based on extension)
+ *
+ * @param name the member name
+ * @return tb_true if it's likely an object file, tb_false otherwise
+ */
+static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *name) {
+ if (!name) return tb_false;
+ tb_size_t len = tb_strlen(name);
+ if (len == 0) return tb_false;
+
+ // check common object file extensions
+ if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') return tb_true;
+ if (len >= 4 && tb_strcmp(name + len - 4, ".obj") == 0) return tb_true;
+
+ // check if it's a COFF/ELF/Mach-O file by detecting format
+ // For now, we'll extract all non-symbol-table members
+ return tb_true;
+}
+
+/* generate unique filename to handle name conflicts
+ *
+ * @param base_name the base filename
+ * @param id the unique ID
+ * @param output output buffer
+ * @param output_size size of output buffer
+ * @return tb_true on success
+ */
+static tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size) {
+ tb_assert_and_check_return_val(base_name && output && output_size > 0, tb_false);
+
+ // find the last dot for extension
+ tb_char_t const *ext = tb_strrchr(base_name, '.');
+ if (ext) {
+ tb_size_t base_len = (tb_size_t)(ext - base_name);
+ tb_size_t ext_len = tb_strlen(ext);
+ if (base_len + ext_len + 16 < output_size) {
+ tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext);
+ return tb_true;
+ }
+ } else {
+ // no extension
+ if (tb_strlen(base_name) + 16 < output_size) {
+ tb_snprintf(output, output_size, "%s_%u", base_name, id);
+ return tb_true;
+ }
+ }
+ return tb_false;
+}
+
+/* extract AR archive to directory
+ *
+ * @param istream the input stream
+ * @param outputdir the output directory
+ * @return tb_true on success, tb_false on failure
+ */
+tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) {
+ tb_assert_and_check_return_val(istream && outputdir, tb_false);
+
+ // check AR magic (!<arch>\n)
+ tb_uint8_t magic[8];
+ if (!tb_stream_seek(istream, 0)) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, magic, 8)) {
+ return tb_false;
+ }
+ if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' ||
+ magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\n') ||
+ (magic[7] != '\n' && magic[7] != '\r')) {
+ return tb_false;
+ }
+
+ // ensure output directory exists
+ if (!tb_directory_create(outputdir)) {
+ return tb_false;
+ }
+
+ tb_bool_t ok = tb_true;
+
+ // iterate through AR members
+ while (ok) {
+ // read AR header
+ xm_ar_header_t header;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
+ // end of file
+ break;
+ }
+
+ // parse member size
+ tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10);
+ if (member_size < 0) {
+ ok = tb_false;
+ break;
+ }
+
+ // get member name
+ tb_char_t member_name[256] = {0};
+ tb_size_t name_len = 0;
+ if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len)) {
+ // skip this member
+ if (member_size > 0) {
+ tb_stream_seek(istream, tb_stream_offset(istream) + (tb_hize_t)member_size);
+ }
+ continue;
+ }
+
+ // skip symbol tables
+ if (xm_binutils_ar_is_symbol_table(member_name)) {
+ if (member_size > 0) {
+ tb_stream_seek(istream, tb_stream_offset(istream) + (tb_hize_t)member_size);
+ }
+ continue;
+ }
+
+ // only extract object files
+ if (!xm_binutils_ar_is_object_file(member_name)) {
+ if (member_size > 0) {
+ tb_stream_seek(istream, tb_stream_offset(istream) + (tb_hize_t)member_size);
+ }
+ continue;
+ }
+
+ // handle name conflicts by checking if file exists and renaming with ID
+ tb_char_t output_name[512] = {0};
+ tb_char_t output_path_check[1024] = {0};
+ tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, member_name);
+
+ // check if file already exists
+ tb_file_info_t info;
+ tb_uint32_t conflict_id = 1;
+ if (tb_file_info(output_path_check, &info)) {
+ // name conflict, try different IDs until we find an available name
+ while (conflict_id < 10000) { // reasonable limit
+ if (!xm_binutils_ar_generate_unique_name(member_name, conflict_id, output_name, sizeof(output_name))) {
+ ok = tb_false;
+ break;
+ }
+ tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, output_name);
+ if (!tb_file_info(output_path_check, &info)) {
+ // found available name
+ break;
+ }
+ conflict_id++;
+ }
+ if (conflict_id >= 10000) {
+ ok = tb_false;
+ break;
+ }
+ } else {
+ // first occurrence, use original name
+ tb_strlcpy(output_name, member_name, sizeof(output_name));
+ }
+
+ // build output path
+ tb_char_t output_path[1024] = {0};
+ tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name);
+
+ // create output file
+ tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
+ if (!ostream) {
+ ok = tb_false;
+ break;
+ }
+
+ if (!tb_stream_open(ostream)) {
+ tb_stream_exit(ostream);
+ ok = tb_false;
+ break;
+ }
+
+ // copy member data to output file
+ tb_byte_t buffer[4096];
+ tb_hize_t remaining = (tb_hize_t)member_size;
+ while (remaining > 0) {
+ tb_size_t to_read = (tb_size_t)tb_min(remaining, (tb_hize_t)sizeof(buffer));
+ if (!tb_stream_bread(istream, buffer, to_read)) {
+ ok = tb_false;
+ break;
+ }
+ if (!tb_stream_bwrit(ostream, buffer, to_read)) {
+ ok = tb_false;
+ break;
+ }
+ remaining -= to_read;
+ }
+
+ tb_stream_clos(ostream);
+ tb_stream_exit(ostream);
+
+ if (!ok) {
+ break;
+ }
+
+ // align to 2-byte boundary (AR format requirement)
+ tb_hize_t current_pos = tb_stream_offset(istream);
+ if (current_pos & 1) {
+ tb_byte_t padding;
+ tb_stream_bread(istream, &padding, 1);
+ }
+
+ }
+
+ return ok;
+}
+
+
diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c
new file mode 100644
index 000000000..7a61d0bde
--- /dev/null
+++ b/core/src/xmake/binutils/extractlib.c
@@ -0,0 +1,126 @@
+/*!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.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "extractlib"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+#include "ar/prefix.h"
+#include "mslib/prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * forward declarations
+ */
+extern tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir);
+extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir);
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+/* extract static library to directory (Lua interface)
+ * Supports AR format (.a) and MSVC lib format (.lib)
+ *
+ * @param lua the lua state
+ * @return 1 on success, 2 on failure (with error message)
+ */
+tb_int_t xm_binutils_extractlib(lua_State *lua) {
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the library file path
+ tb_char_t const *libraryfile = luaL_checkstring(lua, 1);
+ tb_check_return_val(libraryfile, 0);
+
+ // get the output directory
+ tb_char_t const *outputdir = luaL_checkstring(lua, 2);
+ tb_check_return_val(outputdir, 0);
+
+ // open library file
+ tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO);
+ if (!istream) {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: open %s failed", libraryfile);
+ return 2;
+ }
+
+ tb_bool_t ok = tb_false;
+ do {
+ if (!tb_stream_open(istream)) {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: open %s failed", libraryfile);
+ break;
+ }
+
+ // detect format
+ tb_int_t format = xm_binutils_detect_format(istream);
+ if (format < 0) {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: cannot detect format of %s", libraryfile);
+ break;
+ }
+
+ // extract based on format
+ if (format == XM_BINUTILS_FORMAT_AR) {
+ // AR archive format (.a or .lib in AR format)
+ if (!xm_binutils_ar_extract(istream, outputdir)) {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: extract AR archive %s failed", libraryfile);
+ break;
+ }
+ ok = tb_true;
+ } else if (format == XM_BINUTILS_FORMAT_COFF) {
+ // MSVC lib format (.lib in COFF format)
+ // Check if it's actually a library (not just a single object file)
+ // MSVC lib files can be:
+ // 1. Import libraries (different format)
+ // 2. Static libraries (COFF archive format, similar to AR but different)
+ if (!xm_binutils_mslib_extract(istream, outputdir)) {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: extract MSVC lib %s failed", libraryfile);
+ break;
+ }
+ ok = tb_true;
+ } else {
+ lua_pushboolean(lua, tb_false);
+ lua_pushfstring(lua, "extractlib: unsupported format for %s (only AR and MSVC lib are supported)", libraryfile);
+ break;
+ }
+
+ if (ok) {
+ lua_pushboolean(lua, ok);
+ }
+
+ } while (0);
+
+ if (istream) {
+ tb_stream_clos(istream);
+ tb_stream_exit(istream);
+ }
+
+ return ok ? 1 : 2;
+}
+
diff --git a/core/src/xmake/binutils/mslib/extractlib.c b/core/src/xmake/binutils/mslib/extractlib.c
new file mode 100644
index 000000000..5cc4a57b4
--- /dev/null
+++ b/core/src/xmake/binutils/mslib/extractlib.c
@@ -0,0 +1,52 @@
+/*!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.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "mslib_extract"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+/* extract MSVC lib archive to directory (placeholder, not yet implemented)
+ *
+ * @param istream the input stream
+ * @param outputdir the output directory
+ * @return tb_true on success, tb_false on failure
+ */
+tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) {
+ tb_assert_and_check_return_val(istream && outputdir, tb_false);
+
+ // TODO: implement MSVC lib extraction
+ // MSVC lib format extraction is not yet implemented
+ (void)istream;
+ (void)outputdir;
+ return tb_false;
+}
+
diff --git a/core/src/xmake/binutils/mslib/prefix.h b/core/src/xmake/binutils/mslib/prefix.h
new file mode 100644
index 000000000..9bd5fa4b6
--- /dev/null
+++ b/core/src/xmake/binutils/mslib/prefix.h
@@ -0,0 +1,30 @@
+/*!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 prefix.h
+ *
+ */
+#ifndef XM_BINUTILS_MSLIB_PREFIX_H
+#define XM_BINUTILS_MSLIB_PREFIX_H
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "../prefix.h"
+
+#endif
+
diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c
index 4f2702f52..8e1878499 100644
--- a/core/src/xmake/engine.c
+++ b/core/src/xmake/engine.c
@@ -340,6 +340,7 @@ tb_int_t xm_binutils_bin2coff(lua_State *lua);
tb_int_t xm_binutils_bin2macho(lua_State *lua);
tb_int_t xm_binutils_bin2elf(lua_State *lua);
tb_int_t xm_binutils_readsyms(lua_State *lua);
+tb_int_t xm_binutils_extractlib(lua_State *lua);
#ifdef XM_CONFIG_API_HAVE_CURSES
// register curses functions
@@ -663,6 +664,7 @@ static luaL_Reg const g_binutils_functions[] = {
{ "bin2macho", xm_binutils_bin2macho },
{ "bin2elf", xm_binutils_bin2elf },
{ "readsyms", xm_binutils_readsyms },
+ { "extractlib", xm_binutils_extractlib },
{ tb_null, tb_null },
};
diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh
index e40051419..8a8f1224c 100755
--- a/core/src/xmake/xmake.sh
+++ b/core/src/xmake/xmake.sh
@@ -76,6 +76,7 @@ target "xmake"
add_files "binutils/macho/*.c"
add_files "binutils/elf/*.c"
add_files "binutils/ar/*.c"
+ add_files "binutils/mslib/*.c"
add_files "thread/*.c"
if is_plat "mingw"; then
add_files "winos/*.c"
diff --git a/xmake/core/base/binutils.lua b/xmake/core/base/binutils.lua
index 77b17dc92..ea5d04ba8 100644
--- a/xmake/core/base/binutils.lua
+++ b/xmake/core/base/binutils.lua
@@ -30,6 +30,7 @@ binutils._bin2coff = binutils._bin2coff or binutils.bin2coff
binutils._bin2macho = binutils._bin2macho or binutils.bin2macho
binutils._bin2elf = binutils._bin2elf or binutils.bin2elf
binutils._readsyms = binutils._readsyms or binutils.readsyms
+binutils._extractlib = binutils._extractlib or binutils.extractlib
-- generate c/c++ code from the binary file
function binutils.bin2c(binaryfile, outputfile, opt)
@@ -100,6 +101,24 @@ function binutils.readsyms(binaryfile)
end
end
+-- extract static library to directory
+-- Supports AR format (.a) and MSVC lib format (.lib)
+-- @param libraryfile the static library file path (.a or .lib)
+-- @param outputdir the output directory to extract object files
+-- @return true on success, false and error message on failure
+function binutils.extractlib(libraryfile, outputdir)
+ if binutils._extractlib then
+ local ok, errors = binutils._extractlib(libraryfile, outputdir)
+ if ok then
+ return true
+ else
+ return false, errors or "extractlib: unknown error"
+ end
+ else
+ return false, "extractlib: C implementation not available"
+ end
+end
+
-- return module
return binutils
diff --git a/xmake/core/sandbox/modules/import/core/base/binutils.lua b/xmake/core/sandbox/modules/import/core/base/binutils.lua
index b9a502f8d..e2306a2da 100644
--- a/xmake/core/sandbox/modules/import/core/base/binutils.lua
+++ b/xmake/core/sandbox/modules/import/core/base/binutils.lua
@@ -52,6 +52,14 @@ function sandbox_core_base_binutils.readsyms(binaryfile)
end
end
+-- extract static library to directory
+function sandbox_core_base_binutils.extractlib(libraryfile, outputdir)
+ local ok, errors = binutils.extractlib(libraryfile, outputdir)
+ if not ok then
+ raise("extractlib: %s", errors or "unknown errors")
+ end
+end
+
-- return module
return sandbox_core_base_binutils
diff --git a/xmake/modules/utils/binary/extractlib.lua b/xmake/modules/utils/binary/extractlib.lua
new file mode 100644
index 000000000..254f06950
--- /dev/null
+++ b/xmake/modules/utils/binary/extractlib.lua
@@ -0,0 +1,64 @@
+--!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.option")
+import("core.base.binutils")
+
+local options = {
+ {'i', "libraryfile", "kv", nil, "Set the static library file path (.a or .lib)."},
+ {'o', "outputdir", "kv", nil, "Set the output directory to extract object files."}
+}
+
+function _do_extractlib(libraryfile, outputdir)
+ -- 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
+ local ok, errors = binutils.extractlib(libraryfile, outputdir)
+ if not ok then
+ raise("extractlib: %s", errors or "unknown error")
+ end
+
+ -- trace
+ cprint("${bright}extraction completed!")
+end
+
+function main(...)
+ -- parse arguments
+ local argv = {...}
+ local opt = option.parse(argv, options, "Extract object files from static library (AR or MSVC lib format)."
+ , ""
+ , "Usage: xmake l utils.binary.extractlib [options]")
+
+ -- do extractlib
+ _do_extractlib(opt.libraryfile, opt.outputdir)
+end
+