I have a small piece of code that depends on many static libraries (a_1-a_n). I'd like to package up that code in a static library and make it available to other people.
My static library, lets call it X, compiles fine.
I've created a simple sample program that uses a function from X, but when I try to link it to X, I get many errors about missing symbols from libraries a_1 - a_n.
Is there a way that I can create a new static library, Y that contains X and all the functionality needed by X (selected bits from a_1 - a_n), so that I can distribute just Y for people to link their programs to?
UPDATE:
I've looked at just dumping everything with ar and making one mega-lib, however, that ends up including a lot of symbols that are not needed (all the .o files are about 700 MB, however, a statically linked executable is 7 MB). Is there a nice way to include only what is actually needed?
This looks closely related to How to combine several C/C++ libraries into one?.
Static libraries do not link with other static libraries. The only way to do this is to use your librarian/archiver tool (for example ar on Linux) to create a single new static library by concatenating the multiple libraries.
Edit: In response to your update, the only way I know to select only the symbols that are required is to manually create the library from the subset of the .o files that contain them. This is difficult, time consuming and error prone. I'm not aware of any tools to help do this (not to say they don't exist), but it would make quite an interesting project to produce one.
If you are using Visual Studio then yes, you can do this.
The library builder tool that comes with Visual Studio allows you to join libraries together on the command line. I don't know of any way to do this in the visual editor though.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
On Linux or MingW, with GNU toolchain:
ar -M <<EOM
CREATE libab.a
ADDLIB liba.a
ADDLIB libb.a
SAVE
END
EOM
ranlib libab.a
Of if you do not delete liba.a
and libb.a
, you can make a "thin archive":
ar crsT libab.a liba.a libb.a
On Windows, with MSVC toolchain:
lib.exe /OUT:libab.lib liba.lib libb.lib
ar crsT
, which does something like "symlinking" instead of copying, then you need only to ship one copy of data.
A static library is just an archive of .o
object files. Extract them with ar
(assuming Unix) and pack them back into one big library.
Note before you read the rest: The shell script shown here is certainly not safe to use and well tested. Use at your own risk!
I wrote a bash script to accomplish that task. Suppose your library is lib1 and the one you need to include some symbols from is lib2. The script now runs in a loop, where it first checks which undefined symbols from lib1 can be found in lib2. It then extracts the corresponding object files from lib2 with ar
, renames them a bit, and puts them into lib1. Now there may be more missing symbols, because the stuff you included from lib2 needs other stuff from lib2, which we haven't included yet, so the loop needs to run again. If after some passes of the loop there are no changes anymore, i.e. no object files from lib2 added to lib1, the loop can stop.
Note, that the included symbols are still reported as undefined by nm
, so I'm keeping track of the object files, that were added to lib1, themselves, in order to determine whether the loop can be stopped.
#! /bin/bash
lib1="$1"
lib2="$2"
if [ ! -e $lib1.backup ]; then
echo backing up
cp $lib1 $lib1.backup
fi
remove_later=""
new_tmp_file() {
file=$(mktemp)
remove_later="$remove_later $file"
eval $1=$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
find_symbols() {
nm $1 $2 | cut -c20- | sort | uniq
}
new_tmp_file lib2symbols
new_tmp_file currsymbols
nm $lib2 -s --defined-only > $lib2symbols
prefix="xyz_import_"
pass=0
while true; do
((pass++))
echo "Starting pass #$pass"
curr=$lib1
find_symbols $curr "--undefined-only" > $currsymbols
changed=0
for sym in $(cat $currsymbols); do
for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
echo " Found $sym in $obj."
if [ -e "$prefix$obj" ]; then continue; fi
echo " -> Adding $obj to $lib1"
ar x $lib2 $obj
mv $obj "$prefix$obj"
ar -r -s $lib1 "$prefix$obj"
remove_later="$remove_later $prefix$obj"
((changed=changed+1))
done
done
echo "Found $changed changes in pass #$pass"
if [[ $changed == 0 ]]; then break; fi
done
I named that script libcomp
, so you can call it then e.g. with
./libcomp libmylib.a libwhatever.a
where libwhatever is where you want to include symbols from. However, I think it's safest to copy everything into a separate directory first. I wouldn't trust my script so much (however, it worked for me; I could include libgsl.a into my numerics library with that and leave out that -lgsl compiler switch).
Alternatively to Link Library Dependencies
in project properties there is another way to link libraries in Visual Studio.
Open the project of the library (X) that you want to be combined with other libraries. Add the other libraries you want combined with X (Right Click, Add Existing Item...). Go to their properties and make sure Item Type is Library
This will include the other libraries in X as if you ran
lib /out:X.lib X.lib other1.lib other2.lib
Success story sharing
-r
with that the output can be used as an input for ld. If you link once you should get a relocatable the can be surrogate your libraries. (did tried it thogh).