This article will help you create your first Swift Package. We'll use the popular C ++ linear algebra library, Eigen, to demonstrate how you can access it from Swift. For simplicity, we are only porting a subset of Eigen's capabilities.
Difficulties of interaction between C ++ and Swift
C++ Swift . , . 2 API --. C++ Swift (, Scapix, Gluecodium). , , , . , , , , . : .
Swift interop C Objective-C . , C++ interop . C++ – . , C++ Swift . , . , Swift , template template variadic . , Swift , ( C++20 concepts). , C++ .
, C++ , !
++ Eigen, . , . : , Objective-C , Swift.
Objective-C API Swift – C++ Xcode bridging header. , , . , . Swift Swift Package Manager (SPM). , SPM , - . , SPM . Xcode 12, Swift playground.
SPM SwiftyEigen. float . Matrix , . GitHub.
SPM :
foo@bar:~$ mkdir SwiftyEigen && cd SwiftyEigen
foo@bar:~/SwiftyEigen$ swift package init
foo@bar:~/SwiftyEigen$ git init && git add . && git commit -m 'Initial commit'
, (Eigen) :
foo@bar:~/SwiftyEigen$ git submodule add https://gitlab.com/libeigen/eigen Sources/CPP
foo@bar:~/SwiftyEigen$ cd Sources/CPP && git checkout 3.3.9
, Package.swift:
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "SwiftyEigen",
products: [
.library(
name: "SwiftyEigen",
targets: ["ObjCEigen", "SwiftyEigen"]
)
],
dependencies: [],
targets: [
.target(
name: "ObjCEigen",
path: "Sources/ObjC",
cxxSettings: [
.headerSearchPath("../CPP/"),
.define("EIGEN_MPL2_ONLY")
]
),
.target(
name: "SwiftyEigen",
dependencies: ["ObjCEigen"],
path: "Sources/Swift"
)
]
)
. Swift Objective-C Swift . SPM . ObjCEigen Sources/ObjC, Sources/CPP header search paths, EIGEN_MPL2_ONLY, MPL2 Eigen. SwiftyEigen ObjCEigen Sources/Swift.
Objective-C Sources/ObjCEigen/include:
#pragma once
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface EIGMatrix: NSObject
@property (readonly) ptrdiff_t rows;
@property (readonly) ptrdiff_t cols;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)matrixWithZeros:(ptrdiff_t)rows cols:(ptrdiff_t)cols
NS_SWIFT_NAME(zeros(rows:cols:));
+ (instancetype)matrixWithIdentity:(ptrdiff_t)rows cols:(ptrdiff_t)cols
NS_SWIFT_NAME(identity(rows:cols:));
- (float)valueAtRow:(ptrdiff_t)row col:(ptrdiff_t)col
NS_SWIFT_NAME(value(row:col:));
- (void)setValue:(float)value row:(ptrdiff_t)row col:(ptrdiff_t)col
NS_SWIFT_NAME(setValue(_:row:col:));
- (EIGMatrix*)inverse;
@end
NS_ASSUME_NONNULL_END
readonly rows cols, , , .
Sources/ObjCEigen:
#import "EIGMatrix.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#import <Eigen/Dense>
#pragma clang diagnostic pop
#import <iostream>
using Matrix = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
using Map = Eigen::Map<Matrix>;
@interface EIGMatrix ()
@property (readonly) Matrix matrix;
- (instancetype)initWithMatrix:(Matrix)matrix;
@end
@implementation EIGMatrix
- (instancetype)initWithMatrix:(Matrix)matrix {
self = [super init];
_matrix = matrix;
return self;
}
- (ptrdiff_t)rows {
return _matrix.rows();
}
- (ptrdiff_t)cols {
return _matrix.cols();
}
+ (instancetype)matrixWithZeros:(ptrdiff_t)rows cols:(ptrdiff_t)cols {
return [[EIGMatrix alloc] initWithMatrix:Matrix::Zero(rows, cols)];
}
+ (instancetype)matrixWithIdentity:(ptrdiff_t)rows cols:(ptrdiff_t)cols {
return [[EIGMatrix alloc] initWithMatrix:Matrix::Identity(rows, cols)];
}
- (float)valueAtRow:(ptrdiff_t)row col:(ptrdiff_t)col {
return _matrix(row, col);
}
- (void)setValue:(float)value row:(ptrdiff_t)row col:(ptrdiff_t)col {
_matrix(row, col) = value;
}
- (instancetype)inverse {
const Matrix result = _matrix.inverse();
return [[EIGMatrix alloc] initWithMatrix:result];
}
- (NSString*)description {
std::stringstream buffer;
buffer << _matrix;
const std::string string = buffer.str();
return [NSString stringWithUTF8String:string.c_str()];
}
@end
Objective-C Swift Sources/Swift ( Swift Forums):
@_exported import ObjCEigen
API:
extension EIGMatrix {
public subscript(row: Int, col: Int) -> Float {
get { return value(row: row, col: col) }
set { setValue(newValue, row: row, col: col) }
}
}
:
import SwiftyEigen
// Create a new 3x3 identity matrix
let matrix = EIGMatrix.identity(rows: 3, cols: 3)
// Change a specific value
let row = 0
let col = 1
matrix[row, col] = -2
// Calculate the inverse of a matrix
let inverseMatrix = matrix.inverse()
, , , SwiftyEigen. 2x2 . , iOS Xcode, Finder project navigator, , SwiftyEigen . UI :
!