我有一个Swift框架,我们可以对其进行编译并分发给第三方开发人员。我想在项目中包含一些C代码,但使它起作用的唯一方法是将C标头导入框架的标头并将C标头设置为public。这会将所有C代码公开给第三方开发人员,这不是我们想要的。
我在网上可以找到的所有有关此方法的信息都是该方法的一种变体:https : //spin.atomicobject.com/2015/02/23/c-libraries-swift/
但是此方法的警告是“请注意,使用此技术构建的任何框架的使用者也都必须将模块添加到他们的Swift搜索路径中。” 并且我们已经尝试了这一点,并且确定我们的第三方开发人员肯定会得到一个错误Missing required module 'CGeodesic'
,该错误是我们定义的指向C标头的模块。
我们如何才能将C代码直接编译到我们的框架中,同时保持代码的私密性,又不要求第三方开发人员更改其构建设置才能使其正常工作呢?我不介意在我们的项目中设置这些子模块,但是最终,我希望将其直接编译成单个平面框架二进制文件,而不需要动态链接或搜索路径或类似的东西。
编辑
该项目是与Swift代码并排的C代码。我的项目中有一个子目录,如下所示:
Swift文件包装了C代码,使其更整洁地工作。我在该目录中也有一个module.modulemap文件,但是就像我之前说的那样,它不起作用。我宁愿将C代码与我的Swift代码并排放置,但我愿意为了解决这个问题而放弃。
只是为了重述您的问题:您基本上想将C代码包装在Swift中,并防止直接访问封装的C代码。这意味着要防止从Swift以及Objective-C进行访问。
这是可能的,但是需要对构建过程进行一些调整,并进行一些后期处理。
框架中的C和Swift互操作
您想要包装在Swift中的所有C代码都必须在编译期间通过伞标头或使用模块映射公开。这里的重要部分:在编译时。框架没有完整性检查,这意味着您可以对其进行后处理(例如,使用创建一个胖二进制框架lipo
)。这就是我们在这里需要做的。
准备构建
除了将所有C标头依赖项放入伞形标头之外,您还可以将它们放入module.modulemap
文件中。这有一个优点:您可以在Headers
构建阶段将标头设为私有。
因此,请module.modulemap
在您的项目中创建一个文件,然后Module Map File
在该Packaging
部分的“构建”设置(MODULEMAP_FILE
在xcconfig文件中)中设置其路径,例如$(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代码,因为我们将头文件放在module.modulemap
已复制到的文件中MyFramework.framework/Modules/module.modulemap
。
幸运的是,我们可以通过一些后期处理来摆脱这两个问题:
PrivateHeaders
从框架捆绑包中删除文件夹。header "XYZ.h"
语句,例如,将其命名为public.modulemap
。Run Script
构建阶段这是公共模块图:
# 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
希望对您有所帮助!
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句