platform-espressif32 icon indicating copy to clipboard operation
platform-espressif32 copied to clipboard

Unable to build Swift library by adding custom target and dependency

Open oleksandr-kosylov opened this issue 1 year ago • 1 comments

In order to support ability to use Swift programming language with Embedded platform support, I've adjusted CMakeLists according to Example at https://github.com/apple/swift-embedded-examples/tree/main/esp32-led-strip-sdk and installed dev snapshot of swift toolchain that supports embedded platforms.

Project structure: src/ Main.swift Dummy.c BridgingHeader.h CMakeLists.txt

platform.ini [env:esp32-c6-devkitc-1] platform = espressif32 @ 6.7.0 board = esp32-c6-devkitc-1 framework = espidf

Main idea of approach is to build Swift sources and link to main target. It's being achieved by next steps:

  1. creating of custom command (add_custom_command) that produces library.o object.
  2. creating of custom target that depends on library.o (add_custom_target)
  3. linking of _idf_main with library.o
  4. setting dependency of _idf_main on custom target (add_dependencies)

This works fine from terminal by idf.py build BUT looks like custom command and target are not being built in VS Code with PlatformIO, I've tried to replace swift build command with test one and it's net being executed.

Build fails because of missing implementation for app_main function that is declared in Main.swift, so because of library wasn't built.

Please advice what can cause an ignoring of custom target and command by build system. I see that build.ninja contains build commands for custom target and command based on CMakeLists.txt but looks they are not executed.

CMakeLists.txt

oleksandr-kosylov avatar Jun 15 '24 18:06 oleksandr-kosylov

Hi @oleksandr-kosylov, thanks for reaching out. The current ESP-IDF integration is meant to be used only with generic ASM/C/C++ based projects. Anyway, the problem you're experiencing is caused by limited CMake's API which currently doesn't export any information about custom build targets. It means that all extra build steps need to be implemented using PlatformIO build API manually. In case with your example, I believe it's possible implement a small workaround using an extra script that will compile Swift sources and inject the resulting binary into the linker command. Please beware, I haven't tested the code below, but it should look something like this:

[platformio]
; Use the common IDF build folder to make CMake happy
src_dir = main

[env:esp32-c6-devkitc-1]
platform = espressif32
framework = espidf
monitor_speed = 115200
board = esp32-c6-devkitc-1

; Compile and inject the Swift library
extra_scripts = 
    compile_swift.py

compile_swift.py:


import os

from platformio.builder.tools.piomaxlen import _file_long_data

Import("env")

# Swift files are located in the `main` build folder
SWIFT_SOURCE_FILES = ("Main.swift", "LedStrip.swift")

def compile_swift_sources(swift_sources):
    assert len(swift_sources) > 0, "Missing Swift source files"
    swift_obj = env.Command(
        os.path.join("$BUILD_DIR", "_swiftcode.o"),
        swift_sources,
        env.VerboseAction(
            " ".join(
                [
                    "swiftc",
                    "-target",
                    "riscv32-none-none-eabi",
                    "-Xfrontend",
                    "-function-sections",
                    "-enable-experimental-feature",
                    "Embedded",
                    "-wmo",
                    "-parse-as-library",
                    "-Osize",
                    "-import-bridging-header",
                    os.path.join("$PROJECT_SRC_DIR", "BridgingHeader.h"),
                    "$SOURCES",
                    "-c",
                    "-o",
                    "$TARGET",
                    '@"%s"'
                    % _file_long_data(
                        env,
                        " ".join(
                            ["-I%s" % inc for inc in env.get("CPPPATH", [])]
                        ),
                    ),
                ]
            ),
            "Compiling Swift `$SOURCES` files to `$TARGET`",
        ),
    )

    return swift_obj


swift_sources = [
    os.path.join(env.subst("$PROJECT_SRC_DIR"), f)
    for f in SWIFT_SOURCE_FILES
]

swift_obj_lib = compile_swift_sources(swift_sources)
env.Prepend(LINKFLAGS=[swift_obj_lib])
env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", swift_obj_lib)

valeros avatar Jun 17 '24 11:06 valeros

This issue has been automatically marked as stale because it has not had recent activity. Please provide more details or it will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 25 '25 01:02 stale[bot]