加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何将C代码编译成Swift Framework

发布时间:2020-12-14 19:55:47 所属栏目:百科 来源:网络整理
导读:我有一个 Swift框架,我们编译并分发给第三方开发人员.我想在项目中包含一些C代码,但我能够使其工作的唯一方法是将C头导入我的框架头并将C头设置为public.这会将所有C代码暴露给第三方开发人员,这不是我们想要的. 我在网上可以找到的有关如何执行此操作的所有
我有一个 Swift框架,我们编译并分发给第三方开发人员.我想在项目中包含一些C代码,但我能够使其工作的唯一方法是将C头导入我的框架头并将C头设置为public.这会将所有C代码暴露给第三方开发人员,这不是我们想要的.

我在网上可以找到的有关如何执行此操作的所有内容都是此方法的变体:https://spin.atomicobject.com/2015/02/23/c-libraries-swift/

但是这个方法的警告是“请注意,使用这种技术构建的任何框架的消费者也必须将模块添加到他们的Swift搜索路径中.”我们已经尝试了这一点,当然我们的第三方开发人员得到一个错误缺少所需的模块’CGeodesic’,这是我们定义的指向C头的模块.

我们怎样才能将C代码直接编译到我们的框架中,同时保持代码私有,并且不要求第三方开发人员更改其构建设置以使其工作?我不介意在我们的项目中设置这些子模块,但在一天结束时我希望它直接编译成单个平面框架二进制文件,没有动态链接或搜索路径或类似的东西.

编辑

该项目是与Swift代码并排的C代码.我的项目中有一个子目录,如下所示:

>测地线/

> Geodesic.h
> Geodesic.c
> Geodesic.swift

Swift文件包装C代码,使其更清晰.我在该目录中也有一个module.modulemap文件,但就像我之前说过的那样无效.我宁愿保持C代码与我的Swift代码并排,但我愿意放弃它以解决这个问题.

解决方法

只是为了重新解释你的问题:你基本上想要在Swift中包装C代码并阻止直接访问封装的C代码.这意味着要阻止Swift和Objective-C的访问.

这是可能的,但需要对构建过程和一些后期处理进行一些调整.

框架中的C和Swift Interop

您希望在Swift中包装的任何C代码都需要在编译期间通过伞标头或使用模块映射公开.这里的重要部分:在编译期间.框架没有完整性检查,这意味着您可以对它们应用后期处理(例如,使用lipo创建胖二进制框架).这就是我们在这里需要做的事情.

准备构建

您可以将它们放入module.modulemap文件中,而不是将所有C头依赖项放入伞形头中.这有一个优点:您可以在标头构建阶段将标头设为私有.

因此,在项目中创建module.modulemap文件,并在Packaging部分的模块映射文件构建设置(xcconfig文件中的MODULEMAP_FILE)中设置它的路径,例如$(SRCROOT)/MyFramework/module.modulemap.

您的module.modulemap文件应具有以下内容:

# module.modulemap

framework module MyFramework {

    umbrella header "MyFramework.h"  

    export *
    module * {export *}

    # All C Files you want to wrap in your Swift code

    header "A.h"
    header "B.h"
}

到现在为止还挺好.您现在应该能够构建代码并从Swift和Objective-C访问它.唯一的问题是:您仍然可以在Swift和Objective-C中访问C头文件.

后期处理

如果您查看最终的Framework捆绑包,您会注意到所有私有头文件都已复制到MyFramework.framework / PrivateHeaders文件夹中.这意味着你仍然可以通过#import< MyFramework / A.h>访问它们.在Objective-C中.

在Swift中,您仍然可以访问C代码,因为我们将头文件放在已复制到MyFramework.framework / Modules / module.modulemap的module.modulemap文件中.

幸运的是,我们可以通过一些后处理来摆脱这两个问题:

>从框架包中删除PrivateHeaders文件夹.
>创建一个单独的模块映射并删除所有标题“XYZ.h”语句,例如,将其命名为public.modulemap.
>将所有这些放在运行脚本构建阶段

这是公共模块映射:

# public.modulemap

framework module MyFramework {

    umbrella header "MyFramework.h"  

    export *
    module * {export *}

    # No more C Headers here
}

您应该添加到框架构建阶段结束的运行脚本:

# Delete PrivateHeaders folder
rm -rf ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/PrivateHeaders

# Remove module.modulemap file
rm ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap

# Copy public.modulemap file and rename it to module.modulemap
cp ${SRCROOT}/test/public.modulemap ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap

# Append the Swift module so you can access you Swift code in Objective-C via @import MyFramework.Swift
echo "module ${PRODUCT_NAME}.Swift { header "${PRODUCT_NAME}-Swift.h" }" >> ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap

希望有所帮助!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读