When using LIBADD in automake, libtool links incorrectly

609 Views Asked by At

I'm using automake to build my project. I have some third-party (open source) libraries as git submodules in my project that I want to individually build and link. Here's an edited (names changed) version of my Makefile.am:

lib_LTLIBRARIES = libfoo.la libbar.la
libbar_la_SOURCES = ../submodules/bar/bar.c

libfoo_la_LIBADD = libbar.la
libfoo_la_SOURCES = \
    some_source.c \
    some_other_source.c

libfoo_la_CFLAGS = $(CFLAGS)
libfoo_la_LDFLAGS = $(LIBS)

if OS_LINUX
libfoo_la_SOURCES += \
    linux/some_source.c \
    linux/some_other_source.c

libfoo_la_CFLAGS += $(PTHREAD_CFLAGS)
libfoo_la_LDFLAGS += $(PTHREAD_LIBS)
endif

if OS_WINDOWS_MSYS
libfoo_la_SOURCES += \
    nt/some_source.c \
    nt/some_other_source.c

libfoo_la_LDFLAGS += -no-undefined
endif

bin_PROGRAMS = main
main_SOURCES = main.c
main_LDADD = libfoo.la

autoreconf, configure and make run normally but make install fails with

/usr/bin/ld: cannot find -lbar
collect2: error: ld returned 1 exit status

It seems autoconf is trying to use libbar as a global, installed library instead of a local one? LDADD on the main target works fine though.

autoreconf -V outputs

autoreconf (GNU Autoconf) 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+/Autoconf: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David J. MacKenzie and Akim Demaille.

EDIT: I am on Linux. Don't mind the windows parts.

1

There are 1 best solutions below

1
ndim On

I tried to reproduce this on https://github.com/ndim/stackoverflow-q70584133 by basically copying the Makefile.am you have given and adding a few very basic source files.

I found that building on Linux for Linux (Fedora 35, autoconf 2.69-37, automake 1.16.2-5, libtool 2.4.6-42) worked fine. Also running the make installed result:

[user@host stackoverflow-q70584133]$ mkdir _b-host && cd _b-host
[user@host _b-host]$ ../configure --prefix=$PWD/_i
[user@host _b-host]$ make && make install && ./_i/bin/main
[...]
main: x86_64-pc-linux-gnu
foo_func
bar_func
foo_host_func: Linux 331524 = 0x50f04 = 5.15.4 (5.15.4)
[user@host _b-host]$ _

So if you have problems building on and for Linux, something else must be off.

I presume you have run make distclean and then re-run autoreconf and configure to make sure your buildsystem and source tree and build tree are in a well defined state.

However, building on Fedora 35 for Windows (both 32 and 64bit) failed for me when building libbar.la without -no-undefined:

/bin/sh ../libtool  --tag=CC   --mode=link i686-w64-mingw32-gcc  -g -O2   -o libbar.la -rpath /home/user/stackoverflow-q70584133/_b-w32/_i/lib ../bar/libbar_la-bar.lo  
libtool: warning: undefined symbols not allowed in i686-w64-mingw32 shared libraries; building static only
libtool: link: i686-w64-mingw32-ar cru .libs/libbar.a  ../bar/libbar_la-bar.o
libtool: link: i686-w64-mingw32-ranlib .libs/libbar.a
libtool: link: ( cd ".libs" && rm -f "libbar.la" && ln -s "../libbar.la" "libbar.la" )
/bin/sh ../libtool  --tag=CC   --mode=link i686-w64-mingw32-gcc  -g -O2 -no-undefined  -o libfoo.la -rpath /home/user/stackoverflow-q70584133/_b-w32/_i/lib foo/libfoo_la-foo.lo  foo/libfoo_la-foo-nt.lo libbar.la  

*** Warning: This system cannot link to static lib archive libbar.la.
*** I have the capability to make that library automatically link in when
*** you link to this library.  But I can only do this if you have a
*** shared version of the library, which you do not appear to have.
libtool: link: i686-w64-mingw32-gcc -shared  foo/.libs/libfoo_la-foo.o foo/.libs/libfoo_la-foo-nt.o    -g -O2   -o .libs/libfoo-0.dll -Wl,--enable-auto-image-base -Xlinker --out-implib -Xlinker .libs/libfoo.dll.a
/usr/lib/gcc/i686-w64-mingw32/11.2.1/../../../../i686-w64-mingw32/bin/ld: foo/.libs/libfoo_la-foo.o: in function `foo_func':
/home/user/stackoverflow-q70584133/_b-w32/src/../../src/foo/foo.c:10: undefined reference to `bar_func'
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:521: libfoo.la] Error 1

Adding a line to Makefile.am like

libbar_la_LDFLAGS += -no-undefined

fixed the linking for Windows problem and made the whole thing build and run (built on Linux, run on Linux using wine):

[user@host stackoverflow-q70584133]$ mkdir _b-w64 && cd _b-w64
[user@host _b-w64]$ ../configure --host=x86_64-w64-mingw32 --prefix=$PWD/_i
[user@host _b-w64]$ make && make install && ./_i/bin/main.exe
[...]
main: x86_64-w64-mingw32
foo_func
bar_func
foo_host_func: Windows 0x0a00 = 10.0
[user@host _b-w64]$ _

(And BTW, LIBS and _LIBS type variables should probably be added to a _LIBADD or _LDADD variable, not to a _LDFLAGS variable.)

UPDATE

Building on Debian 10 (autoconf 2.69-11, automake 1:1.16.1-4, libtool 2.4.6-9), does produce a linker error when main_LDADD is missing libbar.la and src/main.c calls the bar_func() function from libbar (uncomment the #define in src/main.c to reproduce):

[user@host _b-host]$ make
[...]
/bin/bash ../libtool  --tag=CC   --mode=link gcc  -g -O2   -o main main-main.o libfoo.la 
libtool: link: gcc -g -O2 -o .libs/main main-main.o  ./.libs/libfoo.so -pthread -Wl,-rpath -Wl,/home/user/stackoverflow-q70584133/_b-host/_i/lib
/usr/bin/ld: main-main.o: undefined reference to symbol 'bar_func'
/usr/bin/ld: //home/user/stackoverflow-q70584133/_b-host/src/.libs/libbar.so.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:525: main] Error 1
make[1]: Leaving directory '/home/user/stackoverflow-q70584133/_b-host/src'
make: *** [Makefile:390: all-recursive] Error 1
[user@host _b-host]$ _

However, after removing the direct calls to libbar's bar_func() from src/main.c, the make command will work again, as does make install:

[user@host _b-host]$ make install && ./_i/bin/main
main: x86_64-pc-linux-gnu
foo_func
bar_func
foo_host_func: Linux 267216 = 0x413d0 = 4.19.208
[user@host _b-host]$ _

This suggests that calling a function from libbar from a linking unit without explicitly linking that unit against libbar is an error, and that does make sense.

So I still cannot reproduce OP's report of make working but make install failing. OP is using newer autoconf (2.71) than I do (2.69). Perhaps OP is using different automake/libtool versions as well with different set of bugs (dpkg -l autoconf automake libtool, rpm -q autoconf automake libtool, etc.)?