-
g++链接动态库和静态库问题
2019-11-22 17:11:20库文件有两种,一种为动态库,一种为静态库,具体的区别很简单,通俗的讲,动态库是在运行时动态加载,静态库是在链接的时候直接把库文件复制到程序中,运行的时候不再依赖库文件。 例如我们在程序中用到libtiff库和...在用g++编译链接C++程序时,当我们其中有包含第三方库的时候,需要我们手动的指定我们需要的库文件。库文件有两种,一种为动态库,一种为静态库,具体的区别很简单,通俗的讲,动态库是在运行时动态加载,静态库是在链接的时候直接把库文件复制到程序中,运行的时候不再依赖库文件。
例如我们在程序中用到libtiff库和libxml2库:
1.动态库的链接
g++ *.cpp -o main -I./kufile/libxml/include/libxml2 -I ./kufile/tiff/include \ -L./kufile/libxml/lib -L./kufile/tiff/lib -lxml2 -ltiff
分析一下上面的代码,编译并链接当前所有.cpp文件为可执行文件main。在编译链接过程中,g++会去系统默认路径寻找头文件和链接库。这些目录为/lib,lib64/,/usr/lib,usr/include等,具体大家可自行查看。
- -I表示:将后面的目录加入g++头文件的搜索路径,在此处我的<tiff.h>等头文件放在上面目录中。如果包含第三方头文件,而不将相应的目录包含进来的话,会出现“无法找到<tiff.h>头文件"等类似错误。
- -L表示:将后面的目录加入g++链接库的搜索路径,在此处我将libxml2.so, libtiff.so放入上述目录中。同时要将相应链接的库-lxml2, -ltiff显示写出。如果不写-L只写-lxml2等时,会出现"无法找到-lxml2"等类似错误;如果不将链接库的目录显示加入搜索目录中时,会出现"未定义的声明"等类似错误。
注意:当编译链接完生成可执行文件后,在运行时会出现"无法找到libxml.so,libtiff.o"等类似错误,在此处科普一下,g++在链接时搜索到第三方库时,链接成功。但是在执行过程中,当调用相应的外部函数时,程序再一次会去找第三方库,因为默认搜索目录没有,所以会出现找不到库的情况。这时需要我们修改编译链接命令:
g++ *.cpp -o main -I./kufile/libxml/include/libxml2 -I./kufile/tiff/include \ -L./kufile/libxml/lib -L./kufile/tiff/lib -lxml2 -ltiff \ -Wl,-rpath=/home/inter-rpath/Integrationfinal/alllib
需要加入-Wl,-rpath=“具体目录”,将第三方库路径显示加入程序运行时搜索目录,在此处我将上面的第三方可都放入/home/inter-rpath/Integrationfinal/alllib目录下了。
注意:我建议此处用绝对路径,如果你最后的可执行程序放在和源代码同一目录下并且不被其他程序类似用system(“main”)等命令调用,那么你可以用相对路径。如果你的可执行文件最后不和源代码放入同一目录下或程序被其他程序用类似system(“main”)调用,那么用相对目录会出现无法找见libxml2.so,libtiff.so等动态链接库。
2.静态库的链接
首先我不太建议使用静态链接库,对于一些复杂的程序,一方面会使可执行文件体积变得很大,另一方面在编译链接时会出现各种莫名的错误。
以下列出三种基本的链接静态库的方法:
注意:将动态库和静态库放在同一目录下,用上面的方法会默认优先调用动态链接库。- 使用上面链接静态库的方法,那个目录只可以放静态库,否则会优先链接动态库。
- 使用全路径 【推荐】
g++ main.cpp build/libtest.a ‐o helloworld
- ‐static : 强制所有的库都使用静态库版本
g++ main.cpp ‐o helloworld ‐static ‐Lbuild ‐ltest
缺点: 所有的库(包括libc , libstdc++)都必须提供静态库版本,少一个都不行。
-
linux动态库和静态库依赖问题
2018-06-17 08:45:20linux下动态库.so文件和.a文件是否是独立可用的? 比如我有个dynamic.so和static.o文件,这两个文件是否可能依赖于别的so和a文件,甚至有没有可能依赖于.cpp/.c文件,或者只可能依赖其中的一种?即so和a文件是否一定... -
iOS 动态库和静态库的的区别 动态库的隔离与静态库的吸附问题以及解决方法
2017-05-03 10:40:21动态库和静态库 介绍 静态库和动态库的区别 举个例子, iOS 项目中使用 Embeded Framework 静态库和动态库如何构建和加载 静态库和动态库依赖关系 Xcode 项目结构 iOS ...-
起因
-
理论功底
-
动态库和静态库
-
介绍
-
静态库和动态库的区别
-
举个例子, iOS 项目中使用 Embeded Framework
-
静态库和动态库如何构建和加载
-
静态库和动态库依赖关系
-
-
Xcode 项目结构
-
iOS 依赖管理事实上的标准
-
-
解决问题
-
制作动态库
-
-
剖析下动态库 Framework 吧
-
回过头来看 Embened Framework
-
Why Swift does not Support Staic Libraies
-
CocoaPods 使用 Use_framework!
-
动态库 Framework 的文件结构
-
更愉快的导入文件
资源问题
-
-
-
-
参考
起因
去年,公司iOS端,之前由于所有的业务端代码都是混乱管理,造成开发有很多痛点无法单测,团队成员提交代码冲突机率大,CI配合效果差,功能性代码多端无法复用,单仓库代码量大,编译时间长 等等痛点,领导和组内多次沟通开始着手组件化开发,希望能改进这些开发中的痛点,成立组件化团队。
组件化的方案大同小异,基础性代码封装私有库,业务组件交互交由中间件负责,项目依赖工具用iOS项目事实上的标准CocoaPods
前期的基础性组件拆分都较为顺利,从依赖树的叶子节点开发是最合适的方案。
随着组件抽离的越来越多,私有库的依赖体系也越来越复杂,慢慢过渡到了业务组件。业务组件用了Swift的第三方组件,用了Swift库的同学都知道必须加上use_frameworks!,这个标记是说Pod管理的依赖全部编译为动态库,然后呢我们的很多组件又依赖了诸如百度地图,微信分享等静态库,于是我在执行 pod install 报了一个没有碰见过的错误。
1[!] The
'Pods-LJA_Example'
target has transitive dependencies that include static binaries:
这就尴尬了,于是一阵疯狂的搜索google stackoverflow等,然而并没有什么卵用,而且上面催得急,根本没时间处理这些小问题 业务重构是最主要的,以至于我们的业务组件没有做到独立仓库拆分。
直到最近终于找到了解决办法:( 主要是自己的功力不够深厚)
理论功底
动态库和静态库
介绍
首先静态库和动态库都是以二进制提供代码复用的代码库
-
静态库 常见的是 .a
-
动态库常见的是 .dll(windows),.dylib(mac),so(linux)
-
framework(in Apple): Framework 是Cocoa/Cocoa Touch程序中使用的一种资源打包方式,可以将代码文件、头文件、资源文件、说明文档等集中在一起,方便开发者使用。也就是说我们的 framework其实是资源打包的方式,和静态库动态库的本质是没有关系的
静态库和动态库的区别
静态库: 链接时会被完整的复制到可执行文件中,所以如果两个程序都用了某个静态库,那么每个二进制可执行文件里面其实都含有这份静态库的代码
动态库: 链接时不复制,在程序启动后用dyld加载,然后再决议符号,所以理论上动态库只用存在一份,好多个程序都可以动态链接到这个动态库上面,达到了节省内存(不是磁盘是内存中只有一份动态库),还有另外一个好处,由于动态库并不绑定到可执行程序上,所以我们想升级这个动态库就很容易,windows和linux上面一般插件和模块机制都是这样实现的。
But我们的苹果爸爸在iOS平台上规定不允许存在动态库,并且所有的 IPA 都需要经过苹果爸爸的私钥加密后才能用,基本你用了动态库也会因为签名不对无法加载,(越狱和非 APP store 除外)。于是就把开发者自己开发动态库掐死在幻想中。
直到有一天,苹果爸爸的iOS升级到了8,iOS出现了APP Extension,swift编程语言也诞生了,由于iOS主APP需要和Extension共享代码,Swift语言的机制也只能有动态库,于是苹果爸爸尴尬了,不过这难不倒我们的苹果爸爸,毕竟我是爸爸,规则是我来定,我想怎样就怎样,于是提出了一个概念Embedded Framework,这种动态库允许APP和APP Extension共享代码,但是这份动态库的生命被限定在一个APP进程内。简单点可以理解为被阉割的动态库。
举个例子,iOS项目中使用Embeded Framework
如果你把某个自己开发的动态库(系统的不算,毕竟苹果是爸爸)放在了Linked Frameworks and Libraries里面,程序一启动就会报Reason: Image Not Found,你只能把它放在Embeded Binaries里面才能正常使用,
看图:
静态库和动态库如何构建和加载
简单点,说话的方式简单点~~
上面的介绍貌似有点抽象啊套用在美团技术分享大会上的话就是:
-
静态库: 一堆目标文件(.o/.obj)的打包体(并非二进制文件)
-
动态库: 一个没有main函数的可执行文件
这里我们来复习下C语言的基本功,编译和链接
-
编译: 将我们的源代码文件编译为目标文件
-
链接: 将我们的各种目标文件加上一些第三方库,和系统库链接为可执行文件。
由于某个目标文件的符号(可以理解为变量,函数等)可能来自其他目标文件,其实链接这一步最主要的操作就是决议符号的地址。
-
若符号来自静态库(本质就是.o 的集合包)或 .o,将其纳入链接产物,并确定符号地址
-
若符号来自动态库,打个标记,等启动的时候再说---交给dyld去加载和链接符号
于是链接加装载就有了不同的情况
-
Load 装载:将库文件载入内存
Static Loading:启动时
Dynamic Loading:启动后(使用时)
-
Link 链接:决议符号地址
Static Linking:构建(链接)时
Dynamic Linking:运行时(启动时或使用时)
然后组合起来就是 2 * 2 = 4 了
-
Static Loading + Static Linking
-
Static Loading + Dynamic Linking
-
Dynamic Loading + Dynamic Linking
-
~~Dynamic Loading + Static Linking~~
第一种是纯静态库相关了
第二种就是静态加载(启动时),动态链接,链接时,动态库参与链接,但是这时候只是给符号打了标记告诉我这个符号来自与动态库,程序启动时,iOS或者Mac OS操作系统的dyld自动load + link。
既然全部都是自动的。那么符号的调用方完全不知道你到底是源码还是静态库,动态库 。
第三种收到调用dlopen + performSelector通常iOS的APP不适用这里不讨论
第四种,没见过,个人也不是特别懂
有需求请参看文后的程序员的自我修养一书
静态库和动态库依赖关系
既然有 2 种库,那么依赖关系又是 2 * 2 喽
-
libA.a dependency libB.a
-
UIKit.dylib dependency Foundation.dylib
-
libA.a dependency Foundation.dylib
-
MyXX.dylib dependency libA.a
第一种 静态库互相依赖,这种情况非常常见,制作静态库的时候只需要有被依赖的静态库头文件在就能编译出来。但是这就意味者你要收到告诉使用者你的依赖关系
幸运的是CocoaPod就是这样做的
第二种动态库依赖动态库,两个动态库是相互隔离的具有隔离性,但是制作的静态库的时候需要被依赖动态库参与链接,但是具体的符号决议交给dyld来做。
第三种,静态库依赖动态库,也很常见,静态库制作的时候也需要动态库参与链接,但是符号的决议交给dyld来做。
第四种,动态库依赖静态库,这种情况就有点特殊了。首先我们设想动态库编译的时候需要静态库参与编译,但是静态库交由dyld来做符号决议,but这和我们前面说的就矛盾了啊。静态库本质是一堆.o 的打包体,首先并不是二进制可执行文件,再者你无法保证主程序把静态库参与链接共同生成二进制可执行文件。这就尴尬了。
怎么办?
目前的编译器的解决办法是,首先我无法保证主程序是否包含静态库,再者静态库也无法被dyld加载,那么我直接把你静态库的.o 偷过来,共同组成一个新的二进制。也被称做吸附性
那么我有多份动态库都依赖同样的静态库,这就尴尬了,每个动态库为了保证自己的正确性会把静态库吸附进来。然后两个库包含了同样的静态库,于是问题就出现了。 看到这里想必前面出现的错误你已经能猜出来了把~_~
后面再详细解释
先来个总结
可执文件(主程序或者动态库)在构建的链接阶段
-
遇到静态库,吸附进来
-
遇到动态库,打标记,彼此保持独
Xcode 项目结构
-
target:对于一个产物(app,.a ,.framework)
-
project:一个项目包含多个 target
-
workspace: 一个包含多个 target
-
schema: 指定了一个产物是按照何种的依赖关系,编译-链接到最终的一个产物
iOS 依赖管理事实上的标准
这么多年,Apple的博客和文档也就告诉了我们什么是静态库什么是动态库,如何制作等。但是并没有给我们提供一系列的依赖管理工具。所以CocoaPods成了事实上的标准。
通常CocoaPods管理的工程结构如下:
那么当我们按下CMD + B的时候,整个项目按照先编译被依赖Pod,然后依赖其他Pod的Pod也被构建出来,最终所有的组件被编译为一个lib-Pods-XXXAPP.a被添加进项目进去。资源通过CocoaPods提供的脚本也一并被复制进去。想了解CocoaPods做了什么的读者可以参看后面的链接
解决问题
这么多理论功底的建立,相信我们已经能分析出来之前pod install的原因了。就是用了use_framework那么我们的所有Pod都会以动态库(Embeded Framework)的形式去构建,于是那些非开源的库(如百度地图,微信分享)如果被多个Pod依赖(组件化开发中太常见了)于是被吸附到动态库里面,所以CocoaPod直接就不让我们install成功。因为你现在的依赖管理就是错误的。
在听取美团叶樉老师分享的时候 他们的出发点是因为要绕过苹果爸爸在iOS9以下对__text 段60M的限制使用了动态库方案,我们是因为某些swift库必须要用到(历史遗留原因)动态库。美团的做法是摘除依赖关系,自定义CocoaPods(开源的本来就是用着不爽我就改)。但是我是个小菜鸡啊。我也不会 ruby(以后会学的),但是叶樉老师给我提了别的idea。前面我们知道 动态库和动态库是隔离性,动态库依赖静态库具有吸附性,那么我们可以自定义一个动态库把百度地图这种静态库吸附进来。对外整体呈现的是动态库特性。其他的组件依赖我们自定义的动态库,由于隔离性的存在,不会出现问题。
制作动态库
1 创建动态库项目这里以 wx 举例
2 按照微信的官方文档。添加依赖库(我是因为pod install巨慢所以我直接拽进来了)
3 将wx的PublicHeader暴露出来,注意由于我并没有使用到wx相关API所以链接器帮我们链接动态库的时候可能并不会把wx静态库吸附进来。我们手动在build Setting的other link flags加上-all_load标记
4.在Schema里面跳转编译配置为Release,并且选择所有的CPU架构
5 然后选择模拟器或者 Generic iOS Device 运行编译就会生成对应版本的 Framework 了。
6.但是为了保证开发者使用的时候是真机模拟器都能正常使用,我们需要合并不同架构
这里在Build Phases里添加以下脚本,真机和模拟器都Build一遍之后就会在工程目录下生成Products文件夹,
12345678910111213141516if
[
"${ACTION}"
=
"build"
]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if
[ -d
"${INSTALL_DIR}"
]
then
rm -rf
"${INSTALL_DIR}"
fi
mkdir -p
"${INSTALL_DIR}"
cp -R
"${DEVICE_DIR}/"
"${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create
"${DEVICE_DIR}/${PROJECT_NAME}"
"${SIMULATOR_DIR}/${PROJECT_NAME}"
-output
"${INSTALL_DIR}/${PROJECT_NAME}"
open
"${DEVICE_DIR}"
open
"${SRCROOT}/Products"
fi
于是我们有了我们自己的私有动态库LJWXSDK,那么我们来验证我们之前的问题
首先指定一个LJWXSDK.podspec这里我直接传到了我的Github上面
123456789101112131415161718192021222324#
# Be sure to run `pod lib lint LJPod.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod:: Spec.
new
do
|s|
s.name =
'LJWXSDK'
s.version =
'0.1.0'
s.summary =
'A short description of LJWXSDK.'
s.description = <
'MIT'
, : file =>
'LICENSE'
}
s.author = {
'ValiantCat'
=>
'519224747@qq.com'
}
s.ios.deployment_target =
'8.0'
s.default_subspec =
'zip'
s.subspec
'zip'
do
|zip|
puts
'-------------------------------------------------------------------'
puts
'Notice: LJWXSDK is zip now'
puts
'-------------------------------------------------------------------'
zip.ios.vendored_frameworks =
'*.framework'
end
end
注意上面我是把二进制压缩丢进了七牛的 oss 文件存储。毕竟免费还快。
然后通过 pod lib create 创建了一个 pod 用来验证之前我们的传递性依赖问题,
文件夹结构如下
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102.
├── Example
│ ├── LJA
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Images.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── LJA-Info.plist
│ │ ├── LJA-Prefix.pch
│ │ ├── LJAppDelegate.h
│ │ ├── LJAppDelegate.m
│ │ ├── LJViewController.h
│ │ ├── LJViewController.m
│ │ ├── en.lproj
│ │ │ └── InfoPlist.strings
│ │ └── main.m
│ ├── LJA.xcodeproj
│ ├── LJA.xcworkspace
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Pods
│ │ ├── Headers
│ │ ├── LJWXSDK
│ │ │ └── LJWXSDK.framework
│ │ │ ├── Headers
│ │ │ │ ├── LJWXSDK.h
│ │ │ │ ├── WXApi.h
│ │ │ │ ├── WXApiObject.h
│ │ │ │ └── WechatAuthSDK.h
│ │ │ ├── Info.plist
│ │ │ ├── LJWXSDK
│ │ │ ├── Modules
│ │ │ │ └── module.modulemap
│ │ │ ├── _CodeSignature
│ │ │ │ └── CodeResources
│ │ │ └── read_me.txt
│ │ ├── Local\ Podspecs
│ │ │ ├── LJA.podspec.json
│ │ │ ├── LJB.podspec.json
│ │ │ └── LJWXSDK.podspec.json
│ │ ├── Manifest.lock
│ │ ├── Pods.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace
│ │ ├── Target\ Support\ Files
│ │ │ ├── LJA
│ │ │ │ ├── Info.plist
│ │ │ │ ├── LJA-dummy.m
│ │ │ │ ├── LJA-prefix.pch
│ │ │ │ ├── LJA-umbrella.h
│ │ │ │ ├── LJA.modulemap
│ │ │ │ └── LJA.xcconfig
│ │ │ ├── LJB
│ │ │ │ ├── Info.plist
│ │ │ │ ├── LJB-dummy.m
│ │ │ │ ├── LJB-prefix.pch
│ │ │ │ ├── LJB-umbrella.h
│ │ │ │ ├── LJB.modulemap
│ │ │ │ └── LJB.xcconfig
│ │ │ ├── Pods-LJA_Example
│ │ │ │ ├── Info.plist
│ │ │ │ ├── Pods-LJA_Example-acknowledgements.markdown
│ │ │ │ ├── Pods-LJA_Example-acknowledgements.plist
│ │ │ │ ├── Pods-LJA_Example-dummy.m
│ │ │ │ ├── Pods-LJA_Example-frameworks.sh
│ │ │ │ ├── Pods-LJA_Example-resources.sh
│ │ │ │ ├── Pods-LJA_Example-umbrella.h
│ │ │ │ ├── Pods-LJA_Example.debug.xcconfig
│ │ │ │ ├── Pods-LJA_Example.modulemap
│ │ │ │ └── Pods-LJA_Example.release.xcconfig
│ │ │ └── Pods-LJA_Tests
│ │ │ ├── Info.plist
│ │ │ ├── Pods-LJA_Tests-acknowledgements.markdown
│ │ │ ├── Pods-LJA_Tests-acknowledgements.plist
│ │ │ ├── Pods-LJA_Tests-dummy.m
│ │ │ ├── Pods-LJA_Tests-frameworks.sh
│ │ │ ├── Pods-LJA_Tests-resources.sh
│ │ │ ├── Pods-LJA_Tests-umbrella.h
│ │ │ ├── Pods-LJA_Tests.debug.xcconfig
│ │ │ ├── Pods-LJA_Tests.modulemap
│ │ │ └── Pods-LJA_Tests.release.xcconfig
│ │ └── libWeChatSDK
│ │ ├── README.md
│ │ ├── WXApi.h
│ │ ├── WXApiObject.h
│ │ ├── WechatAuthSDK.h
│ │ └── libWeChatSDK.a
├── LICENSE
├── LJA
│ ├── Assets
│ └── Classes
│ └── LJA.m
├── LJA.podspec
├── LJB
│ ├── Assets
│ └── Classes
│ └── LJB.m
├── LJB.podspec
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj
测试工程我也丢在7牛上面。下载测试即可
编译运行。完美。我们又可以愉快的和swift第三方库配合使用。
很多人可能会问 诸如百度地图 微信这种sdk为什么官方不支持动态库版(所说的都是embeded Framework),猜测是为了兼容更低iOS7版本吧
很多人会觉得麻烦的要死。首先每个公司多多少少都有历史包袱,麻烦也要做,再者这是一次对基本功的补充,即便你们没有用到,但是为了学习,这篇教程所做的也值得你尝试一次。
剖析下动态库 Framework 吧
上述解决了我们一开始遇到的问题。but既然动态库和静态库压根就不一回事,所以里面还是有很多细节值得我们去了解的。
回过头来看 Embened Framework
首先我们之前记得如果一个动态库加在LinkedFrameworksand Libraies程序启动就会报ImageNotFound,如果放在EmbededBinaries里面就可以。这是为什么呢。我们拿MacoView来看下两种情况下可执行文件的细节
其中@rpth 这个路径表示的位置可以查看Xcode中的链接路径问题
这样我们就知道了其实加在EmbededBinaries里面的东西其实会被复制一份到xx.app里面,所以这个名字起得还是不错的直译就是嵌入的框架
Why Swift does not Support Staic Libraies
造成这个的主要原因是Swift的运行时库(不等同于OC的runtime概念),由于Swift的ABI不稳定,静态库会导致最终的目标程序中包含重复的运行库,相关可以看下最后的参考文章SwiftInFlux#static-libraries。等到我们的SwiftABI稳定之后,我们的静态库支持可能就又会出现了。当然也可能不出Swift伴随诞生的SPM(Swift,Package Manager),可能有更好的官方的包依赖管理工具。让我们期待吧。
CocoaPods使用Use_framework!
既然加了Swift的第三方库之后就需要在Podfile里面加上use_framework! 那么CocoaPods就会帮我们生成动态库,但是奇怪的是,我们并没有在主工程的embeded binaries看到这个动态库,这又是什么鬼。其实是CocoaPods使用脚本帮我们加进去了。脚本位置在主工程的build Phase下的Emded Pods frameworks
1"${SRCROOT}/Pods/Target Support Files/Pods-LJA_Example/Pods-LJA_Example-frameworks.sh"
动态库Framework的文件结构
123456789101112.
├── Headers
│ ├── LJWXSDK.h
│ ├── WXApi.h
│ ├── WXApiObject.h
│ └── WechatAuthSDK.h
├── Info.plist
├── LJWXSDK
├── Modules
│ └── module.modulemap
└── _CodeSignature
└── CodeResources
-
Headers 一般是头文件。非private里面的头文件都会在里面
-
info.plist 配置信息,不深究
-
Modules 这个文件夹里有个module.modulemap文件,后面在讲解
-
二进制文件,这就是上面提到的不带main的二进制文件了,.o 的打包体
-
_codeSignature签名文件 (苹果爸爸的约束)
-
more资源文件。这里暂时没用到,所以没有 ,但是这个也是个大坑
更愉快的导入文件
-
@class,@protocol:不说了就是声明一个类,并不导入。
-
#import <>, #import"":是加强版的#include<>,#include"" 防止重复导入的。
-
#import<> : 通过build setting里面中的header Search Path里面去找
-
#import"" : 第一步先搜索user Header search Path再搜索 header search Path 。所以对我们的framework来说,CocoaPod帮我们加到了Header search Path目前2种导入方式都是可以支持的。
上面的导入方式都带了 某个framework的路径"xx/xx.h" ,我们在开发自己主工程的时候会发现我们导入主工程其他类是不需要导入前缀的。 这又是怎么回事。
看下面的配置
目前的配置是non-recursive。如果把non去掉意思就是我可以递归的去查找某些framework下面的头文件了。 但是Xcode的效率肯定就会有影响。
还是不建议修改的好。
大家都知道iOS7之后多了@import,这又是什么鬼。
简单理解这个方式叫做Module导入,好处就是使用了@import 之后不需要在project setting手动添加framework,系统会自动加载,而且效率更高。
最主要的是swift也只能这样用。
导入的时候系统会查找如果有模块同名的文件就会导入这个文件。如果没有CocoaPods帮我们生成一个module-umbrela.hl文件,然后就是导入的这个文件。
回过头来看我们的framework的结构 里面有个Modules文件夹,里面有个文件module.modulemap
123456framework module LJWXSDK {
umbrella header
"LJWXSDK.h"
export *
module * { export * }
}
我们可以看到其实被暴露的header就是这个文件,之前我在按照#import "/"的时候有个警告
而且按照@import 导入的东西发现没有导入可用的头文件就是因为并没有在umbrella header的头文件中加入其他头文件。
加入之后我们就可以完美的使用@import ,并且#import"/" 也不会报warning
更多关于umbrella Header 参看文后参考
资源问题
首先我们来看常见的资源文件: 主要分为图片和其他类资源那么加载图片和加载其他资源都是怎么做的?
1: [UIimage imageNamed:]
2: [NSbundle bundleForclass[XXX class]]
其实方式1去本质就是去mainBundle去拿资源,方式2从XXX所在的框架里面去拿。
前面也说道framework只是资源的打包方式,本质上是有两种的。
我们这个framework如果本质是静态库,那么无需改变使用方式,资源最终都会打包到Main Bundle里面
如果我们这个framework本质是动态库,那么我们的资源就发生了变化,资源就会被存放在framework里面。所以我们需要使[NSbundle bundleForclass[XXX class]]。需要注意的是很多人为了简单,下意
的使用self class传递,但是有可能这个self实例不在资源所属的framework。所以会出现资源加载失败。一定要谨慎使用。
-
-
apache动态编译和静态编译问题
2013-04-08 18:17:04编译和安装apache分为动态、静态两种方式。 动态编译是指在以后的使用中随时调整配置文件就可以加载模块;静态则相反,在编译时就决定了相应的模块。 举例: 以mod_rewrite模块为例: 错误方式: ./...转自:http://blog.163.com/lgh_2002/blog/static/44017526201002455551991/
编译和安装apache分为动态、静态两种方式。
动态编译是指在以后的使用中随时调整配置文件就可以加载模块;静态则相反,在编译时就决定了相应的模块。
举例: 以mod_rewrite模块为例:
错误方式:
./configure
--prefix=/usr/local/apache2
--enable-so
--enable-mods-shared=most
--enable-rewrite
--enable-speling
--enable-forward
--enable-ssl
--with-ssl=/usr/local/openssl会导致,ssl启动apache的时候报告:
apachectl startssl
Syntax error on line 246 of /usr/local/apache2/conf/httpd.conf:
Cannotload /usr/local/apache2/modules/mod_ssl.so into server:/usr/local/apache2/modules/mod_ssl.so: undefined symbol: X509_free解释:
问题出在–enable-so,–enable-so表示让apache核心装载DSO,但是不实际编译任何动态模块;
–enable-ModuleName表示,编译并包含模块ModuleName;
–enable-ModuleName=shared表示,将这个模块编译成动态的。正确方式:
搞清除上面所述的内容,就ok了:
应该去掉–enable-so这行;
如何希望动态编译模块:比如:–enable-rewrite应该替换为: –enable-rewrite=shared
最后,我将要编译的应该为:
./configure
--prefix=/usr/local/apache2
--enable-mods-shared=most
--enable-rewrite
--enable-speling
--enable-forward
--enable-ssl
--with-ssl=/usr/local/openssl
解释:–enable-mods-shared=most表示,动态的编译进来大多数的模块。那么,–enable-mods-shared=all是指动态的编译所有的模块。如果把-shared去掉,就是静态的编译了。
最后再总结一下:动态、静态apache编译安装的方式的区别。
静态编译,就是将module直接在安装的过程中放到apache中,当apache使用module的时候,就可以直接使用了。而动态编译安装,只是将module引入到apache之中,在使用的时候才会真正的去寻找,但是在动态中必须有正确的地址,否则就会出现上文提到的错误。
-
后台面试经典问题-gcc生成动态库和静态库
2018-10-22 17:22:48gcc生成静态库: 第一步:生成test.o目标文件,使用gcc -c test.c -o test.o 第二步:使用ar将test.o打包成libtest.a静态库,ar rcs -o libtest.a test.o 第三步:ar t libtest.a可查看...gcc生成动态库: 第...gcc生成静态库:
第一步:生成test.o目标文件,使用gcc -c test.c -o test.o
第二步:使用ar将test.o打包成libtest.a静态库,ar rcs -o libtest.a test.o
第三步:ar t libtest.a可查看静态库包含哪些文件。
第四步:使用libtest.a,链接时-llibtest.a即可。
gcc生成动态库:
第一步:生成test.o目标文件,gcc -c -o test.o -fPIC test.c,其中-fPIC参数用于生成位置无关代码以供生成动态库使用。
第二步:使用-shared参数生成动态库,使用如下命令:gcc -shared -o libshare.so test.o。
上面两步的命令可合为一个:gcc -shared -fPIC -o libshare.so test.c
第三步:使用libshare.so动态库,gcc -o app_share main.c ./libshare.so
-
linux下静态库和动态库问题
2016-11-05 16:30:25文档介绍了linux下静态库和动态库生成以及使用问题。文档介绍了linux下静态库和动态库生成以及使用问题。 -
关于动态库和静态库的问题
2015-04-03 15:03:57关于静态库的使用 静态库不需要main函数,其他函数的定义也没有太大的区别,需要设置项目属性中的: 生产一个xxx.lib的文件 关于静态库的使用 新建一个项目,然后将xxx.lib文件拷贝过来,放在这个工程文件... -
linux下g++ 编译时动态库和静态库的链接和头文件问题
2018-03-30 09:35:21原来编译的时候都是用的很随意,没用系统的总结一下,这几天在编译的时候遇到一些...1.动态库和静态库简介 静态库在程序链接的时候会自动的链接到程序里,所以一旦编译完成,静态库就不需要了,静态库以.a -
制作传统动态库和静态库遇到的问题
2019-05-06 16:01:35之前整理过两种打包静态库的方法与使用:iOS制作.framework静态库、 iOS使用.framework类型的静态库和iOS制作.a类型的静态库、iOS使用.a类型的静态库。不过这种方式的缺点很明显,以我们要开发的SDK自定义库为例子:... -
动态链接库和静态链接库若干的问题
2018-02-12 21:41:50动态链接库和静态链接库若干的问题 参考: 动态链接和静态链接库 显式加载与隐式加载区别 Window下隐式和显式调用动态库 Linux下隐式和显式调用动态库 问题1:动态链接需不需要lib(导入库)及其区别 问题2:... -
关于VS动态库和静态库编译问题
2017-06-18 12:15:08解决问题:需要制作一个动态库A,其中A调用了B和C两个外部库中的一些方法。 方法:在VS中选择Win32项目->dll 注:一定要保证依赖库B和C的编译方式(MT/MD)与A的方式相同。 假设生成A的项目调用BC有以下情况: 1,B... -
linux下动态库和静态库引用问题解决
2012-01-14 12:15:27linux下动态库和静态库引用问题解决 基本概念 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。 例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在库文件名后... -
Java框架学习:SpringMVC之动态资源和静态资源访问冲突问题、常用注解
2020-06-08 10:39:59文章目录动态资源和静态资源访问冲突问题出现的问题解决方案常用注解@RequestMapping 动态资源和静态资源访问冲突问题 出现的问题 web.xml配置文件 <servlet> <servlet-name>DispatcherServlet</... -
动态网页和静态网页
2020-07-13 15:32:20动态网页和静态网页 首先必须要明白一点:所有的网页,不管是动态网页还是静态网页,都是由Web服务器所创建的。 动态网页和静态网页的最明显区别在于:显示内容是否变化。 静态网页就是内容固定、不会变化的网页,... -
解决全站字符编码问题--动态代理和静态代理
2018-03-06 15:32:04动态代理和静态代理的区别动态代理是在运行时,将代理类加载到内存中静态代理是提前把代理类写好,然后再启动项目的时候把代理类加载到内存中 动态代理 public class EncodingFilter implements Filter { public ... -
QT环境配置的常见问题(动态库和静态库)
2021-01-05 16:19:47LIBS:静态库(直接在 .pro文件里面配置) DLL:动态库(要么在计算机的环境变量中添加,要么直接把需要的动态库添加到需要的debug目录下) -
Linux下动态库和静态库及相关问题
2014-01-07 09:55:55.o 和.obj 是经过编译程序得到的目标文件,只是未经过链接(大家都知道程序编译经过 ....a 和.lib 是静态库,.a一般是linux系统下动态库,.lib一般是windows下的静态库。其中静态库基本是将.o或者.obj文件打包。 . -
xcode编译动态库需要依赖其他动态库和静态库的问题
2019-07-11 14:33:15在用xcode编译dylib的时候,需要依赖第三方的dylib和.a文件时,当为debug版本没有出现编译出来的dylib库需要依赖相应的.a文件的.dylib文件,为release版本时就不行了。 举个例子:编译c.dylib需要依赖b.a,当为... -
linux动态库和静态库
2021-02-09 16:03:57如何生成静态库动态库;nm查看库中包含那些函数、ar生成静态库,查看库中包含那些.o文件、ldd查看程序依赖的.so文件;gcc/g++与库相关的参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索的过程;... -
动态链接和静态链接
2019-08-11 11:08:55静态链接的问题 当静态库更新时那么整个程序都要重新链接; 对于printf这种标准函数库,如果每个程序都要代码,这将会极大的浪费资源。 动态链接 在给定的文件系统中一个库只有一个文件,所有引用该库的可... -
动态分配和静态分配
2019-06-28 21:06:11动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。 例如我们定义一个float型数组:float score[100]; 但是,在使用数组的... -
动态库和静态库
2019-04-22 11:49:00程序库(函数库)分为静态库和动态库。 前者在链接的时候加入到执行代码中,链接之后可以删除,不会影响程序执行; 后者在链接时只是指定了库的位置,不会加入代码中,程序执行前删除动态库会出问题。 动... -
关于android 动态库和静态库的问题
2012-03-06 12:57:25我是不是也要把 libbridge.so 和 libOMX_Core.so这两个动态库跟测序程序的执行文件放在一起导入真机里呀? 还有是不是还待把ti 编码组件的so文件(libOMX.TI.Video.encoder.so)也导进去吧? 但是为什么LOCAL_... -
控件动态创建和静态创建的问题。
2012-01-01 10:42:37比如我现在疑惑的控件动态创建和静态创建的问题。 我在VS2005,对话框的资源视图的一个对话框里,随手拖一个控件,写上ID号IDD_p2SetData。然后根据孙鑫的书添上响应右键消息的一个非模态对话框的创建代码。 P2... -
动态lacp和静态lacp区别_液压静态和动态负荷传感转向系统区别和应用
2021-01-04 15:50:58下面进一步讨论静态与动态负荷转向系统的区别。早期商业化负荷传感转向系统LS信号属于静态的信号,即在负荷信号稳态条件下,LS管路中没有流量,而且系统采用定量泵供油,泵给出的是恒定流量,对泵无变量要求的问题。... -
gcc编译工具生成动态库和静态库之三----问题及重要知识点分析
2016-08-17 15:09:14gcc编译工具生成动态库和静态库
-
局域网互相ping失败解决办法
-
牛牛量化策略交易
-
性能调优攻略
-
MHA 高可用 MySQL 架构与 Altas 读写分离
-
i710750h和r74800h玩游戏哪个好 r7 4800h和i7 10750h哪个性能好
-
龙芯实训平台应用实战(希云)
-
LVS + Keepalived 实现 MySQL 负载均衡与高可用
-
2021 年该学的 CSS 框架 Tailwind CSS 实战视频
-
SpringMVC的RESTFulCRUD-源码
-
FastDFS 分布式文件系统部署
-
go-hostpool:从Go应用程序智能灵活地在多个主机之间进行池化-源码
-
SIBO USB无线网卡驱动
-
numpy.around之谜
-
MySQL 四类管理日志(详解及高阶配置)
-
kevlar-tz:KEVLAR-TZ信息库-源码
-
鸿蒙系统Harmonyos源码架构分析-第1期第2课
-
access应用的3个开发实例
-
一、认识promise
-
程序员必修基础套餐课
-
MySQL Router 实现高可用、负载均衡、读写分离