#7 slibtool doesn't work with llvm-ar
Closed 9 months ago by midipix. Opened 4 years ago by orbea.

Original issue: https://github.com/midipix-project/slibtool/issues/13
Opened by: https://github.com/RJVB

RJVB commented on Feb 14, 2019:

I ran into another obstable: llvm-ar doesn't support the mri script (-M) mode. I cannot seem to figure out if this mode is invoked after the initial creation via the usual invocation (which is suggested on the terminal) or instead of:

```

slibtool --ar=llvm-ar-5.0 --tag=CC --mode=link ccache /opt/local/bin/clang-mp-5.0 -fvisibility=hidden -O3 -flto=thin -g -flto=thin -fstrict-aliasing -m64 -fno-strict-aliasing -Wl,-Bsymbolic-functions -Wl,-z,nodelete -version-info 5800:3:5800 -export-dynamic -L/opt/local/lib -Wl,-R,/opt/local/lib -O3 -flto=thin -g -flto=thin -o libglib-2.0.la -rpath /opt/local/lib deprecated/libglib_2_0_la-gallocator.lo deprecated/libglib_2_0_la-gcache.lo deprecated/libglib_2_0_la-gcompletion.lo deprecated/libglib_2_0_la-grel.lo deprecated/libglib_2_0_la-gthread-deprecated.lo libglib_2_0_la-garcbox.lo libglib_2_0_la-garray.lo libglib_2_0_la-gasyncqueue.lo libglib_2_0_la-gatomic.lo libglib_2_0_la-gbacktrace.lo libglib_2_0_la-gbase64.lo libglib_2_0_la-gbitlock.lo libglib_2_0_la-gbookmarkfile.lo libglib_2_0_la-gbytes.lo libglib_2_0_la-gcharset.lo libglib_2_0_la-gchecksum.lo libglib_2_0_la-gconvert.lo libglib_2_0_la-gdataset.lo libglib_2_0_la-gdate.lo libglib_2_0_la-gdatetime.lo libglib_2_0_la-gdir.lo libglib_2_0_la-genviron.lo libglib_2_0_la-gerror.lo libglib_2_0_la-gfileutils.lo libglib_2_0_la-ggettext.lo libglib_2_0_la-ghash.lo libglib_2_0_la-ghmac.lo libglib_2_0_la-ghook.lo libglib_2_0_la-ghostutils.lo libglib_2_0_la-giochannel.lo libglib_2_0_la-gkeyfile.lo libglib_2_0_la-glib-init.lo libglib_2_0_la-glib-private.lo libglib_2_0_la-glist.lo libglib_2_0_la-gmain.lo libglib_2_0_la-gmappedfile.lo libglib_2_0_la-gmarkup.lo libglib_2_0_la-gmem.lo libglib_2_0_la-gmessages.lo libglib_2_0_la-gnode.lo libglib_2_0_la-goption.lo libglib_2_0_la-gpattern.lo libglib_2_0_la-gpoll.lo libglib_2_0_la-gprimes.lo libglib_2_0_la-gqsort.lo libglib_2_0_la-gquark.lo libglib_2_0_la-gqueue.lo libglib_2_0_la-grand.lo libglib_2_0_la-grcbox.lo libglib_2_0_la-grefcount.lo libglib_2_0_la-grefstring.lo libglib_2_0_la-gregex.lo libglib_2_0_la-gscanner.lo libglib_2_0_la-gsequence.lo libglib_2_0_la-gshell.lo libglib_2_0_la-gslice.lo libglib_2_0_la-gslist.lo libglib_2_0_la-gstdio.lo libglib_2_0_la-gstrfuncs.lo libglib_2_0_la-gstring.lo libglib_2_0_la-gstringchunk.lo libglib_2_0_la-gtestutils.lo libglib_2_0_la-gthread.lo libglib_2_0_la-gthreadpool.lo libglib_2_0_la-gtimer.lo libglib_2_0_la-gtimezone.lo libglib_2_0_la-gtranslit.lo libglib_2_0_la-gtrashstack.lo libglib_2_0_la-gtree.lo libglib_2_0_la-guniprop.lo libglib_2_0_la-gutf8.lo libglib_2_0_la-gunibreak.lo libglib_2_0_la-gunicollate.lo libglib_2_0_la-gunidecomp.lo libglib_2_0_la-gurifuncs.lo libglib_2_0_la-gutils.lo libglib_2_0_la-guuid.lo libglib_2_0_la-gvariant.lo libglib_2_0_la-gvariant-core.lo libglib_2_0_la-gvariant-parser.lo libglib_2_0_la-gvariant-serialiser.lo libglib_2_0_la-gvarianttypeinfo.lo libglib_2_0_la-gvarianttype.lo libglib_2_0_la-gversion.lo libglib_2_0_la-gwakeup.lo libglib_2_0_la-gprintf.lo libglib_2_0_la-glib-unix.lo libglib_2_0_la-gthread-posix.lo libglib_2_0_la-gspawn.lo libglib_2_0_la-giounix.lo libcharset/libcharset.la -liconv -L/opt/local/lib -lpcre -lpthread glib_probes.lo -L/opt/local/lib -lintl
/opt/local/var/lnxports/build/_opt_local_linux-ports_devel_glib2/glib2/work/glib-2.58.3/glib
slibtool: link: llvm-ar-5.0 crs .libs/libglib-2.0.a deprecated/.libs/libglib_2_0_la-gallocator.o deprecated/.libs/libglib_2_0_la-gcache.o deprecated/.libs/libglib_2_0_la-gcompletion.o deprecated/.libs/libglib_2_0_la-grel.o deprecated/.libs/libglib_2_0_la-gthread-deprecated.o .libs/libglib_2_0_la-garcbox.o .libs/libglib_2_0_la-garray.o .libs/libglib_2_0_la-gasyncqueue.o .libs/libglib_2_0_la-gatomic.o .libs/libglib_2_0_la-gbacktrace.o .libs/libglib_2_0_la-gbase64.o .libs/libglib_2_0_la-gbitlock.o .libs/libglib_2_0_la-gbookmarkfile.o .libs/libglib_2_0_la-gbytes.o .libs/libglib_2_0_la-gcharset.o .libs/libglib_2_0_la-gchecksum.o .libs/libglib_2_0_la-gconvert.o .libs/libglib_2_0_la-gdataset.o .libs/libglib_2_0_la-gdate.o .libs/libglib_2_0_la-gdatetime.o .libs/libglib_2_0_la-gdir.o .libs/libglib_2_0_la-genviron.o .libs/libglib_2_0_la-gerror.o .libs/libglib_2_0_la-gfileutils.o .libs/libglib_2_0_la-ggettext.o .libs/libglib_2_0_la-ghash.o .libs/libglib_2_0_la-ghmac.o .libs/libglib_2_0_la-ghook.o .libs/libglib_2_0_la-ghostutils.o .libs/libglib_2_0_la-giochannel.o .libs/libglib_2_0_la-gkeyfile.o .libs/libglib_2_0_la-glib-init.o .libs/libglib_2_0_la-glib-private.o .libs/libglib_2_0_la-glist.o .libs/libglib_2_0_la-gmain.o .libs/libglib_2_0_la-gmappedfile.o .libs/libglib_2_0_la-gmarkup.o .libs/libglib_2_0_la-gmem.o .libs/libglib_2_0_la-gmessages.o .libs/libglib_2_0_la-gnode.o .libs/libglib_2_0_la-goption.o .libs/libglib_2_0_la-gpattern.o .libs/libglib_2_0_la-gpoll.o .libs/libglib_2_0_la-gprimes.o .libs/libglib_2_0_la-gqsort.o .libs/libglib_2_0_la-gquark.o .libs/libglib_2_0_la-gqueue.o .libs/libglib_2_0_la-grand.o .libs/libglib_2_0_la-grcbox.o .libs/libglib_2_0_la-grefcount.o .libs/libglib_2_0_la-grefstring.o .libs/libglib_2_0_la-gregex.o .libs/libglib_2_0_la-gscanner.o .libs/libglib_2_0_la-gsequence.o .libs/libglib_2_0_la-gshell.o .libs/libglib_2_0_la-gslice.o .libs/libglib_2_0_la-gslist.o .libs/libglib_2_0_la-gstdio.o .libs/libglib_2_0_la-gstrfuncs.o .libs/libglib_2_0_la-gstring.o .libs/libglib_2_0_la-gstringchunk.o .libs/libglib_2_0_la-gtestutils.o .libs/libglib_2_0_la-gthread.o .libs/libglib_2_0_la-gthreadpool.o .libs/libglib_2_0_la-gtimer.o .libs/libglib_2_0_la-gtimezone.o .libs/libglib_2_0_la-gtranslit.o .libs/libglib_2_0_la-gtrashstack.o .libs/libglib_2_0_la-gtree.o .libs/libglib_2_0_la-guniprop.o .libs/libglib_2_0_la-gutf8.o .libs/libglib_2_0_la-gunibreak.o .libs/libglib_2_0_la-gunicollate.o .libs/libglib_2_0_la-gunidecomp.o .libs/libglib_2_0_la-gurifuncs.o .libs/libglib_2_0_la-gutils.o .libs/libglib_2_0_la-guuid.o .libs/libglib_2_0_la-gvariant.o .libs/libglib_2_0_la-gvariant-core.o .libs/libglib_2_0_la-gvariant-parser.o .libs/libglib_2_0_la-gvariant-serialiser.o .libs/libglib_2_0_la-gvarianttypeinfo.o .libs/libglib_2_0_la-gvarianttype.o .libs/libglib_2_0_la-gversion.o .libs/libglib_2_0_la-gwakeup.o .libs/libglib_2_0_la-gprintf.o .libs/libglib_2_0_la-glib-unix.o .libs/libglib_2_0_la-gthread-posix.o .libs/libglib_2_0_la-gspawn.o .libs/libglib_2_0_la-giounix.o .libs/glib_probes.o
llvm-ar-5.0: Unknown command: OPEN.
slibtool: error logged in slbt_archive_import(), line 151: flow error: unexpected condition or other.
slibtool: < returned to > slbt_exec_link_create_archive(), line 1219.
slibtool: < returned to > slbt_exec_link(), line 1770.
Exit 2
```

The code doesn't speak volumes to me here. Do I understand correctly that slbt_exec_link_create_archive first constructs a "legacy" commandline, prints that, and then does something completely different to do the actual work?

How hard would it be to detect llvm-ar* and just execute the printed command instead of using a script?

midipix commented on Feb 14, 2019:

Thanks for reporting! This is again a known topic, and your current testing (on osx and of llvm-ar) provides further motivation for solving this once and for all. In brief, the main problem is that there's no portable interface for archive merging, where you take the objects of one .a archive and place them in another. As I see it, the most effective approach there is to not invoke ar(1) whatsoever, specifically since the format is simple enough to allow for manual archive creation and parsing (the midipix mdso(1) tool, by the way, already does something very similar when creating midipix-specific import libraries).

The reason I haven't implemented that yet in slibtool was that I wanted to also avoid invocation of ranlib(1), which means creating on the fly not only the raw archive, but also the index, hence requiring minimal parsing capabilities of PE, ELF, and MACH-O. Since the latter aspect is a mere bonus, however, all that is needed for now is to manually create the merged archive from within slibtool, then invoke the appropriate ranlib(1) tool for index creation.

RJVB commented on Feb 14, 2019:

I'm not certain though that merging is what failed in my situation. I've thrown together the very simple patch (disregarding formatting...) patch below. With that the static archive is created correctly when I invoke the command separately, but only if I use slibtool-static. I am however not certain that a static archive is what should be created here; in any case rlibtool doesn't seem to think so. And that may be the bigger hurdle for use as a drop-in replacement: you have to be able to be confident that the tool does what is expected, i.e. what you configured to happen. Otherwise you might well end up spending more time in chasing elusive issues than you gain by avoiding the scripted libtool... diff --git a/src/logic/slbt_exec_link.c b/src/logic/slbt_exec_link.c index 0bfe7e0432bdba0405bdd137391688f9d5222db0..52390ceee86ca47c859cdf3a206c2d7c5d686960 100644 --- a/src/logic/slbt_exec_link.c +++ b/src/logic/slbt_exec_link.c @@ -1208,15 +1208,22 @@ static int slbt_exec_link_create_archive( arfilename,true)) return SLBT_NESTED_ERROR(dctx); - /* ar spawn */ - if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode) - return SLBT_SPAWN_ERROR(dctx); - - /* input objects associated with .la archives */ - for (parg=ectx->cargv; *parg; parg++) - if (slbt_adjust_wrapper_argument(*parg,true)) - if (slbt_archive_import(dctx,ectx,output,*parg)) - return SLBT_NESTED_ERROR(dctx); + if (strstr(program, "llvm-ar")) { + ectx->argv = ectx->altv; + /* ar spawn */ + if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode) + return SLBT_SPAWN_ERROR(dctx); + } else { + /* ar spawn */ + if ((slbt_spawn(ectx,true) < 0) || ectx->exitcode) + return SLBT_SPAWN_ERROR(dctx); + + /* input objects associated with .la archives */ + for (parg=ectx->cargv; *parg; parg++) + if (slbt_adjust_wrapper_argument(*parg,true)) + if (slbt_archive_import(dctx,ectx,output,*parg)) + return SLBT_NESTED_ERROR(dctx); + } if (fprimary && (dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_SHARED)) { strcpy(arlink,output);

RJVB commented on Feb 14, 2019:

Oh dang, I think I found the issue...

ccache!

As I think is usual with autoconf-based projects I inject ccache via CC, CXX and family, and as a result slibtool seems to see ccache as the compiler/linker driver to invoke, which explains the error

ccache: error: execv of deprecated/.libs/libglib_2_0_la-gallocator.o failed: Permission denied

Ccache is a dummy wrapper when linking, so you could probably just skip it (so /any/path/to/ccache foo would become just foo).

The fact I tripped over the llvm-ar issue is thus purely a coincidence due to slibtool misinterpreting the intended type of library to generate.

midipix commented on Feb 14, 2019:

due to slibtool misinterpreting the intended type of library to generate.

Happy to further look into that, however I would recommend not jumping to conclusions so quickly. As you've pointed out, the main issue has something to do with the ccache wrapper, which might just happen to work with libtool as a result of some de facto behavior. In terms of shared vs. static library, see my other comment regarding rlibtool vs. slibtool.

On another related note, llvm-ar actually does support MRI scripts, and seems to have done so since at least version 5.0.0. I do still intend to implement archive creation as outlined above, however my current understanding is that right now this is not a blocker. Could you please confirm that an independent llvm-ar -M also works on your end?

RJVB commented on Feb 15, 2019:

which might just happen to work with libtool as a result of some de facto behavior.
I'm guessing the libtool authors might have taken the use of ccache into account?
On another related note, llvm-ar actually does support MRI scripts, and seems to have done so since at least version 5.0.0. I do still intend to implement archive creation as outlined above, however my current understanding is that right now this is not a blocker. Could you please confirm that an independent llvm-ar -M also works on your end?
Well I can only confirm that it does not work with llvm-ar v 5.0.2 installed from the official LLVM.org debuntu packaging, on Linux. It gives an error on the initial OPEN command, which I posted. I'm not familiar with the protocol but if you have a little test script I'd be happy to run it through a few of the other versions I have installed. Possibly a script that could serve in a built-in check to determine if the <ar> candidate supports the feature?

midipix commented on Feb 15, 2019:

Grepping a stock libtool script it does seem to do something with ccahe (will read into that later), however that is not documented in the libtool manual. Can probably be added to slibtool without too much effort.

midpix commented on Feb 15, 2019:

As for llvm-ar, if MRI scripts do not work out of the box then that's yet another reason to create the raw archives internally as outlined above. Lack of proper MRI script support has also been an issue on some bsd machines, where they needed gnu ar in order to use slibtool. Note that libtool's approach here, namely to extract the objects from both archives to a temporary directory and then pass the results of ls to ar(1), is arguably fragile, insecure, and subject to file system race conditions.

RJVB commented on Feb 15, 2019:

See #14 :) I can now compare build times from the ccache with libtool and with rlibtool. In my test project (still glib2) a full rebuild takes about 2'15" using the libtool script while it takes about 1'20" using rlibtool. That seems impressive but I expect the absolute different to remain identical when not using ccache - and then it'll be much less impressive. The real test will be on Mac, to see if the use of a single executable will prevent the security subsystem from burning as much CPU as it does when using shell scripts.

RJVB commented on Feb 15, 2019:

Sounds like a good reason to get your hands dirty...

RJVB commented on Feb 16, 2019:

Another thing to consider: the -undefined linker flag which instructs what to do when a shared library refers to symbols not resolved at link time. Example (here using GNU ar from MacPorts port:binutils as a temporary solution): CD zfs-git/lib/libuutil/ rlibtool --verbose --ar=/opt/local/bin/gar --tag=CC --silent --mode=link ccache /opt/local/bin/clang-mp-5.0 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wno-tautological-constant-out-of-range-compare -D_GNU_SOURCE -D__EXTENSIONS__ -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DTEXT_DOMAIN=\"zfs-osx-user\" -O3 -march=native -g -mmacosx-version-min=10.9 -isysroot/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -arch x86_64 -g -version-info 1:1:0 -L/opt/local/lib -Wl,-headerpad_max_install_names -O3 -march=native -g -mmacosx-version-min=10.9 -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -arch x86_64 -o libuutil.la -rpath /opt/local/lib uu_alloc.lo uu_avl.lo uu_dprintf.lo uu_ident.lo uu_list.lo uu_misc.lo uu_open.lo uu_pname.lo uu_string.lo uu_strtoint.lo ../../lib/libavl/libavl.la ../../lib/libspl/libspl.la ../../lib/libefi/libefi.la /Volumes/Debian/Users/bertin/work/src/MacOSX/osxzfs/zfs-git/lib/libuutil /opt/local/bin/gar: BFD (GNU Binutils) 2.30 assertion fail archive.c:1859 <SNIP> ld: warning: option -noall_load is obsolete and being ignored ld: warning: option -noall_load is obsolete and being ignored ld: warning: option -noall_load is obsolete and being ignored Undefined symbols for architecture x86_64: "_CFDictionaryGetValueIfPresent", referenced from: _CFDictionaryValueIfPresentMatchesSubstring in libefi.a(rdwr_efi.o) _isDeviceMatchForKeyAndSubstr in libefi.a(rdwr_efi.o) Adding -Wl,-undefined -Wl,dynamic_lookup (just after -Wall) fixes the issue. I'm attaching the libtool script for this project. libtool.txt

midipix mentioned this issue on Feb 16, 2019
supporting -Wl,-undefined -Wl,dynamic_lookup when targeting Mach-O:
https://github.com/midipix-project/slibtool/issues/15

midipix mentioned this issue on Oct 24, 2019
VLC 3.0.7 doesn't build with s[r]libtool, clang and LTO:
https://github.com/midipix-project/slibtool/issues/18


  • internal archive merging has now been both implemented and integrated (see 89caff5, and then the minor fix in the following commit c1e423b).

  • in rlibtool mode, AR and RANLIB are now derived from the located libtool (d29f9c6); specifying --ar=llvm=ar on the command line (again, in rlibtool mode) is thus no longer needed.

  • Closing this for now as fixed, but please test and confirm!

Metadata Update from @midipix:
- Issue assigned to midipix
- Issue status updated to: Closed (was: Open)

9 months ago

Login to comment on this ticket.

Metadata