Re: [C Question] Determine if gcc provides erfl() function
by Corion (Patriarch) on May 28, 2015 at 13:26 UTC
|
I seem to remember to have used Devel::CheckLib for that - it can test whether a library is available and also whether a function exists:
$HAVE{erfl} =
check_lib(
function => 'foo();if(libversion() > 5) return 0; else return
+1;'
incpath => ...
libpath => ...
lib => ...
header => ...
);
if( $HAVE{erfl} ) {
# set CC define HAVE_ERFL
};
| [reply] [d/l] |
Re: [C Question] Determine if gcc provides erfl() function
by davido (Cardinal) on May 28, 2015 at 18:29 UTC
|
Do a test compile/link within Makefile.PL and watch the exit status of the compiler.
We currently do this in Inline::CPP to verify whether the target compiler ships with headers that lack the .h extension (newer compilers that support the 'namespace' keyword do), or whether the target compiler is an older compiler that requires .h extensions (and doesn't put standard library functions in namespace std.)
| [reply] |
|
|
Do a test compile/link within Makefile.PL
I currently do that.
The source includes a file named 'try.in' that contains:
/*
Check whether erfl and isnanl can be linked.
*/
#include <stdio.h>
#include <math.h>
int main(void) {
long double rop, op = 0.6L;
int ret;
rop = erfl(op);
ret = isnanl(op);
return 0;
}
The Makefile.PL builds the executable:
my $out = `$cc $opt -o try.exe -x c try.in -lm 2>&1`;
and then runs it:
my $diag = $^O =~ /mswin32/i ? `try.exe 2>&1` : `./try.exe 2>&1`;
All of which is done successfully - though there's a warning about erfl() during the building of the executable.
However, it's just occurred to me that the executable actually doesn't do anything.
Could it be that success is achieved only because the problem I'm trying to expose is being optimised away ?
I'll rewrite the script so that it actually does something, and see if that catches the unavailability of erfl().
Or is the warning I'm seeing during the building of the executable sufficient to indicate that erfl() is unavailable ? That warning is:
try.in:12:8: warning: incompatible implicit declaration of built-in fu
+nction 'erfl'
Is there anything else I might've missed ?
(I guess I'll try Devel::CheckLib if I can't get this right, myself.)
Thanks guys.
Cheers, Rob
| [reply] [d/l] [select] |
|
|
However, it's just occurred to me that the executable actually doesn't do anything.
Could it be that success is achieved only because the problem I'm trying to expose is being optimised away ?
So, I made the test executable actually do something, and uploaded a new version (0.14) of Math::LongDouble.
Unfortunately, I still get the same failure reports from Bingos' NetBSD smoker(s), and the test executable works fine.
I guess the next thing is to try compiling the test executable using the same cflags ($Config{ccflags}) as are used during the module build.
So, I'll try that.
Should I also include $Config{ldflags} in the build of the test executable ?
Any other ideas ? (Any other flags to include ?)
Cheers, Rob
| [reply] |
|
|
|
|
These functions are gcc builtins. They are optimised away. On linux, too. (Compile with -save-temps to see what is produced, or check the disassembly with objdump -d.)
To do a proper test, use separate compilation units.
/* test_isnanl.c */
#include <math.h>
int test_isnanl(long double x) { return isnanl(x); }
And link: cc main.o test_isnanl.o -lm && ./a.out || FAIL
However, the above is not entirely future-proof either—it's defeated with link-time optimisation (-flto).
So perhaps it would be better to
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
long double x = strtold(argv[1], NULL);
printf("%d", isnanl(x));
printf("%Lf", erfl(x));
return 0;
}
Finally, if you limit your scope to the usual gcc/clang, then there is the -fno-builtin option that will make your original test work as is. This might be the best option of all.
| [reply] [d/l] [select] |
|
|
|
|
|
Re: [C Question] Determine if gcc provides erfl() function
by RichardK (Parson) on May 28, 2015 at 14:50 UTC
|
Feature Test Macro Requirements for glibc (see feature_test_macros(
+7)):
erf():
_BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE || _ISOC99_SOU
+RCE || _POSIX_C_SOURCE >= 200112L;
or cc -std=c99
erff(), erfl():
_BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE >= 600 || _ISO
+C99_SOURCE || _POSIX_C_SOURCE >= 200112L;
or cc -std=c99
so feature_test_macros is where it's at :)
| [reply] [d/l] |
|
|
feature_test_macros is where it's at
I take it this means that erfl() is available if either:
a) the "-std=c99" flag is set; or
b) "_BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L" is true.
And, if neither of those 2 conditions is met, then erfl() is unavailable.
Is that the correct way to read it ?
Update: If I #define _BSD_SOURCE at the beginning of LongDouble.xs, does this necessarily mean that erfl() is made available on these problem BSD systems ?
Cheers, Rob
| [reply] |
|
|
Negative.
On Linux/glibc, normally the _BSD_SOURCE, _SVID_SOURCE, _POSIX_SOURCE are on by default. See /usr/include/features.h. On ~BSD, some long double variants may be missing, or implemented as wrappers to a standard double function (with precision loss). Google around (for manpages and discussions). E.g. erfl() appears on FreeBSD 10.1 manpages, but not on 10.0. And no powl(). The sinhl/coshl/tanhl may be wrappers.
I started up a decade-old FreeBSD 6.0 install; looking in libm.a (and libc.a), there is no erfl. The gcc-3.4.4 recognizes __builtin_erfl(), but this just defers to system erfl, and it fails to link.
So, you're out of luck. Furthermore, (some) tests for availability ought to verify the precision, too.
| [reply] [d/l] [select] |
|
|
The man page for feature_test_macros has lots of details on how to use these, and the info page has even more.
But the easiest way is to set the compiler command line option -std=c99 to ensure that everything (compiler/libc) complies with the C99 standard.
| [reply] |
|
|