Using xcframework with an external static C library within an Xcode project

I have a C file containing a function my_library_function() that I have compiled into a static library using gcc and packaged into an xcframework called mylib.xcframework using xcodebuild -create-framework. I have added this framework to an Xcode project for a Mac App. However within my Mac App I am unable to call this function, and am generally unsure about how to do so. I have tried import mylib from within Swift files and tried to directly call the function my_library_function() but in both cases have gotten compiler errors No such module mylib and Use of unresolved identifier 'my_library_function'. The only workaround I have found is to create a bridging header and #include the header file from its path within the xcframework. However, since eventually I would like to work with a more complex library and cross compile and have the xcframework include static libraries for multiple targets this seems like a hacky workaround. Is there some way I can do this without the bridging headers, am I missing something in this process?

Below are detailed instructions of exactly what I did but was unable to use the xcframework in Xcode.
First I compiled the C code into a static library. The source code for the library contains a single function:

#include <stdio.h>
void my_library_function(void) {
  printf("called from a static library");
}

mylib.c

I also have a header for the above:

void my_library_function(void);

mylib.h

The tree for the source code is as follows:

.
├── include
│   └── mylib.h
└── mylib.c

Project source tree

I then compiled the C code into a static library using:

> gcc -c mylib.c -o mylib.o
> ar rcs mylib.a mylib.o

Then I created an xcframework with:

xcodebuild -create-xcframework -library mylib.a -headers include -output mylib.xcframework

This resulted in an xcframework as so:

.
├── Info.plist
└── macos-x86_64
    ├── Headers
    │   └── mylib.h
    └── mylib.a

mylib.xcframework source tree

I then created a new Xcode project using Xcode 11.

At the root of the project I created a new group and called it Frameworks. I then dragged and dropped the xcframework into the Xcode frameworks group and checked the copy items if needed checkbox and the create groups radio button.

In the Xcode projects general tab, under Frameworks, Libraries and Embedded Content I set the framework to Embed & Sign.

Under the Build Settings tab, under Signing, I set Other Code Signing Flags to --deep to prevent a codesign error. In the same Build Settings tab, under Linking, the Runpath Search Paths is set to @executable_path/../Frameworks/. Additionally in the Build Settings tab under Search Paths, I have tried to set the Framework Search Paths, Library Search Paths and Header Search Paths to this same value @executable_path/../Frameworks/ and I have also tried with these paths as empty.

Unfortunately I am not able to use the my_library_function() from anywhere in the application, nor am I able to import mylib from Swift.

The only workaround I have found is to create an objective C bridging header and make a #include explicitly point within the framework folder into the Headers/mylib.h to be able to call my function. This seems like a hacky solution though as eventually I would like to cross compile my code and will have separate header files for each separate library for different architectures and it might get quite complex to do it this way. Is there something I am missing as to how to include my function from within an XCFramework with a MacOS Swift project?

Why are using gcc? clang is probably the better option, especially since you need to provide a clang module map for your framework in order for Swift to see your library as a module. The documentation at clang.llvm.org is pretty good about describing a module map

I hadn't read about modules before but I'll check that out. Presumably you are saying I will have to do something with modules before building my static library using clang, and then package that library in an xcframework, and that should allow the xcode project to interface with my xcframework?

I included a modulemap alongside my header file and built with clang and it worked when including in xcode. Thanks @jonprescott.

You are welcome

Hi,

I am also trying to include a (existing) static library, but in order to use it under iOS, and I am wondering how you included the modulemap ?

I tried to put it in the header directory when creating the xcframework but I still get the "no such module" error. I named my modulemap module.modulemap.

my modulemap is very simple :

module FreeType {
    umbrella header "ft2build.h"
    export *
}

Thank you

If you are doing this manually, you will need to create a Modules directory in your framework, and put the module map there. Xcode takes care of that automatically, either using a module map you supply as a file in you project (your file name will do), or synthesizing one from the base header (ft2build.h, in your case).

Best thing to do would be to find a framework on your machine from Apple, and look at the contents of the framework to see how it is built.

I didn’t know about @jonprescott’s solution so you can try that as well but I simply manually included it in my Headers directory alongside my mylib.h file. I didn’t use an umbrella header but I don’t think that should make much difference to your error. Are you certain that umbrella header name points to the exact relative path from the modulemap file? Also are you Sure that Xcode is actually embedding the framework (Check the general and build settings and build phases tabs; Are those options similar to mine in my post above)?

Thanks @jonprescott and @guy_incog

Well, I had no success :cry:

I indeed try to do the xcframework manually since the library I try to import (Freetype) is quite large and I don't really know how to compile it under XCode.

Using it on macOS or Linux is really easy, by simply adding a .systemLibrary in the Package.swift, it works like a charm. The modulemap works well and all the functions are available in Swift.

I managed without too much difficulty to build .a libraries for iOS and the iOS simulator using clang. Now actually using it in Swift on iOS looks like a challenge !

What I tried :

  • manually put the module.modulemap alongside the headers in the Headers directory of each library in the xcframework (ios-arm64, ios-x86_64-simulator, etc.).
  • Create a Modules subdirectory for each library (or even inside the framework itself) with the modulemap inside.
  • Set the header to the relative paths or let the name as it is found in the Headers directory.
  • Check that my xcframework is listed as "Embed & Sign" in my target, and that in build phases, XCode link it and embed it.

A find command did not list any xcframework on my system except mine. I managed to find some on the web but they all are built around a Swift library not a C static library and the Modules directory is quite different.

That’s really weird, I’m not sure how to proceed with that.

Well hopefully I have another way to do, but it is much more dirty, I hopped the xcframework would make things clean.

Thanks for taking time to answer :slight_smile:

In the meantime I investigated the module.modulemap documentation in clang which is quite interesting, one possibility is that the modulemap is in fact not as simple as the one I provided when the library is made of several subdirectories of headers... but I did not yet succeeded in producing something that works...

@Ant01n3 Have you found a solution?
It looks like I have the same struggle and it would really help me if you could share your solution :slightly_smiling_face: