packaging: prelink static libraries that need to be linked fully
Some of the Lix libraries always need to be linked in full due to their reliance on static initializers. This was achieved internally using link_whole, but they are still easy to abuse by external users who manually need to remember passing linker flags such as `--whole-archive` (GNU) or `-force_load` (Apple), and the obvious way to shove it in pkg-config breaks Meson due to potentially including a library's flags multiple times, and then deduplicating only the file names leaving a stale `-force_load` around causing trouble. Instead we now "prelink" the static libraries, by merging them into one object file. Since the static linker will always link entire object files, this will have the same effect as whole-archive linking (except the library won't be included if it's completely unused, which should not cause trouble since it's unused after all, and dynamic libraries behave the same way). Unfortunately Meson's native prelink functionality cannot be used due to missing (non-Apple) Clang support [1], so write our own one. While not particularly portable, it should work with Clang which is the only officially supported compiler, as well as GCC. [1] https://github.com/mesonbuild/meson/pull/14846 Change-Id: I6a6a6964a82241ce3b0b11fe8397fd451b8027f2
This commit is contained in:
+41
-23
@@ -270,32 +270,59 @@ libexpr_headers = files(
|
||||
# keep-sorted end
|
||||
)
|
||||
|
||||
libexpr = library(
|
||||
'lixexpr',
|
||||
dependencies = [
|
||||
liblixutil,
|
||||
liblixstore,
|
||||
liblixfetchers,
|
||||
boehm,
|
||||
boost,
|
||||
toml11,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
]
|
||||
|
||||
libexpr_temp = library(
|
||||
is_static ? 'lixexpr_temp' : 'lixexpr',
|
||||
libexpr_sources,
|
||||
libexpr_settings_header,
|
||||
libexpr_generated_headers,
|
||||
register_builtins_header,
|
||||
register_builtin_constants_header,
|
||||
dependencies : [
|
||||
liblixutil,
|
||||
liblixstore,
|
||||
liblixfetchers,
|
||||
boehm,
|
||||
boost,
|
||||
toml11,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
],
|
||||
dependencies : dependencies,
|
||||
# for shared.hh
|
||||
include_directories : [
|
||||
'../libmain',
|
||||
],
|
||||
cpp_pch : cpp_pch,
|
||||
install : true,
|
||||
install : not is_static,
|
||||
# FIXME(Qyriad): is this right?
|
||||
install_rpath : libdir,
|
||||
)
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
# FIXME: replace by prelink when https://github.com/mesonbuild/meson/pull/14846 is widely available.
|
||||
if is_static
|
||||
libexpr_prelink = custom_target(
|
||||
'lixexpr-prelink',
|
||||
output : 'lixexpr-prelink.o',
|
||||
input : libexpr_temp,
|
||||
command : [
|
||||
cxx.cmd_array(),
|
||||
'-r',
|
||||
'-o',
|
||||
'@OUTPUT@',
|
||||
is_darwin ? '-Wl,-force_load' : '-Wl,--whole-archive',
|
||||
'@INPUT@',
|
||||
],
|
||||
)
|
||||
libexpr = library(
|
||||
'lixexpr',
|
||||
[libexpr_prelink],
|
||||
dependencies : dependencies,
|
||||
install : true,
|
||||
)
|
||||
else
|
||||
libexpr = libexpr_temp
|
||||
endif
|
||||
|
||||
install_headers(
|
||||
libexpr_headers,
|
||||
@@ -312,16 +339,7 @@ liblixexpr = declare_dependency(
|
||||
)
|
||||
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
if is_static
|
||||
liblixexpr_mstatic = declare_dependency(
|
||||
include_directories : include_directories('../..'),
|
||||
sources : libexpr_settings_header,
|
||||
dependencies : [boehm],
|
||||
link_whole : libexpr,
|
||||
)
|
||||
else
|
||||
liblixexpr_mstatic = liblixexpr
|
||||
endif
|
||||
liblixexpr_mstatic = is_static ? liblixexpr.as_link_whole() : liblixexpr
|
||||
meson.override_dependency('lix-expr', liblixexpr_mstatic)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
|
||||
+37
-20
@@ -46,22 +46,49 @@ libfetchers_settings_header = custom_target(
|
||||
install_dir : includedir / 'lix/libfetchers',
|
||||
)
|
||||
|
||||
libfetchers = library(
|
||||
'lixfetchers',
|
||||
dependencies = [
|
||||
liblixstore,
|
||||
liblixutil,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
]
|
||||
|
||||
libfetchers_temp = library(
|
||||
is_static ? 'lixfetchers_temp' : 'lixfetchers',
|
||||
libfetchers_settings_header,
|
||||
libfetchers_sources,
|
||||
dependencies : [
|
||||
liblixstore,
|
||||
liblixutil,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
],
|
||||
dependencies : dependencies,
|
||||
include_directories : [ '../..' ],
|
||||
cpp_pch : cpp_pch,
|
||||
install : true,
|
||||
install : not is_static,
|
||||
# FIXME(Qyriad): is this right?
|
||||
install_rpath : libdir,
|
||||
)
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
# FIXME: replace by prelink when https://github.com/mesonbuild/meson/pull/14846 is widely available.
|
||||
if is_static
|
||||
libfetchers_prelink = custom_target(
|
||||
'lixfetchers-prelink',
|
||||
output : 'lixfetchers-prelink.o',
|
||||
input : libfetchers_temp,
|
||||
command : [
|
||||
cxx.cmd_array(),
|
||||
'-r',
|
||||
'-o',
|
||||
'@OUTPUT@',
|
||||
is_darwin ? '-Wl,-force_load' : '-Wl,--whole-archive',
|
||||
'@INPUT@',
|
||||
],
|
||||
)
|
||||
libfetchers = library(
|
||||
'lixfetchers',
|
||||
[libfetchers_prelink],
|
||||
dependencies : dependencies,
|
||||
install : true,
|
||||
)
|
||||
else
|
||||
libfetchers = libfetchers_temp
|
||||
endif
|
||||
|
||||
install_headers(libfetchers_headers, subdir : 'lix/libfetchers', preserve_path : true)
|
||||
|
||||
@@ -85,14 +112,4 @@ liblixfetchers = declare_dependency(
|
||||
link_with : libfetchers,
|
||||
)
|
||||
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
if is_static
|
||||
liblixfetchers_mstatic = declare_dependency(
|
||||
include_directories : include_directories('../..'),
|
||||
sources : libfetchers_settings_header,
|
||||
link_whole : libfetchers,
|
||||
)
|
||||
else
|
||||
liblixfetchers_mstatic = liblixfetchers
|
||||
endif
|
||||
meson.override_dependency('lix-fetchers', liblixfetchers_mstatic)
|
||||
meson.override_dependency('lix-fetchers', liblixfetchers)
|
||||
|
||||
+29
-14
@@ -402,8 +402,8 @@ if host_machine.system() == 'freebsd'
|
||||
dependencies += [ libprocstat ]
|
||||
endif
|
||||
|
||||
libstore = library(
|
||||
'lixstore',
|
||||
libstore_temp = library(
|
||||
is_static ? 'lixstore_temp' : 'lixstore',
|
||||
libstore_sources,
|
||||
libstore_generated_sources,
|
||||
libstore_settings_headers,
|
||||
@@ -413,10 +413,35 @@ libstore = library(
|
||||
dependencies : dependencies,
|
||||
cpp_args : cpp_args,
|
||||
cpp_pch : cpp_pch,
|
||||
install : true,
|
||||
install : not is_static,
|
||||
# FIXME(Qyriad): is this right?
|
||||
install_rpath : libdir,
|
||||
)
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
# FIXME: replace by prelink when https://github.com/mesonbuild/meson/pull/14846 is widely available.
|
||||
if is_static
|
||||
libstore_prelink = custom_target(
|
||||
'lixstore-prelink',
|
||||
output : 'lixstore-prelink.o',
|
||||
input : libstore_temp,
|
||||
command : [
|
||||
cxx.cmd_array(),
|
||||
'-r',
|
||||
'-o',
|
||||
'@OUTPUT@',
|
||||
is_darwin ? '-Wl,-force_load' : '-Wl,--whole-archive',
|
||||
'@INPUT@',
|
||||
],
|
||||
)
|
||||
libstore = library(
|
||||
'lixstore',
|
||||
[libstore_prelink],
|
||||
dependencies : dependencies,
|
||||
install : true,
|
||||
)
|
||||
else
|
||||
libstore = libstore_temp
|
||||
endif
|
||||
|
||||
install_headers(libstore_headers, subdir : 'lix/libstore', preserve_path : true)
|
||||
|
||||
@@ -427,17 +452,7 @@ liblixstore = declare_dependency(
|
||||
link_with : libstore,
|
||||
)
|
||||
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
if is_static
|
||||
liblixstore_mstatic = declare_dependency(
|
||||
include_directories : include_directories('../..'),
|
||||
sources : libstore_settings_headers,
|
||||
link_whole : libstore,
|
||||
)
|
||||
else
|
||||
liblixstore_mstatic = liblixstore
|
||||
endif
|
||||
meson.override_dependency('lix-store', liblixstore_mstatic)
|
||||
meson.override_dependency('lix-store', liblixstore)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
# while meson migration is in progress, and we want to not include boost here
|
||||
|
||||
+45
-41
@@ -323,8 +323,23 @@ foreach rpc : libutil_rpc
|
||||
libutil_rpc_sources += rpc[1]
|
||||
endforeach
|
||||
|
||||
libutil = library(
|
||||
'lixutil',
|
||||
dependencies = [
|
||||
aws_sdk,
|
||||
aws_s3,
|
||||
boehm,
|
||||
boost,
|
||||
cpuid,
|
||||
seccomp,
|
||||
libarchive,
|
||||
brotli,
|
||||
openssl,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
capnp_rpc,
|
||||
]
|
||||
|
||||
libutil_temp = library(
|
||||
is_static ? 'lixutil_temp' : 'lixutil',
|
||||
libutil_sources,
|
||||
libutil_rpc_sources,
|
||||
libutil_rpc_headers,
|
||||
@@ -333,25 +348,37 @@ libutil = library(
|
||||
deprecated_features_header,
|
||||
deprecated_features_impl_header,
|
||||
libutil_settings_headers,
|
||||
dependencies : [
|
||||
aws_sdk,
|
||||
aws_s3,
|
||||
boehm,
|
||||
boost,
|
||||
cpuid,
|
||||
seccomp,
|
||||
libarchive,
|
||||
brotli,
|
||||
openssl,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
capnp_rpc,
|
||||
],
|
||||
dependencies : dependencies,
|
||||
include_directories : [ '../..' ],
|
||||
cpp_pch : cpp_pch,
|
||||
implicit_include_directories : true,
|
||||
install : true,
|
||||
install : not is_static,
|
||||
)
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
# FIXME: replace by prelink when https://github.com/mesonbuild/meson/pull/14846 is widely available.
|
||||
if is_static
|
||||
libutil_prelink = custom_target(
|
||||
'lixutil-prelink',
|
||||
output : 'lixutil-prelink.o',
|
||||
input : libutil_temp,
|
||||
command : [
|
||||
cxx.cmd_array(),
|
||||
'-r',
|
||||
'-o',
|
||||
'@OUTPUT@',
|
||||
is_darwin ? '-Wl,-force_load' : '-Wl,--whole-archive',
|
||||
'@INPUT@',
|
||||
],
|
||||
)
|
||||
libutil = library(
|
||||
'lixutil',
|
||||
[libutil_prelink],
|
||||
dependencies : dependencies,
|
||||
install : true,
|
||||
)
|
||||
else
|
||||
libutil = libutil_temp
|
||||
endif
|
||||
|
||||
install_headers(libutil_headers, subdir : 'lix/libutil', preserve_path : true)
|
||||
|
||||
@@ -389,27 +416,4 @@ liblixutil = declare_dependency(
|
||||
link_with : libutil
|
||||
)
|
||||
|
||||
# FIXME: remove when https://git.lix.systems/lix-project/lix/issues/359 is fixed.
|
||||
if is_static
|
||||
liblixutil_mstatic = declare_dependency(
|
||||
include_directories : include_directories('../..'),
|
||||
sources : [
|
||||
experimental_features_header,
|
||||
deprecated_features_header,
|
||||
libutil_settings_headers,
|
||||
libutil_rpc_headers,
|
||||
],
|
||||
dependencies: [
|
||||
boost,
|
||||
# Everything has to link to kj if it uses libutil internally (ensured by
|
||||
# lix-base pkg-config externally)
|
||||
kj,
|
||||
libarchive,
|
||||
capnp_rpc,
|
||||
],
|
||||
link_whole : libutil,
|
||||
)
|
||||
else
|
||||
liblixutil_mstatic = liblixutil
|
||||
endif
|
||||
meson.override_dependency('lix-util', liblixutil_mstatic)
|
||||
meson.override_dependency('lix-util', liblixutil)
|
||||
|
||||
+4
-4
@@ -169,10 +169,10 @@ nix = executable(
|
||||
dependencies : [
|
||||
libasanoptions,
|
||||
liblixcmd,
|
||||
liblixutil_mstatic,
|
||||
liblixstore_mstatic,
|
||||
liblixexpr_mstatic,
|
||||
liblixfetchers_mstatic,
|
||||
liblixutil,
|
||||
liblixstore,
|
||||
liblixexpr,
|
||||
liblixfetchers,
|
||||
liblixmain,
|
||||
boehm,
|
||||
nlohmann_json,
|
||||
|
||||
-13
@@ -16,19 +16,6 @@
|
||||
#
|
||||
# Finally, lix/nix/meson.build defines the Nix command itself, relying on all prior meson files.
|
||||
#
|
||||
# libstore, libexpr, and libfetchers have some special handling to make static builds work.
|
||||
# Their use static constructors for dynamic registration of primops, store backends, etc
|
||||
# gets borked during static link. We can't simply wholesale apply `link_whole :` either,
|
||||
# because these libraries get linked multiple times since Lix's components are transitively
|
||||
# dependent. So instead, each of those libraries have two dependency objects:
|
||||
# liblix{store,expr,fetchers,util} and liblix{store,expr,fetchers,util}_mstatic ("maybe static").
|
||||
# The _mstatic versions should be used in the `dependencies :` arguments to ALL EXECUTABLES
|
||||
# but executables ONLY. When we are not building statically (default_library != 'static'),
|
||||
# they are equivalent. When we are building statically, the _mstatic version will be
|
||||
# `link_whole :` rather than `link_with :`.
|
||||
# FIXME: This hack should be removed when https://git.lix.systems/lix-project/lix/issues/359
|
||||
# is fixed.
|
||||
#
|
||||
# lix-doc is built with Meson in lix-doc/meson.build, and linked into libcmd in
|
||||
# lix/libcmd/meson.build. When building outside the Nix sandbox, Meson will use the .wrap
|
||||
# files in subprojects/ to download and extract the dependency crates into subprojects/.
|
||||
|
||||
@@ -87,7 +87,7 @@ libutil_tester = executable(
|
||||
rapidcheck,
|
||||
gtest,
|
||||
liblixutil,
|
||||
liblixexpr_mstatic,
|
||||
liblixexpr,
|
||||
liblixutil_test_support,
|
||||
nlohmann_json,
|
||||
kj,
|
||||
@@ -155,7 +155,7 @@ libstore_tester = executable(
|
||||
libasanoptions,
|
||||
liblixstore_test_support,
|
||||
liblixutil_test_support,
|
||||
liblixstore_mstatic,
|
||||
liblixstore,
|
||||
liblixutil,
|
||||
rapidcheck,
|
||||
gtest,
|
||||
@@ -221,10 +221,10 @@ libexpr_tester = executable(
|
||||
libasanoptions,
|
||||
liblixexpr_test_support,
|
||||
liblixstore_test_support,
|
||||
liblixstore_mstatic,
|
||||
liblixstore,
|
||||
liblixutil,
|
||||
liblixexpr_mstatic,
|
||||
liblixfetchers_mstatic,
|
||||
liblixexpr,
|
||||
liblixfetchers,
|
||||
rapidcheck,
|
||||
gtest,
|
||||
nlohmann_json,
|
||||
@@ -253,8 +253,8 @@ libcmd_tester = executable(
|
||||
liblixcmd,
|
||||
liblixutil,
|
||||
liblixmain,
|
||||
liblixexpr_mstatic,
|
||||
liblixstore_mstatic,
|
||||
liblixexpr,
|
||||
liblixstore,
|
||||
gtest,
|
||||
boost,
|
||||
kj,
|
||||
|
||||
Reference in New Issue
Block a user