How to add libswiftUnicodeDataTables.a to a esp-idf project

Hi, I'm trying to program an ESP32 in Swift and I would like to use Strings. I read the user manual here swift/docs/EmbeddedSwift/UserManual.md at main · swiftlang/swift · GitHub, but, unfortunately, I could not find any examples of how to use ld with the CMake. Trying to learn CMake now, but it looks like a quite big task. Maybe you have an example? I'm basing my code on esp-idf examples (and CMake configuration) from here: swift-embedded-examples/esp32-led-blink-sdk at main · apple/swift-embedded-examples · GitHub

Thanks!

3 Likes

This boils down to implementing the linking steps from the manual:

... link in the libswiftUnicodeDataTables.a that's in Swift toolchain's resource directory (lib/swift/) under the target triple that you're using:

$ swiftc <inputs> -target armv6m-none-none-eabi -enable-experimental-feature Embedded -wmo -c -o output.o
$ ld ... -o binary output.o $(dirname `which swiftc`)/../lib/swift/embedded/armv6m-none-none-eabi/libswiftUnicodeDataTables.a

in your build system. In this case it's CMake, so adding the following lines to your CMakeLists.txt should do (and in ESP IDF, ${COMPONENT_LIB} is the CMake target with the Swift source code):

get_filename_component(compiler_bin_dir ${CMAKE_Swift_COMPILER} DIRECTORY)
target_link_directories(${COMPONENT_LIB} PUBLIC "${compiler_bin_dir}/../lib/swift/embedded/riscv32-none-none-eabi")
target_link_libraries(${COMPONENT_LIB} PUBLIC
    -Wl,--whole-archive
    swiftUnicodeDataTables
    -Wl,--no-whole-archive
    )

(For some reason that I don't fully understand, I had to use the --whole-archive/--no-whole-archive flags to get this to link. If someone has better insights into the semantics of ELF linking, I'd love to learn why :slight_smile:)

3 Likes

Got it, thanks a lot!

As a note my homebrew installed version of swiftly doesn't let me create a valid location from ${compiler_bin_dir}/../lib/swift/embedded/riscv32-none-none-eabi" so I copied the needed library into my project directory for now.

cp ~/Library/Developer/Toolchains/swift-6.2-RELEASE.xctoolchain/usr/lib/swift/embedded/riscv32-none-none-eabi/libswiftUnicodeDataTables.a helpers/libswiftUnicodeDataTables.a

I did not need to link the directory to make it compile, because I just put the full link to the library in.

target_link_libraries(${COMPONENT_LIB} PUBLIC
    -Wl,--whole-archive
    ${CMAKE_SOURCE_DIR}/helpers/riscv32-none-none-eabi/libswiftUnicodeDataTables.a
    -Wl,--no-whole-archive
    )

I haven't made sure everything works, but it does compile.

UPDATE
This also compiles and uses the fancy swiftly detect from the Zephyr directions with some changes, including stripping whitespace from the variables.

set(ESP32C6_COMPILER_TARGET "riscv32-none-none-eabi")

find_program(SWIFTLY "swiftly")
IF(SWIFTLY)
  execute_process(COMMAND swiftly use --print-location OUTPUT_VARIABLE toolchain_path OUTPUT_STRIP_TRAILING_WHITESPACE)
  cmake_path(SET additional_lib_path NORMALIZE "${toolchain_path}/usr/lib/swift/embedded/${ESP32C6_COMPILER_TARGET}")
ELSE()
  get_filename_component(compiler_bin_dir ${CMAKE_Swift_COMPILER} DIRECTORY)
  cmake_path(SET additional_lib_path NORMALIZE "${compiler_bin_dir}/../lib/swift/embedded/${ESP32C6_COMPILER_TARGET}")
ENDIF()

target_link_directories(${COMPONENT_LIB} PUBLIC "${additional_lib_path}")
target_link_libraries(${COMPONENT_LIB}
    -Wl,--whole-archive
    swiftUnicodeDataTables
    -Wl,--no-whole-archive
    )
1 Like