Mach-O 平台上的库版本控制
Library versioning on Mach-O platforms
当 SOVERSION
目标 属性 的文档提到在 Mach-O 系统(例如 OS X 和iOS对应的是"compatibility version",而VERSION
对应的是"current version".
在Linux上,它只是类似VERSION 5.4.2
和SOVERSION 5
的东西,表示该库与5.0及更新版本兼容,VERSION
用作Windows 上 <major>.<minor>
形式的 DLL 映像版本(我不确定 SOVERSION
对 Windows 有何影响)。
但是,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 版本保持兼容? "compatible" 是什么意思?
首先,为了解决这个问题,框架只是名为 Something.framework/Something
而不是 libsomething.dylib
的动态库。尽管文件格式完全相同,因此在整个过程中 post 我将简单地将它们称为 dylibs。
现在,让我们从 mach-o/loader.h
header(Mach-O 文件格式的 de-facto 权威来源)的摘录开始:
/*
* 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
用于确定库是否 "new enough" 用于要加载它的二进制文件。
current_version
用于在多个库可用时选择一个库。
至于您对 16.4.0
的当前版本与 1.0.0
的兼容版本感到困惑:从 some sources 来看,Apple 似乎会在有引入的任何类型的功能,并使用次要版本几乎仅修复错误,AFAIK。
所以他们称之为 16.4.0
,我可能会称之为 1.16.4
。 ;)
当 SOVERSION
目标 属性 的文档提到在 Mach-O 系统(例如 OS X 和iOS对应的是"compatibility version",而VERSION
对应的是"current version".
在Linux上,它只是类似VERSION 5.4.2
和SOVERSION 5
的东西,表示该库与5.0及更新版本兼容,VERSION
用作Windows 上 <major>.<minor>
形式的 DLL 映像版本(我不确定 SOVERSION
对 Windows 有何影响)。
但是,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 版本保持兼容? "compatible" 是什么意思?
首先,为了解决这个问题,框架只是名为 Something.framework/Something
而不是 libsomething.dylib
的动态库。尽管文件格式完全相同,因此在整个过程中 post 我将简单地将它们称为 dylibs。
现在,让我们从 mach-o/loader.h
header(Mach-O 文件格式的 de-facto 权威来源)的摘录开始:
/*
* 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
用于确定库是否 "new enough" 用于要加载它的二进制文件。current_version
用于在多个库可用时选择一个库。
至于您对 16.4.0
的当前版本与 1.0.0
的兼容版本感到困惑:从 some sources 来看,Apple 似乎会在有引入的任何类型的功能,并使用次要版本几乎仅修复错误,AFAIK。
所以他们称之为 16.4.0
,我可能会称之为 1.16.4
。 ;)