资讯专栏INFORMATION COLUMN

Xcode 依赖管理带来的静态库动态库思考

reclay / 2114人阅读

摘要:依赖三个系统框架,如果我们将其编译为静态库,然后这个静态库被其他工程依赖,那么其他工程依旧需要引入这三个框架。最终生成的静态库根本不知道动态库的存在。

最近整理一些项目以前依赖留下的问题,在使用 CocoaPods 和 Carthage 的时候引出了关于静态库和动态库的思考,手动编译静态库的朋友应该知道,如果自己编译了一个静态库,这个静态库依赖了 iOS 自带的库,即使你在 Xcode 中显式指定了依赖,当你在另一个工程中使用这个静态库的时候,依旧需要显式在那个工程指定这个静态库所依赖的系统库。

举个栗子

AFNetworking 是个好东西,大家都喜欢用,在日常使用的时候,一般都是使用 CocoaPods 引入这个库,笔者前面有篇文章分析了 CocoaPods 做了什么工作,但是却没有分析 CocoaPods 为何如此设计,这里先卖个关子不讲。AFNetworking 依赖 Security.framework MobileCoreServices.framework SystemConfiguration.framework 三个系统框架,如果我们将其编译为静态库,然后这个静态库被其他工程依赖,那么其他工程依旧需要引入这三个框架。如果我们将其编译为动态库,则不需要依赖这三个框架。这个情况引起了笔者的兴趣

分析

既然问题是编译链接,那么就需要从动态库和静态库入手分析,首先,我们需要明确的是,系统提供的 framework 都是动态库的形式提供的。这很好理解,因为 UIKit 这类 framework 被使用的太频繁了,内存中完全只需要保留一份副本。这样也能减轻 App 的大小。那么直接来着手模拟一下其编译过程。

模拟静态库的编译

创建一个动态库用于模拟系统库

dynamic.h
----------
void hello();

dynamic.c
----------
#include "dynamic.h"
#include 

void hello() {
    printf("Hello World");
}

然后编译打包动态库

> gcc -c -o dynamic.o dynamic.c # 编译为对象文件
> gcc -shared dynamic.o -o libdynamic.so

创建一个静态库用于模拟第三方静态库

static.h
--------
void sayHello();

static.c
--------
#include "static.h"
#include "dynamic.h"

void sayHello() {
    hello();
}

然后编译静态库

> gcc -c -o static.o static.c
> ar -r libstatic.a static.o

这里大家有没有发现一个问题,静态库实际上并没有链接动态库,仅仅只是 include 了一个头文件用于编译通过。最终生成的静态库根本不知道动态库的存在。
然后创建一个带有 main 函数的程序

hello.c
-------
#include "static.h"
int main(int argc, char *argv[]) {
    sayHello();
}

然后编译

> gcc -o hello hello.c -L. -lstatic
# 直接报错没有找到 hello() 的二进制代码
Undefined symbols for architecture x86_64:
  "_hello", referenced from:
      _sayHello in libstatic.a(static.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
模拟动态库的编译

创建一个动态库用于模拟系统库

dynamic1.h
----------
void hello();

dynamic1.c
----------
#include "dynamic1.h"
#include 

void hello() {
    printf("Hello World");
}

然后编译打包动态库

> gcc -c -o dynamic1.o dynamic1.c # 编译为对象文件
> gcc -shared dynamic1.o -o libdynamic1.so

创建动态库用于模拟第三方动态库

dynamic2.h
--------
void sayHello();

dynamic2.c
--------
#include "dynamic2.h"
#include "dynamic1.h"

void sayHello() {
    hello();
}

然后编译打包动态库

> gcc -c -o dynamic2.o dynamic2.c # 编译为对象文件
> gcc -shared dynamic2.o -o libdynamic2.so
# 报错,显示 dynamic2.o 中没有 hello() 二进制代码
Undefined symbols for architecture x86_64:
  "_hello", referenced from:
      _sayHello in dynamic2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
> gcc -shared dynamic2.o -o libdynamic2.so -L. -ldynamic1
# 成功,无报错

然后创建一个带有 main 函数的程序

hello.c
-------
#include "static.h"
int main(int argc, char *argv[]) {
    sayHello();
}

然后编译

> gcc -o hello hello.c -L. -ldynamic2
总结

从上面两个编译过程大家应该也能明白了,静态库实际上只是对象文件的打包,也就是说,只经过了编译过程,而没有链接过程,编译一个静态库甚至只需要满足所有函数的声明就行,而动态库虽然没有经过正规的链接,但是实际上还是通过 gcc 做了跟其他动态库的链接,动态库自身有了依赖的概念。所以不需要在工程中显式依赖了。
这里可能有朋友想要问,这种知识有什么用处?实际上这种知识在依赖管理中有用,前面说过 CocoaPods 对工程修改了很多内容,这是有原因的,因为 iOS8 之前是不存在动态库的,只存在静态库,CocoaPods 不得不对目标工程也作出修改来添加对其他库的依赖,因为静态库不知道自身依赖什么库。而 Carthage 则只支持 iOS8 和动态库,所以完全可以没有侵入性,只需要提供一个动态库,然后工程依赖这个动态库就行了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/16314.html

相关文章

  • iOS 静态动态与 Framework

    摘要:静态库静态库即静态链接库下的,和下的。静态库的好处很明显,编译完成之后,库文件实际上就没有作用了。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。使用静态库是不支持的。 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。 什么时候我们会用到库呢?一种情况是某些代码需要给别人...

    韩冰 评论0 收藏0
  • Cocopods应用及插件

    摘要:静态库一堆目标文件的打包体并非二进制文件。加载静态库启动时,动态库使用时启动后。四其它插件参考链接插件安装及说明参考链接官网安装教程文件的具体说明发布开源库到官方仓库动态库和静态库分析 声明: 最后更新时间:2019年3月18日 为保证时效性,持续更新地址为:Cocopods安装和使用 一、安装和使用Cocopods 网上已有很多教程,参考示例:CocoaPods安装教程 二、让...

    OldPanda 评论0 收藏0
  • iOS - 收藏集 - 掘金

    摘要:动画系列之五基础动画之缩放篇旋转篇掘金这一篇主要介绍基础动画之缩放和旋转。本文主要会基于一些开源代码和个人实践,对功能性和实用性均佳,应用领域广泛的幻灯片播放库掘金的多选掘金好久 PPAsyncDrawingKit - 实现了一系列基础 UI 控件的轻量级 ASDK - iOS - 掘金一年 iOS,求职中,上海地区,邮箱:dskcpp@gmail.com PPAsyncDrawing...

    dingda 评论0 收藏0
  • 在linux平台实现atosl

    摘要:重整符号名称在这样的语言中任何给定的名字符号只能对应唯一的一个函数或数据不需要名字重整。因此编译器使用一组严格的编码规则重整了符号。接下来要想办法将这个小程序移植到平台下。 原文出自【听云技术博客】:http://blog.tingyun.com/web/a... 序言 怎么在linux 平台下实现一个类似于mac 平台下的 atos 工具( iOS 符号化解析)? 分析问题 在git...

    gnehc 评论0 收藏0
  • Cocoa依赖管理工具

    摘要:和区别是一个深度依赖包管理器,所以默认情况下会自动创建并且更新工作空间和所有的依赖,包括之类,使用命令编译框架,但是需要用户自己整合到工程中,当然实际上这个整合工作非常非常方便。 Carthage iOS 作为目前最大的移动端开发平台,开发者的生态环境也是非常繁荣。在 iOS 早期时候,开发者想要使用第三方库就必须将其源代码引入工程,或者说是以 git submodule 的形式引入项...

    Sanchi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<