文档章节

Xcode - Other Linker Flags

Jerod
 Jerod
发布于 2016/07/28 12:07
字数 1221
阅读 38
收藏 0

背景

在ios开发过程中,有时候会用到第三方的静态库(.a文件),然后导入后发现编译正常但运行时会出现selector not recognized的错误,从而导致app闪退。接着仔细阅读库文件的说明文档,你可能会在文档中发现诸如在Other Linker Flags中加入-ObjC或者-all_load这样的解决方法。

那么,Other Linker Flags到底是用来干什么的呢?还有-ObjC-all_load到底发挥了什么作用呢?

链接器

首先,要说明一下Other Linker Flags到底是用来干嘛的。说白了,就是ld命令除了默认参数外的其他参数。ld命令实现的是链接器的工作,详细说明可以在终端man ld查看。

如果有人不清楚链接器是什么东西的话,我可以作个简单的说明。

一个程序从简单易读的代码到可执行文件往往要经历以下步骤:

源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件

源文件经过一系列处理以后,会生成对应的.obj文件,然后一个项目必然会有许多.obj文件,并且这些文件之间会有各种各样的联系,例如函数调用。链接器做的事就是把这些目标文件和所用的一些库链接在一起形成一个完整的可执行文件。

可能我描述的比较肤浅,因为我自己了解的也不是很深,建议大家读一下这篇文章,可以对链接器做的事情有个大概的了解:链接器做了什么

为什么会闪退

苹果官方Q&A上有这么一段话:

The "selector not recognized" runtime exception occurs due to an issue between the implementation of standard UNIX static libraries, the linker and the dynamic nature of Objective-C. Objective-C does not define linker symbols for each function (or method, in Objective-C) - instead, linker symbols are only generated for each class. If you extend a pre-existing class with categories, the linker does not know to associate the object code of the core class implementation and the category implementation. This prevents objects created in the resulting application from responding to a selector that is defined in the category.

翻译过来,大概意思就是Objective-C的链接器并不会为每个方法建立符号表,而是仅仅为类建立了符号表。这样的话,如果静态库中定义了已存在的一个类的分类,链接器就会以为这个类已经存在,不会把分类和核心类的代码合起来。这样的话,在最后的可执行文件中,就会缺少分类里的代码,这样函数调用就失败了。

解决方法

解决方法在背景那块我就提到了,就是在Other Linker Flags里加上所需的参数,用到的参数一般有以下3个:

  • -ObjC
  • -all_load
  • -force_load

下面来说说每个参数存在的意义和具体做的事情。

首先是-ObjC,一般这个参数足够解决前面提到的问题,苹果官方说明如下:

This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.

简单说来,加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中,虽然这样可能会因为加载了很多不必要的文件而导致可执行文件变大,但是这个参数很好地解决了我们所遇到的问题。但是事实真的是这样的吗?

如果-ObjC参数真的这么有效,那么事情就会简单多了。

Important: For 64-bit and iPhone OS applications, there is a linker bug that prevents -ObjC from loading objects files from static libraries that contain only categories and no classes. The workaround is to use the -allload or -forceload flags.

当静态库中只有分类而没有类的时候,-ObjC参数就会失效了。这时候,就需要使用-all_load或者-force_load了。

-all_load会让链接器把所有找到的目标文件都加载到可执行文件中,但是千万不要随便使用这个参数!假如你使用了不止一个静态库文件,然后又使用了这个参数,那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件,所以建议在遇到-ObjC失效的情况下使用-force_load参数。

-force_load所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载。

本文转载自:http://small.qiang.blog.163.com/blog/static/978493072013112571950/

共有 人打赏支持
Jerod
粉丝 5
博文 30
码字总数 9456
作品 0
普陀
iOS工程师
使用ASIHTTPRequest 编译提示找不到"libxml/HTMLparser.h"的解决方法

使用ASIHTTPRequest xcode编译提示找不到"libxml/HTMLparser.h",解决方法如下: 1>.在xcode中左边选中项目的root节点,在中间编辑区的搜索框中输入"header search paths", 双击Header Search P...

总是搞不懂
2013/01/26
270
0
使用ASIHTTPRequest 编译提示找不到"libxml/HTMLparser.h"的解决

使用ASIHTTPRequest xcode编译提示找不到"libxml/HTMLparser.h",解决方法如下: 1>.在xcode中左边选中项目的root节点,在中间编辑区的搜索框中输入"header search paths", 双击Header Search P...

GIFCOOL
2016/01/02
14
0
让Xcode日志输出中文

  有的时候xcode打印后台返回的日志,明明后台返回的是中文,但是在xcode的日志里面却不是中文,而是unicode编码,这个就比较坑,因为看不到内容。   其实解决办法有两种:   第一种就...

红角羚羊
2017/03/29
0
0
Project -> Active Target -> 按钮在哪里

http://developer.baidu.com/map/index.php?title=iossdk/guide/buildproject 根据百度地图说明,想引入百度地图到ios。 第二步、引入所需的系统库 百度地图SDK中提供了定位功能和动画效果,...

慢跑20
2015/10/14
307
1
IOS版使用移动广告平台集成Google Mobile Ads SDK教程

一:要求 1.IOS4.3或更高版本 2.Xcode4.5或更高版本 二:加入SDK 1. 右键点击Xcode中的项目,选择Add Files to "BannerExample"... 2. 选择除插件文件夹以外的所有项目(除非您需要这个文件夹中...

大街小巷
2015/12/16
969
0

没有更多内容

加载失败,请刷新页面

加载更多

技术工坊|如何降低区块链应用的使用门槛(上海)

当区块链技术从专业研究走向市场应用,开发者需要考虑用户的使用场景和使用门槛,例如通过ETH支付gas手续费,或者注册一个16进制的用户名,普通用户都难以接受。 10月20日,HiBlock区块链社区...

HiBlock
29分钟前
1
0
Daemon线程--《Java并发编程的艺术》学习笔记

daemon线程即守护线程 当一个JVM中不存在非Daemon线程时,JVM将会退出 也就是说当非Daemon线程都执行完毕时,java程序也就结束了。 可以通过调用Thread.setDaemon(true)将线程设置为Daemon线...

karma123
35分钟前
0
0
scala类型参数的上界和下界

class Pair[T <: Comparable[T]](val first:T,val second:T) //类型T必须要是Comparable接口的子类(即T是Comparable的下界){ def bigger = if(first.compareTo(second) > 0) first e......

whoisliang
45分钟前
1
0
Vue中路由管理器Vue Router使用介绍(一)

一、在模块编程中安装VueRouter 1.Npm安装vue-router npm install vue-router 2.在main.js中引用并使用VueRouter import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(Vu......

tianma3798
47分钟前
1
0
TypeScript基础入门之声明合并(一)

转发 TypeScript基础入门之声明合并(一) 声明合并 介绍 TypeScript中的一些独特概念描述了类型级别的JavaScript对象的形状。 TypeScript特别独特的一个例子是"声明合并"的概念。 在使用现有J...

durban
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部