Xcode、clang、c++ stdlib:Swift 使用系统库的包,构建失败,未找到 'stdexcept' 文件

Xcode, clang, c++ stdlib: Swift Package using a system library, build fails with 'stdexcept' file not found

我正在编写一个可执行文件 Swift 包,我需要在其中使用系统库(用 C++ 编写)。

AFAIK 我正确编写了 package.swift、module.modulemap 和伞头文件。

当我在 main.swift 文件中为库添加 import 时,出现错误 'stdexcept' file not found。错误来自系统库的 public 头文件之一中的 #include <stdexcept>

目前运行:

我认为问题与 Xcode 的命令行工具有关,但我该如何解决?

Package.swift

// swift-tools-version:5.5
import PackageDescription

let package = Package(
    name: "GeodesicApp",
    platforms: [.macOS(.v11)],
    dependencies: [
    ],
    targets: [
      .systemLibrary(name: "geographiclib",
                     pkgConfig: "geographiclib",
                     providers: [
                      .brew(["geographiclib"])
                     ]
                    ),
        .executableTarget(
            name: "GeodesicApp",
            dependencies: ["geographiclib"])
    ]
)

module.modulemap

module geographiclib {
  umbrella header "geographiclib.h"
  export *
  link "geographiclib"
}

伞头(geographiclib.h)

#include <GeographicLib/Config.h>
#include <GeographicLib/Geodesic.hpp>

main.swift

import geographiclib     // error: 'stdexcept' file not found

...  // 

错误。

回答我自己的问题。 我只能通过围绕系统库创建一个 C 包装程序包来获得一个可行的解决方案;然后,该 C 包装器包又被另一个 Swift 包装器包装以公开 'Swifty-style' 代码 - 我无法获得包含所有必需部分的单个包。

我的工作解决方案如下...

包:CGeographicLib

系统库的 C 包装器的文件夹结构是:

.
├── Package.swift
├── README.md
└── Sources
    ├── CGeographicLib
    │   ├── CGeodesic.cpp
    │   └── include
    │       └── CGeodesic.h
    └── geographiclib
        ├── geographiclib.h
        └── module.modulemap

已更新Package.swift

import PackageDescription

let package = Package(
    name: "CGeographicLib",
    platforms: [.macOS(.v11)],
    products: [
      .library(name: "CGeographicLib", targets: ["CGeographicLib"])
    ],
    targets: [
      .systemLibrary(name: "geographiclib",
                     pkgConfig: "geographiclib",
                     providers: [
                      .brew(["geographiclib"])
                     ]),
      .target(name: "CGeographicLib", dependencies: ["geographiclib"])
    ],
    cxxLanguageStandard: .cxx20
)

我添加了platforms: [.macOS(.v11)]因为最新版本的GeographicLib系统库只支持macOS v11或更高版本

我正在使用的系统库有一些 C++11 扩展,我添加了语言标准 .cxx20,但这同样可以是 .cxx11,它应该仍然适用于系统我正在使用的图书馆。

已更新module.modulemap

module geographiclib [system] {
  umbrella header "geographiclib.h"
  link "geographiclib"
  export *
}

伞头,geographiclib.h不变。

对于新的 C 包装器元素: CGeodesic.h:

#ifdef __cplusplus
extern "C"  {
#endif

double geoLibInverse(double lat1, double lon1, double lat2, double lon2);

#ifdef __cplusplus
}
#endif

CGeodesic.cpp:

#include "include/CGeodesic.h"
#include "../../geographiclib/geographiclib.h"

double geoLibInverse(double lat1, double lon1, double lat2, double lon2) {
  
  using namespace std;
  using namespace GeographicLib;
  
  Geodesic geod(Constants::WGS84_a(), Constants::WGS84_f());
  double s12;
  geod.Inverse(lat1, lon1, lat2, lon2, s12);
    
  return s12;
}

包:SwiftyGeographicLib

使用 C 包装程序包的 Swift 包的文件夹结构是:

.
├── Package.swift
├── README.md
├── Sources
│   └── SwiftyGeographicLib
│       └── Geodesic.swift
└── Tests
    └── SwiftyGeographicLibTests
        └── SwiftyGeographicLibTests.swift

Package.swift:

import PackageDescription

let package = Package(
    name: "SwiftyGeographicLib",
    platforms: [.macOS(.v11)],
    products: [
        .library(
            name: "SwiftyGeographicLib",
            targets: ["SwiftyGeographicLib"]),
    ],
    dependencies: [
      .package(name: "CGeographicLib",
               url: "/Users/kieran/codeProjects/z.TestProjects/SPM/CGeographicLib",
               branch: "master")
    ],
    targets: [
        .target(
            name: "SwiftyGeographicLib",
            dependencies: ["CGeographicLib"]),
        .testTarget(
            name: "SwiftyGeographicLibTests",
            dependencies: ["SwiftyGeographicLib"]),
    ]
)

此示例中的包依赖项指向本地包 - 我同样可以在 GitHub.

上上传并创建版本标签

Geodesic.swift:

import Foundation
import CGeographicLib

public func geodesicInverse(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {
  
  return geoLibInverse(lat1, lon1, lat2, lon2)
}