Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

missing -ltinfo when linking bytecode with -custom #7164

Closed
vicuna opened this issue Mar 4, 2016 · 9 comments
Closed

missing -ltinfo when linking bytecode with -custom #7164

vicuna opened this issue Mar 4, 2016 · 9 comments

Comments

@vicuna
Copy link

vicuna commented Mar 4, 2016

Original bug ID: 7164
Reporter: @sliquister
Status: resolved (set by @xavierleroy on 2017-10-15T14:18:59Z)
Resolution: not a bug
Priority: normal
Severity: minor
Version: 4.02.3
Category: configure and build/install
Related to: #6735
Monitored by: @gasche @diml

Bug description

I was trying to pass --as-needed to link exes, but when ocamlc links bytecode exes with -custom, it doesn't pass -ltinfo despite depending on it (which I suppose is wrong?), resulting in the failure below.
If I add -ltinfo to Config.bytecomp_c_libraries, it fixes the problem.

Steps to reproduce

$ touch a.ml; ocamlc -verbose a.ml -ccopt -Wl,--as-needed -custom -o a

  • gcc -o 'a' '-L$DIR/lib/ocaml' -Wl,--as-needed '/tmp/camlprim9cc349.c' '-lcamlrun' -I'/j/office/app/ocaml/builds/4.02.3+gc-2+j2-cent6_20151110_095047GMT/lib/ocaml' -lrt -lm -ldl -lcurses -lpthread
    $DIR/lib/ocaml/libcamlrun.a(terminfo.o): In function caml_terminfo_resume': terminfo.c:(.text+0x27): undefined reference to tputs'
    $DIR/lib/ocaml/libcamlrun.a(terminfo.o): In function caml_terminfo_standout': terminfo.c:(.text+0x61): undefined reference to tputs'
    $DIR/lib/ocaml/libcamlrun.a(terminfo.o): In function caml_terminfo_backup': terminfo.c:(.text+0x96): undefined reference to tputs'
    $DIR/lib/ocaml/libcamlrun.a(terminfo.o): In function caml_terminfo_setup': terminfo.c:(.text+0x10a): undefined reference to tgetent'
    terminfo.c:(.text+0x11d): undefined reference to tgetnum' terminfo.c:(.text+0x132): undefined reference to tgetstr'
    terminfo.c:(.text+0x148): undefined reference to tgetstr' terminfo.c:(.text+0x15e): undefined reference to tgetstr'
    terminfo.c:(.text+0x174): undefined reference to tgetstr' terminfo.c:(.text+0x199): undefined reference to tgetstr'
    $DIR/lib/ocaml/libcamlrun.a(terminfo.o):terminfo.c:(.text+0x1af): more undefined references to `tgetstr' follow
    collect2: ld returned 1 exit status
    File "a.ml", line 1:
    Error: Error while building custom runtime system
@vicuna
Copy link
Author

vicuna commented Mar 19, 2016

Comment author: junsli

It works for me on Linux. What platform?

@vicuna
Copy link
Author

vicuna commented Mar 23, 2016

Comment author: @sliquister

Linux. configure says tgetent and co are defined by -lcurses, but I
think ./hasgot doesn't work properly because that's just not true:

$ (cd config/auto-aux/; cc=gcc ./hasgot -lcurses tgetent tgetstr); echo $?
0
$ cat /usr/lib64/libcurses.so
INPUT(-lncurses)
$ readelf -W -s /lib64/libncurses.so.5 | grep tgetent

However, curses depends on libtinfo, which does define it:

$ ldd /lib64/libncurses.so.5
linux-vdso.so.1 => (0x00007ffc2bfff000)
libc.so.6 => /lib64/libc.so.6 (0x0000003d2ea00000)
libdl.so.2 => /lib64/libdl.so.2 (0x0000003d2f200000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x0000003d41a00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003d2e200000)
$ readelf -W -s /lib64/libtinfo.so.5 | grep tgetent
158: 0000003d41a10f00 1457 FUNC GLOBAL DEFAULT 11 tgetent

If I add -Wl,--as-needed in the initial value of opts in hasgot, then
it detects tgetent comes from -ltermcap instead (this is the only
changes in the output of configure).

$ cat /usr/lib64/libtermcap.so
INPUT(-ltinfo)

And as shown above, ltinfo contains the right symbols. So it looks
like detecting termcap is much better than detecting curses in my
case.
To double check that linking does work, I ran this:

Given a.c:
extern int tgetent (char * buffer, char * name);

int main() {
  tgetent(0, 0);
  return 0;
}

$ gcc -c a.c
$ gcc a.o
a.o: In function main': a.c:(.text+0xf): undefined reference to tgetent'
collect2: ld returned 1 exit status
$ gcc a.o -lcurses
$ gcc a.o -ltermcap
$ gcc -Wl,--as-needed a.o -lcurses
a.o: In function main': a.c:(.text+0xf): undefined reference to tgetent'
collect2: ld returned 1 exit status
$ gcc -Wl,--as-needed a.o -ltermcap
$

So maybe this is an ok patch:

diff --git a/config/auto-aux/hasgot b/config/auto-aux/hasgot
index 1ba464c..a842c5f 100755
--- a/config/auto-aux/hasgot
+++ b/config/auto-aux/hasgot
@@ -15,7 +15,7 @@
#* *
#**************************************************************************

-opts=""
+opts="-Wl,--as-needed"
libs="$cclibs"
args=$*
rm -f hasgot.c

@vicuna
Copy link
Author

vicuna commented Mar 24, 2016

Comment author: @damiendoligez

Could you describe what --as-needed is supposed to do? I've read the ld man page and it's not very enlightening.

@vicuna
Copy link
Author

vicuna commented Mar 24, 2016

Comment author: @sliquister

By default, if you give -lfoo to ld/gcc, the exe gets a runtime dependency on foo, even if no symbol is used from that library.
With --as-needed, the executable gets a runtime dependency on foo only if some symbol from foo is used.
Concretely:
$ echo 'int main() { return 0; }' > a.c
$ gcc a.c && ldd a.out | grep curses
$ gcc a.c -l curses && ldd a.out | grep curses
libncurses.so.5 => /lib64/libncurses.so.5 (0x0000003774200000)
$ gcc -Wl,--as-needed a.c -l curses && ldd a.out | grep curses
$

(in the context of ocaml, it could be that you're linking a.cmxa, which contains some modules that have dynamic C dependencies on libfoo and some that don't (so it's reasonable for the cmxa will to -lfoo). Even if the ocaml linker decides to link none of the modules from a.cmxa that depend on -lfoo, it still passes -lfoo to the C linker, and so the above means that the executable will depend on libfoo anyway. With -Wl,--as-needed, the C linker will not create a dynamic dependency on libfoo just because of the spurious -lfoo)

@vicuna
Copy link
Author

vicuna commented Mar 24, 2016

Comment author: @sliquister

And perhaps it's clearer if I try to explain what the suggested change to hasgot does in
my case. I am definitely not a C toolchain expert, but I think it goes like this:

  • run gcc a.o -lcurses, where a.o depends on tgetent
  • the linker processes a.o, notices that tgetent is missing
  • the linker processes -lcurses, notices it defines no undefined symbols
    • without --as-needed, curses is marked as needed anyway
    • with --as-needed, nothing happens
  • the linker notices the end of the command line, checks for remaining undefined symbols.
    • without --as-needed, apparently the linker considers transitive dependencies ie exe->curses->tinfo, which defines tgetent, so ok
    • with --as-needed, tgetent is defined nowhere so error

@vicuna
Copy link
Author

vicuna commented Feb 24, 2017

Comment author: @damiendoligez

It looks like a problem in our autoconfig scripts, which we are trying to replace with autoconf anyway. In the meantime, I think adding -cclib -ltinfo to your command line should work around the problem?

@vicuna
Copy link
Author

vicuna commented Oct 9, 2017

Comment author: @xavierleroy

"Technical Standard X/Open Curses Issue 4", which is the most authoritative document I could find, states that

  • tgetent, tgetstr, etc, are part of this standard, although "TO BE WITHDRAWN" at some point later;
  • the proper way to use the functions from this standard is to link with "-lcurses".

So, I think --as-needed doesn't play nice with the curses/terminfo libraries on your system, but that's a problem with your system, not with OCaml.

This said, I fully agree with the other comments: 1- ocamlc -custom should not link with -lcurses to begin with, and 2- autoconf might help.

I move to close this PR as resolved/no change required.

@vicuna
Copy link
Author

vicuna commented Oct 15, 2017

Comment author: @xavierleroy

Marking as resolved/no change required.

@vicuna vicuna closed this as completed Oct 15, 2017
@vicuna
Copy link
Author

vicuna commented Oct 16, 2017

Comment author: @xavierleroy

Also: the dependency on curses/terminfo should go away soon, see #1431

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant