How to create a framework that uses C with Xcode
Step 1: Create a Cocoa Touch Framework
File -> New -> Project -> Cocoa Touch Framework
Name it SwiftCFramework
Step 2: Create xcconfig file:
Xcode build configuration files, more commonly known by their [xcconfig](https://nshipster.com/xcconfig/) file extension, allow build settings for your app to be declared and managed without Xcode.
Step 3: Add xcconfig to the Configurations section of the Project Info
Step 4: Add swiftcframework.mapmodule and public.mapmodule files to the project
Step 5: Add C header files and make sure their Target Membership is set to Private
Step 6: Add a run script to remove private headers and create a public modulemap file
Name the script “Make C Header Files Private”
# Delete PrivateHeaders folder
rm -rf ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/PrivateHeaders
# Remove module.modulemap file
rm ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap
# Copy public.modulemap file and rename it to module.modulemap
cp ${SRCROOT}/Supporting/public.modulemap ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap
# Append the Swift module so you can access you Swift code in Objective-C via @import MyFramework.Swift
echo "module ${PRODUCT_NAME}.Swift { header \"${PRODUCT_NAME}-Swift.h\" }" >> ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemapStep 7: Add the framework to a test application
The code is available on the SwiftCFramework GitHub repository.
FAQ
- How do I create a Swift framework that wraps C code in Xcode?
- Create a Cocoa Touch Framework target, configure an xcconfig file for build settings, add C headers and module map files to describe your C APIs, and then link the framework into a sample app so Swift code can import and call the C functions.
- How can I keep C headers private while still exposing them through a module map?
- Mark C headers as Private in the framework target and add a run script build phase that removes the PrivateHeaders folder, replaces the default module.modulemap with a curated public.modulemap, and appends a Swift submodule entry so Objective-C can import the generated Swift header.
Welcome to The infinite monkey theorem
Somewhere a monkey just typed Shakespeare in TypeScript. Be the first to read the masterpieces (and the hilarious misfires) landing on the blog.

