Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Include macro tests on Windows
Browse files Browse the repository at this point in the history
samdeane committed Jan 27, 2025

Verified

This commit was signed with the committer’s verified signature.
samdeane Sam Deane
1 parent 2f4e4e2 commit a53098b
Showing 53 changed files with 338 additions and 205 deletions.
69 changes: 69 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"fileScopedDeclarationPrivacy": {
"accessLevel": "private"
},
"indentation": {
"spaces": 4
},
"indentConditionalCompilationBlocks": true,
"indentSwitchCaseLabels": false,
"lineBreakAroundMultilineExpressionChainComponents": false,
"lineBreakBeforeControlFlowKeywords": false,
"lineBreakBeforeEachArgument": false,
"lineBreakBeforeEachGenericRequirement": false,
"lineLength": 200,
"maximumBlankLines": 1,
"multiElementCollectionTrailingCommas": true,
"noAssignmentInExpressions": {
"allowedFunctions": [
"XCTAssertNoThrow"
]
},
"prioritizeKeepingFunctionOutputTogether": false,
"respectsExistingLineBreaks": true,
"rules": {
"AllPublicDeclarationsHaveDocumentation": false,
"AlwaysUseLiteralForEmptyCollectionInit": false,
"AlwaysUseLowerCamelCase": true,
"AmbiguousTrailingClosureOverload": true,
"BeginDocumentationCommentWithOneLineSummary": false,
"DoNotUseSemicolons": true,
"DontRepeatTypeInStaticProperties": true,
"FileScopedDeclarationPrivacy": true,
"FullyIndirectEnum": true,
"GroupNumericLiterals": true,
"IdentifiersMustBeASCII": true,
"NeverForceUnwrap": false,
"NeverUseForceTry": false,
"NeverUseImplicitlyUnwrappedOptionals": false,
"NoAccessLevelOnExtensionDeclaration": true,
"NoAssignmentInExpressions": true,
"NoBlockComments": true,
"NoCasesWithOnlyFallthrough": true,
"NoEmptyTrailingClosureParentheses": true,
"NoLabelsInCasePatterns": true,
"NoLeadingUnderscores": false,
"NoParensAroundConditions": true,
"NoPlaygroundLiterals": true,
"NoVoidReturnOnFunctionSignature": true,
"OmitExplicitReturns": false,
"OneCasePerLine": true,
"OneVariableDeclarationPerLine": true,
"OnlyOneTrailingClosureArgument": true,
"OrderedImports": true,
"ReplaceForEachWithForLoop": true,
"ReturnVoidInsteadOfEmptyTuple": true,
"TypeNamesShouldBeCapitalized": true,
"UseEarlyExits": false,
"UseLetInEveryBoundCaseVariable": true,
"UseShorthandTypeNames": true,
"UseSingleLinePropertyGetter": true,
"UseSynthesizedInitializer": true,
"UseTripleSlashForDocumentationComments": true,
"UseWhereClausesInForLoops": false,
"ValidateDocumentationComments": false
},
"spacesAroundRangeFormationOperators": false,
"tabWidth": 4,
"version": 1
}
2 changes: 1 addition & 1 deletion Generator/Generator/UnsafePointerHelpers.swift
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ func generateUnsafePointerHelpers(_ p: Printer) {
/// }
/// ```
private func generateUnsafeRawPointersN(_ p: Printer, pointerCount count: Int) {
p("struct UnsafeRawPointersN\(count)") {
p("public struct UnsafeRawPointersN\(count)") {
for i in 0..<count {
p("let p\(i): UnsafeRawPointer?")
}
43 changes: 23 additions & 20 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -121,7 +121,14 @@ var targets: [Target] = [
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
],
swiftSettings: [.swiftLanguageMode(.v5)]
swiftSettings: [
.swiftLanguageMode(.v5),
.unsafeFlags(
[
"-Xfrontend", "-entry-point-function-name",
"-Xfrontend", "wWinMain",
], .when(platforms: [.windows])),
]
),
// This contains sample code showing how to use the SwiftGodot API
.target(
@@ -154,24 +161,21 @@ var targets: [Target] = [
],
swiftSettings: [.swiftLanguageMode(.v5)]
),
]

// Macro tests don't work on Windows yet
#if !os(Windows)
// Macro tests
// Idea: -mark_dead_strippable_dylib
targets.append(
.testTarget(
name: "SwiftGodotMacrosTests",
dependencies: [
"SwiftGodotMacroLibrary",
"SwiftGodot",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
],
swiftSettings: [.swiftLanguageMode(.v5)]
))
#endif
.testTarget(
name: "SwiftGodotMacrosTests",
dependencies: [
"SwiftGodotMacroLibrary",
"SwiftGodot",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
],
swiftSettings: [.swiftLanguageMode(.v5)]
),
]

// libgodot is only available for macOS and testability runtime depends on it
// libgodot is only available for macOS and most of the tests depend on it
#if os(macOS)
/// You might want to build your own libgodot, so you can step into it in the debugger when fixing failing tests. Here's how:
///
@@ -181,7 +185,7 @@ var targets: [Target] = [
/// 4. Change `#if true` to `#if false` below.
///
#if true
let libgodot_tests = Target.binaryTarget(
let libgodot_runtime = Target.binaryTarget(
name: "libgodot_tests",
url: "https://github.com/migueldeicaza/SwiftGodotKit/releases/download/4.3.5/libgodot.xcframework.zip",
checksum: "865ea17ad3e20caab05b3beda35061f57143c4acf0e4ad2684ddafdcc6c4f199"
@@ -195,8 +199,7 @@ var targets: [Target] = [

targets.append(contentsOf: [
// Godot runtime as a library

libgodot_tests,
libgodot_runtime,

// Base functionality for Godot runtime dependant tests
.target(
@@ -239,7 +242,7 @@ let package = Package(
name: "SwiftGodot",
platforms: [
.macOS(.v14),
.iOS (.v17)
.iOS(.v17),
],
products: products,
dependencies: [
38 changes: 38 additions & 0 deletions Sources/SwiftGodot/Core/Wrapped+Testing.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
public extension Wrapped {
struct Testing {
/// Public API for tracking live objects
public struct LiveObjects {
/// All framework objects.
/// For Testing purposes only.
public static var framework: [Wrapped] { Array(liveFrameworkObjects.values) }

/// All user-defined objects
/// For Testing purposes only.
public static var subtyped: [Wrapped] { Array(liveSubtypedObjects.values) }

/// All objects
/// For Testing purposes only.
public static var all: [Wrapped] { framework + subtyped }

/// Reset all existing tracked objects
/// For Testing purposes only.
public static func reset() {
liveFrameworkObjects.removeAll()
liveSubtypedObjects.removeAll()
}
}

/// Public API for monitoring class names.
public struct ClassNames {
/// Set a callback to be called when a duplicate class name is detected.
/// For Testing purposes only.
public static func setDuplicateNameCallback(_ callback: @escaping DuplicateNameCallback) -> DuplicateNameCallback {
let old = duplicateClassCallback
duplicateClassCallback = callback
return old
}
}
}
}


28 changes: 17 additions & 11 deletions Sources/SwiftGodot/Core/Wrapped.swift
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@
//
// We ensure that all Godot


@_implementationOnly import GDExtension

func pd (_ str: String) {
@@ -318,12 +319,18 @@ func bindGodotInstance(instance: some Wrapped, handle: UnsafeRawPointer) {

var userTypes: [String:(UnsafeRawPointer)->Wrapped] = [:]

// @_spi(SwiftGodotTesting) public
var duplicateClassNameDetected: (_ name: StringName, _ type: Wrapped.Type) -> Void = { name, type in
/// Callback to be called when a duplicate class name is detected.
/// In normal operation, this should never be called, and if it is, it is a fatal error.
/// For testing purposes however, you can set this to a custom callback to test the behavior.
/// (see Wrapped+Testing.swift)
public typealias DuplicateNameCallback = (StringName, Wrapped.Type) -> Void

/// Callback to be called when a duplicate class name is detected.
internal var duplicateClassCallback: DuplicateNameCallback = { name, type in
preconditionFailure(
"""
Godot already has a class named \(name), so I cannot register \(type) using that name. This is a fatal error because the only way I can tell whether Godot is handing me a pointer to a class I'm responsible for is by checking the class name.
"""
"""
Godot already has a class named \(name), so I cannot register \(type) using that name. This is a fatal error because the only way I can tell whether Godot is handing me a pointer to a class I'm responsible for is by checking the class name.
"""
)
}

@@ -334,7 +341,7 @@ func register<T:Wrapped> (type name: StringName, parent: StringName, type: T.Typ

let existingClassTag = gi.classdb_get_class_tag(&nameContent)
if existingClassTag != nil {
duplicateClassNameDetected(name, type)
duplicateClassCallback(name, type)
}

func getVirtual(_ userData: UnsafeMutableRawPointer?, _ name: GDExtensionConstStringNamePtr?) -> GDExtensionClassCallVirtual? {
@@ -387,10 +394,11 @@ public func unregister<T:Wrapped> (type: T.Type) {
}
}


/// Currently contains all instantiated objects, but might want to separate those
/// (or find a way of easily telling appart) framework objects from user subtypes
var liveFrameworkObjects: [UnsafeRawPointer:Wrapped] = [:]
var liveSubtypedObjects: [UnsafeRawPointer:Wrapped] = [:]
internal var liveFrameworkObjects: [UnsafeRawPointer: Wrapped] = [:]
internal var liveSubtypedObjects: [UnsafeRawPointer: Wrapped] = [:]

// Lock for accessing the above
var tableLock = NIOLock()
@@ -399,9 +407,6 @@ var tableLock = NIOLock()
// this contains the handle to use, and prevents a new Godot object peer to
// be created
fileprivate var bindingObject: UnsafeMutableRawPointer? = nil

///
/// Looks into the liveSubtypedObjects table if we have an object registered for it,

///
/// Looks into the liveSubtypedObjects table if we have an object registered for it,
@@ -644,3 +649,4 @@ struct CallableWrapper {
return content
}
}

97 changes: 23 additions & 74 deletions Sources/SwiftGodot/EntryPoint.swift
Original file line number Diff line number Diff line change
@@ -7,62 +7,6 @@

@_implementationOnly import GDExtension

public protocol ExtensionInterface {

func variantShouldDeinit(content: UnsafeRawPointer) -> Bool

func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool

func objectInited(object: Wrapped)

func objectDeinited(object: Wrapped)

func getLibrary() -> UnsafeMutableRawPointer

func getProcAddr() -> OpaquePointer

}

class LibGodotExtensionInterface: ExtensionInterface {

/// If your application is crashing due to the Variant leak fixes, please
/// enable this flag, and provide me with a test case, so I can find that
/// pesky scenario.
public let experimentalDisableVariantUnref = false

private let library: GDExtensionClassLibraryPtr
private let getProcAddrFun: GDExtensionInterfaceGetProcAddress

public init(library: GDExtensionClassLibraryPtr, getProcAddrFun: GDExtensionInterfaceGetProcAddress) {
self.library = library
self.getProcAddrFun = getProcAddrFun
}

public func variantShouldDeinit(content: UnsafeRawPointer) -> Bool {
return !experimentalDisableVariantUnref
}

public func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool {
return true
}

public func objectInited(object: Wrapped) {}

public func objectDeinited(object: Wrapped) {}

public func getLibrary() -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(mutating: library)
}

public func getProcAddr() -> OpaquePointer {
return unsafeBitCast(getProcAddrFun, to: OpaquePointer.self)
}

}

/// The pointer to the Godot Extension Interface
var extensionInterface: ExtensionInterface!

/// This variable is used to trigger a reloading of the method definitions in Godot, this is only needed
/// for scenarios where SwiftGodot is being used with multiple active Godot runtimes in the same process
public var swiftGodotLibraryGeneration: UInt16 = 0
@@ -74,16 +18,6 @@ func loadFunctions(loader: GDExtensionInterfaceGetProcAddress) {

}

///
/// This method is used to configure the extension interface for SwiftGodot to
/// operate. It is only used when you use SwiftGodot embedded into an
/// application - as opposed to using SwiftGodot purely as an extension
///
public func setExtensionInterface(interface: ExtensionInterface) {
extensionInterface = interface
loadGodotInterface(unsafeBitCast(interface.getProcAddr(), to: GDExtensionInterfaceGetProcAddress.self))
}

// Extension initialization callback
func extension_initialize(userData: UnsafeMutableRawPointer?, l: GDExtensionInitializationLevel) {
//print ("SWIFT: extension_initialize")
@@ -421,8 +355,8 @@ public func initializeSwiftModule(
_ godotGetProcAddrPtr: OpaquePointer,
_ libraryPtr: OpaquePointer,
_ extensionPtr: OpaquePointer,
initHook: @escaping (GDExtension.InitializationLevel) -> (),
deInitHook: @escaping (GDExtension.InitializationLevel) -> (),
initHook: @escaping (GDExtension.InitializationLevel) -> Void,
deInitHook: @escaping (GDExtension.InitializationLevel) -> Void,
minimumInitializationLevel: GDExtension.InitializationLevel = .scene
) {
let getProcAddrFun = unsafeBitCast(godotGetProcAddrPtr, to: GDExtensionInterfaceGetProcAddress.self)
@@ -440,12 +374,7 @@ public func initializeSwiftModule(
let initialization = UnsafeMutablePointer<GDExtensionInitialization>(extensionPtr)
initialization.pointee.deinitialize = extension_deinitialize
initialization.pointee.initialize = extension_initialize
#if os(Windows)
typealias RawType = Int32
#else
typealias RawType = UInt32
#endif
initialization.pointee.minimum_initialization_level = GDExtensionInitializationLevel(RawType(minimumInitializationLevel.rawValue))
initialization.pointee.minimum_initialization_level = minimumInitializationLevel.asCType
initialization.pointee.userdata = UnsafeMutableRawPointer(libraryPtr)
}

@@ -458,3 +387,23 @@ public func initializeSwiftModule(
func withArgPointers(_ _args: UnsafeMutableRawPointer?..., body: ([UnsafeRawPointer?]) -> Void) {
body(unsafeBitCast(_args, to: [UnsafeRawPointer?].self))
}

#if os(Windows)
typealias RawType = Int32
#else
typealias RawType = UInt32
#endif

extension GDExtension.InitializationLevel {
/// Converts the public Swift type to the private Godot type.
var asCType: GDExtensionInitializationLevel {
GDExtensionInitializationLevel(RawType(rawValue))
}
}

extension GDExtensionInitializationLevel {
/// Converts the private Godot type to the public Swift type.
var asSwiftType: GDExtension.InitializationLevel {
GDExtension.InitializationLevel(rawValue: Int64(exactly: rawValue)!)!
}
}
Loading

0 comments on commit a53098b

Please sign in to comment.