On 2011-06-27 04:32, Eric McCorkle wrote:
I've both seen reports and experienced make buildworld with clang
failing in usr.bin/xlint/lint1 (really, make kernel-toolchain is what
fails), because lint1 is statically linked, and there is a definition of
__isnanf in both libc and libm.  GCC, on the other hand, builds just fine.
...

I have never seen this failure, and neither does the clang buildbot, so
maybe there is something in your build environment causing this problem?
Can you please post:

- Your build architecture (e.g. i386 or amd64)
- Your /etc/make.conf and /etc/src.conf, if applicable
- Any build-related environment variables (WITH_FOO, WITHOUT_FOO,
  CFLAGS, etc)


The file tree.c in usr.bin/xlint/lint1 calls both isnan and finite from
math.h.  After some investigation, I figured out what's going on.
math.h includes a macro version of isnan, which expands out to an
expression that calls isnan, __isnanl, and __isnanf.  GCC seems to treat
all of these as builtin functions, and implements them with its code
generator, rather than generating calls.  Clang, on the other hand, does
not, which leaves calls to __isnanf in the resulting object file, which
will result in multiple definitions at link time.

I don't see this at all here.  Clang simply expands the macro:

#define isnan(x)                                        \
    ((sizeof (x) == sizeof (float)) ? __isnanf(x)       \
    : (sizeof (x) == sizeof (double)) ? isnan(x)        \
    : __isnanl(x))

then sees x is a double, so eliminates the unneeded parts of the ?:
operators, and simply calls the isnan() function.  There is no trace of
__isnanf() anywhere in the resulting .s or .o file.

Maybe you compiled with non-default optimization flags?  If so, please
supply them.


There are several possible solutions.  The workaround I used is to add
-Wl,--allow-multiple-definition to LDADD in the makefile for xlint.

Actually, I think the problem is that there are multiple definitions of
__isnanf(), one in libc and one in libm.  In lib/libc/gen/isnan.c,
there is this comment:

/*
 * XXX These routines belong in libm, but they must remain in libc for
 *     binary compat until we can bump libm's major version number.
 */

after which both __isnan() and __isnanf() are defined, and weakly bound
to isnan() and isnanf().  Then, in lib/msun/src/s_isnan.c, the isnan()
definition is commented out, but not the __isnanf() definition.

I think this never caused a problem with gcc, since, as you said, it
usually expands it using builtins.

Weirdly enough, a small test program that directly calls __isnanf(), and
is linked with -lm doesn't cause any problems here, neither with gcc,
nor with clang.


A better solution, I think, is to modify math.h with something like this:

#ifdef __clang__
#define isnan(n) __builtin_isnan(n)
...
#endif

(It might be a good idea to add these kinds of definitions for all of
clang's builtins, actually.)

I'm not sure why gcc inserts builtins for isnan() and friends, since if
you wanted those, you should probably #define isnan as __builtin_isnan.
Otherwise, the implementations in libc and libm would never be used.

I hope those are 'better' than the ones builtin to gcc (or clang), but
this is not really for me to say, better ask Bruce Evans, David Schultz
or Steve Kargl. :)
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to