#
# $Id: configure.ac,v 1.40 2005/07/09 20:04:35 will_mason Exp $
#

# ObjectiveLib - a library of containers and algorithms for Objective-C
#
# Copyright (c) 2004
# Will Mason
#
# Portions:
#
# Copyright (c) 1994
# Hewlett-Packard Company
#
# Copyright (c) 1996,1997
# Silicon Graphics Computer Systems, Inc.
#
# Copyright (c) 1997
# Moscow Center for SPARC Technology
#
# Copyright (c) 1999 
# Boris Fomitchev
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# You may contact the author at will_mason@users.sourceforge.net.

AC_PREREQ(2.53)
AC_INIT([ObjectiveLib], [0.10])
AC_REVISION([$Revision: 1.40 $])
AC_CONFIG_HEADERS([Config.h ConfigPrivate.h test/Config.h])

# Enable options to configure
AC_ARG_WITH([xcodebuild], AC_HELP_STRING([--with-xcodebuild=PATH], [use the xcodebuild executable at PATH]), [XCODE_PATH=${withval}])
AC_ARG_WITH([doxygen], AC_HELP_STRING([--with-doxygen=PATH], [use the doxygen executable at PATH]), [DOXYGEN_PATH=${withval}])
AC_ARG_WITH([dot], AC_HELP_STRING([--with-dot=PATH], [use the dot executable at PATH]), [DOT_PATH=${withval}])
AC_ARG_WITH([fwk-dir], AC_HELP_STRING([--with-fwk-dir=PATH], [install the framework in the directory indicated by PATH @<:@${HOME}/Library/Frameworks@:>@]), [FWK_DIR=${withval}])
AC_ARG_WITH([doc-dir], AC_HELP_STRING([--with-doc-dir=PATH], [install the documentation in the directory indicated by PATH @<:@${HOME}/Documents@:>@]), [DOC_DIR=${withval}])
AC_ARG_WITH([gnustep], AC_HELP_STRING([--with-gnustep], [build with GNUstep even if building on a Darwin machine]), [BUILD_COCOA=no])
AC_ARG_WITH([zlib], AC_HELP_STRING([--with-zlib], [check for zlib (default is yes)]), [BUILD_ZLIB=${withval}], [BUILD_ZLIB="yes"])
AC_ARG_WITH([bzlib], AC_HELP_STRING([--with-bzlib], [check for bzlib (default is yes)]), [BUILD_BZLIB=${withval}], [BUILD_BZLIB="yes"])

# Variables to output
AC_SUBST([DOXYGEN_PATH])
AC_SUBST([DOT_PATH])
AC_SUBST([HAVE_DOT])
AC_SUBST([DOC_DIR])
AC_SUBST([HAVE_KEYED_ARCHIVES])
AC_SUBST([BUILD_COCOA])
AC_SUBST([BUILD_DIR])

# This one's easy
BUILD_DIR=build

# Version numbers
MAJOR_VERSION=`echo AC_PACKAGE_VERSION | awk '{ split($0, v, ".") ; print v[[1]] }'`
AC_DEFINE_UNQUOTED([OL_MAJOR_VERSION], ${MAJOR_VERSION})
MINOR_VERSION=`echo AC_PACKAGE_VERSION | awk '{ split($0, v, ".") ; print v[[2]] }'`
AC_DEFINE_UNQUOTED([OL_MINOR_VERSION], ${MINOR_VERSION})

# Check to see whether we build Cocoa or GNUstep
AC_CANONICAL_BUILD
if test -z "${BUILD_COCOA}" ; then
    if echo ${ac_cv_build} | grep darwin > /dev/null ; then
        BUILD_COCOA=yes
        AC_SUBST([XCODE_PATH])
        AC_SUBST([FWK_DIR])
        AC_SUBST([XCODE_TARGET])
    else
        BUILD_COCOA=no
        AC_SUBST([ADDL_GNUSTEP_LIBS])
        AC_SUBST([HAVE_ZLIB])
        AC_SUBST([HAVE_BZLIB])
    fi
fi
if test "${BUILD_COCOA}" = "yes" ; then
    AC_MSG_NOTICE([building with Cocoa])
else
    AC_MSG_NOTICE([building with GNUstep])
    if echo ${ac_cv_build} | grep mingw32 > /dev/null ; then
        BUILD_MINGW=yes
    fi
    if echo ${ac_cv_build} | grep cygwin > /dev/null ; then
        BUILD_CYGWIN=yes
    fi
fi

# Check for Xcode if it wasn't set in the with options
if test "${BUILD_COCOA}" = "yes" ; then
    if test -z "${XCODE_PATH}" ; then
        AC_CHECK_PROGS([XCODE_PATH], [xcodebuild])
        if test -z "${XCODE_PATH}" ; then
            AC_MSG_ERROR([xcodebuild is required. You may either set the location of xcodebuild with --with-xcodebuild=PATH or disable Cocoa with --with-gnustep.])
        fi
    else
        AC_CHECK_FILE([${XCODE_PATH}], , [AC_MSG_ERROR([${XCODE_PATH} does not exist, and xcodebuild is required.])])
    fi
else
    AC_CHECK_PROGS([GDB_PATH], [gdb])
fi

# Check for doxygen
if test -z "${DOXYGEN_PATH}" ; then
    AC_CHECK_PROGS([DOXYGEN_PATH], [doxygen])
else
    AC_CHECK_FILE([${DOXYGEN_PATH}], , [DOXYGEN_PATH=])
fi

# Check for dot
if test -z "${DOT_PATH}" ; then
    AC_CHECK_PROGS([DOT_PATH], [dot])
else
    AC_CHECK_FILE([${DOT_PATH}], , [DOT_PATH=])
fi
if test -z ${DOT_PATH} ; then
    HAVE_DOT=NO
else
    HAVE_DOT=YES
    if test -f "${DOT_PATH}" ; then
        DOT_PATH=`dirname ${DOT_PATH}`/
    else
        DOT_PATH=
    fi
fi

# Set the framework directory
if test "${BUILD_COCOA}" = "yes" ; then
    if test -z "${FWK_DIR}" ; then
        FWK_DIR=${HOME}/Library/Frameworks
    fi
    AC_MSG_NOTICE([the framework will be installed at ${FWK_DIR}])
fi

# Set the documentation directory
if test -z "${DOC_DIR}" ; then
    DOC_DIR=${HOME}/Documents
fi
AC_MSG_NOTICE([the documentation will be installed at ${DOC_DIR}])

# The bottom line is that keyed archives don't work on GNUstep
if test "${BUILD_COCOA}" = "yes" ; then
    AC_DEFINE([HAVE_KEYED_ARCHIVES])
    AC_MSG_NOTICE([enabling keyed archives in the unit tests])
else
    AC_MSG_NOTICE([disabling keyed archives in the unit tests])
fi

# Check for inttypes.h
AC_CHECK_HEADER([inttypes.h], AC_DEFINE([OL_HAVE_INTTYPES_H]), AC_MSG_ERROR([inttypes.h is required]))

# Ensure byte-swapping functions are available.
if test "${BUILD_COCOA}" = "yes" ; then
    AC_CHECK_HEADER([architecture/byte_order.h], , AC_MSG_ERROR([architecture/byte_order.h not found]))
fi

# On MinGW we must have pthreads and libw32c (for lrand48) available.
if test "${BUILD_MINGW}" = "yes" ; then
    ADDL_GNUSTEP_LIBS="-lgw32c ${LIBS}"

    AC_CHECK_HEADER([pthread.h], , AC_MSG_ERROR([pthread.h is required: see Build.html for details]))

    # There are several possible names for the pthread lib on MinGW.
    for lib_name in pthreadGC pthreadGCE pthreadGC1 pthreadGC2 \
                    pthreadGCE1 pthreadVC pthreadVCE pthreadVSE \
                    pthreadVC1 pthreadVCE1 pthreadVSE1 pthread ; do
        AC_CHECK_LIB([${lib_name}], [pthread_key_create], [ADDL_GNUSTEP_LIBS="-l${lib_name} ${ADDL_GNUSTEP_LIBS}" ; break])
    done

    echo ${ADDL_GNUSTEP_LIBS} | grep pthread > /dev/null || AC_MSG_ERROR([pthreads not installed; see Build.html for details.])

    AC_CHECK_LIB([gw32c], [lrand48], , AC_MSG_ERROR([libgw32c not installed: see Build.html for details.]))
fi

# We've got to have zlib to build the zlib streams
if test "${BUILD_ZLIB}" = "yes" ; then
    AC_CHECK_HEADER([zlib.h], AC_CHECK_LIB([z], [deflate], [HAVE_ZLIB=yes]))
    if test "${HAVE_ZLIB}" = "yes" ; then
        ADDL_GNUSTEP_LIBS="-lz ${ADDL_GNUSTEP_LIBS}"
        HAVE_ZLIB="yes"
        AC_DEFINE([HAVE_ZLIB])
    else
        AC_MSG_NOTICE([The library will be built without zlib support])
        HAVE_ZLIB="no"
    fi
else
    XCODE_TARGET="ObjectiveLib No Zlib"
fi

# We've got to have bzlib to build bzlib streams
if test "${BUILD_BZLIB}" = "yes" ; then
    AC_CHECK_HEADER([bzlib.h], AC_CHECK_LIB([bz2], [BZ2_bzDecompress], [HAVE_BZLIB=yes]))
    if test "${HAVE_BZLIB}" = "yes" ; then
        ADDL_GNUSTEP_LIBS="-lbz2 ${ADDL_GNUSTEP_LIBS}"
        HAVE_BZLIB="yes"
        AC_DEFINE([HAVE_BZLIB])
    else
        AC_MSG_NOTICE([The library will be built without bzlib support])
        HAVE_BZLIB="no"
    fi
fi

# Now figure out which Xcode target to build
if test "${HAVE_ZLIB}" = "yes" ; then
    if test "${BUILD_BZLIB}" = "yes" ; then
        XCODE_TARGET="ObjectiveLib"
    else
        XCODE_TARGET="ObjectiveLib No Bzlib"
    fi
else
    if test "${HAVE_BZLIB}" = "yes" ; then
        XCODE_TARGET="ObjectiveLib No Zlib"
    else
        XCODE_TARGET="ObjectiveLib No Zlib No Bzlib"
    fi
fi

# Check to see if realpath sucks
AC_MSG_CHECKING([whether realpath sucks])
AC_RUN_IFELSE(
        AC_LANG_PROGRAM([[[#include <stdlib.h>
char nameBuf[1024 * 32];]]],
[return realpath("doggyboy.diddly", nameBuf) == NULL ? 0 : 1]),
        AC_DEFINE([OL_REALPATH_SUCKS]) AC_MSG_RESULT([yes]),
        AC_MSG_RESULT([no]))

# Handy structure checker
AC_DEFUN([OL_CHECK_STRUCT],
AC_MSG_CHECKING([for $1])
AC_COMPILE_IFELSE(AC_LANG_PROGRAM([$4
$1 val;], []),
    $2
AC_MSG_RESULT([yes]),
    $3
AC_MSG_RESULT([no]))
)

# On Windows, we need WinSock headers for the socket-related tests.

if test "${BUILD_MINGW}" = "yes"; then

# Check for sockaddr_in
OL_CHECK_STRUCT([struct sockaddr_in],
        ,
        AC_MSG_ERROR([The required structure sockaddr_in could not be found]),
        [#include <winsock2.h>])

# Check for sockaddr_in.sin_len
AC_CHECK_MEMBER(struct sockaddr_in.sin_len,
        AC_DEFINE([OL_HAVE_SIN_LEN]),
        ,
        [#include <winsock2.h>])

# Check for sockaddr_in6
OL_CHECK_STRUCT([struct sockaddr_in6], HAVE_SOCKADDR_IN6=yes, ,
        [#include <winsock2.h>])

# Check for sockaddr_in6.sin6_len
if test "${HAVE_SOCKADDR_IN6}" = "yes" ; then
    AC_DEFINE([OL_HAVE_INET6_SOCKETS])
    AC_CHECK_MEMBER(struct sockaddr_in6.sin6_len,
        AC_DEFINE([OL_HAVE_SIN6_LEN]),
        ,
        [#include <winsock2.h>])
fi

# Check for sockaddr_un
    OL_CHECK_STRUCT([struct sockaddr_un], AC_DEFINE([OL_HAVE_UNIX_SOCKETS]), ,
        [#include <winsock2.h>])

# Check for getaddrinfo
AC_CHECK_DECL([getaddrinfo], AC_DEFINE([OL_HAVE_GETADDRINFO]), HAVE_GETADDRINFO=no,
        [#include <winsock2.h>])

if test "${HAVE_GETADDRINFO}" = "no" ; then
    AC_CHECK_DECL([gethostbyname],
        AC_DEFINE([OL_HAVE_GETHOSTBYNAME]),
        AC_MSG_ERROR([Neither getaddrinfo nor gethostbyname could be located]),
        [#include <winsock2.h>])
    # Sanity check
    AC_CHECK_DECL([getservbyname], ,
        AC_MSG_ERROR([Somehow you've got gethostbyname but not getservbyname. How'd you do that?]),
        [#include <winsock2.h>])
fi

# Check for getnameinfo
AC_CHECK_DECL([getnameinfo], AC_DEFINE([OL_HAVE_GETNAMEINFO]), HAVE_GETNAMEINFO=no,
        [#include <winsock2.h>])

if test "${HAVE_GETNAMEINFO}" = "no" ; then
    AC_CHECK_DECL([gethostbyaddr],
        AC_DEFINE([OL_HAVE_GETHOSTBYADDR]),
        AC_MSG_ERROR([Neither getnameinfo nor gethostbyaddr could be located]),
        [#include <winsock2.h>])
fi

else    # not Windows

# Some platforms have SO_REUSEPORT and some don't
AC_CHECK_DECL([SO_REUSEPORT],
        AC_DEFINE([OL_HAVE_SO_REUSEPORT]),
        ,
        [#include <sys/types.h>
#include <sys/socket.h>])

# Check for sockaddr_in
OL_CHECK_STRUCT([struct sockaddr_in],
        ,
        AC_MSG_ERROR([The required structure sockaddr_in could not be found]),
[#include <sys/types.h>
#include <netinet/in.h>])

# Check for sockaddr_in.sin_len
AC_CHECK_MEMBER(struct sockaddr_in.sin_len,
                AC_DEFINE([OL_HAVE_SIN_LEN]),
                ,
                [#include <sys/types.h>
#include <netinet/in.h>])

# Check for sockaddr_in6
OL_CHECK_STRUCT([struct sockaddr_in6], HAVE_SOCKADDR_IN6=yes, ,
[#include <sys/types.h>
#include <netinet/in.h>])

# Check for sockaddr_in6.sin6_len
if test "${HAVE_SOCKADDR_IN6}" = "yes" ; then
    AC_DEFINE([OL_HAVE_INET6_SOCKETS])
    AC_CHECK_MEMBER(struct sockaddr_in6.sin6_len,
                    AC_DEFINE([OL_HAVE_SIN6_LEN]),
                    ,
                    [#include <sys/types.h>
#include <netinet/in.h>])
fi

# Check for sockaddr_un
#   Cygwin offers simulated local sockets using IP, but they are disabled
#   here due to failed unit test.
if test "${BUILD_CYGWIN}" != "yes"; then

    OL_CHECK_STRUCT([struct sockaddr_un], AC_DEFINE([OL_HAVE_UNIX_SOCKETS]), ,
[#include <sys/types.h>
#include <sys/un.h>])
	 
fi

# Check for getaddrinfo
AC_CHECK_DECL([getaddrinfo], AC_DEFINE([OL_HAVE_GETADDRINFO]), HAVE_GETADDRINFO=no,
[#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>])

if test "${HAVE_GETADDRINFO}" = "no" ; then
    AC_CHECK_DECL([gethostbyname],
        AC_DEFINE([OL_HAVE_GETHOSTBYNAME]),
        AC_MSG_ERROR([Neither getaddrinfo nor gethostbyname could be located]),
        [#include <netdb.h>])
    # Sanity check
    AC_CHECK_DECL([getservbyname], ,
        AC_MSG_ERROR([Somehow you've got gethostbyname but not getservbyname. How'd you do that?]),
        [#include <netdb.h>])
fi

# Check for getnameinfo
AC_CHECK_DECL([getnameinfo], AC_DEFINE([OL_HAVE_GETNAMEINFO]), HAVE_GETNAMEINFO=no,
[#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>])

if test "${HAVE_GETNAMEINFO}" = "no" ; then
    AC_CHECK_DECL([gethostbyaddr],
        AC_DEFINE([OL_HAVE_GETHOSTBYADDR]),
        AC_MSG_ERROR([Neither getnameinfo nor gethostbyaddr could be located]),
        [#include <netdb.h>])
fi

fi

# Output files
AC_OUTPUT([GNUmakefile test/GNUmakefile DocTools/Doxygen.cfg])
