Swift c++ interoperability ,cmake is failing to send macros to hpp (used in swift through module.map)

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()
1 Like