Swift Framework using (static) C Libraries

Currently I'm working on a Framework, written in C, which was planned to encapsulate different C libraries around the topic of Spatial / GIS data. To compile those C libraries (mainly GEOS and Proj.4) there is even a github project which downloads the source code and compiles it all for iOS and Simulator.


I linked it into my framework, added a Module map to be able to call the C methods from within Swift and wrote my Swift class.

Checked with XCTest that the correct methods are called correctly. Everything is awesome.


I hooked up the framework in my iOS app, run it in the simulator: Everything is awesome.

I ran it on my device and got null pointers when calling the C functions. And I began to wonder.


To be honest, I haven't had the necessity (until now) to spend too much time on linking issues in C/C++/ObjC so I'm not quite sure what I've missed:

  • The module.map points on the header files of those libraries relatively (using [extern_c]).
  • The "Runpath Search Paths" points to the directory containing the .a files
  • The "Header Search Paths" points to the directory containing all the .h files
  • The "Library Search Paths" also points to the directory containing the .a fiels
  • The .a files are dragged into the projects "Linked Frameworks and Libraries"


Can I somehow verify if the libraries are statically linked into my framework?

And what might I have missed which causes the libs to not be included? (Or isn't that possible?)


I'm just guessing, but is your framework being compiled for all the necessary architectures?

The simulator (which is also used for XCTest testing within Xcode) uses a different architecture than actual devices.


I'd assume you would get a build error when you tried to compile an app to run on your testing device if the binaries for the right architecture aren't included in the framework, but maybe not?

I see that my Swift code of the framework is (partly) executed. Up until the C library function is called.

Can I check for which architectures an .a lib was compiled? Maybe there I miss the required architecture.

You can check using the tool lipo.


$ lipo -info libLibrary.a
Architectures in the fat file: libLibrary.a are: armv7 armv7s i386 x86_64 arm64

Thanks!


According to Lipo all my .a libraries as well as my .Framework are built for both, the simulator (i386 x86_64) and the device (arm64, armv7).

I did some reading about static libraries, and ran across this:

samdmarshall.com/blog/static_and_dynamic_libraries.html


Due to the fact this is not an executable binary file, static libraries do not retain any linkage they might need. This pushes the burden of tracking which dependencies to use onto the linked target executable file rather than on the static library itself. Luckily, Apple has implemented a load command for handling this, LC_LINKER_OPTION. This appears in a target's build settings in Xcode under the name "Link Frameworks Automatically". Enabling this option will append new load commands to each object file that specify linker flags that should be used with each object file. These flags can be displayed by using the following command:


$ otool -l <static library> | grep LC_LINKER_OPTION -A 4


That seems to indicate that the C static libraries won't be linked within your framework and would still need to be linked by the app.

Interesting reading.

Afterwards I added all the other libs the C-libs depend on as dependencies to my target App => Does not have any effect


I then checked using nm if the C-lib symbols are in any way inside the generated Framework binary and it seems so. As I see there symbols to the methods from the C-lib.

I even extracted the armv7 arch and checked if that part of the fat binary has those symbols: Check


Will now prepare a striped-down example and contact Apple via DTS as I don't have a clue

Accepted Answer

I have found the problem.

Although it manifested where I call the C-Library it had another cause.


All the C libraries and all its methods have acutally been correctly linked into the Swift framework. But internally they worked differently in one (quite important) aspect on the Device then on Mac/Simulator which I noticed too late because of all the "opaque pointers" masking it partially.


Thanks LCS and Magicman for the clues which helped me track the core problem down.

Swift Framework using (static) C Libraries
 
 
Q