Jura Skrlec
••3 min readIt's been a long time since I've posted something here. I thought that I could do a post every two weeks, but I needed a little break. And a little break turned into a bigger break. Anyway, I'll do a post every month.
I had an interesting problem last year that I wanted to tackle; how to add Swift files to a framework written in Objective-C through CMake and make it work.
The basic concept is:
- Add a Swift file to your sources. This is important, if you don't Swift Compiler will be turned off. You can create an empty Swift file (dummy).
- We need to turn on and force Swift Compiler (swiftc) for CMake to recognize its builds settings.
- Add CMake SET for swiftc build settings
- Remove other Swift flags
- Use Swift :)
Let's tackle one by one.
- Add a Swift file to your sources; add this where you list your source files for cmake:
list( APPEND <your_source_list> ... <path>/Empty.swift ... )
- Force load
swiftc
in your<project>.cmake
:
execute_process( COMMAND xcrun --find swiftc OUTPUT_VARIABLE SWIFTC_EXECUTABLE OUTPUT_STRIP_TRAILING_WHITESPACE) set( SWIFTC_FOUND TRUE ) message( STATUS "Found swiftc: ${SWIFTC_EXECUTABLE}" ) if ( SWIFTC_FOUND ) message(STATUS "Setting swiftc: ${SWIFTC_EXECUTABLE}") # We need to tell cmake where swiftc is set( CMAKE_Swift_COMPILER ${SWIFTC_EXECUTABLE} ) # This line is important, we need to force load it set( CMAKE_Swift_COMPILER_FORCED ON ) endif() if( CMAKE_Swift_COMPILER ) # Enable Swift, tell cmake there's now new swiftc build settings, without this, cmake can't properly configure attributes enable_language(Swift) else() message(FATAL_ERROR "FATAL ERROR! Did not find swiftc?!") endif()
- Add
swiftc
build settings to your<project>.cmake
:
# Swift Features message( STATUS "Setting Swift Settings:" ) # Swift requires modules set( CMAKE_XCODE_ATTRIBUTE_DEFINES_MODULE "YES" ) # Enable modules for ObjectiveC - Swift set( CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" ) # Set Swift to ObjC Interface name set( CMAKE_XCODE_ATTRIBUTE_SWIFT_INSTALL_OBJC_HEADER "YES") set( CMAKE_XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "${FRAMEWORK_OUTPUT_NAME}-Swift.h" ) # Set name for the source code module constructed for this target, and which will be used to import the module in implementation source files set( CMAKE_XCODE_ATTRIBUTE_PRODUCT_MODULE_NAME "${FRAMEWORK_OUTPUT_NAME}" ) # Set paths to be searched by the Swift compiler for additional Swift modules. This is used to use ObjectiveC in Swift. Set all ObjC private headers to use for internal use in module.modulemap set( CMAKE_XCODE_ATTRIBUTE_SWIFT_INCLUDE_PATHS "<path>/ProjectModule" ) # Set Swift Version set( CMAKE_XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" ) set( CMAKE_XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "$<$<CONFIG:Release>:-O>$<$<CONFIG:Debug>:-Onone>" ) # Set for every target set ( CMAKE_XCODE_ATTRIBUTE_OTHER_SWIFT_FLAGS "")
- Remove other Swift flags:
set_target_properties( ${PROJECT_NAME} PROPERTIES FRAMEWORK TRUE ... XCODE_ATTRIBUTE_OTHER_SWIFT_FLAGS "" XCODE_ATTRIBUTE_BUILD_LIBRARY_FOR_DISTRIBUTION "YES" ... )
- Use Swift. But be aware, you'll need to wrap some things when using Swift in the Objective-C file if you want them private :)
Feel free to message me on Twitter if you want to talk about this, or anything tech related :)