diff options
| author | ruki <[email protected]> | 2025-11-24 23:08:17 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-11-24 23:08:17 +0800 |
| commit | 4198e9bb7a885fb8d18915533b26434bd01e2f67 (patch) | |
| tree | f95e810b7ee03e641c3eb52799f21c30673a237f | |
| parent | 49a1737db8d36a9715f71d9cb1acbffe8e7e7faf (diff) | |
improve to merge archive libs
| -rw-r--r-- | xmake/modules/utils/archive/merge_staticlib.lua | 113 |
1 files changed, 93 insertions, 20 deletions
diff --git a/xmake/modules/utils/archive/merge_staticlib.lua b/xmake/modules/utils/archive/merge_staticlib.lua index 41f256740..bf5c52b19 100644 --- a/xmake/modules/utils/archive/merge_staticlib.lua +++ b/xmake/modules/utils/archive/merge_staticlib.lua @@ -22,31 +22,104 @@ import("core.base.option") import("private.tools.vstool") +-- merge *.a archive libraries using libtool +function _merge_for_ar_libtool(target, program, outputfile, libraryfiles, opt) + os.vrunv("libtool", table.join("-static", "-o", outputfile, libraryfiles)) +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 + local tmpdir = os.tmpfile() .. ".dir" + os.mkdir(tmpdir) + local oldir = os.cd(tmpdir) + local objfiles = {} + local objfile_set = {} + for idx, libraryfile in ipairs(libraryfiles) do + if os.isfile(libraryfile) then + -- list all files in the archive first to avoid overwriting during extraction + local ok, list = os.iorunv(program, {"-t", path.absolute(libraryfile)}) + if ok and list then + local file_counter = {} + for line in list:gmatch("[^\r\n]+") do + line = line:trim() + if line:endswith(".o") then + local basename = path.basename(line, path.extension(line)) + local ext = path.extension(line) + -- count occurrences of this basename in current library + file_counter[basename] = (file_counter[basename] or 0) + 1 + local counter = file_counter[basename] - 1 + -- generate unique name with library index prefix to avoid conflicts + local unique_name + if counter == 0 then + unique_name = string.format("lib%d_%s%s", idx, basename, ext) + else + unique_name = string.format("lib%d_%s_%d%s", idx, basename, counter, ext) + end + -- ensure global uniqueness by adding counter if needed + local global_counter = 0 + while objfile_set[unique_name] do + global_counter = global_counter + 1 + unique_name = string.format("lib%d_%s_%d_%d%s", idx, basename, counter, global_counter, ext) + end + objfile_set[unique_name] = true + -- extract single file and rename immediately to avoid overwriting + os.vrunv(program, {"-x", path.absolute(libraryfile), line}) + if os.isfile(line) then + os.mv(line, unique_name) + table.insert(objfiles, unique_name) + end + end + end + end + end + end + -- create new archive with all object files + if #objfiles > 0 then + os.mkdir(path.directory(outputfile)) + local outputfile_abs = path.absolute(outputfile) + -- remove output file if exists to avoid appending + os.tryrm(outputfile_abs) + -- create new archive with -c (create) and -r (replace/insert) + os.vrunv(program, table.join("-cr", outputfile_abs, objfiles)) + end + os.cd(oldir) + os.rm(tmpdir) +end + +-- merge *.a archive libraries for GNU ar (using -M interactive mode) +function _merge_for_ar_gnu(target, program, outputfile, libraryfiles, opt) + -- we can't generate directly to outputfile, + -- because on windows/ndk, llvm-ar.exe may fail to write with no permission, even though it's a writable temp file. + -- + -- @see https://github.com/xmake-io/xmake/issues/1973 + local archivefile = target.autogenfile and target:autogenfile((hash.uuid(outputfile):gsub("%-", ""))) .. ".a" or (os.tmpfile() .. ".a") + os.mkdir(path.directory(archivefile)) + local tmpfile = os.tmpfile() + local mrifile = io.open(tmpfile, "w") + mrifile:print("create %s", archivefile) + for _, libraryfile in ipairs(libraryfiles) do + mrifile:print("addlib %s", libraryfile) + end + mrifile:print("save") + mrifile:print("end") + mrifile:close() + os.vrunv(program, {"-M"}, {stdin = tmpfile}) + os.cp(archivefile, outputfile) + os.rm(tmpfile) + os.rm(archivefile) +end + -- merge *.a archive libraries for ar function _merge_for_ar(target, program, outputfile, libraryfiles, opt) opt = opt or {} if target:is_plat("macosx", "iphoneos", "watchos", "appletvos") then - os.vrunv("libtool", table.join("-static", "-o", outputfile, libraryfiles)) + _merge_for_ar_libtool(target, program, outputfile, libraryfiles, opt) + elseif target:is_plat("solaris") then + _merge_for_ar_fallback(target, program, outputfile, libraryfiles, opt) else - -- we can't generate directly to outputfile, - -- because on windows/ndk, llvm-ar.exe may fail to write with no permission, even though it's a writable temp file. - -- - -- @see https://github.com/xmake-io/xmake/issues/1973 - local archivefile = target.autogenfile and target:autogenfile((hash.uuid(outputfile):gsub("%-", ""))) .. ".a" or (os.tmpfile() .. ".a") - os.mkdir(path.directory(archivefile)) - local tmpfile = os.tmpfile() - local mrifile = io.open(tmpfile, "w") - mrifile:print("create %s", archivefile) - for _, libraryfile in ipairs(libraryfiles) do - mrifile:print("addlib %s", libraryfile) - end - mrifile:print("save") - mrifile:print("end") - mrifile:close() - os.vrunv(program, {"-M"}, {stdin = tmpfile}) - os.cp(archivefile, outputfile) - os.rm(tmpfile) - os.rm(archivefile) + _merge_for_ar_gnu(target, program, outputfile, libraryfiles, opt) end end |
