Guidance for working with swift-netcdf, a Swift wrapper for the NetCDF C library with type-safe APIs and proper resource management
Guidance for working with swift-netcdf, a Swift wrapper for the NetCDF (Network Common Data Form) C library.
swift-netcdf uses a three-layer structure:
1. **netcdf-c (C library)**: Git submodule at `Sources/CNetCDF/netcdf-c`
- Official Unidata netCDF C library built from source using CMake
- Configured for minimal build (netCDF-3 only, no HDF5/DAP/NCZarr)
2. **CNetCDF (C module)**: Swift Package Manager C target at `Sources/CNetCDF`
- Module map at `Sources/CNetCDF/module.modulemap` defines the C module
- Built library artifacts in `Sources/CNetCDF/lib/` (generated, not in git)
- Exposes C headers to Swift
3. **NetCDF (Swift wrapper)**: Swift library at `Sources/NetCDF/`
- Type-safe Swift interfaces (NetCDFFile, NetCDFMode, NetCDFError)
- Swift-like APIs with computed properties, URL-based methods, and proper error handling
- Manages resource lifecycle
When working with this project for the first time:
1. Initialize git submodules to fetch the netcdf-c library:
```bash
git submodule update --init --recursive
```
2. Build the netcdf-c library (creates headers and static library):
```bash
./scripts/build-netcdf.sh
```
3. Build the Swift package:
```bash
swift build
```
4. Run tests to verify setup:
```bash
swift test
```
The netCDF C library must be built before the Swift package can compile. The build script:
**Critical**: If you update platform versions in Package.swift (e.g., macOS 15 to 26), you MUST rebuild the C library to avoid runtime crashes:
```bash
rm -rf .build/netcdf-build Sources/CNetCDF/lib
./scripts/build-netcdf.sh
swift build
```
The CNetCDF target uses specific configuration:
The wrapper uses separate types for different operations:
**AccessMode** (opening existing files):
**CreationMode** (creating new files):
**Convenience initializers**:
```swift
// Opening existing files
init(reading: URL) throws // Read-only
init(writing: URL) throws // Read-write
init(opening: URL, mode: AccessMode) // Explicit mode
// Creating new files
init(creating: URL) throws // Overwrite if exists
init(creating: URL, mode: CreationMode) // Explicit creation mode
```
This design prevents API misuse at compile time (e.g., passing creation mode to open operation).
Follow these patterns when extending the API:
1. **Computed properties with throwing getters** instead of `getX()` methods:
```swift
let count = try file.dimensionCount // Not getDimensionCount()
```
2. **URL-based APIs as primary** with String convenience:
```swift
init(reading: URL) throws // Primary
init(reading: String) throws // Convenience wrapper
```
3. **Equatable error types** for testability:
```swift
public enum NetCDFError: Error, CustomStringConvertible, Equatable {
case fileNotFound(path: String)
// ... enables pattern matching in tests
}
```
4. **Sendable conformance** for Swift 6 concurrency
NetCDFError provides:
Provide both manual and automatic cleanup:
**Manual**:
```swift
let file = try NetCDFFile(reading: url)
defer { try? file.close() }
// ... use file
```
**Automatic with scoped helpers**:
```swift
let result = try NetCDFFile.withFile(reading: url) { file in
try file.dimensionCount
}
```
The `withFile` methods ensure files are always closed, propagating errors correctly.
This project uses **Swift Testing** (built into Swift 6.2+):
Example:
```swift
import Testing
@testable import NetCDF
@Suite("NetCDF File Operations")
struct NetCDFTests {
@Test("Create NetCDF file with URL")
func createFileWithURL() throws {
// Test implementation
}
}
```
Run tests with `swift test`.
`NetCDFFile` is designed for single-threaded use. The underlying C library is not thread-safe for concurrent operations on the same file handle.
When using in concurrent contexts:
1. **One file per task**: Each concurrent task should open its own file handle
2. **Synchronize access**: If sharing a handle, use Swift actors or locks
3. **Sendable conformance**: Mode structs are Sendable for cross-task usage
**Cause**: Deployment target mismatch between C library build and Swift package.
**Solution**: Rebuild the C library:
```bash
rm -rf .build/netcdf-build Sources/CNetCDF/lib
./scripts/build-netcdf.sh
swift build
```
**Cause**: Xcode requires at least one source file per target.
**Solution**: Ensure `Sources/CNetCDF/dummy.c` exists and is listed in Package.swift `sources: ["dummy.c"]`.
**Solution**:
1. Run `./scripts/build-netcdf.sh` successfully
2. Verify `Sources/CNetCDF/lib/include/netcdf.h` exists
3. Verify `Sources/CNetCDF/module.modulemap` exists with correct header paths
Check:
These versions provide Swift Testing framework and latest concurrency features.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/swift-netcdf-wrapper-development/raw