概括:

  1. 文件中重复定义了一个函数、变量(比如全局变量)
  2. 工程中包含同名的文件。

一般的解决方法

  • 1 在使用import 引入头文件时,由于疏忽,误引入.m 文件。
  • 2 同名文件放在不同的文件夹下。
  • 3.在 Targets 的 Build Phrases 设置里,查看下 Complie Sources这一项,看看出现问题的类是不是重复的.如果是重复的,删除掉重新添加也能解决这个问题.
  • 4.文件里面使用C语言定义的全局变量名或是函数名,在导入的时候因为重复产生了冲突。 
    比如:在.m 文件的函数如果是用 C 语言的形式写的时候,程序在编译的时候,只看文件名,而不在乎你后面有多少参数,如果是文件名相同的话也是不行的.
    a.m中
    void drawCircle()
    b.m中
    void drawCircle(CGContextRef ctx, int radius, CGFloat centerX, CGFloat centerY)

引入.a产生冲突

参考文章1:duplicate symbol问题解决方法
参考文章2: iOS 第三方库冲突的处理
参考文章3:iOS 解决一个因三方静态库冲突产生的duplicate symbol的问题 
1. 如果是两个静态库冲突的话,可以将两个.a静态库解压,删除其中一个里面重复的.o文件(编译时产生的临时文件),然后用lipo命令合并两个静态库;比如libx.a文件

1 创建临时文件夹,用于存放armv7平台解压后的.o文件:
mkdir armv7 2 取出armv7平台的包:
lipo libx.a -thin armv7 -output armv7/libx-armv7.a 3 查看库中所包含的文件列表:
ar -t armv7/libx-armv7.a 4 进入armv7文件夹,并解压出object file(即.o后缀文件):
cd armv7 && ar xv libx-armv7.a 5 找到冲突的包(比如 JSONKit),删除掉
rm JSONKit.o 6 重新打包,生成libx-armv7.a
object file:cd .. && ar rcs libx-armv7.a armv7/*.o,可以再次使用[3]中命令确认是否已成功将文件去除 7 将其他几个平台(armv7s, i386)包逐一做上述[1-6]操作 8 重新合并为fat file的.a文件libMiPushSDK-new.a:
lipo -create libx-armv7.a libx-armv7s.a libx-i386.a -output libMiPushSDK-new.a 9 拷贝到项目中覆盖源文件:
cp libMiPushSDK-new.a /Users/tony/Desktop/XXXProject/Lib/libMiPushSDK.a

ar总结:

-t  显示库文件中所包含的文件
-x  自库文件中取出成员文件
-v  程序执行时显示详细的信息
-r  将文件插入库文件中
-c  建立库文件
-s  若库文件中包含了对象模式,可利用此参数建立备存文件的符号表。

2.工程文件和静态库冲突的话,报错会显示XXX.o文件。

1 Build Phrase里面搜索这个类名
2 显示出来的那几个 .m文件给remove掉就OK
或者(不建议下边这样)
1 在Xcode左侧,工程文件目录结构中找到.m文件
2 中并将Target Membership的勾选去掉,效果一样
注意:
对工程Add Files to一份拷贝的文件夹之后,默认选中了Target Membership。所以在工程目录的结构简单的整理一下后,有时会出现这种错误。 

拓展

1 拓展:

lipo的一些解释:
lipo 是一个在 Mac OS X 中处理通用程序(Universal Binaries)的工具。现在发售或者提供下载的许多(几乎所有)程序都打上了“Universal”标志,意味着它们同时具有 PowerPC 和 Intel 芯片能够处理的代码。不过既然你可能不在意其中的一个,你就能够使用 lipo 来给你的程序“瘦身” 

1.1 ios中合成静态库:

合成静态库:

将模拟器和设备的静态库文件合并成一个文件输出了,以后在发布可以库的时候不用发一个模拟器版的和一个真机版的了,这样子的一个库可以在编译的时候自动识别需要连接的库

lipo –create Release-iphoneos/libiphone.a Debig-iphonesimulator/libiphone.a –output libiphone.a

1.2 查看A.a中的.m文件:

查看.m文件

  看一下该文件包含几种arch
输入:file A.a
输出:
A.a: Mach-O universal binary with 2 architectures
A.a (for architecture armv7): current ar archive random library
A.a (for architecture arm64): current ar archive random library
结论:
可以看到该文件包含两种arch,分别是armv7和arm64。 2 由于下面抽离object的时候必须是要单一的库,所以这里我们抽出armv7并命名为v7.a:
输入:lipo A.a -thin armv7 -output v7.a
输出:生成一个v7.a文件。
结论:目录下多了一个v7.a文件 3 抽离.a文件的object
输入:ar -x v7.a
输出:生成一些.o文件
结论:目录下多出一些.o文件 4 获取文件,比如:View.o文件
输入:nm View.o > view.m
输出:生成view.m文件
结论:可以查看view.m文件

2 拓展:

2.1 Target membership是什么?

Target membership是指XCode中,一个文件属于哪一个工程,在XCode左侧的工程面板中选中一个文件,在XCode右侧的属性面板中会显示其Target Membership。

注意:
以前遇到一个错误,就是UIImage创建的时候返回nil,仔细查看发现,图片的Target Membership选项没有勾上。这个错误比较难以发现,特此记之。

3 拓展:

Other linker flags

    项目编译时的链接方式

3.1 编译过程:

从C代码到可执行文件经历的步骤是:源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件
在最后一步需要把.o文件和C语言运行库链接起来,这时候需要用到ld命令。源文件经过一系列处理以后,会生成对应的.obj文件,然后一个项目必然会有许多.obj文件,并且这些文件之间会有各种各样的联系,例如函数调用。链接器做的事就是把这些目标文件和所用的一些库链接在一起形成一个完整的可执行文件。
Other linker flags设置的值实际上就是ld命令执行时后面所加的参数

3.2 Xcode里-ObjC, -all_load, -force_load

下面逐个介绍3个常用参数:

-ObjC:加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中

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

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

引用.a产生“selector not recognized”错误的原因:

1. Unix的标准静态库实现和Objective-C的动态特性之间有一些冲突:Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现"selector not recognized",也就是找不到方法定义的错误。为了解决这个问题,引入了-ObjC标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来。

2. 本来这样就可以解决问题了,不过在64位的Mac系统或者iOS系统下,链接器有一个bug,会导致只包含有类别的静态库无法使用-ObjC标志来加载文件。变通方法是使用-all_load 或者-force_load标志,它们的作用都是加载静态库中所有文件,不过all_load作用于所有的库,而-force_load后面必须要指定具体的文件。 

4 拓展:

什么时候该用@class,什么时候该用#import进行声明

    1.一般如果有继承关系的用#import,如B是A的子类那么在B中声明A时用#import

    2. 另外就是如果有循环依赖关系,如:A->B,B->A这样相互依赖时,如果在两个文件的头文件中用#import分别声明对方,那么就会出现头文件循环利用的错误,这时在头文件中用@class声明就不会出错

    3.还有就是自定义代理的时候,如果在头文件中想声明代理的话如@interface SecondViewController:UIViewController时应用#import不然的话会出错误,注意XXXXDelegate是自定义的

Xcode工程编译之duplicate symbol问题引发的一些知识的更多相关文章

  1. xcode工程编译错误:No architectures to compile for

    问题 开发环境:xcode6,iPhone6模拟器 xcode工程编译错误:No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active ...

  2. 关于 xcode 工程编译报错 undefined symbol _res_9_init的解决办法

    将libresolv.dylib 添加到工程引用中(通过build phases中).补充:    _res_9_init定义在resolv.h中,可以参考http://www.opensource. ...

  3. xcode工程编译错误:missing required architecture i386 解决方法

    可能原因一:项目内保存了.framework文件,在复制分发到不同计算机的时候可能会引发该错误 解决方法一:来到Targets->Build Settings->Framework Sea ...

  4. Xcode工程编译错误之iOS开发之Xcode9报错 Compiling IB documents for earlier than iOS7 is no longer supported.

    概要: 在我们升级到Xcode9时,最低的编译版本为iOS8,但是在使用一些SDK的时候就会报出Compiling IB documents for earlier than iOS7 is no l ...

  5. xcode工程编译错误:一般错误总结

    1.Apple LLVM 8.0 Error Group /’all-product-headers.yaml’ not found 最近升级了xcode打包后出现了个BUG,记录解决的方法. 现象: ...

  6. Xcode工程编译错误之iOS开发之The Xcode build system has crashed. Please close and reopen your workspace

    解决方法: . 删除DerivedData . 参照上面的链接设置:File -> Workspace Settings -> Build System -> Legacy Buil ...

  7. Xcode工程编译错误:“Cannot assign to 'self' outside of a method in the init family”

    #import <Foundation/Foundation.h> @interface EOCRectangle : NSObject<NSCoding> @property ...

  8. Xcode工程编译错误之iOS开发之Sending '__strong typeof (xxx)' (aka 'xxxx *__strong') to parameter of incompatible type 'id<xxx>'

    iphone开发出现警告: Sending '__strong typeof (xxx)' (aka 'xxxx *__strong') to parameter of incompatible ty ...

  9. xcode工程编译错误之iOS解决CUICatalog: Invalid asset name supplied问题

    [问题分析]: 这个问题其实是老问题,产生原因就是因为在使用的时候 [UIImage imageNamed:]时,图片不存在或者传入的图片名为nil. [解决方法]: 添加一个系统断点,来判断如果图片 ...

随机推荐

  1. HTTP Status 500 - Unable to create directory

    分析原因: 例如:java web项目 上传图片创建文件夹cd /data/apps/static-web/sjk/driver/attachment/编号/文件名称.jpg 在创建文件目录 /dat ...

  2. Django-Signals信号量

    信号量最为Django的一个核心知识点,在项目中很少有使用到,所以很多人都不了解或者没听过过(包括我).简单来说就是在进行一些操作的前后我们可以发出一个信号来获得特定的操作,这些操作包括(信息来自:h ...

  3. python + django + dwebsocket 实现简单的聊天室

    使用库dwebsocket,具体参考此处 views.py: from dwebsocket.decorators import accept_websocket,require_websocket ...

  4. Android Launcher分析和修改12——Widget列表信息收集

    很久没写Launcher分析的文章,最近实在太忙.今天七夕本来是想陪女朋友逛街 ,碰巧打台风呆在家里,就继续写一篇文章.今天主要是讲一下Launcher里面的Widget列表,这方面信息比较多,今天重 ...

  5. 【emWin】例程二十九:窗口对象——Messagebox

    简介: 使用MESSAGEBOX 小工具可在带有标题栏和“确定”按钮(必须按下才能关闭窗口)的 框架窗口中显示消息.本实验通过点击下图中的按键来创建一个Messagebox对话框. 触摸校准(上电可选 ...

  6. hdoj:2035

    #include <iostream> using namespace std; int main() { long a, b; && b != ) { long resu ...

  7. IntelliJ IDEA 中文乱码配置

    总共有下面几种乱码的解决方案: 工程乱码 执行main函数时,控制台乱码 运行tomcat时,控制台乱码 PS: 如果下面方案不生效时,打开IDEA安装目录找到 idea.exe.vmoptions( ...

  8. prototype [ˈprəʊtətaɪp] 原型

    <script> Array.prototype.mysort = function(){ let s = this; for(i=0;i<s.length;i++){ s[i] = ...

  9. Linux命令行下常用的快捷键

    ctrl+a:光标移到行首.ctrl+e:光标移到行尾.ctrl+b:光标左移一个字母ctrl+f:光标右移一个字母 ctrl+h:删除光标前一个字符,同 backspace 键相同.ctrl+d:删 ...

  10. [React] 06 - Route: koa makes your life easier

    听说koa比express更傻瓜化,真的? Koa 框架教程 本身代码只有1000多行,所有功能都通过插件实现,很符合 Unix 哲学. 搭建简单服务器 Koa, 架设一个简单的服务器 // demo ...