When you have multiple static libraries (.a files) and need to combine them into a single archive, GNU ar provides several approaches. The most straightforward method uses ar‘s MRI mode for clarity and maintainability.
Using ar MRI Mode
The cleanest approach is to use ar -M with an MRI script. This method is explicit and easy to version control.
Create a script file (e.g., merge-libs.mri):
create libmerged.a
addlib libfirst.a
addlib libsecond.a
save
end
Then run:
ar -M < merge-libs.mri
This creates a new archive libmerged.a containing all object files from both input libraries. The save and end commands tell ar to write the archive and exit.
Using ar with Object Extraction
An alternative approach that’s more portable and doesn’t rely on MRI mode is to extract all object files and re-archive them:
mkdir -p merge_tmp
cd merge_tmp
ar x ../libfirst.a
ar x ../libsecond.a
ar cr ../libmerged.a *.o
cd ..
rm -rf merge_tmp
This method:
- Creates a temporary directory
- Extracts all
.ofiles from each input library - Creates a new archive from the combined object files
- Cleans up temporary files
Using ar with Direct Concatenation
For a quick one-liner without MRI scripts:
ar cr libmerged.a $(ar t libfirst.a | xargs -I {} ar p libfirst.a {} ) $(ar t libsecond.a | xargs -I {} ar p libsecond.a {})
This is less readable but avoids temporary files.
Verifying the Merge
After merging, verify the contents:
ar t libmerged.a
This lists all object files in the merged archive. You can also check symbols:
nm libmerged.a | head -20
Considerations for Build Systems
If you’re using CMake, modern practice is to use object libraries instead of manually merging:
add_library(libfirst OBJECT source1.c)
add_library(libsecond OBJECT source2.c)
add_library(libmerged STATIC $<TARGET_OBJECTS:libfirst> $<TARGET_OBJECTS:libsecond>)
This avoids the merge step entirely and gives the build system better dependency tracking.
For Meson:
libfirst = static_library('first', 'source1.c')
libsecond = static_library('second', 'source2.c')
libmerged = static_library('merged',
objects: [libfirst.extract_all_objects(recursive: true),
libsecond.extract_all_objects(recursive: true)])
Performance and Symbol Conflicts
When merging libraries, ensure there are no duplicate symbols. If both libraries define the same function, the linker will fail with a duplicate symbol error. Use nm to check for conflicts before merging:
comm -23 <(nm libfirst.a | grep ' T ' | awk '{print $3}' | sort) <(nm libsecond.a | grep ' T ' | awk '{print $3}' | sort)
The MRI approach is recommended for production use because it’s explicit, version-controllable, and clearly documents which libraries are being merged. The object extraction method is most portable if you’re working with non-GNU toolchains.
