How to remove @available(9999) in embedded swift

I want to test the Span feature, I am using Embedded Swift so I am not even linking the system Swift module dynamically — making the available attribute completely arbitrary, no?

How do I make the compiler get out of my way :slight_smile:


Found a flag -Xfrontend -disable-availability-checking. Not sure where this is documented, it was really hard to find.

Can you share a small sample and compile command?

-disable-availability-checking is intentionally undocumented. It's a frontend flag, and all frontend flags are considered unstable implementation details, only for use by the driver and compiler test suite. This flag in particular is a useful nuisance which is overused in the compiler test suite and can be a big footgun when used elsewhere. It exists mainly as a convenience for compiler tests, but even in those there are better alternatives now. Using it to experiment with Span sounds fine to me, but just keep in mind that it's not an official feature.

2 Likes

If this is to be undocumented I think the language shouldn't have issues that force me to use it.
An unstable implementation detail probably shouldn't be the only way to use/test these — and I would question marking features like Span unavailable in nightly toolchains in the first place, as testing them is kind of the point.

Similarly, this kind of availability does not apply to the embedded standard library, it has next to no dependencies and can't even import Apple's frameworks. Even concurrency is linked statically.

Fundamentally, I don't need this potentially unsafe unstable flag, I need the standard library to use @available correctly.

To be clear, if the standard library used availability “correctly” here, you still wouldn’t be able to use it without this flag. This type does not exist in macOS 15.2 (the latest available version of macOS), so we have no choice but to say it’s available in some arbitrary future version of macOS.

No I understand, absolutely do that, but Embedded Swift doesn't link the macOS provided standard library. What is and isn't available isn't tied to the macOS version, so if I were to build for a version where something is "unavailable" it would still work.

This of course means I can't use Swift or Objective-C frameworks but I don't mind, I prefer to use C libraries anyway.

I think Swift sometimes forgets it isn't exclusively used for writing apps for the app store :slightly_smiling_face:

> otool -L /Users/teampuzel/Minecraft/build/release/minecraft 
/Users/teampuzel/Minecraft/build/release/minecraft:
	@rpath/SDL3.framework/Versions/A/SDL3 (compatibility version 107.0.0, current version 107.0.0)
	/usr/lib/swift/libswift_Concurrency.dylib (compatibility version 1.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

It looks like I'm accidentally linking system concurrency though.

1 Like

The main issue IMO is that the embedded standard library uses the same sources as the actual standard library (as an aside). If we truly wanted to fix this then we'd have to resort to littering the stdlib with:

#if !hasFeature(Embedded)
@available(SwiftStdlib ..., *)
#endif
public func hello() { ... }

everywhere, which will unfortunately be the most likely solution.

That shouldn't be necessary because embedded platforms are not macOS, iOS, etc. for availability purposes, and the availability for those platforms should not be considered when targeting an embedded platform. As rauhul asked:

Seeing the compilation invocation would help because it sounds like the target is not being set correctly.

You can target macOS using embedded though no?

Yes, the commands are being set correctly, and I am running this on macOS.

Even if so, it shouldn't be considered to use macOS availability since there is no runtime dependency on the OS runtime and no ABI compatibility with "regular" Swift using the OS runtime. Embedded is effectively a separate platform in its current state.

1 Like

I agree, but it seems from the OP that isn't the case currently. To be fair, availability may still make sense with embedded (targeting platforms like macOS, iOS, etc.) because you can still link against a system C library or such that only has X symbol after Y OS. But the stdlib's availability is always available however.

That sounds like your problem, because (AIUI) it is not currently supported to use normal "desktop" targets as is in embedded mode, and you probably need different settings. Please share your compilation invocation.

1 Like

Here you go TeamPuzel/BlockGameSwift - BlockGameSwift - Gitea: Git with a cup of tea

CMake file
cmake_minimum_required(VERSION 3.31)
project(Minecraft LANGUAGES CXX C Swift)

set(CMAKE_Swift_LANGUAGE_VERSION 6)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# MARK: - Dependencies -------------------------------------------------------------------------------------------------

find_package(SDL3 REQUIRED COMPONENTS SDL3)
add_library(GLAD STATIC lib/glad/src/glad.c)
target_include_directories(GLAD PUBLIC lib/glad/include)

# MARK: - Setup --------------------------------------------------------------------------------------------------------

set(CMAKE_Swift_FLAGS
    "-parse-as-library -wmo\
    -enable-experimental-feature BuiltinModule\
    -enable-experimental-feature Extern\
    -enable-experimental-feature Embedded\
    -enable-experimental-feature Span\
    -Xfrontend -disable-availability-checking\
    -Xcc -fmodule-map-file=${CMAKE_SOURCE_DIR}/lib/SDL3/module.modulemap\
    -Xcc -fmodule-map-file=${CMAKE_SOURCE_DIR}/lib/glad/include/module.modulemap"
)

file(GLOB_RECURSE CORE_MODULE      src/Core/*.swift)
file(GLOB_RECURSE ENGINE_MODULE    src/Engine/*.swift)
file(GLOB_RECURSE MINECRAFT_MODULE src/Minecraft/*.swift)

# MARK: - Core module --------------------------------------------------------------------------------------------------

add_library(Core STATIC ${CORE_MODULE})

# MARK: - Engine module ------------------------------------------------------------------------------------------------

add_library(Engine STATIC ${ENGINE_MODULE})
add_dependencies(Engine Core)
target_link_libraries(Engine PRIVATE Core)
target_link_libraries(Engine PRIVATE GLAD)
target_link_libraries(Engine PRIVATE SDL3::SDL3)
target_link_libraries(Engine PRIVATE swift_Concurrency)

# MARK: - Minecraft module ---------------------------------------------------------------------------------------------

add_executable(minecraft ${MINECRAFT_MODULE})
target_link_libraries(minecraft PRIVATE Engine)

# MARK: - Assets -------------------------------------------------------------------------------------------------------

file(GLOB_RECURSE ASSETS assets/*)
file(GLOB_RECURSE SHADERS shaders/*)

foreach(ASSET ${ASSETS})
    file(COPY ${ASSET} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bundle")
endforeach()

foreach(SHADER ${SHADERS})
    file(COPY ${SHADER} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bundle")
endforeach()

I thought it was supported, given that the standard library module is provided for these platforms in the toolchain.


I doubt it's building at the moment as I'm kind of in the middle of rewriting the C++ code, a lot of code references methods I didn't yet implement. But it did work perfectly fine a few commits ago, aside from a compiler crash I reported.

This is not the only way to test Span and unreleased APIs like it, though. The runtime for development toolchains special cases the version 9999 in OS availability so that checks for it always succeed. Using standard availability syntax and supplying 9999 as the version to check for is the designated way to work with unreleased standard library APIs. This is definitely a problem that could use a more elegant solution, but it's also expected that there's a bit of friction to using unreleased APIs; they're not finalized yet so code depending on them should only be experimental.

You're also right that gating the availability of most standard library APIs on macOS operating system version doesn't make sense when compiling for Embedded Swift since the implementation of the standard library is statically linked into your binary. However, that doesn't mean that the concept of OS version based availability is completely superfluous. Marking declarations with OS version based @available attributes ought to still be necessary in Embedded Swift to enclose code that interacts with C-based APIs from the system that have availability requirements. Availability simultaneously serves as a mechanism to influence linkage of external symbols and also as a type checking constraint that ensures code that depends on external symbols only executes when those external symbols have been proven to be available.

We should rethink how platform specific availability annotations are applied to the standard library when it is built for Embedded Swift. But please also keep in mind that you are using Swift on the bleeding edge on multiple dimensions here; it's not expected that the way you are using the tools is polished yet. Embedded Swift as a whole is an experimental feature, and using Embedded Swift to target macOS is extra experimental. Your feedback while trying this out is very valuable, but expect rough edges.

5 Likes

Of course :slightly_smiling_face:

Maybe most of my posts here seem very negative, but I like the language and I just want to report issues I run into, and it happens a lot since like you said I'm using lots of experimental features.

I would say that the overall experience is still far less miserable than trying to do this in C++, which is why I'm rewriting the code in Swift.

2 Likes