meson: Meson outputs incorrectly-named shared libraries on OpenBSD

Meson can’t find shared libraries like /usr/lib/libm.so.10.1 in OpenBSD, but uses static libraries like /usr/lib/libm.a. OpenBSD uses ELF shared libraries but (unlike other ELF systems) has no symbolic link named libm.so. I have OpenBSD/amd64 6.3 and meson 0.47.0.dev1 (8a9f7cf).

Sometimes the compiler still uses the shared library, but sometimes it doesn’t. For example, OpenBSD’s package of libiconv installs /usr/local/lib/libiconv.a and /usr/local/lib/libiconv.so.6.0. The compiler and Meson don’t look in /usr/local by default, and libiconv doesn’t use pkg-config, so I will tell Meson to look for libiconv in /usr/local if the system is OpenBSD.

I have this C program iopen.c

#include <iconv.h>
#include <stdio.h>

int main(int argc, char **argv) {
    iconv_t cd = iconv_open("UTF-8", "EUC-JP");
    printf("got %lld", (long long)cd);
}

and its meson.build

project('cbrt', 'c')
cc = meson.get_compiler('c')
dirs = []
if host_machine.system() == 'openbsd'
    dirs += '/usr/local/lib'
    add_global_arguments('-I/usr/local/include', language: 'c')
endif
libiconv = cc.find_library('iconv', dirs: dirs, required: false)
executable('iopen', 'iopen.c', dependencies: libiconv)

Now I build it:

$ meson build
The Meson build system
Version: 0.47.0.dev1
Source dir: /home/kernigh/park/example
Build dir: /home/kernigh/park/example/build
Build type: native build
Project name: cbrt
Native C compiler: cc (clang 5.0.1 "OpenBSD clang version 5.0.1 (tags/RELEASE_50
1/final) (based on LLVM 5.0.1)")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Library iconv found: YES
Build targets in project: 1
Found ninja-1.8.2 at /usr/local/bin/ninja
$ ninja -vC build
ninja: Entering directory `build'
[1/2] cc -Iiopen@exe -I. -I.. -I/usr/local/include -Xclang -fcolor-diagnostics -
pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -O0 -g  -MD -MQ 'iopen@exe/iopen
.c.o' -MF 'iopen@exe/iopen.c.o.d' -o 'iopen@exe/iopen.c.o' -c ../iopen.c
[2/2] cc  -o iopen 'iopen@exe/iopen.c.o' -Wl,--no-undefined -Wl,--as-needed -Wl,
--start-group /usr/local/lib/libiconv.a -Wl,--end-group  

Meson used /usr/local/lib/libiconv.a, not /usr/local/lib/libiconv.so.6.0.

Meson might need to look for libraries named libiconv.so.X.Y, and pick the one with the highest version; see “Understanding shared libraries number rules”.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 1
  • Comments: 22 (22 by maintainers)

Commits related to this issue

Most upvoted comments

Meson’s master, having merged #3851, can now find shared libraries like libiconv.so.6.0.

I found a problem: if there are multiple versions of the same library, Meson picks any one of them. Meson might pick a version that is too old, then the build might be wrong. I had deleted most of my old libraries, so my builds are working for now. To demonstrate the problem on OpenBSD,

  • duck.c is a library that just returns a version string
const char *quack(void) { return V; }
  • new.sh builds several versions of that library
set -e
dir=/tmp/lib
mkdir -p "$dir"
for version in "$@"; do
  file=libduck.so.$version
  cc -shared -o "$dir/$file" -Wl,-soname,"$file" -DV=\""$version"\" duck.c
  echo made "$file"
done
  • example.c is a program to print the library’s version
#include <stdio.h>
const char *quack(void);
int main(void) { printf("Quack %s\n", quack()); }
  • meson.build finds the library and builds the program
project('example', 'c')
dir = '/tmp/lib'
libduck = meson.get_compiler('c').find_library('duck', dirs: dir)
executable('example', 'example.c', dependencies: libduck,
  build_rpath: dir, install_rpath: dir)

I build 5 major versions of the library, then build the program.

$ sh new.sh 3.0 4.0 5.0 1.0 2.0
made libduck.so.3.0
made libduck.so.4.0
made libduck.so.5.0
made libduck.so.1.0
made libduck.so.2.0
$ meson build
...
Library duck found: YES
...
$ ninja -C build
ninja: Entering directory `build'
[2/2] Linking target example.
$ build/example
Quack 3.0

Meson picked version 3.0 instead of version 5.0. If the program needs some feature that wasn’t in 3.0, or some struct changed between 3.0 and 5.0, then the program might not work now.

I want Meson to pick the highest version. In my draft code, I tried to pick the highest version using a regexp ending in '\.([0-9]+)\.([0-9]+)\Z' to capture version = tuple(map(int, match.group(1, 2))) to compare version > best_v. The code by @nirbheek uses a glob pattern to get the correct filenames; perhaps the pattern should come with a function that turns libduck.so.5.0 into (5, 0), so one can use Python’s max().