对于提供名称上遮盖系统库的库的 RPM 打包来说,最佳实践是什么?
背景:
对于 RPM 支持的 Linux 系统,我正在打包一个“自包含”的应用程序foo
,该应用程序希望位于 /opt 下并提供尽可能多的自己的依赖项,以免依赖主系统上安装的版本。(foo
使用 LD_LIBRARY_PATH 来避免系统库。)
不幸的是,其中一个foo
依赖项是库,其版本与主系统所需的grunk
版本完全相同。RPM 的自动libgrunk.so
提供:然后,generation 会将两个 RPM 标识为提供此库。(事实并非如此 — 只有系统包才会让任何程序都可以使用该库,而 包foo
只会让 可以使用该库foo
。)
这有时会使自动依赖性解析变得混乱。例如,yum
可能会安装错误的包,或者在需要两个包时只安装一个包。
例子:
grunk-libs-1.2-3.$arch.rpm # System Library
Files:
%{_libdir}/libgrunk.so.1
%{_libdir}/libgrunk.so.1.2
Provides:
libgrunk.so.1()(%{_arch})
foo-x.y.z-r.$arch.rpm # App
Files:
/opt/foo
/opt/foo/bin/...
Requires:
libgrunk.so.1()(%{_arch}) # foo needs grunk, but wants its own instance
foo-grunklibs-1.2-1.$arch.rpm # App Dependency
Files:
/opt/foo/libs/libgrunk.so.1
/opt/foo/libs/libgrunk.so.1.2
Provides:
libgrunk.so.1()(%{_arch}) # <-- same as from system "grunk-libs"
我暂时禁用了 AutoReqProv,但我希望能够利用 RPM 的自动功能和依赖项生成。我希望 RPM 知道确实foo.rpm
需要foo-grunklibs.rpm
后者的libgrunk.so.1
,但也知道主系统 rpm 中的相同库是不够的。
我认为我已经达到常规使用的极限了。有没有一种打包技术可以解决这个问题?
答案1
经过一段时间的考虑,我认为更正确的方法是使用 RPM 虚拟资源“命名空间”。例如:
Provides: resource # 'resource' is available to the whole system
Provides: namespace(resource) # 'resource' is specifically available only to "namespace"
RPM 最终看起来像这样:
grunk-libs.rpm
Provides: libgrunk.so.1()(%{_arch}) # System library. unchanged
foo.rpm
Requires: /bin/sh
Requires: libc.so.6()(%{_arch})
Requires: foo(libgrunk.so.1()(%{_arch})) # Note special foo(...) namespace
foo-grunklibs.rpm
Provides: foo(libgrunk.so.1()(%{_arch})) # Note special foo(...) namespace
这样,foo
对特殊构建的依赖性libgrunk
就无法通过普通的 RPM 来满足grunk-libs
,而必须由该库的 foo 特定构建来满足。
我的概念证明如下:
Name: foo
...
Source99: find-namespaced-requires # Here's the magic
%define _use_internal_dependency_generator 0
%define __find_requires %{SOURCE99} foo /bin/sh glibc
脚本查找命名空间需要包装标准 RPM%{_rpmconfigdir}/find-requires并过滤其输出。它的第一个参数是"foo(...)"
要使用的命名空间 (),后续参数是依赖项或提供依赖项的 RPM,这些依赖项应该不是被命名空间化。在这个例子中,我想要foo
需要主系统的 /bin/sh 以及来自 的普通 libc、libdl、libm 等glibc
,但其他所有依赖项都应假定为特定于foo
。
通过将上述大部分内容包装在构建时 RPM 中并说类似的话,可以使其更清晰、更通用:
Name: foo
BuildRequires: special-deps-macros
%define _namespace foo # defaults to %{name} ?
%define _generic_dependencies ... # defaults to /bin/sh glibc libselinux ?