我可以使用Swift包管理器在同一个Swift包中混合使用C++和Swift吗?

jdg4fx2g  于 2023-09-29  发布在  Swift
关注(0)|答案(2)|浏览(152)

我想用C写一个模块,用C写一些在Swift中可以访问的函数。
我有点困惑,因为无论我做什么,SPM坚持试图编译C
代码,就好像它是Objective-C一样,当然它找不到正确的头。
这是我的尝试。
源目录结构:

  1. Sources
  2. |
  3. +-CxxModule
  4. | |
  5. | +-include
  6. | | |
  7. | | +-CxxModule.hpp
  8. | |
  9. | +-CxxModule.cpp
  10. |
  11. +-SwiftModule
  12. |
  13. +-SwiftModule.swift

清单Package.swift如下:

  1. // swift-tools-version: 5.6
  2. import PackageDescription
  3. let package = Package(
  4. name: "CxxLibrary",
  5. products: [
  6. .library(
  7. name: "CxxLibrary",
  8. targets: ["SwiftModule"]),
  9. ],
  10. dependencies: [
  11. ],
  12. targets: [
  13. .target(
  14. name: "CxxModule",
  15. dependencies: []),
  16. .target(
  17. name: "SwiftModule",
  18. dependencies: ["CxxModule"],
  19. path: "Sources/SwiftModule"
  20. ),
  21. ]
  22. )

CxxModule.hpp如下:

  1. #ifndef CxxModule_hpp
  2. #define CxxModule_hpp
  3. #include <iostream>
  4. extern "C" void printHello();
  5. #endif /* CxxModule_hpp */

CxxModule.cpp如下:

  1. #include "CxxModule.hpp"
  2. void printHello() {
  3. // use something from the standard library to make sure
  4. // c++ is really being used
  5. std::cout << "Hello, world!" << std::endl;
  6. }

最后,SwiftModule.swift

  1. import CxxModule

我错过了什么?有没有办法告诉SPM这个模块应该是C的?或者这只是目前不受支持?
注意:如果我删除Swift目标,C
编译得很好。

jqjz2hbq

jqjz2hbq1#

我能够解决这个问题。答案是“是的”,只要暴露给Swift的头在纯C中可读。
首先,我将所有特定于C++的代码(特别是引用标准库的头文件)移到源cpp文件中:

  1. #include <iostream>
  2. #include "CxxModule.hpp"
  3. void printHello() {
  4. // use something from the standard library to make sure
  5. // c++ is really being used
  6. std::cout << "Hello, world!" << std::endl;
  7. }

其次,我添加了宏,使标题在C和C++中都可读:

  1. #ifndef CxxModule_hpp
  2. #define CxxModule_hpp
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. void printHello();
  7. #ifdef __cplusplus
  8. }
  9. #endif
  10. #endif /* CxxModule_hpp */

文件结构和Swift模块保持不变。
教训:任何将被C和Swift读取的头部必须两者都可读。(Swift能够理解C头文件,但不能理解C头文件,至少在目前的状态下是这样。

展开查看全部
brccelvz

brccelvz2#

对于其他在C和Swift中挣扎的人来说,有几个注意事项(对于C来说,“简单地”是一个命名的问题。我确实知道,但是如果没有一个正常运行的C代码,C是不可能完成使命。
回顾一下:
1.假设您有“C”代码,让我们称之为libC(一个文件夹),它包含 *.c和 *.h文件。
1.如果要构建一个 Package 器,可以说libCWrapper
1.在Xcode中构建一个名为libCWrapper的包

  1. Xcode应该构建一个类似于以下内容的Package.swift:(已删除评论)
  1. import PackageDescription
  2. let package = Package(
  3. name: "libCWrapper",
  4. products: [
  5. .library(
  6. name: "libCWrapper",
  7. targets: ["libCWrapper"]),
  8. ],
  9. targets: [
  10. .target(
  11. name: "libCWrapper",
  12. dependencies: []),
  13. .testTarget(
  14. name: "libCWrapperTests",
  15. dependencies: ["libCWrapper"]),
  16. ]
  17. )

1.现在第一个技巧:我们需要两个目标和两个产品。因此,补充:

  1. products: [
  2. .library( name: "libCWrapper", targets: ["libCWrapper"]),
  3. .library( name: "libC", targets: ["libC"]),
  4. ],
  5. ..
  6. .target(
  7. name: "libCWrapper",
  8. dependencies: ["libC"]),
  9. .target(
  10. name: "libC",
  11. dependencies: []),

**注意:**swift libCWrapper依赖于libC。

1.我们还必须添加/更改“C源代码:
所有的“C”代码必须进入一个饲料名称为“C”目标,但包括一个级别。所以:
Sources ->[libC] sampleCall.c [include] -> [sampleCall.h]
所以:

  1. pls也添加目标,如果你需要做一些测试:
    平台:[ .macOS(.v10_12),.iOS(.v9)],
    1.内部测试:
    @testable import libCWrapper**@testable import libC**
    添加C产品。所以测试可以是:
  1. import XCTest
  2. @testable import libCWrapper
  3. @testable import libC
  4. final class libCWrapperTests: XCTestCase {
  5. func testExample() throws {
  6. // This is an example of a functional test case.
  7. // Use XCTAssert and related functions to verify your tests produce the correct
  8. // results.
  9. XCTAssertEqual(libCWrapper().text, "Hello, World!")
  10. }
  11. func testGimmeFive(){
  12. let n = gimmeFive()
  13. XCTAssertEqual(n, 5)
  14. }
  15. }

在C中,我们有:

  1. //
  2. // sampleCall.c.c
  3. //
  4. //
  5. // Created by ing.conti on 24/08/22.
  6. //
  7. #include "sampleCall.h"
  8. int gimmeFive(void){
  9. return 5;
  10. }

现在,你可以在测试中从Swift调用C,这只是一个“open”/“public”和类似的问题。

展开查看全部

相关问题