当SOVERSION
目标属性的文档提到在Mach-O系统(例如OS X和iOS)上,它对应于“兼容版本”时,我正在查看一个小型个人项目的共享库的版本。 ,而VERSION
对应于“当前版本”。
在Linux上,它类似于VERSION 5.4.2
和SOVERSION 5
之类的内容,表明该库与5.0版及更高版本兼容,并且VERSION
用作DLL映像版本,形式为在Windows上<major>.<minor>
(我不确定在Windows上SOVERSION
有什么区别)。
但是,the docs for the referenced FRAMEWORK
target property中的示例说明了如何在Mach-O平台上拥有VERSION 16.4.0
和SOVERSION 1.0.0
(我对构建框架不感兴趣,只是想知道版本控制方案。)
在Mach-O世界中版本控制如何工作?如果删除某些功能(如果会破坏兼容性),我习惯于碰到主要版本,那么16.4.0版的库如何与该库的1.0.0版保持兼容? “兼容”是什么意思?
答案 0 :(得分:3)
首先,只是为了解决这个问题,框架只是名为Something.framework/Something
而不是libsomething.dylib
的dylib。但是,文件格式完全相同,因此在本篇文章中,我仅将它们称为dylib。
现在,让我们从mach-o/loader.h
标头(Mach-O文件格式的实际权威来源)摘录开始:
/*
* Dynamicly linked shared libraries are identified by two things. The
* pathname (the name of the library as found for execution), and the
* compatibility version number. The pathname must match and the compatibility
* number in the user of the library must be greater than or equal to the
* library being used. The time stamp is used to record the time a library was
* built and copied into user so it can be use to determined if the library used
* at runtime is exactly the same as used to built the program.
*/
struct dylib {
union lc_str name; /* library's path name */
uint32_t timestamp; /* library's build time stamp */
uint32_t current_version; /* library's current version number */
uint32_t compatibility_version; /* library's compatibility vers number*/
};
/*
* A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
* contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
* An object that uses a dynamically linked shared library also contains a
* dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
* LC_REEXPORT_DYLIB) for each library it uses.
*/
struct dylib_command {
uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
LC_REEXPORT_DYLIB */
uint32_t cmdsize; /* includes pathname string */
struct dylib dylib; /* the library identification */
};
如评论中所述,struct dylib
既嵌入在库中,又嵌入到针对它的二进制链接中,都包含current_version
和compatibility_version
的副本。后者的工作方式已在此处进行了说明,但前者未解决。
可以在dyld
手册页上找到相关文档(来源为here,但在man
之外很难看):
DYLD_VERSIONED_FRAMEWORK_PATH
This is a colon separated list of directories that contain potential override frame-
works. The dynamic linker searches these directories for frameworks. For each
framework found dyld looks at its LC_ID_DYLIB and gets the current_version and
install name. Dyld then looks for the framework at the install name path. Whichever
has the larger current_version value will be used in the process whenever a framework
with that install name is required. This is similar to DYLD_FRAMEWORK_PATH except
instead of always overriding, it only overrides is the supplied framework is newer.
Note: dyld does not check the framework's Info.plist to find its version. Dyld only
checks the -current_version number supplied when the framework was created.
[...]
DYLD_VERSIONED_LIBRARY_PATH
This is a colon separated list of directories that contain potential override
libraries. The dynamic linker searches these directories for dynamic libraries. For
each library found dyld looks at its LC_ID_DYLIB and gets the current_version and
install name. Dyld then looks for the library at the install name path. Whichever
has the larger current_version value will be used in the process whenever a dylib
with that install name is required. This is similar to DYLD_LIBRARY_PATH except
instead of always overriding, it only overrides is the supplied library is newer.
简而言之:
compatibility_version
用于确定库是否对于要加载的二进制文件来说“足够新”。current_version
用于在多个库可用时选择一个库。关于您对使用当前版本的16.4.0
和兼容版本的1.0.0
感到困惑:从查看some sources来看,Apple似乎会在出现任何主要版本时撞到主要版本引入了新功能,并使用次要版本仅修复了AFAIK错误。
因此,他们称之为16.4.0
,我可能会称之为1.16.4
。 ;)