From 3edac66312bf339d5253122c57db81bdc96e5e3f Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Wed, 20 Dec 2023 17:13:27 +0100 Subject: [PATCH 1/5] Add Linux support (and possibly other platforms) Changes to the CMake config: - Relax minimum CMake version requirement. - The Swift compiler is not configured by setting CMAKE_Swift_COMPILER. We no longer look consider the TOOLCHAINS variable because it's macOS-specific as far as I know. - You must specify the full path to swiftc in CMAKE_Swift_COMPILER, as opposed to toolchain's bundle identifier in the TOOLCHAINS variable. Example for macOS: `cmake -DCMAKE_Swift_COMPILER=/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-12-07-a.xctoolchain/usr/bin/swiftc` - Verify that the Swift compiler supports Embedded Swift and abort if it doesn't. --- CMakeLists.txt | 89 +++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa507c3..9b0cbff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,59 +1,74 @@ -cmake_minimum_required(VERSION 3.28) +cmake_minimum_required(VERSION 3.22) -# User configuration -# Change these values to match your config. -# -# 1) Path to Raspberry Pi Pico C/C++ SDK -# This assumes the SDK is cloned to a sibling directory of this project. -# Alternatively, you can set PICO_SDK_PATH as an environment variable in your shell. +# Path to Raspberry Pi Pico C/C++ SDK +# +# This assumes the SDK is cloned to a sibling directory of this project. +# Alternatively, you can set PICO_SDK_PATH as an environment variable +# in your shell or pass the path directly to cmake: +# +# cmake -DPICO_SDK_PATH="/path/to/pico-sdk"` if (NOT (DEFINED ENV{PICO_SDK_PATH}) AND (NOT PICO_SDK_PATH)) set(PICO_SDK_PATH "${CMAKE_CURRENT_LIST_DIR}/../pico-sdk") - message("PICO_SDK_PATH is not set in environment, using value from CMakeLists.txt ('${PICO_SDK_PATH}')") -endif () -# 2) Swift toolchain -# Change this to the current Swift nightly toolchain you installed. -# The ID is in /Library/Developer/Toolchains/[TOOLCHAIN].xctoolchain/Info.plist -# Alternatively, set the TOOLCHAINS environment variable. -if (NOT (DEFINED ENV{TOOLCHAINS})) - set(Swift_Toolchain "org.swift.59202312071a") - message("Swift toolchain: ('${Swift_Toolchain}') (using value from CMakeLists.txt as TOOLCHAINS is not set in environment)") -else () - set(Swift_Toolchain "$ENV{TOOLCHAINS}") - message("Swift toolchain: ('${Swift_Toolchain}') (using TOOLCHAINS value from environment)") + message("PICO_SDK_PATH is not set, using value from CMakeLists.txt ('${PICO_SDK_PATH}')") endif () -# initialize the SDK based on PICO_SDK_PATH -# note: this must happen before project() +# Initialize the SDK based on PICO_SDK_PATH +# Note: this must happen before `project()`. include(pico_sdk_import.cmake) -# Configure Swift. This must happen before `project()`. I don't know why. -# Use nightly Swift compiler, configured for Embedded Swift. -# Find path to swiftc and store it in swiftc_Path -execute_process( - COMMAND xcrun --toolchain "${Swift_Toolchain}" --find swiftc - OUTPUT_VARIABLE swiftc_Path - OUTPUT_STRIP_TRAILING_WHITESPACE -) -set(CMAKE_Swift_COMPILER - "${swiftc_Path}" -) +# Configure Swift +# +# CMAKE_Swift_COMPILER must be set to an up-to-date nightly Swift toolchain +# with Embedded Swift support. The default value (at least on macOS and Linux) +# is /usr/bin/swiftc. +# +# You can set this either by passing the flag directly to CMake or by setting +# CMAKE_Swift_COMPILER=/path/to/swiftc as an environment variable. +# +# Example for macOS: +# +# cmake -DCMAKE_Swift_COMPILER="/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-12-07-a.xctoolchain/usr/bin/swiftc" +if ((DEFINED ENV{CMAKE_Swift_COMPILER}) AND (NOT CMAKE_Swift_COMPILER)) + set(CMAKE_Swift_COMPILER "$ENV{CMAKE_Swift_COMPILER}") + message("CMAKE_Swift_COMPILER: ${CMAKE_Swift_COMPILER} (using value set in environment)") +endif () +set(targetTripleLLVM "armv6m-none-none-eabi") set(CMAKE_Swift_FLAGS # -wmo: Whole-module optimization is always required for Embedded Swift. - # -Xfrontend -function-sections: enables dead stripping of unused runtime functions. - "-target armv6m-none-none-eabi \ + # -Xfrontend -function-sections: enables dead stripping of unused Swift + # runtime functions. + "-target ${targetTripleLLVM} \ -enable-experimental-feature Embedded \ -wmo \ -Xfrontend -function-sections" ) -# Disable CMake’s automatic Swift compiler check. The compiler check always -# fails for Embedded Swift because it tries to compile a Swift program that -# includes `print()`, which isn't available in Embedded Swift. +# Skip CMake’s automatic Swift compiler check +message("Skipping CMake's check for working Swift compiler. The check would always fail for Embedded Swift because it tries to compile a Swift program containing `print()`, which isn't available (yet) in Embedded Swift") set(CMAKE_Swift_COMPILER_FORCED TRUE) # === Begin project configuration project(SwiftPico LANGUAGES C CXX Swift) +# Abort if the Swift compiler doesn't support the target architecture. +# +# I'd also like to test if the Swift compiler supports Embedded Swift, +# but I don't know how to do that on the command line +# (see https://forums.swift.org/t/how-to-test-if-swiftc-supports-an-upcoming-experimental-feature/69095). +# +# Note: This must happen after `project()` because we can now rely on +# the `CMAKE_Swift_COMPILER` variable not being empty. +message("CMAKE_Swift_COMPILER: ${CMAKE_Swift_COMPILER}") +execute_process( + COMMAND "${CMAKE_Swift_COMPILER}" -target "${targetTripleLLVM}" -print-target-info + RESULT_VARIABLE swiftcSupportsTarget + OUTPUT_QUIET + ERROR_QUIET +) +if (NOT(swiftcSupportsTarget EQUAL "0")) + message(FATAL_ERROR "Swift compiler '${CMAKE_Swift_COMPILER}' doesn't support target '${targetTripleLLVM}'. Are you using an up-to-date nightly Swift toolchain that supports Embedded Swift?\nPass the path to swiftc to CMake via `cmake -DCMAKE_Swift_COMPILER=/path/to/swiftc` or by setting CMAKE_Swift_COMPILER=/path/to/swiftc in the environment.\nExample for macOS: `cmake -DCMAKE_Swift_COMPILER=\"/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-12-07-a.xctoolchain/usr/bin/swiftc\"`") +endif () + # Initialize the Raspberry Pi Pico SDK pico_sdk_init() From b327507b0b903fc6ed24e6f6b4270af2f05325d1 Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Wed, 20 Dec 2023 17:13:54 +0100 Subject: [PATCH 2/5] Configure Swift toolchain for VS Code --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 55b478c..f81bf4e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { // Building Swift with CMake requires Ninja "cmake.generator": "Ninja", + "cmake.configureSettings": { + "CMAKE_Swift_COMPILER": "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-12-07-a.xctoolchain/usr/bin/swiftc", + }, } From d541a9fefe6f876a2ceb79efefdd6e351fec532c Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Fri, 22 Dec 2023 09:52:33 +0100 Subject: [PATCH 3/5] =?UTF-8?q?CMake=203.22=20doesn=E2=80=99t=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b0cbff..5b8c5f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.22) +cmake_minimum_required(VERSION 3.28) # Path to Raspberry Pi Pico C/C++ SDK # From 927d4256fc8b15cd5a2e2750e229d5ee9dc3a446 Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Fri, 22 Dec 2023 19:54:11 +0100 Subject: [PATCH 4/5] Formatting and documentation --- CMakeLists.txt | 33 ++++++++++++++++++++++++--------- SwiftLib/CMakeLists.txt | 8 ++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b8c5f0..a5436db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,13 @@ cmake_minimum_required(VERSION 3.28) if (NOT (DEFINED ENV{PICO_SDK_PATH}) AND (NOT PICO_SDK_PATH)) set(PICO_SDK_PATH "${CMAKE_CURRENT_LIST_DIR}/../pico-sdk") message("PICO_SDK_PATH is not set, using value from CMakeLists.txt ('${PICO_SDK_PATH}')") -endif () +endif() # Initialize the SDK based on PICO_SDK_PATH # Note: this must happen before `project()`. +# +# This include sets PICO_SDK_PATH and then includes +# PICO_SDK_PATH/pico_sdk_init.cmake (Pico SDK pre-init). include(pico_sdk_import.cmake) # Configure Swift @@ -31,7 +34,7 @@ include(pico_sdk_import.cmake) if ((DEFINED ENV{CMAKE_Swift_COMPILER}) AND (NOT CMAKE_Swift_COMPILER)) set(CMAKE_Swift_COMPILER "$ENV{CMAKE_Swift_COMPILER}") message("CMAKE_Swift_COMPILER: ${CMAKE_Swift_COMPILER} (using value set in environment)") -endif () +endif() set(targetTripleLLVM "armv6m-none-none-eabi") set(CMAKE_Swift_FLAGS # -wmo: Whole-module optimization is always required for Embedded Swift. @@ -43,7 +46,10 @@ set(CMAKE_Swift_FLAGS -Xfrontend -function-sections" ) # Skip CMake’s automatic Swift compiler check -message("Skipping CMake's check for working Swift compiler. The check would always fail for Embedded Swift because it tries to compile a Swift program containing `print()`, which isn't available (yet) in Embedded Swift") +# The check would always fail for Embedded Swift because it tries to compile +# a Swift program containing `print()`, which isn't available (yet) in +# Embedded Swift. +message(STATUS "Skipping CMake's check for working Swift compiler.") set(CMAKE_Swift_COMPILER_FORCED TRUE) # === Begin project configuration @@ -67,7 +73,7 @@ execute_process( ) if (NOT(swiftcSupportsTarget EQUAL "0")) message(FATAL_ERROR "Swift compiler '${CMAKE_Swift_COMPILER}' doesn't support target '${targetTripleLLVM}'. Are you using an up-to-date nightly Swift toolchain that supports Embedded Swift?\nPass the path to swiftc to CMake via `cmake -DCMAKE_Swift_COMPILER=/path/to/swiftc` or by setting CMAKE_Swift_COMPILER=/path/to/swiftc in the environment.\nExample for macOS: `cmake -DCMAKE_Swift_COMPILER=\"/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-12-07-a.xctoolchain/usr/bin/swiftc\"`") -endif () +endif() # Initialize the Raspberry Pi Pico SDK pico_sdk_init() @@ -79,15 +85,24 @@ if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") endif() -add_executable(SwiftPico - main.c +add_executable( + SwiftPico + main.c ) add_subdirectory(SwiftLib) -target_link_libraries(SwiftPico - $ - pico_stdlib +target_link_libraries( + SwiftPico + pico_stdlib + # $ is a generator expression: + # + # + # Using just "SwiftLib" here results in a linker error I can't explain: + # "unknown argument: '--specs=nosys.specs'"" + # I think this is because CMake tries to use `swiftc` as the linker in + # this case. I don’t know why. + $ ) # create map/bin/hex file etc. diff --git a/SwiftLib/CMakeLists.txt b/SwiftLib/CMakeLists.txt index 7919d18..f7194a6 100644 --- a/SwiftLib/CMakeLists.txt +++ b/SwiftLib/CMakeLists.txt @@ -1,3 +1,7 @@ -add_library(SwiftLib - SwiftLib.swift +add_library(SwiftLib) + +target_sources( + SwiftLib + PRIVATE + SwiftLib.swift ) From d203589c88dc11fd8defa7f487d10a734267f85b Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Wed, 27 Dec 2023 20:50:29 +0100 Subject: [PATCH 5/5] Add a Dockerfile for Linux (Ubuntu 22.04, Swift nightly) --- Dockerfile | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6bc55ae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# Docker image for building Embedded Swift programs on Linux +# +# Build this image: +# +# docker build --tag ole/embedded-swift . +# +# Start a container: +# +# docker run --rm --privileged --interactive --tty --volume "$(pwd):/src" --workdir /src ole/embedded-swift + +FROM swiftlang/swift:nightly-jammy + +# Install dependencies +RUN apt -y update +RUN apt -y install gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib ninja-build python3 + +# Build CMake from source because we need a newer version than what +# Ubuntu 22.04 ships with. +WORKDIR /root +RUN apt install -y wget +RUN wget https://github.com/Kitware/CMake/releases/download/v3.28.1/cmake-3.28.1.tar.gz +RUN tar xvzf cmake-3.28.1.tar.gz +WORKDIR cmake-3.28.1 +RUN mkdir build +WORKDIR build +RUN ../bootstrap --generator=Ninja -- -DCMAKE_USE_OPENSSL=OFF .. +RUN ninja +RUN ninja install + +WORKDIR /