blob: a6171ab5537902481bb27061ed30ac7ee4b991f9 [file] [log] [blame]
#!/bin/sh
#
# $Id$
#
##############################################################################
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed
# with this work for additional information regarding copyright
# ownership. The ASF licenses this file to you under the Apache
# License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# Copyright 2001-2007 Rogue Wave Software, Inc.
#
##############################################################################
#
# Test to determine which ANSI C library functions are declared in the
# respective header or, if not, whether they are defined in the library
# binary (libc or libm)
#
# To test, perform the following steps after making sure that vars.sh
# exists in the cwd, or after defining the appropriate shell variables:
#
# $ rm -f header.h logfile.log
# $ touch header.h logfile.log
# $ libc_decl header.h logfile.log [function [headers]]
#
##############################################################################
output=/dev/tty
logfile=/dev/tty
OSNAME=`uname -s`
if [ $OSNAME = "SunOS" -a -x /usr/xpg4/bin/basename ]; then
# use the POSIX basename rather than the one in /usr/bin
# to avoid interpreting the suffix in a special way
basename=/usr/xpg4/bin/basename
else
basename=basename
fi
[ ! -d "$TMPDIR" ] && TMPDIR=/tmp
# set the output file if specified, otherwise use the console
if [ -f "$1" ]; then
output="$1"
fi
# set the log file if specified, otherwise use the console
if [ -f "$2" ]; then
logfile="$2"
fi
if [ ! -z "$3" ]; then
function="$3"
fi
[ -r vars.sh ] && . ./vars.sh
# include headers.inc file
. $TOPDIR/etc/config/src/headers.inc
if [ ! -z "$4" ]; then
hdrs="$4"
fi
CPPFLAGS="`echo $CPPFLAGS | sed 's:-I *[^ ]*::g'`"
if [ "$CXX" = "aCC" ] ; then
cxx_major="`echo $CXX_VER | sed 's/.*\.\([0-9][0-9]*\)\..*/\1/'`"
echo $CXXFLAGS | grep '[-]Aa' >/dev/null 2>&1
has_Aa=$?
if [ "$cxx_major" -le "05" -a $has_Aa -eq 0 ] ; then
# prepend -I/usr/include to CXXOPTS for HP aCC when the -Aa
# command line option is specified (aCC 3 and 5 but not aCC
# 6 on IPF)
CXXFLAGS="$CXXFLAGS -I/usr/include"
fi
unset cxx_major
fi
LDFLAGS="$LDFLAGS $LDLIBS"
capitalize='sed y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
##############################################################################
# determine whether each header exists and its full pathname
no_new_headers=0
for h in $hdrs ; do
hdr_base=`${basename} $h \.h`
hdr=$h
if [ "$hdr_base" = "$h" ] ; then
# check for C++ C library headers first
if [ $h != new -a $h != typeinfo ] ; then
hdr="c$h"
fi;
printf "%-50.50s " "checking for <$hdr>"
tmpfile=$TMPDIR/$h-$$
echo "#include <$hdr>" > $tmpfile.cpp
sym="`echo $hdr | $capitalize`"
echo "$CXX -E $CPPFLAGS $CXXFLAGS $tmpfile.cpp >$tmpfile.i" >>$logfile
$CXX -E $CPPFLAGS $CXXFLAGS $tmpfile.cpp >$tmpfile.i 2>>$logfile
if [ $? -eq 0 ] ; then
echo "ok"
echo "// #define _RWSTD_NO_${sym}" >>$output
else
echo "no (_RWSTD_NO_${sym})"
echo "#define _RWSTD_NO_${sym}" >> $output
# <ciso646> is a bogus header, ignore if missing
[ $sym != ciso646 ] && no_new_headers=1
fi
fi
# check for (deprecated C++) C library headers
# or for any headers specified with the .h suffix
printf "%-50.50s " "checking for <$hdr_base.h>"
tmpfile=$TMPDIR/$hdr_base-$$
echo "#include <$hdr_base.h>" > $tmpfile.cpp
sym="`echo $hdr_base | $capitalize`"
echo "$CXX -E $CPPFLAGS $CXXFLAGS $tmpfile.cpp >$tmpfile.i" >>$logfile
$CXX -E $CPPFLAGS $CXXFLAGS $tmpfile.cpp >$tmpfile.i 2>>$logfile
if [ $? -eq 0 ] ; then
path=` cat $tmpfile.i \
| sed -n "s|[^\"]* \(\".*/$hdr_base\.h\"\).*|\1|p" \
| head -n 1`
# handle headers implemented internally by some compilers
# (such as <stdarg.h> with the vanilla EDG eccp)
[ "$path" = "" ] && path="<$hdr_base.h>"
echo "ok ($path)"
if [ "$hdr_base" = "$h" ]; then
echo "#define _RWSTD_ANSI_C_${sym}_H $path" >>$output
else
echo "// #define _RWSTD_NO_${sym}_H /* $path */" >>$output
fi
else
echo "no (_RWSTD_NO_${sym}_H)"
echo "#define _RWSTD_NO_${sym}_H" >>$output
fi
rm -f $tmpfile.cpp $tmpfile.i
done
##############################################################################
# determine the support for namespaces
printf "%-50.50s " "checking for namespaces"
no_namespace=0
echo "$CXX -c $CPPFLAGS $CXXFLAGS $TOPDIR/etc/config/src/NAMESPACE.cpp" \
>>$logfile
$CXX -c $CPPFLAGS $CXXFLAGS $TOPDIR/etc/config/src/NAMESPACE.cpp \
>>$logfile 2>&1
if [ $? -eq 0 ] ; then
echo "ok"
echo "// #define _RWSTD_NO_NAMESPACE" >>$output
else
echo "no (_RWSTD_NO_NAMESPACE)"
echo "#define _RWSTD_NO_NAMESPACE" >>$output
no_namespace=1
fi
##############################################################################
# determine wheteher each function is declared/defined
# create a test source file template into which each iteration below
# substitutes the header name, function name, and function arguments
tmpsrc=$TMPDIR/libc_decl_tmpsrc-$$.cpp
cat << EOF > $tmpsrc
extern "C"
{
typedef void (*funptr_t)();
}
// take the address of the function in a way
// that foils even clever optimizers
union funptr_type {
funptr_t pf;
unsigned long ul;
} funptri;
#ifdef CHECK_DECL
# if defined (__linux__) && defined (__GNUG__) && __GNUG__ < 3
// prevent empty exception specifications from triggering
// gcc 2.9x -fhonor-std link errors looking for std::terminate()
# include <features.h>
# undef __THROW
# define __THROW
# endif // gcc < 3 on Linux
# include HDRNAME
# if !$no_namespace
namespace std { }
using namespace std;
# endif // no_namespace
int main (int argc, char**)
{
// with gcc, prevent intrinsics from causing false positives
# if TAKE_ADDR
funptri.pf = (funptr_t)&FUNNAME;
return (argc < 1 ? !funptri.ul : !!funptri.ul) + 0;
# else // if !TAKE_ADDR
// disable warnings about an unused variable
(void)&argc;
// call the function using the supplied arguments
(void)FUN;
return 0;
# endif // TAKE_ADDR
}
#else // if !defined (CHECK_DECL)
extern "C" void FUNNAME ();
int main (int argc, char**)
{
funptri.pf = (funptr_t)&FUNNAME;
return (argc < 1 ? !funptri.ul : !!funptri.ul) + 0;
}
#endif // CHECK_DECL
EOF
for h in $hdrs ; do
hdr_base=`${basename} $h \.h`
eval funs=\$$hdr_base
if [ -z "$funs" ] ; then
continue
fi
if [ "$hdr_base" = "math" ] ; then
lib=m
else
lib=c
fi
# float and long double versions of <math.h> functions
# are not expected to be declared in <cmath> or in std
use_libc_header=0
for f in $funs; do
# determine whether the tested function is followed by
# a function argument list; if so, call it, otherwise
# take its address
funname=`echo $f | sed "s/\([a-zA-Z_][a-zA-Z_0-9]*\).*/\1/"`
if [ "$function" != "" -a "$function" != "$funname" ]; then
continue
fi
if [ "$funname" = "$f" ] ; then
# take the address of the function
# (the function must not be overloaded)
take_addr=1
else
# function may be overloaded, call it instead
take_addr=0
fi
# starting with acosf(), look in <math.h> rather than <cmath>
[ "$f" = acosf ] && use_libc_header=1
std=""
# determine which form of the header to #include
if [ $use_libc_header -eq 1 ] ; then
hdrname="${h}.h"
elif [ $no_new_headers -eq 0 ] ; then
hdrname="c${h}"
if [ $no_namespace -eq 0 ] ; then
std="std::"
fi
else
hdrname="${h}.h"
fi
printf "%-50.50s " "checking for $std$funname() in <$hdrname>"
# temporary object file, and executable file names
tmpobj=$TMPDIR/$funname-$$.o
tmpexe=$TMPDIR/$funname-$$
sym="_RWSTD_NO_`echo $funname | $capitalize`"
echo "$CXX -c -DCHECK_DECL $CXXFLAGS $WARNFLAGS " \
"-DHDRNAME=\"<$hdrname>\" -DFUNNAME=$funname " \
"-DFUN=$f -DTAKE_ADDR=$take_addr " \
"$tmpsrc -o $tmpobj" >>$logfile 2>&1
# spell out all arguments just like above, being careful
# about quoting HDRNAME
$CXX -c -DCHECK_DECL $CXXFLAGS $WARNFLAGS \
-DHDRNAME="<$hdrname>" -DFUNNAME=$funname \
-DFUN=$f -DTAKE_ADDR=$take_addr \
$tmpsrc -o $tmpobj >>$logfile 2>&1 \
&& $LD $tmpobj $LDFLAGS -l$lib >>$logfile 2>&1
if [ $? -eq 0 ] ; then
echo "ok"
sym="// #define $sym"
echo $sym >>$output
else
# if a symbol isn't declared in the header,
# see if it maybe exists in the library
echo "no ($sym)"
echo "#define $sym" >>$output
sym="`echo ${sym}_IN_LIB$lib | $capitalize`"
printf "%-50.50s " "checking for extern \"C\" $funname() in lib$lib"
# define cxxflags for convenience
cxxflags="$CXXFLAGS $WARNFLAGS -DFUNNAME=$funname"
echo "$CXX -c $cxxflags $tmpsrc -o $tmpobj \
&& $LD $tmpobj $LDFLAGS -l$lib" >>$logfile
$CXX -c $cxxflags $tmpsrc -o $tmpobj >>$logfile 2>&1 \
&& $LD $tmpobj $LDFLAGS -l$lib >>$logfile 2>&1
if [ $? -eq 0 ] ; then
echo "ok"
sym="// #define $sym"
else
echo "no ($sym)"
sym="#define $sym"
fi
echo $sym >>$output
fi
rm -f $tmpobj
done
done
rm -f $tmpsrc
exit
##############################################################################
##############################################################################
#
# helper script to generate the contents of <cmath> (needs editing)
#
c90_funs="acosf asinf atanf atan2f ceilf cosf coshf expf fabsf floorf fmodf frexpf ldexpf logf log10f modff powf sinf sinhf sqrtf tanf tanhf acos asin atan atan2 ceil cos cosh exp fabs floor fmod frexp ldexp log log10 modf pow sin sinh sqrt tan tanh acosl asinl atanl atan2l ceill cosl coshl expl fabsl floorl fmodl frexpl ldexpl logl log10l modfl powl sinl sinhl sqrtl tanl tanhl"
c99_funs="cbrtf copysignf erfcf erff expm1f exp2f fdimf fmaf fmaxf fminf hypotf ilogbf lgammaf logbf log1pf log2f llrintf lrintf lroundf llroundf nanf nearbyintf nextafterf nexttowardf remainderf remquof rintf roundf scalbnf scalblnf tgammaf cbrt copysign erf erfc expm1 exp2 fdim fma fmax fmin hypot ilogb lgamma logb log1p log2 llrint lrint lround llround nan nearbyint nextafter nexttoward remainder remquo rint round scalbn scalbln tgamma cbrtl copysignl erfcl erfl expm1l exp2l fdiml fmal fmaxl fminl hypotl ilogbl lgammal logbl log1pl log2l llrintl lrintl lroundl llroundl nanl nearbyintl nextafterl nexttowardl remainderl remquol rintl roundl scalbnl scalblnl tgammal"
cap='sed y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
for f in $c90_funs ; do
sym=`echo $f | $cap`
type=double
echo $f | grep "[^f]f$" >/dev/null
if [ $? -eq 0 ] ; then
type=float
else
echo $f | grep "[^l]l$" >/dev/null
if [ $? -eq 0 ] ; then
type="long double"
fi
fi
# assume a non-conforming header with all libc names in global namespace
echo "#ifndef _RWSTD_NO_$sym"
echo "# define _$sym(x) ::$f (x)"
echo "#elif !defined (_RWSTD_NO_${sym}_IN_LIBM)"
echo "extern \"C\" $type $f ($type);"
echo "# define _$sym(x) ::$f (x)"
echo "#else"
echo "# define _$sym(x) ::$f (double (x))"
echo "#endif // _RWSTD_NO_$sym"
echo
done