7
votes

I have a big static library I would like to package into an iOS static framework for ease of use. The library is actually several .a files, one per logical module of the library.

I have the compiled .a files built for the device (fat file with armv7, armv7s, arm64) and for the simulator (fat file with i386, x86_64).

Now, AFAIK, I need to combine all those files into one big file in order to build a proper framework.

Using the technique described here (Combine static libraries), I could do :

libtool -static -o new.a old1.a old2.a

But apparently both old1.a and old2.a include the same symbols. Thus, when linking against my framework, I get the linker error (for a valid reason) duplicate symbols.

A more correct way to do that (thus avoiding duplicate symbols) seems to be unpacking the .o files, and combining them into a big .a file (How to pack multiple library archives (.a) into one archive file?)

ar x old1.a
ar x old2.a
ar rcs new.a *.o

Now, remember, old1.a and old2.a are fat files, so I need to separate that per architecture.

So here's what I do:

lipo old1.a -thin armv7 -output armv7/old1.a
cd armv7; ar x old1.a; cd ..
...
lipo old1.a -thin x86_64 -output x86_64/old1.a
cd x86_64; ar x old1.a; cd ..

// Same goes for old2.a ...

// Then, 
libtool -static -o new.a armv7/*.o armv7s/*.o arm64/*.o // ... etc

But for some reason ,when linking against the thus created framework, the linker can't find any symbol (even though nm reveals them all).

Any idea how to build that static framework?

2
Can't you just compile the libraries from source code? Unless you want to do voodoo magic with symbols, this is probably easiest.SevenBits
Well, I would need to somehow compile all the code into one static library, which would require a lot of modifications on the build system of 3rd party codeOlotiar

2 Answers

2
votes

You can pre-link your static library objects into a single one, also you can prelink other static libraries into one. It will actually link objects with the linker (almost like in dynamic library).

  1. In your single library (the main one) go to Build Settings and find Perform Single-Object Prelink in Linking sections. Switch that to Yes
  2. In Prelink libraries you can specify other libraries you want to include. There you need to put not just names, but full file name. If other libraries are also from your project, then you can use $(CONFIGURATION_BUILD_DIR) variable. So if you have library foo, then it will be $(CONFIGURATION_BUILD_DIR)/libfoo.a
  3. You can add additional flags in Single-Object Prelink Flags
  4. If you want to strip out local symbols, then make sure that you have Deployment Postprocessing set to Yes, as by default static libraries are not stripped out.

If your libraries have duplicate symbols, then there is something wrong in the structure of your modules.

1
votes

Is libtool truly creating fat library? We do something simular, but directly use "lipo -create"

ar -r armv7.a a/armv7/*.o b/armv7/*.o c/armv7/*.o d/armv7/*.o e/armv7/*.o
ar -r armv7s.a a/armv7s/*.o b/armv7s/*.o c/armv7s/*.o d/armv7s/*.o e/armv7s/*.o
ar -r i386.a a/i386/*.o b/i386/*.o c/i386/*.o d/i386/*.o e/i386/*.o


$LIPO \
        -create \
        -arch armv7 "objs/armv7.a" \
        -arch i386  "objs/i386.a" \
        -o "$FRAMEWORK_INSTALL_NAME" \
    || abort "Lipo $1 failed"

We also we ran into an issue where an isv was doing the same thing with our framework, to make their framework, so even though a/foo.o and b/foo.a would go into our armv7.o fine. when they would extract "ar -x" , ar doesn't preserve paths, so only one foo.o would get written.

We fixed it by just renaming every .o and giving it a prefix a_foo.o, before creating the target.a.