Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将C代码编译成Swift框架_C_Xcode_Swift_Llvm_Ios Frameworks - Fatal编程技术网

如何将C代码编译成Swift框架

如何将C代码编译成Swift框架,c,xcode,swift,llvm,ios-frameworks,C,Xcode,Swift,Llvm,Ios Frameworks,我有一个Swift框架,我们编译并分发给第三方开发人员。我想在项目中包含一些C代码,但是我能够使它工作的唯一方法是将C头导入到我的框架头中,并将C头设置为public。这将向第三方开发人员公开所有C代码,这不是我们想要的 我在网上找到的关于如何实现这一点的所有信息都是该方法的变体: 但这种方法的警告是“注意,使用这种技术构建的任何框架的使用者也必须将模块添加到他们的快速搜索路径中。”我们已经尝试过了,并且确信我们的第三方开发人员得到了一个错误缺少所需的模块“CGeodesic”,这是我们定义的指

我有一个Swift框架,我们编译并分发给第三方开发人员。我想在项目中包含一些C代码,但是我能够使它工作的唯一方法是将C头导入到我的框架头中,并将C头设置为public。这将向第三方开发人员公开所有C代码,这不是我们想要的

我在网上找到的关于如何实现这一点的所有信息都是该方法的变体:

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

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

编辑


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

  • 测地线/
    • 测地线
    • 测地线
    • 测地线

Swift文件包装了C代码,使其更易于使用。我在那个目录中也有一个module.modulemap文件,但正如我前面所说的,它不起作用。我更愿意将C代码与我的Swift代码并排保存,但为了解决这个问题,我愿意放弃它。

有一个解决方案,尽管不建议这样做。您可以在
.Swift
文件中,而不是使用C头。

只是为了重新表述您的问题:您基本上希望用Swift包装C代码,并防止直接访问封装的C代码。这意味着阻止Swift和Objective-C的访问

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

C和框架中的Swift互操作

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

准备构建

除了将所有C头依赖项放入伞形头之外,还可以将它们放入
modulemap.modulemap
文件中。这有一个优点:您可以在
headers
构建阶段将头设置为私有

因此,在您的项目中创建一个
modulemap.modulemap
文件,并在
Packaging
部分的
modulemap\u文件
中的
$(SRCROOT)/MyFramework/modulemap.modulemap
中设置它的路径

您的
模块.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头文件

后处理

如果查看最后一个框架包,您会注意到所有私有头文件都已复制到
MyFramework.Framework/PrivateHeaders
文件夹中。这意味着您仍然可以通过Objective-C中的导入来访问它们

在Swift中,您仍然可以访问C代码,因为我们将头文件放在
modulemap.modulemap
文件中,该文件已复制到
MyFramework.framework/Modules/modulemap.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
    

    希望有帮助

    您当前的设置是什么?C代码与Swift代码并排?。这有用吗?C代码是Objective-C,它看起来可以用C和Swift混合编写框架,在用户看来,它就像是用单一语言编写的一样。我自己还没有试过。@OmniProg所以这就是我们目前正在做的。这个方法的问题是,它必须公开所有这些头,这是我们试图避免的。工作非常完美!非常感谢。这个答案当然令人难以置信,@JensMeder,谢谢。有一件事——也许您可以添加一个简单案例的简短附录,其中根本不需要阻止直接访问。这可能会澄清答案。我打赌这对很多人都有帮助。(www上关于这个的所有老文章都随着时间的推移消失了!:)在Xcode 11下,我重新定义了模块构建错误。命名modulemap文件
    MyFramework.modulemap
    而不是
    modulemap.modulemap
    克服了这一问题。我还必须确保我的c头在我的框架的头构建阶段被列为私有,我的伞头在我的框架的头构建阶段被列为公共,以避免伞头未找到构建错误并启用自动完成。感谢您的回答。我发现的一个问题(至少对我来说)是,无论C头上定义了什么函数,在使用框架时,当您cmd+单击模块名称时,它都会出现。知道吗