diff --git a/.gitignore b/.gitignore index 108a40f..22aa1c2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ xcuserdata project.xcworkspace /build /Carthage/Build +/.build \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index e6b6a1f..6afa992 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,12 @@ Not supported by design: keep-alive connections and HTTPS. ## Build & Test -There is no Swift Package Manager `Package.swift`; the build is driven entirely by `GCDWebServer.xcodeproj` (and CocoaPods for consumers). +The library can be built three ways: the Xcode project (`GCDWebServer.xcodeproj`), CocoaPods (`GCDWebServer.podspec`), and Swift Package Manager (`Package.swift`). All three compile the same source files in place — see "Swift Package Manager layout" below for how the SPM `include/` directories relate to the real sources. + +Build via SPM: +```sh +swift build # builds GCDWebServer, GCDWebUploader, GCDWebDAVServer +``` Schemes (`xcodebuild -list -project GCDWebServer.xcodeproj`): - `GCDWebServer (Mac|iOS|tvOS)` — the static library / framework per platform. @@ -71,6 +76,17 @@ Handlers run on **arbitrary GCD threads**, so handler code must be thread-safe a - `iOS/`, `tvOS/` — Swift example apps (`AppDelegate.swift`, `ViewController.swift`). - `Frameworks/` — umbrella header (`GCDWebServers.h`), module map, and the XCTest target source (`Tests.m`). +## Swift Package Manager layout + +SPM needs each target's public headers in a single directory, but the real headers live spread across `GCDWebServer/Core`, `GCDWebServer/Requests`, and `GCDWebServer/Responses`. To support SPM **without moving any files** (keeping the Xcode project and CocoaPods working), the public headers are surfaced through symlinks: + +- `GCDWebServer/include/*.h` are **symlinks** to the real public headers (everything except the private `GCDWebServerPrivate.h`, which is deliberately not linked so it stays out of the public module). `GCDWebUploader/include/GCDWebUploader.h` works the same way. +- `GCDWebServer/include/module.modulemap` is hand-written with `umbrella "."`. This is required: if SPM auto-generated the module map it would pick `include/GCDWebServer.h` as an umbrella *header* (name matches the module) and only export what that one header imports, hiding the request/response subclasses. The umbrella *directory* exports them all. +- All cross-header imports inside the library (including the framework umbrella `Frameworks/GCDWebServers.h`) use quoted form (`#import "GCDWebServerRequest.h"`), not framework-style (`#import `); the quoted form is what lets the flat `include/` symlink directory resolve them. Keep new imports quoted. +- `GCDWebUploader.bundle` is a `.copy` resource. Because SPM nests it inside a generated module bundle, `GCDWebUploader.m` has a `#if SWIFT_PACKAGE` branch that finds it via `SWIFTPM_MODULE_BUNDLE` instead of `bundleForClass:`. + +When adding or renaming a public header, add/remove the matching symlink in the relevant `include/` directory or it won't be visible to SPM consumers. `libxml2` (for WebDAV) needs no special SPM include flag — the macOS/iOS SDK ships a module map that resolves `` automatically. + ## Consumer linking requirements When integrated manually (not via CocoaPods), consuming apps must link `libz`, and WebDAV additionally needs `libxml2` with `$(SDKROOT)/usr/include/libxml2` on the header search path. The `GCDWebServer.podspec` defines three subspecs: `Core` (default), `WebDAV`, and `WebUploader`. diff --git a/GCDWebServer/include/GCDWebServer.h b/GCDWebServer/include/GCDWebServer.h new file mode 120000 index 0000000..a2edc12 --- /dev/null +++ b/GCDWebServer/include/GCDWebServer.h @@ -0,0 +1 @@ +../Core/GCDWebServer.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerConnection.h b/GCDWebServer/include/GCDWebServerConnection.h new file mode 120000 index 0000000..e88251a --- /dev/null +++ b/GCDWebServer/include/GCDWebServerConnection.h @@ -0,0 +1 @@ +../Core/GCDWebServerConnection.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerDataRequest.h b/GCDWebServer/include/GCDWebServerDataRequest.h new file mode 120000 index 0000000..b06dfac --- /dev/null +++ b/GCDWebServer/include/GCDWebServerDataRequest.h @@ -0,0 +1 @@ +../Requests/GCDWebServerDataRequest.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerDataResponse.h b/GCDWebServer/include/GCDWebServerDataResponse.h new file mode 120000 index 0000000..a02e8d6 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerDataResponse.h @@ -0,0 +1 @@ +../Responses/GCDWebServerDataResponse.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerErrorResponse.h b/GCDWebServer/include/GCDWebServerErrorResponse.h new file mode 120000 index 0000000..ce0e19d --- /dev/null +++ b/GCDWebServer/include/GCDWebServerErrorResponse.h @@ -0,0 +1 @@ +../Responses/GCDWebServerErrorResponse.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerFileRequest.h b/GCDWebServer/include/GCDWebServerFileRequest.h new file mode 120000 index 0000000..b8b68d2 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerFileRequest.h @@ -0,0 +1 @@ +../Requests/GCDWebServerFileRequest.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerFileResponse.h b/GCDWebServer/include/GCDWebServerFileResponse.h new file mode 120000 index 0000000..e43cfc8 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerFileResponse.h @@ -0,0 +1 @@ +../Responses/GCDWebServerFileResponse.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerFunctions.h b/GCDWebServer/include/GCDWebServerFunctions.h new file mode 120000 index 0000000..4c69a7b --- /dev/null +++ b/GCDWebServer/include/GCDWebServerFunctions.h @@ -0,0 +1 @@ +../Core/GCDWebServerFunctions.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerHTTPStatusCodes.h b/GCDWebServer/include/GCDWebServerHTTPStatusCodes.h new file mode 120000 index 0000000..e521455 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerHTTPStatusCodes.h @@ -0,0 +1 @@ +../Core/GCDWebServerHTTPStatusCodes.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerMultiPartFormRequest.h b/GCDWebServer/include/GCDWebServerMultiPartFormRequest.h new file mode 120000 index 0000000..24478ec --- /dev/null +++ b/GCDWebServer/include/GCDWebServerMultiPartFormRequest.h @@ -0,0 +1 @@ +../Requests/GCDWebServerMultiPartFormRequest.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerRequest.h b/GCDWebServer/include/GCDWebServerRequest.h new file mode 120000 index 0000000..2302931 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerRequest.h @@ -0,0 +1 @@ +../Core/GCDWebServerRequest.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerResponse.h b/GCDWebServer/include/GCDWebServerResponse.h new file mode 120000 index 0000000..55c7a8b --- /dev/null +++ b/GCDWebServer/include/GCDWebServerResponse.h @@ -0,0 +1 @@ +../Core/GCDWebServerResponse.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerStreamedResponse.h b/GCDWebServer/include/GCDWebServerStreamedResponse.h new file mode 120000 index 0000000..264c9d5 --- /dev/null +++ b/GCDWebServer/include/GCDWebServerStreamedResponse.h @@ -0,0 +1 @@ +../Responses/GCDWebServerStreamedResponse.h \ No newline at end of file diff --git a/GCDWebServer/include/GCDWebServerURLEncodedFormRequest.h b/GCDWebServer/include/GCDWebServerURLEncodedFormRequest.h new file mode 120000 index 0000000..0d719fc --- /dev/null +++ b/GCDWebServer/include/GCDWebServerURLEncodedFormRequest.h @@ -0,0 +1 @@ +../Requests/GCDWebServerURLEncodedFormRequest.h \ No newline at end of file diff --git a/GCDWebServer/include/module.modulemap b/GCDWebServer/include/module.modulemap new file mode 100644 index 0000000..f67e445 --- /dev/null +++ b/GCDWebServer/include/module.modulemap @@ -0,0 +1,4 @@ +module GCDWebServer { + umbrella "." + export * +} diff --git a/GCDWebUploader/GCDWebUploader.m b/GCDWebUploader/GCDWebUploader.m index 086a565..fef723b 100644 --- a/GCDWebUploader/GCDWebUploader.m +++ b/GCDWebUploader/GCDWebUploader.m @@ -66,7 +66,12 @@ NS_ASSUME_NONNULL_END - (instancetype)initWithUploadDirectory:(NSString*)path { if ((self = [super init])) { +#if SWIFT_PACKAGE + // When built with Swift Package Manager, resources live inside the auto-generated module bundle + NSString* bundlePath = [SWIFTPM_MODULE_BUNDLE pathForResource:@"GCDWebUploader" ofType:@"bundle"]; +#else NSString* bundlePath = [[NSBundle bundleForClass:[GCDWebUploader class]] pathForResource:@"GCDWebUploader" ofType:@"bundle"]; +#endif if (bundlePath == nil) { return nil; } diff --git a/GCDWebUploader/include/GCDWebUploader.h b/GCDWebUploader/include/GCDWebUploader.h new file mode 120000 index 0000000..6e86f30 --- /dev/null +++ b/GCDWebUploader/include/GCDWebUploader.h @@ -0,0 +1 @@ +../GCDWebUploader.h \ No newline at end of file diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..546ac19 --- /dev/null +++ b/Package.swift @@ -0,0 +1,55 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "GCDWebServer", + platforms: [ + .iOS(.v16), + .tvOS(.v16), + .macOS(.v12), + ], + products: [ + .library(name: "GCDWebServer", targets: ["GCDWebServer"]), + .library(name: "GCDWebUploader", targets: ["GCDWebUploader"]), + .library(name: "GCDWebDAVServer", targets: ["GCDWebDAVServer"]), + ], + targets: [ + .target( + name: "GCDWebServer", + path: "GCDWebServer", + // Public headers are exposed via symlinks in include/ so that GCDWebServerPrivate.h stays private. + publicHeadersPath: "include", + cSettings: [ + // Source files import sibling headers across these subdirectories with quoted #imports. + .headerSearchPath("Core"), + .headerSearchPath("Requests"), + .headerSearchPath("Responses"), + ], + linkerSettings: [ + .linkedLibrary("z"), + .linkedFramework("CoreServices", .when(platforms: [.iOS, .tvOS])), + .linkedFramework("CFNetwork", .when(platforms: [.iOS, .tvOS])), + .linkedFramework("SystemConfiguration", .when(platforms: [.macOS])), + ] + ), + .target( + name: "GCDWebUploader", + dependencies: ["GCDWebServer"], + path: "GCDWebUploader", + exclude: [".DS_Store"], + resources: [ + .copy("GCDWebUploader.bundle"), + ], + publicHeadersPath: "include" + ), + .target( + name: "GCDWebDAVServer", + dependencies: ["GCDWebServer"], + path: "GCDWebDAVServer", + publicHeadersPath: ".", + linkerSettings: [ + .linkedLibrary("xml2"), + ] + ), + ] +) diff --git a/README.md b/README.md index 72e527e..859c672 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,12 @@ github "swisspol/GCDWebServer" ~> 3.2.5 Then run `$ carthage update` and add the generated frameworks to your Xcode projects (see [Carthage instructions](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application)). +You can also use [Swift Package Manager](https://www.swift.org/package-manager/). Add GCDWebServer as a dependency in your `Package.swift`: +```swift +.package(url: "https://github.com/swisspol/GCDWebServer.git", from: "3.5.4") +``` +Then add the product(s) you need to your target's dependencies: `"GCDWebServer"` for the core server, `"GCDWebUploader"` for the web uploader, and/or `"GCDWebDAVServer"` for the WebDAV server. In Xcode, use File > Add Package Dependencies and enter the repository URL. + Help & Support ==============