mesonbuild / meson

The Meson Build System
http://mesonbuild.com
Apache License 2.0
5.42k stars 1.56k forks source link

cannot link static library with dep #12709

Open stsp opened 6 months ago

stsp commented 6 months ago

Describe the bug static_library() either completely ignore the dependency, or says its not a static library.

To Reproduce

ASFILES = [ 'int23.S', 'int0.S', 'asm.S', sfiles ]
libdjs = dependency('dj64static', static: true)
lib = static_library('dummy', ASFILES,
  link_whole: libdjs)

This results in:

meson.build:106:6: ERROR: <PkgConfigDependency dj64static: True None> is not a static library.

If instead of the link_whole we use

lib = static_library('dummy', ASFILES,
  dependencies: libdjs)

then configuration passes, but the dependencies is completely ignored.

Expected behavior libdummy.a should be linked with the library pointed by libdjs.

dcbaker commented 6 months ago

Do you have install : true in lib? If the lib isn’t installed we may optimize the build by not linking into the static archive, but instead linking it into any targets that link the static archive

stsp commented 6 months ago

Just tried install: true:

[6/6] rm -f libdummy.a && gcc-ar csrD libdummy.a libdummy.a.p/meson-generated_.._preprocessor_0.p_plt.s.o libdummy.a.p/int23.S.o libdummy.a.p/int0.S.o libdummy.a.p/asm.S.o

So nothing changed. The problem is not in the lib, but in the fact that meson believes:

meson.build:106:6: ERROR: <PkgConfigDependency dj64static: True None>
is not a static library.

But it is:

$ pkg-config --static --libs dj64static
/usr/i386-pc-dj64/lib/libc.a
stsp commented 6 months ago

If the lib isn’t installed we may optimize the build by not linking into the static archive, but instead linking it into any targets that link the static archive

In fact, I tried that manually as a work-around, and also failed. I have this custom_target():

libdjs = dependency('dj64static', static: true)
lib = static_library('dummy', ASFILES,
  dependencies: libdjs,
  install: true)
nasm_ld = find_program(['i686-linux-gnu-ld', 'i386-elf-ld', 'x86_64-linux-gnu-ld
elf = custom_target(TARGET + '.elf',
  output: [TARGET + '.elf', TARGET + '.map'],
  input: lib,
  command: [nasm_ld, '-melf_i386', '-static',
    '-Map=@OUTPUT1@', '-o', '@OUTPUT0@', '@INPUT@'])

I've failed to find a way of passing libdjs to this custom_target(). I need get_link_args() or alike to extract the library name, but nothing is exported. So passing directly to target is also broken.

dcbaker commented 6 months ago

Oh, actually, you may need the as_link_whole method: https://mesonbuild.com/Reference-manual_returned_dep.html#depas_link_whole

sorry, I’m on mobile

eli-schwartz commented 6 months ago

Linking two static libraries together is a "fat library". The general idea is to duplicatively bundle your dependencies and then provide a single object that other software can link to.

This works okay with shared libraries since link_whole is a linker flag.

For static libraries, it works differently because static libraries are different -- they don't link at all, they simply archive. To correctly archive a static library one must include the raw object files.

This is why link_whole requires a static_library() compiled by meson and does not support external dependencies for link_whole. In order to handle link_whole we would need to somehow extract object files from a system libdir, know which objects exist and regenerate the build whenever that list changes, and link to the extracted objects.

There is a WIP to do this: #9218

stsp commented 6 months ago

OK, thanks for an explanation. Then lets suppose I don't need to link 2 static libs. All I need is to pass the deps directly to custom_target(), which just calls the linker like this:

ASFILES = [ 'int23.S', 'int0.S', 'asm.S', sfiles ]
lib = static_library('dummy', ASFILES,
  build_by_default: false)
nasm_ld = find_program(['i686-linux-gnu-ld', 'i386-elf-ld', 'x86_64-linux-gnu-ld
libdjs = dependency('dj64static', static: true)
elf = custom_target(TARGET + '.elf',
  output: [TARGET + '.elf', TARGET + '.map'],
  input: [lib.extract_all_objects(recursive: true),
    libdjs.as_link_whole()],
  command: [nasm_ld, '-melf_i386', '-static',
    '-Map=@OUTPUT1@', '-o', '@OUTPUT0@', '@INPUT@'])

Linker does support linking objects and static libs together, but doing the above, I get this:

meson.build:113:11: ERROR: as_link_whole method is only supported on
declare_dependency() objects

So what to do? All I need is to pass the external lib name to the linker.

eli-schwartz commented 6 months ago

I already told you that as_link_whole() is not yet implemented for external dependencies.

I'm not certain what else you want me to say.

stsp commented 6 months ago

I simply wasn't sure I need as_link_whole() just to pass the lib name to the linker, and that there is no other way to do that (seemingly trivial) task. I thought if I don't need to link 2 static libs together, then there is some work-around available, but seems not? :(

stsp commented 6 months ago

Hi @bruchar1

Maybe you can help also with this problem? I am still absolutely unsure why do I need as_link_whole() here. All I need is to pass the external dep name to the linker...

stsp commented 6 months ago

I did a quick fix in #12756 Can we get off of this as_link_whole hook, and discuss the real solutions instead? :)