Embedded Swift + Zephyr: Linker Errors When Using Classes Across Files

Hello everyone!

I'm running into a linker issue while integrating Embedded Swift with Zephyr, following the instructions here:
https://docs.swift.org/embedded/documentation/embedded/integratewithzephyr

Setup

I have a simple Swift project with two files: Main.swift and MyClass.swift:

// Main.swift
@main
struct Main {
  static func main() {
    let my = MyClass(42)
    my.printVal()
  }
}

// MyClass.swift
class MyClass { 
    var val: Int32

    init(_ val: Int32) {
        self.val = val
    }

    func printVal() {
        print("Value is \(self.val)")
    }
}

The only modification I made to CMakeLists.txt is to add MyClass.swift to the target:

add_library(app_swift OBJECT src/Main.swift src/MyClass.swift)

Problem

I get a general linker error message. I wasn't able to find any specific errors.

((.venv) ) xxx-mbp:SwiftZephyrProject xxx$ ninja -C build run
ninja: Entering directory `build'
[2/8] Linking Swift static library app/libapp.a
warning: /Library/Developer/CommandLineTools/usr/bin/ranlib: archive library: app/libapp.a the table of contents is empty (no object file members in the library define global symbols)
[3/8] Linking C executable zephyr/zephyr_pre0.elf
FAILED: zephyr/zephyr_pre0.elf zephyr/zephyr_pre0.map /Users/xxx/projects/SwiftZephyrProject/build/zephyr/zephyr_pre0.map
: && /Users/xxx/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc  -gdwarf-4 -Os zephyr/CMakeFiles/zephyr_pre0.dir/misc/empty_file.c.obj -o zephyr/zephyr_pre0.elf  zephyr/CMakeFiles/offsets.dir/./arch/arm/core/offsets/offsets.c.obj  -T  zephyr/linker_zephyr_pre0.cmd  -Wl,-Map,/Users/xxx/projects/SwiftZephyrProject/build/zephyr/zephyr_pre0.map  -Wl,--whole-archive  app/libapp.a  zephyr/libzephyr.a  zephyr/arch/common/libarch__common.a  zephyr/arch/arch/arm/core/libarch__arm__core.a  zephyr/arch/arch/arm/core/cortex_m/libarch__arm__core__cortex_m.a  zephyr/arch/arch/arm/core/cortex_m/cmse/libarch__arm__core__cortex_m__cmse.a  zephyr/arch/arch/arm/core/mpu/libarch__arm__core__mpu.a  zephyr/lib/libc/picolibc/liblib__libc__picolibc.a  zephyr/lib/libc/common/liblib__libc__common.a  zephyr/lib/posix/c_lib_ext/liblib__posix__c_lib_ext.a  zephyr/drivers/console/libdrivers__console.a  zephyr/drivers/gpio/libdrivers__gpio.a  zephyr/drivers/pinctrl/libdrivers__pinctrl.a  zephyr/drivers/serial/libdrivers__serial.a  zephyr/drivers/timer/libdrivers__timer.a  -Wl,--no-whole-archive  zephyr/kernel/libkernel.a  -L/Users/xxx/projects/SwiftZephyrProject/build/zephyr  zephyr/arch/common/libisr_tables.a  -fuse-ld=bfd  -mcpu=cortex-m55  -mthumb  -mabi=aapcs  -mfp16-format=ieee  -mtp=soft  -Wl,--gc-sections  -Wl,--build-id=none  -Wl,--sort-common=descending  -Wl,--sort-section=alignment  -Wl,-u,_OffsetAbsSyms  -Wl,-u,_ConfigAbsSyms  -nostdlib  -static  -Wl,-X  -Wl,-N  -Wl,--orphan-handling=warn  -Wl,-no-pie  -Wl,--undefined=_sw_isr_table  -Wl,--undefined=_irq_vector_table  -specs=picolibc.specs  -DPICOLIBC_LONG_LONG_PRINTF_SCANF -L/Users/xxx/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/thumb/v8-m.main/nofp -lc -lgcc && cd /Users/xxx/projects/SwiftZephyrProject/build/zephyr && /Users/xxx/homebrew/Cellar/cmake/3.30.3/bin/cmake -E true
/Users/xxx/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: warning: orphan section `.swift_modhash' from `app/libapp.a(Main.swift.obj)' being placed in section `.swift_modhash'
/Users/xxx/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: warning: orphan section `.swift_modhash' from `app/libapp.a(MyClass.swift.obj)' being placed in section `.swift_modhash'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

What Works

  • If I move the class definition from MyClass.swift to Main.swift, everything builds and runs fine.
  • If I call a function defined in MyClass.swift from Main.swift (without using classes at all), everything builds and runs fine.

Has anyone seen this issue before? Thanks in advance for any insights or suggestions!

1 Like

Yes, I’ve had that since day 1 (summer 2024), see this test project: EmbeddedSwift-nRF52-ClassVsStruct.

@kubamracek suggested to try changing the optimization level and indeed, using -O worked for me (at least in the test project, not sure I encountered further errors down the road).

In general, I've had this type of error where the linker just fails with no information for a couple of different issues, very frustrating as I have no idea how to investigate.