I'm trying to convert my RPi Pico cpp project to Swift, though keeping CMake since I need SDK for this.
I almost got it compiled but there're some __atomic*
linker errors:
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o: in function `$ss17swift_allocObject8metadata12requiredSize0E13AlignmentMaskSpys04HeapC0VGSpys13ClassMetadataVG_S2itF':
_swiftcode.o:(.text.$ss17swift_allocObject8metadata12requiredSize0E13AlignmentMaskSpys04HeapC0VGSpys13ClassMetadataVG_S2itF+0x4e): undefined reference to `posix_memalign'
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o: in function `$ss12swift_retain6objectBpBp_tF':
_swiftcode.o:(.text.$ss12swift_retain6objectBpBp_tF+0x16): undefined reference to `__atomic_load_4'
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o:(.text.$ss12swift_retain6objectBpBp_tF+0x28): undefined reference to `__atomic_fetch_add_4'
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o: in function `$ss13swift_release6objectyBp_tF':
_swiftcode.o:(.text.$ss13swift_release6objectyBp_tF+0x16): undefined reference to `__atomic_load_4'
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o:(.text.$ss13swift_release6objectyBp_tF+0x28): undefined reference to `__atomic_fetch_sub_4'
/Applications/ArmGNUToolchain/13.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o: in function `$ss41swift_isUniquelyReferenced_nonNull_native6objectSbBp_tF':
_swiftcode.o:(.text.$ss41swift_isUniquelyReferenced_nonNull_native6objectSbBp_tF+0x8): undefined reference to `__atomic_load_4'
......
This is what my Swift code looks like:
let BUTTON_PINS: [UInt32] = [0, 1, 2, 3, 4, 5, 6, 7]
let LED_PINS: [UInt32: UInt32] = [0: 8, 1: 9, 2: 10, 3: 11, 4: 12, 5: 13, 6: 14, 7: 15]
let DEFAULT_LED_PIN: UInt32 = 25
let DEBOUNCE_DELAY_MS: UInt32 = 5
let INTERVAL_MS: UInt32 = 1
let KEYS: [UInt32: UInt8] = [0: 0x73, 1: 0x64, 2: 0x66, 3: 0x6c, 4: 0x3b, 5: 0x63, 6: 0x62, 7: 0xa]
var start_ms: UInt32 = 0
var remote_wakeup_enabled: Bool = false
var last_button_state: [UInt32: Bool] = [
0: false, 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false,
]
var last_button_press_ms: [UInt32: UInt32] = [0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0]
@main
struct Main {
static func main() {
board_init()
tusb_init()
for pin in BUTTON_PINS {
gpio_init(pin)
gpio_set_dir(pin, false)
gpio_pull_up(pin)
}
for pin in LED_PINS.values {
gpio_init(pin)
gpio_set_dir(pin, true)
}
while true {
tud_task()
hid_task()
}
}
}
@_cdecl("tud_mount_cb")
func tud_mount_cb() {}
@_cdecl("tud_umount_cb")
func tud_umount_cb() {}
@_cdecl("tud_suspend_cb")
func tud_suspend_cb(remote_wakeup_en: Bool) {
remote_wakeup_enabled = remote_wakeup_en
}
@_cdecl("tud_resume_cb")
func tud_resume_cb() {}
func sendKeys() {
guard tud_hid_ready() else { return }
var report = [UInt8](repeating: 0, count: 8)
var last_idx = 0
for (pin, state) in last_button_state {
if state { // button is pressed
let key = KEYS[pin]!
report[last_idx] = key
last_idx += 1
}
gpio_put(LED_PINS[pin]!, state)
}
tud_hid_report(1 /*REPORT_ID_KEYBOARD*/, report, 8)
}
func hid_task() {
guard to_ms_since_boot(get_absolute_time()) - start_ms > INTERVAL_MS else { return }
start_ms += INTERVAL_MS
for pin in BUTTON_PINS {
guard to_ms_since_boot(get_absolute_time()) - last_button_press_ms[pin]! > DEBOUNCE_DELAY_MS
else { continue }
let state = !gpio_get(pin)
if state != last_button_state[pin] {
last_button_state[pin] = state
last_button_press_ms[pin] = to_ms_since_boot(get_absolute_time())
}
}
sendKeys()
}
@_cdecl("tud_hid_report_complete_cb")
func tud_hid_report_complete_cb(instance: UInt8, report: UnsafePointer<UInt8>, len: UInt16) {}
@_cdecl("tud_hid_get_report_cb")
func tud_hid_get_report_cb(
instance: UInt8, report_id: UInt8, report_type: UnsafePointer<hid_report_type_t>,
buffer: UnsafeMutablePointer<UInt8>, len: UInt16
) -> UInt16 {
// nothing to do
return 0
}
@_cdecl("tud_hid_set_report_cb")
func tud_hid_set_report_cb(
instance: UInt8, report_id: UInt8, report_type: UnsafePointer<hid_report_type_t>,
buffer: UnsafePointer<UInt8>, len: UInt16
) {}
And this is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(game-controller_project C CXX ASM)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
pico_sdk_init()
if(APPLE)
execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
add_executable(game-controller
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
COMMAND
${SWIFTC}
-target armv6m-none-none-eabi -Xcc -mfloat-abi=soft -Xcc -fshort-enums
-Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library
-Xcc -DCFG_TUSB_MCU=OPT_MCU_RP2040
$$\( echo '$<TARGET_PROPERTY:game-controller,INCLUDE_DIRECTORIES>' | tr '\;' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
$$\( echo '${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}' | tr ' ' '\\n' | sed -e 's/\\\(.*\\\)/-Xcc -I\\1/g' \)
-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
${CMAKE_CURRENT_LIST_DIR}/Main.swift
-c -o ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
DEPENDS
${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
${CMAKE_CURRENT_LIST_DIR}/Main.swift
)
add_custom_target(game-controller-swiftcode DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o)
target_include_directories(game-controller PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(game-controller
pico_stdlib
pico_unique_id
hardware_gpio
tinyusb_device
tinyusb_board
${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o
)
add_dependencies(game-controller game-controller-swiftcode)
pico_add_extra_outputs(game-controller)
Seems like the __atomic_load_4
error is because of 32bit integer but I see the example using UInt32
and it compiles without any issues...
Is there anything I can do to fix these error?