概括:

  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. Asp.Net T4模板生成三层架构

    1.T4 Editor安装 T4:根据模板生成文件,例如model等 vs中默认t4模板编码是没有提示和高亮的,需使用以下插件,免费的 https://t4-editor.tangible-engin ...

  2. 安装polyglot出错

    安装polyglot出错 错误 Complete output from command python setup.py egg_info: Traceback (most recent call l ...

  3. 转:pycharm community debug django projects

    原文:https://automationpanda.com/2017/09/14/django-projects-in-pycharm-community-edition/comment-page- ...

  4. 解决python-memcache报错:“Unknown flags on get: 20”

    [本文出自天外归云的博客园] 在使用python的pytho-memcache库时出现了一个问题,在调用get方法获取键值的时候报错:Unknown flags on get: 20 在网上查了,发现 ...

  5. Android Launcher分析和修改4——初始化加载数据

    上面一篇文章说了Launcher是如何被启动的,Launcher启动的过程主要是加载界面数据然后显示出来, 界面数据都是系统APP有关的数据,都是从Launcher的数据库读取,下面我们详细分析Lau ...

  6. 前端异常监控 - BadJS

    前端异常监控 - BadJS 简介:BadJS 是 web 前端异常监控解决方案,提供一种 web 页面的脚本错误监控.上报.统计.查看等系统化的跟踪解决方案.目前BadJS覆盖了腾讯课堂.公众号.邮 ...

  7. 网络协议TCP/IP、IPX/SPX、NETBEUI简介

    网络中不同的工作站,服务器之间能传输数据,源于协议的存在.随着网络的发展,不同的开发商开发了不同的通信方式.为了使通信成功可靠,网络中的所有主机都必须使用同一语言,不能带有方言.因而必须开发严格的标准 ...

  8. Python之获取微信好友信息

    save_info.py: #!/usr/bin/python # -*- coding: UTF-8 -*- import itchat import pickle itchat.auto_logi ...

  9. Java如何根据主机名(域名)获取IP地址?

    在Java编程中,如何根据主机名(域名)获取IP地址? 以下示例显示了如何通过net.InetAddress类的InetAddress.getByName()方法将主机名更改为指定的IP地址. pac ...

  10. Springboot学习笔记(六)-配置化注入

    前言 前面写过一个Springboot学习笔记(一)-线程池的简化及使用,发现有个缺陷,打个比方,我这个线程池写在一个公用服务中,各项参数都定死了,现在有两个服务要调用它,一个服务的线程数通常很多,而 ...