Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
matrix:
os:
- macos-15
- macos-26
- ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/Examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
matrix:
os:
- macos-15
- macos-26
- ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -31,6 +32,7 @@ jobs:
matrix:
os:
- macos-15
- macos-26
- ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -50,6 +52,7 @@ jobs:
matrix:
os:
- macos-15
- macos-26
- ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -77,5 +80,5 @@ jobs:
if: ${{ runner.os == 'macOS' }}
uses: actions/upload-artifact@v4
with:
name: Xkpd
name: Xkpd-${{ matrix.os }}
path: Examples/Xkpd/.build/plugins/PDCPlugin/outputs/Xkpd.pdx
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
main-snapshot-2025-05-25
main-snapshot-2026-01-09
15 changes: 15 additions & 0 deletions Examples/FlappySwift/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions Examples/Pong/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion Examples/Xkpd/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 0 additions & 13 deletions Examples/Xkpd/Package.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// swift-tools-version: 6.1

import Foundation
import PackageDescription

/// Hack to force Xcode builds to not produce a dylib, since linking fails
Expand All @@ -14,16 +13,6 @@ let playdateSDKPath: String = if let path = Context.environment["PLAYDATE_SDK_PA
"\(Context.environment["HOME"]!)/Developer/PlaydateSDK/"
}

let armSysrootPath: String = if let path = Context.environment["ARM_NONE_EABI_SYSROOT_PATH"] {
path
} else {
#if os(Linux)
"/usr/lib/arm-none-eabi"
#else
"/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi"
#endif
}

let package = Package(
name: "Xkpd",
platforms: [.macOS(.v14)],
Expand Down Expand Up @@ -66,7 +55,6 @@ let package = Package(
"-DLODEPNG_NO_COMPILE_DISK",
"-DLODEPNG_NO_COMPILE_ALLOCATORS",
"-DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS",
"-I", "\(armSysrootPath)/include",
])
],
),
Expand All @@ -78,7 +66,6 @@ let package = Package(
cSettings: [
.unsafeFlags([
"-v",
"-I", "\(armSysrootPath)/include",
])
]
),
Expand Down
7 changes: 7 additions & 0 deletions Examples/Xkpd/Sources/CLodePNG/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@

#include <stddef.h>

void *memset(void *, int, size_t);
void *memcpy(void *, const void *, size_t);
void *memmove(void *, const void *, size_t);
int memcmp(const void *, const void *, size_t);
size_t strlen(const char *);
int strcmp(const char *, const char *);

#endif
15 changes: 8 additions & 7 deletions Examples/Xkpd/Sources/CLodePNG/setup.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#ifdef TARGET_PLAYDATE
extern void* pdrealloc(void* ptr, size_t size);
void* lodepng_malloc(size_t size) { return pdrealloc(NULL, size); }
void* lodepng_realloc(void* ptr, size_t size) { return pdrealloc(ptr, size); }
void lodepng_free(void* ptr) { if(ptr) pdrealloc(ptr, 0); }
#include <stddef.h>
extern void* malloc(size_t);
extern void* realloc(void*, size_t);
extern void free(void*);
#else
#include <stdlib.h>
void* lodepng_malloc(size_t size) { return malloc(size); }
void* lodepng_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
void lodepng_free(void* ptr) { free(ptr); }
#endif

void* lodepng_malloc(size_t size) { return malloc(size); }
void* lodepng_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
void lodepng_free(void* ptr) { free(ptr); }

29 changes: 0 additions & 29 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,6 @@

import PackageDescription

let armToolchainPath: String = if let path = Context.environment["ARM_NONE_EABI_GCC_PATH"] {
path
} else {
#if os(Linux)
"/usr/lib/gcc/arm-none-eabi/10.3.1"
#else
"/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1"
#endif
}

let armSysrootPath: String = if let path = Context.environment["ARM_NONE_EABI_SYSROOT_PATH"] {
path
} else {
#if os(Linux)
"/usr/lib/arm-none-eabi"
#else
"/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi"
#endif
}

let playdateSDKPath: String = if let path = Context.environment["PLAYDATE_SDK_PATH"] {
path
} else {
Expand Down Expand Up @@ -50,9 +30,6 @@ let package = Package(
"-Xfrontend", "-function-sections",
"-Xfrontend", "-gline-tables-only",
"-Xcc", "-DTARGET_EXTENSION",
"-Xcc", "-I", "-Xcc", "\(armToolchainPath)/include",
"-Xcc", "-I", "-Xcc", "\(armToolchainPath)/include-fixed",
"-Xcc", "-I", "-Xcc", "\(armSysrootPath)/include",
"-I", "\(playdateSDKPath)/C_API"
]),
]
Expand All @@ -70,9 +47,6 @@ let package = Package(
"-Xfrontend", "-function-sections",
"-Xfrontend", "-gline-tables-only",
"-Xcc", "-DTARGET_EXTENSION",
"-Xcc", "-I", "-Xcc", "\(armToolchainPath)/include",
"-Xcc", "-I", "-Xcc", "\(armToolchainPath)/include-fixed",
"-Xcc", "-I", "-Xcc", "\(armSysrootPath)/include",
"-I", "\(playdateSDKPath)/C_API"
]),
]
Expand All @@ -82,9 +56,6 @@ let package = Package(
cSettings: [
.unsafeFlags([
"-DTARGET_EXTENSION",
"-I", "\(armToolchainPath)/include",
"-I", "\(armToolchainPath)/include-fixed",
"-I", "\(armSysrootPath)/include",
"-I", "\(playdateSDKPath)/C_API"
])
]
Expand Down
32 changes: 31 additions & 1 deletion Plugins/PDCPlugin/PDCPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ import PackagePlugin
}
}

var armToolchainPath: String {
if let path = ProcessInfo.processInfo.environment["ARM_NONE_EABI_GCC_PATH"] {
return path
}
#if os(Linux)
return "/usr/lib/gcc/arm-none-eabi/10.3.1"
#else
return "/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1"
#endif
}

var armSysrootPath: String {
if let path = ProcessInfo.processInfo.environment["ARM_NONE_EABI_SYSROOT_PATH"] {
return path
}
#if os(Linux)
return "/usr/lib/arm-none-eabi"
#else
return "/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi"
#endif
}

var playdateSDKURL: URL { get throws { try URL(filePath: playdateSDKPath) } }

func performCommand(context: PluginContext, arguments: [String]) async throws {
Expand Down Expand Up @@ -136,12 +158,20 @@ import PackagePlugin
verbose: Bool,
extraDeviceOFilesBuildDirs: [String]
) throws {
let deviceParameters = try PackageManager.BuildParameters(
var deviceParameters = try PackageManager.BuildParameters(
configuration: configuration,
logging: verbose ? .verbose : .concise,
echoLogs: verbose
).loadFlags(from: deviceToolset)

let armIncludes = [
"-I", "\(armToolchainPath)/include",
"-I", "\(armToolchainPath)/include-fixed",
"-I", "\(armSysrootPath)/include"
]
deviceParameters.otherCFlags += armIncludes
deviceParameters.otherSwiftcFlags += armIncludes.flatMap { ["-Xcc", $0] }

let result = try packageManager.build(
.target(target.name),
parameters: deviceParameters
Expand Down
3 changes: 3 additions & 0 deletions Sources/CPlaydate/include/CPlaydate.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once
#include "pd_api.h"

int pd_rand(void);
void pd_srand(unsigned int seed);

int formatStringFloat(PlaydateAPI p, char **outstring, float number) {
return p.system->formatString(outstring, "%f", number);
}
Expand Down
24 changes: 24 additions & 0 deletions Sources/CPlaydate/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ void* _malloc_r(struct _reent* _REENT, size_t nbytes) { return pdrealloc(NULL,nb
void* _realloc_r(struct _reent* _REENT, void* ptr, size_t nbytes) { return pdrealloc(ptr,nbytes); }
void _free_r(struct _reent* _REENT, void* ptr ) { if ( ptr != NULL ) pdrealloc(ptr,0); }

// Newlib syscall stubs required by the linker on bare-metal ARM.
int getentropy(void *buffer, size_t length) { return -1; }
int _getentropy(void *buffer, size_t length) { return -1; }
int _kill(int pid, int sig) { return -1; }
int _getpid(void) { return 1; }
int _close(int fd) { return -1; }
int _lseek(int fd, int offset, int whence) { return -1; }
int _read(int fd, void *buf, int count) { return -1; }
int _write(int fd, const void *buf, int count) { return -1; }
int _fstat(int fd, void *buf) { return -1; }
int _isatty(int fd) { return 0; }

#else

void* malloc(size_t nbytes) { return pdrealloc(NULL,nbytes); }
Expand All @@ -29,4 +41,16 @@ void free(void* ptr ) { if ( ptr != NULL ) pdrealloc(ptr,0); }

#endif

int posix_memalign(void **memptr, size_t alignment, size_t size) {
void *ptr = pdrealloc(NULL, size);
if (!ptr) return 12; // ENOMEM
*memptr = ptr;
return 0;
}

void *swift_coroFrameAlloc(size_t bytes, unsigned long long typeId) { return pdrealloc(NULL,bytes); }

// Wrappers for rand/srand. On macOS 16+, the SDK marks these
// __swift_unavailable but they're still callable from C.
int pd_rand(void) { return rand(); }
void pd_srand(unsigned int seed) { srand(seed); }
21 changes: 3 additions & 18 deletions Sources/PlaydateKit/Playdate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public enum Playdate {

public static func initialize(with pointer: UnsafeMutablePointer<PlaydateAPI>) {
_playdateAPI = pointer.pointee
srand(System.millisecondsSinceEpoch)
pd_srand(System.millisecondsSinceEpoch)
System.setUpdateCallback(update: { _ in
(System.updateCallback?() ?? false) ? 1 : 0
}, userdata: nil)
Expand All @@ -41,31 +41,16 @@ public enum Playdate {
private nonisolated(unsafe) static var _playdateAPI: PlaydateAPI?
}

/// Implement `posix_memalign(3)`, which is required by the Embedded Swift runtime but is
/// not provided by the Playdate C library.
@_documentation(visibility: internal)
@_cdecl("posix_memalign") public func posix_memalign(
_ memptr: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
_ alignment: Int,
_ size: Int
) -> CInt {
guard let allocation = malloc(Int(size + alignment - 1)) else { fatalError() }
let misalignment = Int(bitPattern: allocation) % alignment
precondition(misalignment == 0)
memptr.pointee = allocation
return 0
}

/// Implement `arc4random_buf` which is required by the Embedded Swift runtime for Hashable, Set, Dictionary,
/// and random-number generating APIs but is not provided by the Playdate C library.
@_documentation(visibility: internal)
@_cdecl("arc4random_buf") public func arc4random_buf(buf: UnsafeMutableRawPointer, nbytes: Int) {
for i in stride(from: 0, to: nbytes - 1, by: 2) {
let randomValue = UInt16(rand() & Int32(UInt16.max))
let randomValue = UInt16(pd_rand() & Int32(UInt16.max))
(buf + i).assumingMemoryBound(to: UInt16.self).pointee = randomValue
}
if nbytes % 2 == 1 {
let randomValue = UInt8(rand() & Int32(UInt8.max))
let randomValue = UInt8(pd_rand() & Int32(UInt8.max))
(buf + nbytes - 1).assumingMemoryBound(to: UInt8.self).pointee = randomValue
}
}
Expand Down
1 change: 1 addition & 0 deletions Toolsets/toolset_device.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"-mfloat-abi=hard",
"-mfpu=fpv5-sp-d16",
"-D__FPU_USED=1",
"-DTARGET_PLAYDATE=1",

"-falign-functions=16",
"-fshort-enums"
Expand Down