How to merge two "ar" static libraries into one?
Asked Answered
U

9

133

I have 2 static Linux libraries, created by ar cr, libabc.a and libxyz.a.
I want to merge them into one static library libaz.a.
How can I do this.

I want to create a merged static library, not to give both libraries to final link of applications.

Ungraceful answered 29/9, 2010 at 13:13 Comment(3)
See also: libtool-based solution: libtool -static -o new.a old1.a old2.aUngraceful
it works perfect, just a little doubt if those libraries have common file.o(but functionality wise they are different) will it still work?Buzzard
libtool -static -o new.a old1.a old2.a dosen't work on linux(centos 7)Bachelor
C
69

You can extract the object from both the .a files and create your .a file using the extracted .os:

ar -x libabc.a
ar -x libxyz.a
ar -c libaz.a  *.o
Civilize answered 29/9, 2010 at 13:17 Comment(5)
Danger, Will Robinson! This works only if the names of the members in libabc.a and libxyz.a don't overlap. Otherwise you'll overwrite one and it'll be lost.Jersey
Moreover, libabc.a may contain objects having the same name (originated form different directories) -- re-assembling won't work then!Unlive
ar -c didn't work for me (Ubuntu 14.04). I got ar: no operation specified. I did ar -qc instead and that worked well.Cowgirl
ar t lib.a can be used for view the files in library without actually extracting the files.Muticous
how can I do that in automake ?Insphere
P
162

There are at least three ways to do this natively. The first and most portable way is to use libtool. After having built the other libraries also with libtool, you can combine them just by adding the .la libs to an automake libaz_la_LIBADD variable, or directly from a Makefile with something like:

libtool --mode=link cc -static -o libaz.la libabc.la libxyz.la

The other two are at least available when using GNU ar. You can use an MRI script (named for example libaz.mri), such as:

create libaz.a
addlib libabc.a
addlib libxyz.a
save
end

and then execute ar as:

ar -M <libaz.mri

Or you can use a thin archive (option -T), which will allow adding other archives without getting them nested inside, although the downside is that if you want to distribute the static library, the detached object will be missing:

ar -rcT libaz.a libabc.a libxyz.a

All the above methods gracefully handle overlapping member names from the original archives.

Otherwise, you'd have to unpack into different directories and repack again, to avoid replacing overlapping member names:

mkdir abc; cd abc; ar -x ../libabc.a
mkdir xyz; cd xyz; ar -x ../libxyz.a
ar -qc libaz.a abc xyz
Postmaster answered 13/5, 2014 at 2:9 Comment(9)
For those that want a normal archive (not thin), one simple thing that can be done is create a thin archive, then convert it to a normal archive. Something like: ar cqT libaz.a libabc.a libxyz.a && echo -e 'create libaz.a\naddlib libaz.a\nsave\nend' | ar -M. This creates a temporary thin libaz.a, and then converts the thin archive into a normal one (so you can move/distribute it). This also gracefully handles when your library names have special characters (spaced, pluses, or commas) (i.e. ar cqT libbundle.a libfoo++.a 'libbar baz.a'). But +1 from me!Insect
What is the downside to the first MRI script example given?Mannuela
Nice answer! Good to see some options that don't require you extracting and re-achiving. Also i think @Insect idea is good. Maybe should be added to the answer?Bitterweed
Hey when I try to use the command for libtool I get these erros: libtool: link: unable to infer tagged configuration libtool: error: specify a tag with '--tag' Any ideas how to fix that ?Clemmie
@Guillem @Insect Great answer. What if the --Wl,-whole-archive option is required in original linking command for multiple lib*.a, and I need to combine all lib*.a into one.a. When linking again, --Wl,-whole-archive won't work with one.a. What is your suggestion? #56323697Spencerspencerian
It's a pity they don't even mention MRI mode in some newer editions of the AR man pages. The feature is exceptionally useful in the complex builds (because the script itself can be a dependency), while "thin" archive approach (the supposedly more modern alternative to merging) has a nasty habit of breaking CI build pipelines in most unexpected ways.Carloscarlota
if there are overlapping names in an archive, the last method of extracting file will fail, because .o with the same name will overlapBachelor
The last approach seems to use folders as input for ar -qc but when I do I get an error : File format not recognizedKiyokokiyoshi
just as a note the --mode=link cc part is not compatible with apples libtool as of XCode 13. The equivalent there seems to be instead libtool --mode=link cc -static -o libaz.la libabc.la libxyz.la to do clang -r -o libaz.o --all_load libabc.la libxyz.la; ar cr libaz.la libaz.oGlaswegian
C
69

You can extract the object from both the .a files and create your .a file using the extracted .os:

ar -x libabc.a
ar -x libxyz.a
ar -c libaz.a  *.o
Civilize answered 29/9, 2010 at 13:17 Comment(5)
Danger, Will Robinson! This works only if the names of the members in libabc.a and libxyz.a don't overlap. Otherwise you'll overwrite one and it'll be lost.Jersey
Moreover, libabc.a may contain objects having the same name (originated form different directories) -- re-assembling won't work then!Unlive
ar -c didn't work for me (Ubuntu 14.04). I got ar: no operation specified. I did ar -qc instead and that worked well.Cowgirl
ar t lib.a can be used for view the files in library without actually extracting the files.Muticous
how can I do that in automake ?Insphere
W
12

If you simply do it as :

ar x a.a
ar x b.a
ar c c.a  *.o 

you will lost some object files if there are members with same name in both a.a and b.a so, you need to extract members of different archives into different folder:

ar x a.a && mv *.o a_objs
ar x b.a && mv *.o b_objs
ar c c.a a_objs/*.o b_objs/*.o

further more, it is posible that there are multiple members of same name in one archive (say in a.a), if you run ar x a.a, you will get only one for those members of same name.

The only way to extract all members of same name in one archive is to specify the member number by option 'N':

ar xN 1 a.a  xxx.c.o && mv xxx.c.o xxx.c.1.o
ar xN 2 b.a  xxx.c.o && mv xxx.c.o xxx.c.2.o
...

this would be a tedious work, so you will have to write a more sophisticate script to do that job.

One optional solutions is that you can combine multiple archives into one shared library:

g++ -shared -o c.so -Wl,--whole-archive a.a b.a 

this way the linker will handle all things for you!

Weidar answered 9/5, 2014 at 6:25 Comment(2)
Samuel, thank you. But in combining into shared library, all object should be compiled with -fPIC.Ungraceful
This comment was essential to the whole conversation!Ideate
D
2

Even better you perform partial linking on each library and them make an archive of the two resulting object files. That way it operates like shared libraries would

You do partial linking with

gcc -r --nostdlib

so either instead of making the intermediate archive or after reextracting it, run

gcc -r --nostdlib $CFLAGS $OBJECTS_A -o $LIBNAME_A.o
gcc -r --nostdlib $CFLAGS $OBJECTS_B -o $LIBNAME_B.o

then

ar -cr $LIBNAME_JOINED.a $LIBNAME_A.o $LIBNAME_B.o
Demetrius answered 24/10, 2018 at 11:3 Comment(2)
It's not really answering question asked - as he asked for libraries. Many times you don't even have sources for libraries given, or want to keep them prebuilt from other reasons.Relational
It does answer it, you can do with libraries as well, though for static libs you need -Wl,--whole-archive.Demetrius
D
2

You can always do partial linking:

gcc -r -o libnew.o -Wl,--whole-archive libabc.a libxyz.a
ar cr libnew.a libnew.o
Demetrius answered 16/7, 2021 at 11:0 Comment(0)
S
1

This question is specific to Linux. If you're looking for how to do this on macOS, the answer is libtool, as explained here:

libtool -static -o new.a old1.a old2.a
Span answered 4/4, 2021 at 17:45 Comment(0)
H
1

Here is a bash script to link all .a libs from a specified directory into a single library.

Usage: ./unify-static-libs.sh myFinalLib.a /path/to/input/libs

#!/bin/bash
#
# Creates one static library from several.
#
# Usage: copy all your libs to a single directory and call this script.
#
if [[ $# -ne 2 ]]; then
  echo "Usage: unify-static-libs.sh output-name path-to-libs"
  exit 2
fi
# Inputs
LIBNAME=$1
LIBSDIR=$2
# Tmp dir
OBJDIR=/tmp/unify-static-libs
mkdir -p ${OBJDIR}
# Extract .o
echo "Extracting objects to ${OBJDIR}..."
for i in ${LIBSDIR}/*.a
do
    echo $i
    ar --output $OBJDIR -x $i
done
# Link objects into a single lib
echo "Creating $LIBNAME from objects..."
ar -crs $LIBNAME $OBJDIR/*.o
# Clean up
rm -rf ${OBJDIR}
echo "Done."

Heed answered 23/3, 2022 at 10:1 Comment(0)
T
0
ar -x libx264.a
mkdir sub && cd sub
ar -m ../libx264.a `ar -t ../libx264.a |sort|uniq|grep "\.o"`
ar -x ../libx264.a

now you have two version of "macroblock-10.o"

Theosophy answered 28/5, 2019 at 6:42 Comment(0)
H
0
ar crsT libaz.a libabc.a libxyz.a

Here, you create archive of archives and then 'flatten' (thinning) result with T flag. Not sure how it'll work with same name .o files that might be contained within.

Hildehildebrand answered 19/12, 2019 at 23:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.