From a776c91d03af81f8a97a1f63fb6c02660e7623a4 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 5 Aug 2025 23:26:51 +0800 Subject: [PATCH 1/8] Add DebugClient to OGShims --- .../OpenGraphCxx/DebugServer/DebugServer.mm | 6 +- Sources/OpenGraphCxx/DebugServer/interpose.c | 23 +++ Sources/OpenGraphShims/DebugClient.swift | 131 ++++++++++++++++++ .../DebugServerMessageHeader.swift | 18 +++ .../Debug/DebugServerTests.swift | 13 +- .../DebugServer/DebugClient.swift | 128 +---------------- 6 files changed, 183 insertions(+), 136 deletions(-) create mode 100644 Sources/OpenGraphCxx/DebugServer/interpose.c create mode 100644 Sources/OpenGraphShims/DebugClient.swift create mode 100644 Sources/OpenGraphShims/DebugServerMessageHeader.swift mode change 100644 => 120000 Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift diff --git a/Sources/OpenGraphCxx/DebugServer/DebugServer.mm b/Sources/OpenGraphCxx/DebugServer/DebugServer.mm index 08c0ca93..beb49c54 100644 --- a/Sources/OpenGraphCxx/DebugServer/DebugServer.mm +++ b/Sources/OpenGraphCxx/DebugServer/DebugServer.mm @@ -28,6 +28,10 @@ #include #include +OG_EXTERN_C_BEGIN +bool os_variant_has_internal_diagnostics(const char *subsystem); +OG_EXTERN_C_END + // MARK: DebugServer public API Implementation OG::DebugServer::DebugServer(OGDebugServerMode mode) { @@ -260,7 +264,7 @@ if ( (mode & OGDebugServerModeValid) && !OG::DebugServer::has_shared_server() - /*&& os_variant_has_internal_diagnostics("com.apple.AttributeGraph")*/ +// && os_variant_has_internal_diagnostics("org.OpenSwiftUIProject.OpenGraph") ) { _shared_server = new DebugServer(mode); } diff --git a/Sources/OpenGraphCxx/DebugServer/interpose.c b/Sources/OpenGraphCxx/DebugServer/interpose.c new file mode 100644 index 00000000..80d564a6 --- /dev/null +++ b/Sources/OpenGraphCxx/DebugServer/interpose.c @@ -0,0 +1,23 @@ +// +// interpose.c +// OpenGraphCxx + +#include "stdio.h" +#include "stdbool.h" +#include "string.h" + +#define DYLD_INTERPOSE(_replacement,_replacee) \ + __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \ + __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; + +extern bool os_variant_has_internal_diagnostics(const char *subsystem); + +bool os_variant_has_internal_diagnostics_og_hook(const char *subsystem) { + if (strcmp(subsystem, "org.OpenSwiftUIProject.OpenGraph") == 0) { + return true; + } else { + return os_variant_has_internal_diagnostics(subsystem); + } +} + +DYLD_INTERPOSE(os_variant_has_internal_diagnostics_og_hook, os_variant_has_internal_diagnostics) diff --git a/Sources/OpenGraphShims/DebugClient.swift b/Sources/OpenGraphShims/DebugClient.swift new file mode 100644 index 00000000..24a28184 --- /dev/null +++ b/Sources/OpenGraphShims/DebugClient.swift @@ -0,0 +1,131 @@ +// +// DebugServerTests.swift +// OpenGraphShims + +#if canImport(Darwin) +public import Foundation +import Network + +#if canImport(OpenGraphCxx_Private) +public import OpenGraphCxx_Private.DebugServer +#endif + +@_spi(Debug) +public final class DebugClient { + private var connection: NWConnection? + private let queue = DispatchQueue(label: "opengraph.debugserver.client.queue") + + public func connect(to url: URL) async throws { + guard let host = url.host, let port = url.port else { + throw ClientError.invalidURL + } + + let nwHost = NWEndpoint.Host(host) + let nwPort = NWEndpoint.Port(integerLiteral: UInt16(port)) + + connection = NWConnection(host: nwHost, port: nwPort, using: .tcp) + + return try await withCheckedThrowingContinuation { continuation in + connection?.stateUpdateHandler = { state in + switch state { + case .ready: + continuation.resume() + case let .failed(error): + continuation.resume(throwing: error) + case .cancelled: + continuation.resume(throwing: ClientError.connectionCancelled) + default: + break + } + } + connection?.start(queue: queue) + } + } + + public func sendMessage(token: UInt32, data: Data) async throws { + guard let connection else { + throw ClientError.notConnected + } + let header = DebugServerMessageHeader( + token: token, + unknown: 0, + length: numericCast(data.count), + unknown2: 0 + ) + let headerData = withUnsafePointer(to: header) { + Data(bytes: UnsafeRawPointer($0), count: MemoryLayout.size) + } + try await send(data: headerData, on: connection) + guard header.length > 0 else { + return + } + try await send(data: data, on: connection) + } + + public func receiveMessage() async throws -> (header: DebugServerMessageHeader, data: Data) { + guard let connection = connection else { + throw ClientError.notConnected + } + let headerData = try await receive( + length: MemoryLayout.size, + from: connection + ) + let header = headerData.withUnsafeBytes { bytes in + let buffer = bytes.bindMemory(to: UInt32.self) + return DebugServerMessageHeader( + token: buffer[0], + unknown: buffer[1], + length: buffer[2], + unknown2: buffer[3] + ) + } + guard header.length > 0 else { + return (header: header, data: Data()) + } + let payloadData = try await receive( + length: numericCast(header.length), + from: connection + ) + return (header: header, data: payloadData) + } + + public func disconnect() { + connection?.cancel() + connection = nil + } + + private func send(data: Data, on connection: NWConnection) async throws { + return try await withCheckedThrowingContinuation { continuation in + connection.send(content: data, completion: .contentProcessed { error in + if let error { + continuation.resume(throwing: error) + } else { + continuation.resume() + } + }) + } + } + + private func receive(length: Int, from connection: NWConnection) async throws -> Data { + return try await withCheckedThrowingContinuation { continuation in + connection.receive(minimumIncompleteLength: length, maximumLength: length) { data, _, isComplete, error in + if let error { + continuation.resume(throwing: error) + } else if let data { + continuation.resume(returning: data) + } else { + continuation.resume(throwing: ClientError.noDataReceived) + } + } + } + } +} + +enum ClientError: Error { + case invalidURL + case notConnected + case connectionCancelled + case noDataReceived +} + +#endif diff --git a/Sources/OpenGraphShims/DebugServerMessageHeader.swift b/Sources/OpenGraphShims/DebugServerMessageHeader.swift new file mode 100644 index 00000000..bc6df06d --- /dev/null +++ b/Sources/OpenGraphShims/DebugServerMessageHeader.swift @@ -0,0 +1,18 @@ +// +// DebugServerMessageHeader.swift +// OpenGraphShims + +@_spi(Debug) +public struct DebugServerMessageHeader { + public let token: UInt32 + public let unknown: UInt32 + public let length: UInt32 + public let unknown2: UInt32 + + public init(token: UInt32, unknown: UInt32, length: UInt32, unknown2: UInt32) { + self.token = token + self.unknown = unknown + self.length = length + self.unknown2 = unknown2 + } +} diff --git a/Tests/OpenGraphCompatibilityTests/Debug/DebugServerTests.swift b/Tests/OpenGraphCompatibilityTests/Debug/DebugServerTests.swift index 188aec04..4eecefa9 100644 --- a/Tests/OpenGraphCompatibilityTests/Debug/DebugServerTests.swift +++ b/Tests/OpenGraphCompatibilityTests/Debug/DebugServerTests.swift @@ -15,14 +15,13 @@ struct DebugServerTests { #expect(DebugServer.copyURL() == nil) } - // TODO: hook via private API of dyld // To make AG start debugServer, we need to pass internal_diagnostics check. // In debug mode, we can breakpoint on `_ZN2AG11DebugServer5startEj` and // executable `reg write w0 1` after `internal_diagnostics` call. - // Or we can disable SIP on the target darwinOS and run `sudo sysctl kern.osvariant_status=xx` to workaround - @Test( - .disabled(if: compatibilityTestEnabled, "Skip on AG due to internal_diagnostics check"), - ) + // Or we can disable SIP on the target darwinOS and run `sudo sysctl kern.osvariant_status=xx` to workaround. + // Or you can add `breakpoint set -n os_variant_has_internal_diagnostics -C "thread return 1"` + // to your lldbinit or run it before AGDebugServerStart call. + @Test(.disabled(if: compatibilityTestEnabled, "Skip on AG on CI due to internal_diagnostics check")) func testMode1() throws { let _ = try #require(DebugServer.start(mode: [.valid])) let url = try #require(DebugServer.copyURL()) as URL @@ -33,9 +32,7 @@ struct DebugServerTests { DebugServer.stop() } - @Test( - .disabled(if: compatibilityTestEnabled, "Skip on AG due to internal_diagnostics check"), - ) + @Test(.disabled(if: compatibilityTestEnabled, "Skip on AG on CI due to internal_diagnostics check")) func testMode3() throws { let _ = try #require(DebugServer.start(mode: [.valid, .networkInterface])) let url = try #require(DebugServer.copyURL()) as URL diff --git a/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift b/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift deleted file mode 100644 index 14715170..00000000 --- a/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// DebugServerTests.swift -// OpenGraphCxxTests - -#if canImport(Darwin) -import Foundation -import Network -import OpenGraphCxx_Private.DebugServer - -final class DebugClient { - private var connection: NWConnection? - private let queue = DispatchQueue(label: "opengraph.debugserver.client.queue") - - func connect(to url: URL) async throws { - guard let host = url.host, let port = url.port else { - throw ClientError.invalidURL - } - - let nwHost = NWEndpoint.Host(host) - let nwPort = NWEndpoint.Port(integerLiteral: UInt16(port)) - - connection = NWConnection(host: nwHost, port: nwPort, using: .tcp) - - return try await withCheckedThrowingContinuation { continuation in - connection?.stateUpdateHandler = { state in - switch state { - case .ready: - continuation.resume() - case let .failed(error): - continuation.resume(throwing: error) - case .cancelled: - continuation.resume(throwing: ClientError.connectionCancelled) - default: - break - } - } - connection?.start(queue: queue) - } - } - - func sendMessage(token: UInt32, data: Data) async throws { - guard let connection else { - throw ClientError.notConnected - } - let header = DebugServerMessageHeader( - token: token, - unknown: 0, - length: numericCast(data.count), - unknown2: 0 - ) - let headerData = withUnsafePointer(to: header) { - Data(bytes: UnsafeRawPointer($0), count: MemoryLayout.size) - } - try await send(data: headerData, on: connection) - guard header.length > 0 else { - return - } - try await send(data: data, on: connection) - } - - func receiveMessage() async throws -> (header: DebugServerMessageHeader, data: Data) { - guard let connection = connection else { - throw ClientError.notConnected - } - let headerData = try await receive( - length: MemoryLayout.size, - from: connection - ) - let header = headerData.withUnsafeBytes { bytes in - let buffer = bytes.bindMemory(to: UInt32.self) - return DebugServerMessageHeader( - token: buffer[0], - unknown: buffer[1], - length: buffer[2], - unknown2: buffer[3] - ) - } - guard header.length > 0 else { - return (header: header, data: Data()) - } - let payloadData = try await receive( - length: numericCast(header.length), - from: connection - ) - return (header: header, data: payloadData) - } - - func disconnect() { - connection?.cancel() - connection = nil - } - - private func send(data: Data, on connection: NWConnection) async throws { - return try await withCheckedThrowingContinuation { continuation in - connection.send(content: data, completion: .contentProcessed { error in - if let error { - continuation.resume(throwing: error) - } else { - continuation.resume() - } - }) - } - } - - private func receive(length: Int, from connection: NWConnection) async throws -> Data { - return try await withCheckedThrowingContinuation { continuation in - connection.receive(minimumIncompleteLength: length, maximumLength: length) { data, _, isComplete, error in - if let error { - continuation.resume(throwing: error) - } else if let data { - continuation.resume(returning: data) - } else { - continuation.resume(throwing: ClientError.noDataReceived) - } - } - } - } -} - -enum ClientError: Error { - case invalidURL - case notConnected - case connectionCancelled - case noDataReceived -} - -#endif diff --git a/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift b/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift new file mode 120000 index 00000000..14c281b3 --- /dev/null +++ b/Tests/OpenGraphCxxTests/DebugServer/DebugClient.swift @@ -0,0 +1 @@ +../../../Sources/OpenGraphShims/DebugClient.swift \ No newline at end of file From f6edc9ddba29f895ea98bdea73bb116699d0b534 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 5 Aug 2025 23:30:23 +0800 Subject: [PATCH 2/8] Update og_variant_has_internal_diagnostics --- Sources/OpenGraphCxx/DebugServer/DebugServer.mm | 5 +++-- Sources/OpenGraphCxx/DebugServer/interpose.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Sources/OpenGraphCxx/DebugServer/DebugServer.mm b/Sources/OpenGraphCxx/DebugServer/DebugServer.mm index beb49c54..2aa163e1 100644 --- a/Sources/OpenGraphCxx/DebugServer/DebugServer.mm +++ b/Sources/OpenGraphCxx/DebugServer/DebugServer.mm @@ -29,7 +29,8 @@ #include OG_EXTERN_C_BEGIN -bool os_variant_has_internal_diagnostics(const char *subsystem); +// DYLD_INTERPOSE does not work. Directly use the hook one here to match the semantics. +bool og_variant_has_internal_diagnostics(const char *subsystem); OG_EXTERN_C_END // MARK: DebugServer public API Implementation @@ -264,7 +265,7 @@ if ( (mode & OGDebugServerModeValid) && !OG::DebugServer::has_shared_server() -// && os_variant_has_internal_diagnostics("org.OpenSwiftUIProject.OpenGraph") + && og_variant_has_internal_diagnostics("org.OpenSwiftUIProject.OpenGraph") ) { _shared_server = new DebugServer(mode); } diff --git a/Sources/OpenGraphCxx/DebugServer/interpose.c b/Sources/OpenGraphCxx/DebugServer/interpose.c index 80d564a6..9f336f71 100644 --- a/Sources/OpenGraphCxx/DebugServer/interpose.c +++ b/Sources/OpenGraphCxx/DebugServer/interpose.c @@ -12,7 +12,7 @@ extern bool os_variant_has_internal_diagnostics(const char *subsystem); -bool os_variant_has_internal_diagnostics_og_hook(const char *subsystem) { +bool og_variant_has_internal_diagnostics(const char *subsystem) { if (strcmp(subsystem, "org.OpenSwiftUIProject.OpenGraph") == 0) { return true; } else { @@ -20,4 +20,4 @@ bool os_variant_has_internal_diagnostics_og_hook(const char *subsystem) { } } -DYLD_INTERPOSE(os_variant_has_internal_diagnostics_og_hook, os_variant_has_internal_diagnostics) +DYLD_INTERPOSE(og_variant_has_internal_diagnostics, os_variant_has_internal_diagnostics) From e45f09f48ca68a2fe6260984f6051125ebe67a35 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 00:06:10 +0800 Subject: [PATCH 3/8] Fix multi callback from stateUpdateHandler issue --- Sources/OpenGraphShims/DebugClient.swift | 43 +++++++++++-------- .../DebugServer/DebugServerTests.swift | 37 ++++++++++------ 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/Sources/OpenGraphShims/DebugClient.swift b/Sources/OpenGraphShims/DebugClient.swift index 24a28184..43486a31 100644 --- a/Sources/OpenGraphShims/DebugClient.swift +++ b/Sources/OpenGraphShims/DebugClient.swift @@ -4,42 +4,51 @@ #if canImport(Darwin) public import Foundation -import Network +public import Network #if canImport(OpenGraphCxx_Private) public import OpenGraphCxx_Private.DebugServer #endif +public struct ConnectionUpdates: AsyncSequence { + public typealias Element = NWConnection.State + + private let stream: AsyncStream + + fileprivate init(stream: AsyncStream) { + self.stream = stream + } + + public func makeAsyncIterator() -> AsyncStream.AsyncIterator { + stream.makeAsyncIterator() + } +} + @_spi(Debug) public final class DebugClient { private var connection: NWConnection? - private let queue = DispatchQueue(label: "opengraph.debugserver.client.queue") + private let queue = DispatchQueue(label: "org.openswiftuiproject.opengraph.debugclient") - public func connect(to url: URL) async throws { + public func connect(to url: URL) -> ConnectionUpdates { guard let host = url.host, let port = url.port else { - throw ClientError.invalidURL + return ConnectionUpdates(stream: AsyncStream { continuation in + continuation.yield(.failed(NWError.posix(.EINVAL))) + continuation.finish() + }) } - let nwHost = NWEndpoint.Host(host) let nwPort = NWEndpoint.Port(integerLiteral: UInt16(port)) - connection = NWConnection(host: nwHost, port: nwPort, using: .tcp) - - return try await withCheckedThrowingContinuation { continuation in + let stream = AsyncStream { continuation in connection?.stateUpdateHandler = { state in - switch state { - case .ready: - continuation.resume() - case let .failed(error): - continuation.resume(throwing: error) - case .cancelled: - continuation.resume(throwing: ClientError.connectionCancelled) - default: - break + continuation.yield(state) + if case .cancelled = state { + continuation.finish() } } connection?.start(queue: queue) } + return ConnectionUpdates(stream: stream) } public func sendMessage(token: UInt32, data: Data) async throws { diff --git a/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift b/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift index c1b17df8..4f1ffd94 100644 --- a/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift +++ b/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift @@ -24,26 +24,37 @@ struct DebugServerTests { @Test func commandTest() async throws { - let debugServer = OG.DebugServer([.valid]) + var debugServer = OG.DebugServer([.valid]) let cfURL = debugServer.copy_url() let url = try #require(cfURL) as URL let components = try #require(URLComponents(url: url, resolvingAgainstBaseURL: false)) let token = try #require(components.queryItems?.first { $0.name == "token" }?.value.flatMap { UInt32($0) }) debugServer.run(1) let client = DebugClient() - try await client.connect(to: url) - - for command in Command.allCases { - if command == .graphDescription { - continue + let updates = client.connect(to: url) + try await confirmation { confirm in + for try await update in updates { + switch update { + case .ready: + confirm() + for command in Command.allCases { + if command == .graphDescription { + continue + } + try await client.sendMessage( + token: token, + data: data(for: command) + ) + let (_, responseData) = try await client.receiveMessage() + let response = try #require(String(data: responseData, encoding: .utf8)) + #expect(response == command.rawValue) + } + debugServer.shutdown() + // TODO: The shutdown should close the connection, but it does not for OGDebugServer currently. + default: + break + } } - try await client.sendMessage( - token: token, - data: data(for: command) - ) - let (_, responseData) = try await client.receiveMessage() - let response = try #require(String(data: responseData, encoding: .utf8)) - #expect(response == command.rawValue) } } } From dcbc002e3f872f1eeb37b915fd0d704002adda6a Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 00:25:45 +0800 Subject: [PATCH 4/8] Add public Command type --- Sources/OpenGraphShims/DebugClient.swift | 10 ++++++++++ .../DebugServer/DebugServerTests.swift | 8 +------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Sources/OpenGraphShims/DebugClient.swift b/Sources/OpenGraphShims/DebugClient.swift index 43486a31..25f6a48d 100644 --- a/Sources/OpenGraphShims/DebugClient.swift +++ b/Sources/OpenGraphShims/DebugClient.swift @@ -26,9 +26,19 @@ public struct ConnectionUpdates: AsyncSequence { @_spi(Debug) public final class DebugClient { + public enum Command: String, CaseIterable, Hashable { + case graphDescription = "graph/description" + case profilerStart = "profiler/start" + case profilerStop = "profiler/stop" + case profilerReset = "profiler/reset" + case profilerMark = "profiler/mark" + } + private var connection: NWConnection? private let queue = DispatchQueue(label: "org.openswiftuiproject.opengraph.debugclient") + public init() {} + public func connect(to url: URL) -> ConnectionUpdates { guard let host = url.host, let port = url.port else { return ConnectionUpdates(stream: AsyncStream { continuation in diff --git a/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift b/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift index 4f1ffd94..57f715b8 100644 --- a/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift +++ b/Tests/OpenGraphCxxTests/DebugServer/DebugServerTests.swift @@ -9,13 +9,7 @@ import Testing @MainActor struct DebugServerTests { - private enum Command: String, CaseIterable, Hashable { - case graphDescription = "graph/description" - case profilerStart = "profiler/start" - case profilerStop = "profiler/stop" - case profilerReset = "profiler/reset" - case profilerMark = "profiler/mark" - } + typealias Command = DebugClient.Command private func data(for command: Command) throws -> Data{ let command = ["command": command.rawValue] From 6680fc2c531d8be26b96ffae02ee1ca56813fb1e Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 01:54:49 +0800 Subject: [PATCH 5/8] Add AG interpose support --- Sources/OpenGraphCxx/DebugServer/interpose.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/OpenGraphCxx/DebugServer/interpose.c b/Sources/OpenGraphCxx/DebugServer/interpose.c index 9f336f71..087c6c33 100644 --- a/Sources/OpenGraphCxx/DebugServer/interpose.c +++ b/Sources/OpenGraphCxx/DebugServer/interpose.c @@ -15,6 +15,8 @@ extern bool os_variant_has_internal_diagnostics(const char *subsystem); bool og_variant_has_internal_diagnostics(const char *subsystem) { if (strcmp(subsystem, "org.OpenSwiftUIProject.OpenGraph") == 0) { return true; + } else if (strcmp(subsystem, "com.apple.AttributeGraph") == 0) { + return true; } else { return os_variant_has_internal_diagnostics(subsystem); } From 4485c2b92e736badf0e82b36fa3ef31cdc3c2285 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 02:15:26 +0800 Subject: [PATCH 6/8] Fix DebugServerMessageHeader --- Sources/OpenGraphShims/DebugClient.swift | 4 ---- .../DebugServer/DebugServerMessageHeader.swift | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) create mode 120000 Tests/OpenGraphCxxTests/DebugServer/DebugServerMessageHeader.swift diff --git a/Sources/OpenGraphShims/DebugClient.swift b/Sources/OpenGraphShims/DebugClient.swift index 25f6a48d..ab9181ff 100644 --- a/Sources/OpenGraphShims/DebugClient.swift +++ b/Sources/OpenGraphShims/DebugClient.swift @@ -6,10 +6,6 @@ public import Foundation public import Network -#if canImport(OpenGraphCxx_Private) -public import OpenGraphCxx_Private.DebugServer -#endif - public struct ConnectionUpdates: AsyncSequence { public typealias Element = NWConnection.State diff --git a/Tests/OpenGraphCxxTests/DebugServer/DebugServerMessageHeader.swift b/Tests/OpenGraphCxxTests/DebugServer/DebugServerMessageHeader.swift new file mode 120000 index 00000000..abce3da1 --- /dev/null +++ b/Tests/OpenGraphCxxTests/DebugServer/DebugServerMessageHeader.swift @@ -0,0 +1 @@ +../../../Sources/OpenGraphShims/DebugServerMessageHeader.swift \ No newline at end of file From 71b6cd8ee5f1fc0ea2075aa0fce4d1512b94c648 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 02:07:22 +0800 Subject: [PATCH 7/8] Fix platform API issue --- Package.resolved | 2 +- Package.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.resolved b/Package.resolved index 6ff5c87a..34c805da 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "33172a013ea78db9fbfb2be84e0c38eb0aa2efdaf6e752b088afb5349346644a", + "originHash" : "e6d3adb6e1120d8ec888e92e5977e2ce73440a10c3e2f3088b9fb458e554f65f", "pins" : [ { "identity" : "darwinprivateframeworks", diff --git a/Package.swift b/Package.swift index 29f4c244..1f355eca 100644 --- a/Package.swift +++ b/Package.swift @@ -262,6 +262,7 @@ if attributeGraphCondition { } } else { openGraphShimsTarget.dependencies.append("OpenGraph") + package.platforms = [.iOS(.v13), .macOS(.v10_15), .macCatalyst(.v13), .tvOS(.v13), .watchOS(.v5)] } let compatibilityTestCondition = envEnable("OPENGRAPH_COMPATIBILITY_TEST") From edbc46bdc1eef0daf35ecfb1e3b0dc308a06fbc7 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 Aug 2025 02:13:16 +0800 Subject: [PATCH 8/8] Fix os_variant_has_internal_diagnostics link issue on Linux --- Sources/OpenGraphCxx/DebugServer/interpose.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Sources/OpenGraphCxx/DebugServer/interpose.c b/Sources/OpenGraphCxx/DebugServer/interpose.c index 087c6c33..637bd2bc 100644 --- a/Sources/OpenGraphCxx/DebugServer/interpose.c +++ b/Sources/OpenGraphCxx/DebugServer/interpose.c @@ -2,15 +2,14 @@ // interpose.c // OpenGraphCxx +#include #include "stdio.h" #include "stdbool.h" #include "string.h" -#define DYLD_INTERPOSE(_replacement,_replacee) \ - __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \ - __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; - +#if OG_TARGET_OS_DARWIN extern bool os_variant_has_internal_diagnostics(const char *subsystem); +#endif bool og_variant_has_internal_diagnostics(const char *subsystem) { if (strcmp(subsystem, "org.OpenSwiftUIProject.OpenGraph") == 0) { @@ -18,8 +17,18 @@ bool og_variant_has_internal_diagnostics(const char *subsystem) { } else if (strcmp(subsystem, "com.apple.AttributeGraph") == 0) { return true; } else { + #if OG_TARGET_OS_DARWIN return os_variant_has_internal_diagnostics(subsystem); + #else + return false; + #endif } } +#if OG_TARGET_OS_DARWIN +#define DYLD_INTERPOSE(_replacement,_replacee) \ + __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \ + __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; + DYLD_INTERPOSE(og_variant_has_internal_diagnostics, os_variant_has_internal_diagnostics) +#endif