Swift Package通过modulemap引入Objective-C文件未关联实现问题
问题:Swift Package 接入 Objective-C 代码仅识别声明无法链接实现
在Swift包中添加Objective-C文件时,Swift侧可以正常识别OC头文件的声明,但无法关联.m实现文件,编译无警告,运行单元测试时触发unrecognized selector sent to instance错误。
当前项目结构
Root - Package.swift + Sources + ObjC + DataDeflate - DataDeflate.h - module.modulemap - NSData+Deflate.h - NSData+Deflate.m + Swift + DataDeflator - DataDeflator.swift + Tests + DataDeflatorTests - DataDeflatorTests.swift
现有配置内容
Package.swift
import PackageDescription let package = Package( name: "DataDeflator", products: [ .library(name: "DataDeflator", targets: ["DataDeflator"]), ], targets: [ .target( name: "DataDeflator", dependencies: ["DataDeflate"], path: "Sources/Swift/DataDeflator"), .systemLibrary(name: "DataDeflate", path: "Sources/ObjC/DataDeflate"), .testTarget( name: "DataDeflatorTests", dependencies: ["DataDeflator"]), ] )
module.modulemap
module DataDeflate [system] { header "DataDeflate.h" link "DataDeflate" export * }
DataDeflate.h
#ifndef DataDeflate_h #define DataDeflate_h #import "NSData+Deflate.h" #endif /* DataDeflate_h */
问题原因
你错误使用了.systemLibrary target类型来承载本地编译的OC源码:
systemLibrary是专门用来包装系统预装/外部预编译的库,它只会读取modulemap暴露头文件声明,不会编译路径下的.m源码文件,这就是实现没有被打包进产物、运行时找不到方法的核心原因。- 你写的
link "DataDeflate"指令是告诉链接器去找一个名为libDataDeflate的预编译静态/动态库,而你本地根本没有生成这个库,自然链接不到实现。
修复方案
不需要手动编写modulemap,SPM原生支持target内混编Swift和Objective-C,或者用普通.target承载OC源码,调整步骤如下:
- 删除不需要的文件:移除
Sources/ObjC/DataDeflate路径下的module.modulemap文件,SPM会为混编target自动生成桥接模块。 - 修改Package.swift配置:把承载OC代码的target从
.systemLibrary改成普通.target,不需要单独拆分Swift和OC的源码路径,也可以保留路径但要正确指定源文件路径,参考配置如下:import PackageDescription let package = Package( name: "DataDeflator", products: [ .library(name: "DataDeflator", targets: ["DataDeflator"]), ], targets: [ // OC代码用普通target承载,SPM会自动编译路径下所有.m文件 .target( name: "DataDeflate", path: "Sources/ObjC/DataDeflate", publicHeadersPath: "." // 指定公开头文件路径为当前目录 ), .target( name: "DataDeflator", dependencies: ["DataDeflate"], path: "Sources/Swift/DataDeflator"), .testTarget( name: "DataDeflatorTests", dependencies: ["DataDeflator"]), ] ) - 头文件适配:把
DataDeflate.h作为OC target的umbrella头文件,确保你要暴露给Swift的分类声明都在这个头文件里导入,现有DataDeflate.h的写法符合要求。 - 清理缓存重新编译:执行
swift package reset清除之前的构建缓存,再重新编译运行测试即可。
额外注意:Objective-C的NSData分类在静态链接时可能出现符号加载问题,如果修复后仍然报selector找不到,需要在DataDeflate target的链接配置中添加
-ObjC链接标志,对应target配置修改为:.target( name: "DataDeflate", path: "Sources/ObjC/DataDeflate", publicHeadersPath: ".", linkerSettings: [ .unsafeFlags(["-ObjC"]) ] )
内容的提问来源于stack exchange,提问作者General Failure
相关产品推荐
相关产品推荐

