如何解决Swift混编的module编译错误

简介: 前言很多iOS工程都是基于Object-C开发,再逐步向Swift演进,演进过程中不可避免要进行Swift混编。Swift模块需要支持LLVM Module规范,混编工程会遇到各种Module编译错误。这对于不熟悉的同学来说简直是灾难,严重影响开发效率。本文会介绍常见的Module编译错误,希望对大家有所帮助。常见错误1:Could not build module xxx当一个OC模块引用了Sw

前言

很多iOS工程都是基于Object-C开发,再逐步向Swift演进,演进过程中不可避免要进行Swift混编。Swift模块需要支持LLVM Module规范,混编工程会遇到各种Module编译错误。这对于不熟悉的同学来说简直是灾难,严重影响开发效率。本文会介绍常见的Module编译错误,希望对大家有所帮助。

常见错误1:Could not build module xxx

当一个OC模块引用了Swift模块就产生了混编,混编的OC模块依赖链中的所有模块都必须满足LLVM Module Standard。如果AModule依赖了BModule,BModule不符合Module规范,构建会报 “could not build module BModule”的错误。

解决方案1:通过一下设置“Framework Module允许导入非modular的头文件” 临时跳过问题

Approach1:模块的Podspec中设置

CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES

Approach2: 在Podfile里设置

post_install do|installer|

installer.pods_project.build_configuration_list.build_configurations.eachdo|configuration|

configuration.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES']='YES'

end

end

解决方案2:将BModule改造为符合LLVM Module标准(推荐)

常见错误2:No such module 'XXXModule'

原因1:A模块的依赖树里不存在B模块

如果“Pod A” 需要import “BModule”,“AModule”的Podspec描述文件需要声明对于BModule的依赖,否则就会报“No such module 'XXXModule'”错误。Cocoapod会将依赖关系转化成XCode的FRAMEWORK_SEARCH_PATHS或LIBRARY_SEARCH_PATHS,因此只需要检测xcconfig是否存在对应的配置,就能判断Podspec描述是否缺失依赖。

step 1: 打开A模块的xcconfig文件

Pods/Target Support Files/AModule/AModule.xcconfig

Step 2: 查看xcconfig里的frameowork和library配置,如果不存在是模块B,说明A模块的依赖树里没有B,需要再A模块的podspec文件中添加模块B的依赖。

LIBRARY_SEARCH_PATHS "${PODS_CONFIGURATION_BUILD_DIR}/B"

FRAMEWORK_SEARCH_PATHS ="${PODS_ROOT}/B"

原因2:BModule的Framework缺少modulemap文件

符合LLVM Module Standard的Framework里都会有一个.modulemap文件,如果缺少.modulemap文件说明Framework工程没有配置Define Module,同样会报上述的错误。

Step1:检查Pods目录里BModule的Framework是否包含正确的.modulemap文件

../Pods/Masonry/Masonry.framework

Step2: 如果当前版本有问题而历史版本正常,可以查看CocoaPods的Cache目录的各个版本,对比历史版本的Framework

../Library/Caches/CocoaPods/Pods/Release/Masonry/1.1.0-framework-DG-1-cbeee/Masonry.framework

下面是Masonry Framework解包的目录,目录中包含一个module.modulemap文件

framework module Masonry {

umbrella header"Masonry.h"

export *

module * { export * }

}

原因3:umbrella header中引用头文件不符合规范

umbrella header 会暴露给外部引用的public header。LLVM Module规定所有public header都需要使用“<A/A.h> ”的方式应用头文件。iOS工程中通常有下面几种引用方式,只有第一种是符合LLVM Module 规范的。

#import <A/A.h>  right

#import "A/A.h" wrong

#import "A.h" wrong

#import <A.h>    wrong

例如下面Masonry的umbrella header就不符合规范

解决方案是将头文件import方式从“#import "A.h" ”改为“#import <Masonry/xxx.h> ”

原因4:swift compiler incompatible

No such Module 'XModule'

Failed to build module 'AModule'; this SDK is not supported by the compiler (the SDK is built with 'Apple Swift version 5.3.1 (swiftlang-1200.0.41 clang-1200.0.32.8)', while this compiler is 'Apple Swift version 5.5 (swiftlang-1300.0.19.104 clang-1300.0.18.4)'). Please select a toolchain which matches the SDK.

本地调试时可能会遇到,比如AModule是静态库,AModule依赖了XModule, XModule是源码库。具体原因是AModule使用Xcode 12.4构建(Swift version 5.3.1),本地当前正在使用了Xcode12.5(Swift version 5.3.1 )调试。解决方案1是将本地使用的XCode版本先降到低于12.4.1 以下的版本。解决方案2是将AModule用新版本的XCode重新构建发布新版本。

常见错误3:Include of non-modular header inside framework module :

如果Framework Module ’AModule‘中加载了非AModule的头文件,比如AModule.h import了一个OC头文件X.h,而X.h头文件又Include某个C/C++ 的头文件

AModule.h:9:9: error: include of non-modular header inside framework module 'BModule.AModule'

解决方案:设置“Framework Module允许导入非modular的头文件”临时跳过问题

CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES

常见错误4:Definition of 'AMoudle' must be imported from module 'BMoudle.xxxheader' before it is required

如果AMoudle和XModule的公共头文件同时引用了BModule的某个公共头文件,就会出现这个错误。

AMoudle_A.h 文件:

import <BModule/BModule_B.h>

XModule_X.m 文件:

import <BModule/BModule_B.h>

解决方案1:增加import <AModule/AMoudleXXX.h>

XModule_X.m 文件:

import <AModule/AMoudle_A.h>

import <BModule/BModule_B.h>

解决方案2:使用project引入模式调试pod

使用Development pod进行源码调试pod会遇到上述错误,而如果使用project引入模式调试pod可以隔离各个Project,就不会遇到这个错误。project引入模式类似swift package manager的edit模式。

自定义modulemap

OC Framework通过Cocoapod自定义modulemap

AModule是OC模块,可以在Podspec进行如下配置自定义modulemap

spec.preserve_path = 'Modules/module.modulemap'

spec.module_map = 'Modules/module.modulemap'

spec.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2 $(PODS_ROOT)/AModule/Modules/module' }

spec.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '$(PODS_ROOT)/AModule/Modules/module' }

Swift framework不允许自定义modulemap

[!] Using Swift static libraries with custom module maps is currently not supported. Please build `XXModule` as a framework or remove the custom module map.

总结

本文重点介绍了OC和Swift混编常见编译错误,如果你们的项目正从Object-C工程逐步向Swift演化,可以将本文作为参考。

参考

从预编译的角度理解Swift与Objective-C及混编机制

相关文章
|
API Swift iOS开发
45 Swift和OC的混编
Swift和OC的混编
123 0
|
Swift iOS开发
Swift - 与OC混编时如何创建桥接头文件
Swift - 与OC混编时如何创建桥接头文件
474 0
Swift - 与OC混编时如何创建桥接头文件
|
Swift iOS开发
oc与swift混编
1.swift中调用oc;2.oc中调用swift
289 0
oc与swift混编
|
Swift iOS开发
Swift - 如何用Reachability来混编判断网络状况
Swift - 如何用Reachability来混编判断网络状况
301 0
|
Swift iOS开发
Swift与OC的混编
Swift调用OC文件 OC调用Swift文件
380 0
Swift与OC的混编
|
Swift iOS开发
Swift与OC混编
Swift一出来就比较受人欢迎,但是还是有很多的第三方库是不支持Swift的,个人也感觉Swift还有很长的路要走。 而且最近连Swift的创始人都离开苹果公司了。。。。。。。。。 加入Swift用到了第三方的东西那怎么办呢,其实很简单,Xcode会自动帮你创建一个桥接文件,用来连接Swift和OC这两种语言,同样的在OC里面用Swift也是一样。
1319 0
|
C++ Swift
Swift OC混编
<p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px"> swift 语言出来后,可能新的项目直接使用swift来开发,但可能在过程中会遇到一些情况,某些已用OC写好的类或封装好的模块,不想再在swift 中再写
1671 0