Créer un package Swift basé sur la bibliothèque C ++

Photo de Kira auf der Heide sur Unsplash
Photo de Kira auf der Heide sur Unsplash

Cet article vous aidera à créer votre premier package Swift. Nous utiliserons la célèbre bibliothèque d'algèbre linéaire C ++, Eigen, pour montrer comment vous pouvez y accéder depuis Swift. Pour plus de simplicité, nous ne portons qu'un sous-ensemble des capacités d'Eigen.






Difficultés d'interaction entre C ++ et Swift

C++ Swift . , . 2 API --. C++ Swift (, ScapixGluecodium). , , , . , , , , . : .





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 :





 GitHub.






  • SwiftyEigen Project





  • Eigen Linear Algebra Library





  • Swift Package Manager





  • C/Swift Interop





  • Objective-C/Swift Interop





  • Objective-C Bridging Header





  • C++/Swift Interop Manifest





  • C++20 Concepts





  • Automatic Bridging Solutions





!








All Articles