So we making a cross platform application, with c++ as the dominant language and swift used only where required to facilitate cross-platform support for Apple products, We are developing in a layered architecture , with each layer developing specific components, the plus point with c++ is its support for header files , in which we can give declarations , now when (suppose) layer 3 lib is build then all the lower layers don’t need to be build even if their headers are included , no swift does not have the concept of header files, so lower layer swift targets have to be build , this is a not ideal ,
if we were a swift dominant project this would have been unavoidable, but as we have minimal swift files and they seldom changes, we want to build swift lib targets separately from c++ targets and then link them , this way when our developers are working on a layer they don’t need to build all the lower layers for every change in c++ code change.
The problem we are facing with cmake is with its function target_compile_definitions,
suppose there is a hpp file which is used inside of the module.map for a module for example Student
module Student {
header “/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp”
export *
}
(inside of this hpp file the macro WINDOW_KERNEL is used)
when there is swift target with no c++ files and the cmake macro def is as follows
target_compile_definitions (SwiftTarget PRIVATE WINDOW_KERNEL=2), it works but gives the warning that swift target macros cannot have a value.
so we used
target_compile_definitions (SwiftTarget PRIVATE “$<$<COMPILE_LANGUAGE:Swift>:WINDOW_KERNEL>”) (this does not works)
then we tried
target_compile_definitions (SwiftTarget PRIVATE “$<$<COMPILE_LANGUAGE:CXX>:WINDOW_KERNEL=2>”)
(this works but we need to supply an empty c++ file for it to work (or the swift target must have a c++ file) , now this gives a warning that an empty c++ file is fed, also it is opposed to out original aim to distinguishing swift and c++ targets completely),
We are exploring how to do it in ideal way in cmake , or if cmake does not support for it , what is the reason/rational behind it.
our POC project structure.
│CMakeLists.txt
│CMakePresets.json
├───CppLib (folder)
│
│ module.map
│ Student1.cpp
│ Student1.hpp
│
└───SwiftLib (Folder)
│
│ emty.cpp
│ main.swift
The contents of files
CMakeLists.txt
# Sri Ganeshji : Sri Balaji : Sri Pitreshwarji : Sri Durgaji : Sri Venkateshwara
# This is a GENERATED file.
cmake_minimum_required(VERSION 3.26)
project(SampleProject DESCRIPTION "" LANGUAGES CXX Swift)
add_library(CppTarget ./Sources/CppLib/Student1.cpp)
#include the directory to access modulemap content
target_include_directories(CppTarget PUBLIC
${CMAKE_SOURCE_DIR}/Sources/CppLib)
target_compile_definitions (CppTarget PRIVATE "$<$<COMPILE_LANGUAGE:Swift>:WINDOW_KERNEL>")
target_compile_definitions (CppTarget PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:WINDOW_KERNEL=2>")
target_compile_definitions (CppTarget PRIVATE "$<$<COMPILE_LANGUAGE:Swift>:TWFLAG>")
target_compile_definitions (CppTarget PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:TWFLAG>")
add_library(SwiftTarget ./Sources/SwiftLib/main.swift
./Sources/SwiftLib/emty.cpp
) #removing ./Sources/SwiftLib/emty.cpp cause the undeclared refence error for macros WINDOW_KERNEL, TWFLAG,
# build error we are getting on removing
# I cannot directly send them without generator expression because in swift the macros don't have values and it gives warning related to this
# wanted to know what is the ideal way to do this without adding an empty cxx file as this also gives warning
#SwiftCompile normal arm64 /tmp/SampleWorkspace/Sources/SwiftLib/main.swift (in target 'SwiftTarget' from project 'SampleProject')
# cd /tmp/SampleWorkspace
# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -c -primary-file /tmp/SampleWorkspace/Sources/SwiftLib/main.swift -emit-dependencies-path /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/main.d -emit-const-values-path /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/main.swiftconstvalues -emit-reference-dependencies-path /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/main.swiftdeps -serialize-diagnostics-path /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/main.dia -target arm64-apple-macos14.5 -Xllvm -aarch64-use-tbi -enable-objc-interop -stack-check -cxx-interoperability-mode\=default -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk -I /tmp/SampleBuilds/SampleWorkspace/TWLib/MacOS-arm64/Debug -I /tmp/SampleWorkspace/Sources/CppLib -F /tmp/SampleBuilds/SampleWorkspace/TWLib/MacOS-arm64/Debug -no-color-diagnostics -g -swift-version 5 -enforce-exclusivity\=checked -Onone -D WINDOW_KERNEL -D TWFLAG -D TW_KERNEL_APPLE -D TW_KERNEL_LINUX -D TW_SUBKERNEL_LINUX -D TW_OS_MACOS -D TW_TRUNK_DEV -D TW_STAGE_DEVELOPMENT -serialize-debugging-options -const-gather-protocols-file /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/SwiftTarget_const_extract_protocols.json -enable-bare-slash-regex -empty-abi-descriptor -validate-clang-modules-once -clang-build-session-file /var/folders/m9/c84w47j56459rlm525y84vt8j5j0lh/C/org.llvm.clang/ModuleCache.noindex/Session.modulevalidation -Xcc -working-directory -Xcc /tmp/SampleWorkspace -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -enable-anonymous-context-mangled-names -Xcc -DTW_KERNEL_APPLE -Xcc -DTW_KERNEL_LINUX -Xcc -DTW_SUBKERNEL_LINUX -Xcc -DTW_KERNEL_WINDOWS\=0 -Xcc -DTW_KERNEL_UNIKERNEL\=0 -Xcc -DTW_KERNEL_LINUX\=1 -Xcc -DTW_KERNEL_APPLE\=1 -Xcc -DTW_KERNEL_TVOS\=0 -Xcc -DTW_KERNEL_IOS\=0 -Xcc -DTW_KERNEL_WATCHOS\=0 -Xcc -DTW_KERNEL_ANDROID\=0 -Xcc -DTW_SUBKERNEL_LINUX\=1 -Xcc -DTW_SUBKERNEL_APPLE\=0 -Xcc -DTW_SUBKERNEL_TVOS\=0 -Xcc -DTW_SUBKERNEL_IOS\=0 -Xcc -DTW_OS_WINDOWS\=0 -Xcc -DTW_OS_LINUX\=0 -Xcc -DTW_OS_UNIKERNEL\=0 -Xcc -DTW_OS_MACOS\=1 -Xcc -DTW_OS_IOS\=0 -Xcc -DTW_OS_IPADOS\=0 -Xcc -DTW_OS_WATCHOS\=0 -Xcc -DTW_OS_TVOS\=0 -Xcc -DTW_OS_ANDROID_PHONE\=0 -Xcc -DTW_OS_ANDROID_TABLET\=0 -Xcc -DTW_OS_ANDROID_WEARABLE\=0 -Xcc -DTW_OS_ANDROID_TV\=0 -Xcc -DTW_CURRENT_BUILD_OS\=MacOS -Xcc -DTW_ARCH_X64\=0 -Xcc -DTW_ARCH_ARM64\=1 -Xcc -DTW_CURRENT_BUILD_ARCH\=arm64 -Xcc -DTW_TRUNK_DEV\=1 -Xcc -DTW_TRUNK_PRERELEASE\=0 -Xcc -DTW_TRUNK_RELEASE\=0 -Xcc -DTW_STAGE_DEVELOPMENT\=1 -Xcc -DTW_STAGE_ALPHA\=0 -Xcc -DTW_STAGE_INTERNAL\=0 -Xcc -DTW_STAGE_BETA\=0 -Xcc -DTW_STAGE_GOLD\=0 -Xcc -DTW_CONFIG_DEBUG\=1 -Xcc -DTW_CONFIG_MEMDEBUG\=0 -Xcc -DTW_CONFIG_RELEASE\=0 -Xcc -DTW_CONFIG_SIMULATION\=0 -Xcc -DTW_CONFIG_METRICS\=0 -Xcc -DTW_CONFIG_LOGRELEASE\=0 -Xcc -DTW_CURRENT_BUILD_CONFIG\=Debug -Xcc -DTW_OS_MACOS -Xcc -DTW_TRUNK_DEV -Xcc -DTW_STAGE_DEVELOPMENT -Xcc -ivfsstatcache -Xcc /var/folders/m9/c84w47j56459rlm525y84vt8j5j0lh/C/com.apple.DeveloperTools/15.4-15F31d/Xcode/SDKStatCaches.noindex/macosx14.5-23F73-7e3fd6dc4171e65dbd154ba8db3956d2.sdkstatcache -Xcc -I/tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/swift-overrides.hmap -Xcc -I/tmp/SampleBuilds/SampleWorkspace/TWLib/MacOS-arm64/Debug/include -Xcc -I/tmp/SampleWorkspace/Sources/CppLib -Xcc -I/tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/DerivedSources-normal/arm64 -Xcc -I/tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/DerivedSources/arm64 -Xcc -I/tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/DerivedSources -Xcc -DCMAKE_INTDIR\=\"Debug\" -module-name SwiftTarget -frontend-parseable-output -disable-clang-spi -target-sdk-version 14.5 -target-sdk-name macosx14.5 -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/lib/swift/host/plugins\#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/local/lib/swift/host/plugins\#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib/swift/host/plugins\#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/local/lib/swift/host/plugins\#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -plugin-path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/lib/swift/host/plugins -o /tmp/SampleBuilds/SampleWorkspace/TWInt/MacOS-arm64/build/SwiftTarget.build/Debug/Objects-normal/arm64/main.o -index-unit-output-path /SwiftTarget.build/Debug/Objects-normal/arm64/main.o
#<module-includes>:1:9: note: in file included from <module-includes>:1:
##import "/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp"
# ^
#/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp:17:19: error: use of undeclared identifier 'WINDOW_KERNEL'
# static_assert(WINDOW_KERNEL==2, "macro has teh correct value"); //return true in cpp, says not declared in swift
# ^
#<module-includes>:1:9: note: in file included from <module-includes>:1:
##import "/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp"
# ^
#/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp:19:19: error: use of undeclared identifier 'TWFLAG'
# static_assert(TWFLAG, "TW flag is defined"); //return true in cpp, says WIN32 not declared in swift
# ^
#/tmp/SampleWorkspace/Sources/SwiftLib/main.swift:9:8: error: could not build Objective-C module 'Student'
#import Student
target_compile_definitions (SwiftTarget PRIVATE "$<$<COMPILE_LANGUAGE:Swift>:WINDOW_KERNEL>")
target_compile_definitions (SwiftTarget PRIVATE "$<$<COMPILE_LANGUAGE:Swift>:TWFLAG>")
target_compile_definitions (SwiftTarget PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:WINDOW_KERNEL=2>")
target_compile_definitions (SwiftTarget PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:TWFLAG>")
target_include_directories(SwiftTarget PUBLIC
${CMAKE_SOURCE_DIR}/Sources/CppLib)
target_compile_options(SwiftTarget PUBLIC
"$<$<COMPILE_LANGUAGE:Swift>:-cxx-interoperability-mode=default>")
CMakePresets.json( too big to attach)
module.map
module Student {
header "/tmp/SampleWorkspace/Sources/CppLib/Student1.hpp"
export *
}
Student1.cpp
#include "Student1.hpp"
Student::Student (int pAge) : age(pAge) {}
void Student::Introduce () {
std::cout << "Introduce urself" << std::endl;
}
Student1.hpp
#pragma once
//#include <iostream>
#include <string>
class Student {
public:
// Constructor
Student (int pAge);
static_assert(WINDOW_KERNEL==2, "macro has teh correct value"); //return true in cpp, says not declared in swift
static_assert(TWFLAG, "TW flag is defined"); //return true in cpp, says WIN32 not declared in swift
void Introduce ();
private:
int age;
};
empty.cpp
main.swift
import Foundation
import Student
// We have the cpp flag for the cpp target under 'Apple clang Preprocessing'
// For modulemap import to work we need to have the same cpp preprocess flags under 'Apple clang Preprocessing' for swift target
// 'Apple clang Preprocessing' flags in a swift target are not swift compiler flags
func main()
{
var student:Student = Student(13)
student.Introduce()
#if WINDOW_KERNEL
NSLog("valid")
#else
#endif
}
main()