summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-11 23:35:23 +0800
committerruki <[email protected]>2025-12-12 09:00:44 +0800
commit4ccb8514f37fdf7108b41dbcd8ca77143841e1cd (patch)
treeff1b1ae7433fa16acb2bfccffcf4bebc4e9b8b98 /core
parent409b21826872503ef479848321003d7ca4c1aad8 (diff)
set plain as default
Diffstat (limited to 'core')
-rw-r--r--core/src/xmake/binutils/extractlib.c17
-rw-r--r--core/src/xmake/binutils/mslib/extractlib.c88
2 files changed, 97 insertions, 8 deletions
diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c
index d5e8b3759..ec588f213 100644
--- a/core/src/xmake/binutils/extractlib.c
+++ b/core/src/xmake/binutils/extractlib.c
@@ -36,7 +36,7 @@
* 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);
+extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
@@ -46,6 +46,11 @@ extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t co
* Supports AR format (.a) and MSVC lib format (.lib)
*
* @param lua the lua state
+ *
+ * libraryfile = lua[1]
+ * outputdir = lua[2]
+ * plain = lua[3] (optional, default: true)
+ *
* @return 1 on success, 2 on failure (with error message)
*/
tb_int_t xm_binutils_extractlib(lua_State *lua) {
@@ -59,6 +64,12 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) {
tb_char_t const *outputdir = luaL_checkstring(lua, 2);
tb_check_return_val(outputdir, 0);
+ // get the plain mode (optional)
+ tb_bool_t plain = tb_true;
+ if (lua_gettop(lua) >= 3 && !lua_isnil(lua, 3)) {
+ plain = lua_toboolean(lua, 3);
+ }
+
// open library file
tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO);
if (!istream) {
@@ -88,7 +99,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) {
// if the file extension is .lib, we use the msvc lib extractor to support long paths and subdirectories
tb_size_t n = tb_strlen(libraryfile);
if (n > 4 && !tb_strnicmp(libraryfile + n - 4, ".lib", 4)) {
- if (!xm_binutils_mslib_extract(istream, outputdir)) {
+ if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {
error_msg = "extract MSVC lib failed";
break;
}
@@ -105,7 +116,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) {
// 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)) {
+ if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {
error_msg = "extract MSVC lib failed";
break;
}
diff --git a/core/src/xmake/binutils/mslib/extractlib.c b/core/src/xmake/binutils/mslib/extractlib.c
index f56d3eb3e..5dec97f3e 100644
--- a/core/src/xmake/binutils/mslib/extractlib.c
+++ b/core/src/xmake/binutils/mslib/extractlib.c
@@ -34,13 +34,49 @@
* implementation
*/
+/* generate unique name for output file
+ *
+ * @param base_name the base name
+ * @param id the unique id
+ * @param output output buffer
+ * @param output_size output buffer size
+ * @param output_len output: actual output length
+ * @return tb_true on success, tb_false on failure
+ */
+static tb_bool_t xm_binutils_mslib_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) {
+ tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false);
+
+ // find the last dot for extension
+ tb_char_t const *ext = tb_strrchr(base_name, '.');
+ tb_long_t n = -1;
+ 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) {
+ n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext);
+ }
+ } else {
+ // no extension
+ if (tb_strlen(base_name) + 16 < output_size) {
+ n = tb_snprintf(output, output_size, "%s_%u", base_name, id);
+ }
+ }
+
+ if (n >= 0) {
+ *output_len = (tb_size_t)n;
+ return tb_true;
+ }
+ return tb_false;
+}
+
/* extract MSVC lib archive to directory
*
* @param istream the input stream
* @param outputdir the output directory
+ * @param plain extract all object files to the same 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_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain) {
tb_assert_and_check_return_val(istream && outputdir, tb_false);
// check magic (!<arch>\n)
@@ -158,11 +194,53 @@ tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *ou
// check output path length
tb_char_t output_path[1024];
- if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) {
- ok = tb_false;
- break;
+ if (plain) {
+ // get filename only
+ tb_char_t const* name = tb_strrchr(member_name, '/');
+ if (name) name++;
+ else name = member_name;
+
+ // check conflicts
+ tb_char_t output_name[512];
+ tb_size_t output_name_len = tb_strlen(name);
+ tb_size_t outputdir_len = tb_strlen(outputdir);
+
+ if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {
+ ok = tb_false;
+ break;
+ }
+ tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, name);
+
+ if (tb_file_info(output_path, tb_null)) {
+ // name conflict, try different IDs
+ tb_uint32_t conflict_id = 1;
+ while (conflict_id < 10000) {
+ if (!xm_binutils_mslib_generate_unique_name(name, conflict_id, output_name, sizeof(output_name), &output_name_len)) {
+ ok = tb_false;
+ break;
+ }
+ if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {
+ ok = tb_false;
+ break;
+ }
+ tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name);
+ if (!tb_file_info(output_path, tb_null)) {
+ break;
+ }
+ conflict_id++;
+ }
+ if (!ok || conflict_id >= 10000) {
+ ok = tb_false;
+ break;
+ }
+ }
+ } else {
+ if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) {
+ ok = tb_false;
+ break;
+ }
+ tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name);
}
- tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name);
// ensure directory exists
tb_char_t const* p = tb_strrchr(output_path, '/');