diff options
Diffstat (limited to 'build/unix/config_functions')
-rw-r--r-- | build/unix/config_functions | 1139 |
1 files changed, 1139 insertions, 0 deletions
diff --git a/build/unix/config_functions b/build/unix/config_functions new file mode 100644 index 0000000..23adc2d --- /dev/null +++ b/build/unix/config_functions @@ -0,0 +1,1139 @@ +# Auxiliary functions for custom build system +# Copyright (c) 2002 Serge van den Boom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +BUILDLOG=/dev/null +TEMPFILE="/tmp/build.$$.tmp" +#KEEPTEMPFILES=keeptempfiles + + +# Description: perform a command, and set the exit status to the opposite. +# (true +# Arguments: $1 - the command to run +# rest - arguments to the command +not() { + local CMD + CMD=$1 + shift + "$CMD" "$@" + return "$(($? == 0))" +} + +# Description: prints a command to stdout and then executes it +# Arguments: command with arguments +# Returns: the return value of the command +echo_and_perform() { + cat << EOF +$@ +EOF + "$@" +} + +# Description: Get the contents of a variable with a specific name, +# but don't expand it. (evalVar does expand it) +# Use this instead of 'eval', so that you won't have to +# worry about escaping. +# NB. this function only works on global variables. +# Arguments: $1 - the name of the variable +# Returns: 0 +# Prints: the value of the variable +getVar() { + local RESULT + eval RESULT=\$$1 + cat << EOF +$RESULT +EOF +} + +# Description: Get the contents of a variable with a specific name, +# and expand it. (getVar doesn't expand it) +# Use this instead of 'eval', so that you won't have to +# worry about escaping. +# NB. this function only works on global variables. +# Arguments: $1 - the name of the variable +# Returns: 0 +# Prints: the value of the variable +evalVar() { + local RESULT + eval RESULT=\$$1 + eval RESULT=\""$RESULT"\" + cat << EOF +$RESULT +EOF +} + +# Description: Set the value of a variable with a specific name, +# and expand it. +# Use this instead of 'eval', so that you won't have to +# worry about escaping. +# NB. this function only works on global variables. +# Arguments: $1 - the name of the variable +# $2 - the value to assign to it (will not be expanded) +setVar() { + eval $1=\$2 +} + +# Description: delete the files passed as arguments, unless +# $KEEPTEMPFILES is set. +deleteTempFiles() { + if [ -n "$KEEPTEMPFILES" ]; then + return + fi + + rm -f -- "$@" +} + +# Description: read text from stdin to use as a c file to compile +# Arguments: $1 - CFLAGS to use for compilation (optional) +# $2 - LDFLAGS to use for linking (optional) +# Returns: 0 - if compile successful +# something else - if compile failed +try_compile_c() { + local SYSTEM_FLAGS RESULT + + if [ -z "$COMPILE_C" ]; then + echo "Fatal: Program \$COMPILE_C is not defined!" >&2 + exit 1 + fi + + SYSTEM_FLAGS="$SYSTEM_BUILD_CFLAGS $SYSTEM_BUILD_LDFLAGS $SYSTEM_HOST_CFLAGS $SYSTEM_HOST_LDFLAGS" + cat > "$TEMPFILE.c" + + echo_and_perform $COMPILE_C $SYSTEM_FLAGS $1 "$TEMPFILE.c" \ + -o "$TEMPFILE.c.o" >> "$BUILDLOG" 2>&1 + RESULT=$? + + if [ $RESULT -eq 0 ]; then + echo_and_perform $LINK $SYSTEM_FLAGS $2 "$TEMPFILE.c.o" \ + -o "$TEMPFILE.out" >> "$BUILDLOG" 2>&1 + RESULT=$? + fi + + if [ $RESULT -ne 0 ]; then + echo "Failed program was:" >> "$BUILDLOG" + echo "+++ START $TEMPFILE.c" >> "$BUILDLOG" + cat "$TEMPFILE.c" >> "$BUILDLOG" + echo "+++ END $TEMPFILE.c" >> "$BUILDLOG" + fi + + deleteTempFiles "$TEMPFILE.c $TEMPFILE.c.o $TEMPFILE.out" + + echo >> "$BUILDLOG" + return $RESULT +} + +# Description: read text from stdin to use as a c file to compile +# Arguments: $1 - CFLAGS to use for compilation (optional) +# $2 - LDFLAGS to use for linking (optional) +# Returns: 128 - if compiling or linking failed +# otherwise - exit status of the program +try_compile_and_run_c() { + local SYSTEM_FLAGS RESULT + + if [ -z "$COMPILE_C" ]; then + echo "Fatal: Program \$COMPILE_C is not defined!" >&2 + exit 1 + fi + + SYSTEM_FLAGS="$SYSTEM_BUILD_CFLAGS $SYSTEM_BUILD_LDFLAGS $SYSTEM_HOST_CFLAGS $SYSTEM_HOST_LDFLAGS" + cat > "$TEMPFILE.c" + + echo_and_perform $COMPILE_C $SYSTEM_FLAGS $1 "$TEMPFILE.c" \ + -o "$TEMPFILE.c.o" >> "$BUILDLOG" 2>&1 + RESULT=$? + + if [ $RESULT -eq 0 ]; then + echo_and_perform $LINK $SYSTEM_FLAGS $2 "$TEMPFILE.c.o" \ + -o "$TEMPFILE.out" >> "$BUILDLOG" 2>&1 + RESULT=$? + fi + + if [ $RESULT -eq 0 ]; then + "$TEMPFILE.out" + RESULT=$? + fi + + deleteTempFiles "$TEMPFILE.c $TEMPFILE.c.o $TEMPFILE.out" + + echo >> "$BUILDLOG" + return $RESULT +} + +# Description: Output a message to stderr, unless BUILD_SILENT is set +# Arguments: the message +build_message() { + if [ -z "$BUILD_SILENT" ]; then + cat >&2 << EOF +$@ +EOF + fi +} + +# Description: check if a string is lexicographically before +# another string +# Arguments: $1 - the first string +# $2 - the second string +# Returns: 0 if $1 is lexicographically before $2 +# 1 otherwise +lexlt() { + # The 'test' builtin in some sh shells can't do this. + # To execute the non-builtin 'test' you need the path, and + # that differs per system (/bin/test or /usr/bin/test). + # It says '>=' instead of '<' because expr prints '1' for true, + # and sh uses 0. + return `expr "$1" ">=" "$2"` +} + +# Description: Check if one version is sufficiently new. +# Arguments: $1 - the required version +# $2 - the available version +# Returns: 0 - if $2 is at least as new as $1 +# 1 - if $2 is older than $1, or the two strings don't compare +version_match() { + # To compare the two version strings, the numbers in the version + # compared numerically, and all string parts should be equal. + local REST1 REST2 NUM1 NUM2 STR1 STR2 CHECKNUMS + REST1=$1 + REST2=$2 + CHECKNUMS=0 + + while [ -n "$REST1" -a -n "$REST2" ]; do + NUM1=`$SED -e 's/^\([0-9]*\).*$/\1/' << EOF +$REST1 +EOF +` + NUM2=`$SED -e 's/^\([0-9]*\).*$/\1/' << EOF +$REST2 +EOF +` + REST1=`$SED -e 's/^[0-9]*//' << EOF +$REST1 +EOF +` + REST2=`$SED -e 's/^[0-9]*//' << EOF +$REST2 +EOF +` + if [ "(" -n "$NUM1" -a -z "$NUM2" ")" -o \ + "(" -z "$NUM1" -a -n "$NUM2" ")" ]; then + # Only one of the versions contains a number here. No match. + return 1 + fi + if [ "(" -n "$NUM1" -a -z "$NUM2" ")" -o \ + "(" -z "$NUM1" -a -n "$NUM2" ")" ]; then + # Only one of the versions contains a number here. No match. + return 1 + fi + + if [ "$CHECKNUMS" -eq 0 ]; then + if [ "$NUM1" -gt "$NUM2" ]; then + # Too old. + return 1 + fi + if [ "$NUM1" -lt "$NUM2" ]; then + # A major number is larger. Minor numbers may be smaller. + CHECKNUMS=1 + fi + fi + + STR1=`$SED -e 's/^\([^0-9]*\).*$/\1/' << EOF +$REST1 +EOF +` + STR2=`$SED -e 's/^\([^0-9]*\).*$/\1/' << EOF +$REST2 +EOF +` + REST1=`$SED -e 's/^[^0-9]*//' << EOF +$REST1 +EOF +` + REST2=`$SED -e 's/^[^0-9]*//' << EOF +$REST2 +EOF +` + + if [ "x$STR1" "!=" "x$STR2" ]; then + # String parts don't match + return 1 + fi + done + + if [ -n "$REST1" -o -n "$REST2" ]; then + # One version string contains extra information. No match. + return 1 + fi + + return 0 +} + +# Description: try to detect a list of program dependencies. +# This only makes sure the PROG_xxx_PRESENT flag is set. +# It does not bail out if a dependency is not found. +# This function is called for programs in +# PROG_xxx_DEPEND_DETECT_BIN or LIB_xxx_DEPEND_DETECT_BIN. +# Using have_program in the respective depend functions would +# not save the PRESENT flag, as it is executed in a subshell. +# Arguments: $1 - the list of programs +detect_dependencies_program() { + local PROGS PROG + PROGS=$1 + for PROG in $PROGS; do + have_program "$PROG" + done +} + +# Description: try to detect a list of library dependencies. +# This only makes sure the LIB_xxx_PRESENT flag is set. +# It does not bail out if a dependency is not found. +# This function is called for libraries in +# PROG_xxx_DEPEND_DETECT_LIB or LIB_xxx_DEPEND_DETECT_LIB. +# Using have_library in the respective depend functions would +# not save the PRESENT flag, as it is executed in a subshell. +# Arguments: $1 - the list of libaries +detect_dependencies_library() { + local LIBS LIB + LIBS=$1 + for LIB in $LIBS; do + have_library "$LIB" + done +} + +# Description: check if a program is present in the path or as a built-in +# command. +# Arguments: $1 - The name of the program as it is executed +# Returns: 0 - if the command is found +# 1 - if the command is not found +have_command() { + type "$1" > /dev/null 2>&1 || false + # The '|| false' is because if 'type' does not recognise the + # command, it might return a different value than 1, on some + # shells. +} + +# Description: check if a program is present in the path or as a built-in +# command. +# Arguments: $1 - The name of the program as used in config_proginfo after +# "BIN_" +have_program() { + local PROG TEMP_NAME TEMP_FILE TEMP_VERSION TEMP_PRESENT TEMP_DETECT + local TEMP_DEPEND_DETECT_BIN TEMP_DEPEND_DETECT_LIB + + PROG=$1 + TEMP_NAME=`evalVar "PROG_${PROG}_NAME"` + if [ -z "$TEMP_NAME" ]; then + echo "Fatal: Program '$PROG' is not defined!" >&2 + exit 1 + fi + + TEMP_PRESENT=`getVar "PROG_${PROG}_PRESENT"` + if [ -n "$TEMP_PRESENT" ]; then + return "$TEMP_PRESENT" + fi + + # If a detection method is specified, try that one first. + TEMP_DETECT=`evalVar "PROG_${PROG}_DETECT"` + if [ -n "$TEMP_DETECT" ]; then + TEMP_DEPEND_DETECT_BIN=`evalVar "PROG_${PROG}_DEPEND_DETECT_BIN"` + TEMP_DEPEND_DETECT_LIB=`evalVar "PROG_${PROG}_DEPEND_DETECT_LIB"` + detect_dependencies_program "$TEMP_DEPEND_DETECT_BIN" + detect_dependencies_library "$TEMP_DEPEND_DETECT_LIB" + $TEMP_DETECT + # NB. TEMP_DETECT should make sure PROG_${PROG}_VERSION and + # PROG_${PROG}_FILE are set. + case $? in + 0) # Program found + setVar "PROG_${PROG}_PRESENT" 0 + ;; + 1) # Lib not found + setVar "PROG_${PROG}_PRESENT" 1 + ;; + 2) # Use default detection + ;; + esac + fi + + # If detection via a specified detection method was inconclusive, + # or no detection method was specified, try default detection + # based on whether the command name exists. + TEMP_PRESENT=`getVar "$PROG_${PROG}_PRESENT"` + if [ -z "$TEMP_PRESENT" ]; then + TEMP_FILE=`evalVar "PROG_${PROG}_FILE"` + have_command "${TEMP_FILE%% *}" + if [ $? -eq 0 ]; then + # Program found + setVar "PROG_${PROG}_PRESENT" 0 + fi + fi + + # If detection has yielded no results so far, we're calling it + # "not found". + TEMP_PRESENT=`getVar "PROG_${PROG}_PRESENT"` + if [ -z "$TEMP_PRESENT" ]; then + setVar "PROG_${PROG}_PRESENT" 1 + fi + + TEMP_PRESENT=`getVar "PROG_${PROG}_PRESENT"` + if [ "$TEMP_PRESENT" -eq 1 ]; then + build_message "$TEMP_NAME not found." + return 1 + fi + + # We have found the program. + # Test whether the version is sufficient. + if [ $# -gt 1 ]; then + # Minimum version supplied + TEMP_VERSION=`evalVar "PROG_${PROG}_VERSION"` + if [ -z "$TEMP_VERSION" ]; then + setVar "PROG_${PROG}_PRESENT" 1 + echo "Fatal: Could not determine the version of $TEMP_NAME" >&2 + exit 1 + fi + if not version_match "$2" "$TEMP_VERSION"; then + setVar "PROG_${PROG}_PRESENT" 1 + build_message "Found version $TEMP_VERSION of $TEMP_NAME, \ +but version $2 is required!" + return 1 + fi + setVar "PROG_${PROG}_PRESENT" 0 + build_message "$TEMP_NAME version $TEMP_VERSION found." + return 0 + fi + + setVar "PROG_${PROG}_PRESENT" 0 + build_message "$TEMP_NAME found." + return 0 +} + +# Description: check if a build tool is present, and define the appropriate +# environment variable for it. +# Arguments: $1 - The type of compile tool. One of PREPROC_C, MKDEP_C, +# COMPILE_C, PREPROC_OBJC, MKDEP_OBJC, COMPILE_OBJC, +# and LINK. +have_build_tool() { + local TOOL TEMP_NAME TEMP_PRESENT DEPENDS DEPEND SUCCESS COMMAND + + TOOL=$1 + + TEMP_NAME=`evalVar "BUILDTOOL_${TOOL}_NAME"` + if [ -z "$TEMP_NAME" ]; then + echo "Fatal: Build tool '$TOOL' is not defined!" >&2 + exit 1 + fi + + TEMP_PRESENT=`getVar "BUILDTOOL_${TOOL}_PRESENT"` + if [ -n "$TEMP_PRESENT" ]; then + return "$TEMP_PRESENT" + fi + + SUCCESS=0 + DEPENDS=`getVar "BUILDTOOL_${TOOL}_DEPEND"` + for DEPEND in $DEPENDS; do + if not have_program "$DEPEND"; then + SUCCESS=1 + fi + done + + setVar "BUILDTOOL_${TOOL}_PRESENT" "$SUCCESS" + + COMMAND=`evalVar "BUILDTOOL_${TOOL}_COMMAND"` + # Environment variables in $BUILDTOOL_xxx_COMMAND are expanded. + + if [ $SUCCESS -eq 0 ]; then + build_message "We have a $TEMP_NAME." + setVar "$TOOL" "$COMMAND" + else + build_message "No $TEMP_NAME found." + fi + + return $SUCCESS +} + +have_build_tools_language() { + local LANGUAGE + + LANGUAGE=$1 + + have_build_tool "PREPROC_$LANGUAGE" || return 1 + have_build_tool "MKDEP_$LANGUAGE" || return 1 + have_build_tool "COMPILE_$LANGUAGE" || return 1 + + return 0 +} + + +# Description: check if a library is present on the system +# Arguments: $1 - The name of the library as used in config_proginfo after +# "LIB_" +# $2 - (optional) minimum version required +# Pre: variables LIB_${1}_NAME, LIB_${1}_CFLAGS, and +# LIB_${1}_LDFLAGS are expected to exist. If two arguments are +# supplied, so is LIB_${1}_VERSION. +# Returns: 0 - if the library is found +# 1 - if the library is not found +have_library() { + local LIB TEMP_NAME TEMP_PRESENT TEMP_LDFLAGS TEMP_CFLAGS \ + TEMP_VERSION TEMP_DETECT + local TEMP_DEPEND_DETECT_BIN TEMP_DEPEND_DETECT_LIB + + LIB=$1 + TEMP_NAME=`evalVar "LIB_${LIB}_NAME"` + if [ -z "$TEMP_NAME" ]; then + echo "Fatal: Library '$LIB' is not defined!" >&2 + exit 1 + fi + + TEMP_PRESENT=`getVar "LIB_${LIB}_PRESENT"` + if [ -n "$TEMP_PRESENT" ]; then + return "$TEMP_PRESENT" + fi + + # If a detection method is specified, try that one first. + TEMP_DETECT=`evalVar "LIB_${LIB}_DETECT"` + if [ -n "$TEMP_DETECT" ]; then + TEMP_DEPEND_DETECT_BIN=`evalVar "LIB_${LIB}_DEPEND_DETECT_BIN"` + TEMP_DEPEND_DETECT_LIB=`evalVar "LIB_${LIB}_DEPEND_DETECT_LIB"` + detect_dependencies_program "$TEMP_DEPEND_DETECT_BIN" + detect_dependencies_library "$TEMP_DEPEND_DETECT_LIB" + $TEMP_DETECT + # NB. TEMP_DETECT should make sure PROG_$LIB_VERSION is set. + # return value of $TEMP_DETECT is used below. + case $? in + 0) # Lib found + setVar "LIB_${LIB}_PRESENT" 0 + ;; + 1) # Lib not found + setVar "LIB_${LIB}_PRESENT" 1 + ;; + 2) # Use default detection + ;; + esac + fi + + # If detection via a specified detection method was inconclusive, + # or no detection method was specified, try default detection + # based on whether we can compile against the library. + TEMP_PRESENT=`getVar "LIB_${LIB}_PRESENT"` + if [ -z "$TEMP_PRESENT" ]; then + TEMP_CFLAGS=`evalVar "LIB_${LIB}_CFLAGS"` + TEMP_LDFLAGS=`evalVar "LIB_${LIB}_LDFLAGS"` + + try_compile_c "$CFLAGS $TEMP_CFLAGS" "$LDFLAGS $TEMP_LDFLAGS" << EOF +int main(void) { + return 0; +} +EOF + if [ $? -eq 0 ]; then + # Build successful + setVar "LIB_${LIB}_PRESENT" 0 + fi + fi + + # If detection has yielded no results so far, we're calling it + # "not found". + TEMP_PRESENT=`getVar "LIB_${LIB}_PRESENT"` + if [ -z "$TEMP_PRESENT" ]; then + setVar "LIB_${LIB}_PRESENT" 1 + fi + + TEMP_PRESENT=`getVar "LIB_${LIB}_PRESENT"` + if [ "$TEMP_PRESENT" -eq 1 ]; then + build_message "$TEMP_NAME not found." + return 1 + fi + + # We have found the library. + # Test whether the version is sufficient. + if [ $# -gt 1 ]; then + # Minimum version supplied + TEMP_VERSION=`evalVar "LIB_${LIB}_VERSION"` + if [ -z "$TEMP_VERSION" ]; then + setVar "LIB_${LIB}_PRESENT" 1 + echo "Fatal: Could not determine the version of $TEMP_NAME" >&2 + exit 1 + fi + if not version_match "$2" "$TEMP_VERSION"; then + setVar "LIB_${LIB}_PRESENT" 1 + build_message "Found version $TEMP_VERSION of $TEMP_NAME, \ +but version $2 is required!" + return 1 + fi + setVar "LIB_${LIB}_PRESENT" 0 + build_message "$TEMP_NAME version $TEMP_VERSION found." + return 0 + fi + + setVar "LIB_${LIB}_PRESENT" 0 + build_message "$TEMP_NAME found." + return 0 +} + +# Description: check if a library is present on the system. +# If it is, add the appropriate flags to CFLAGS and LDFLAGS. +# If not, bail out. +# Arguments: $1 - The name of the library as used in config_proginfo after +# "LIB_" +# $2 - (optional) minimum version required +# Pre: variables LIB_${1}_NAME, LIB_${1}_CFLAGS, and +# LIB_${1}_LDFLAGS are expected to exist. If two arguments are +# supplied, so is LIB_${1}_VERSION. +use_library() { + local TEMP_CFLAGS TEMP_LDFLAGS + have_library "$@" + [ $? -eq 0 ] || exit 1 + + TEMP_CFLAGS=`evalVar "LIB_${1}_CFLAGS"` + TEMP_LDFLAGS=`evalVar "LIB_${1}_LDFLAGS"` + CFLAGS="$CFLAGS $TEMP_CFLAGS" + LDFLAGS="$LDFLAGS $TEMP_LDFLAGS" + return 0 +} + +# Description: check if a library are being provided by a framework outside +# of the normal system build process. +# If it is, mark it as found and add appropriate flags +# If not, do nothing. Do not even mark it as not found; it might +# be available by some other means. +# This function is currently specific to macOS builds. +# Arguments: $1 - The name of the library as used in config_proginfo +# $2 - (optional, default $1) the name of the framework +# DEPS_PATH - environment variable that if set specifies where to +# check for the framework. +# Pre: LIB_${1}_NAME is expected to exist. +have_framework() { + local TEMP_LIBNAME LIB LIBVAR FRAMEWORK_PATH + # If we aren't on a Mac, there is no framework + if [[ "x$HOST_SYSTEM" != "xDarwin" ]]; then + return 1 + fi + # If DEPS_PATH was not configured, there is no framework + if [[ -z "$DEPS_PATH" ]]; then + return 1 + fi + LIBVAR=$1 + LIB=$2 + if [[ -z "$2" ]]; then + LIB=$LIBVAR + fi + TEMP_LIBNAME=`evalVar "LIB_${LIBVAR}_NAME"` + FRAMEWORK_PATH="${DEPS_PATH}/${LIB}.framework" + if [[ -d "$FRAMEWORK_PATH" ]]; then + build_message "${TEMP_LIBNAME} found in ${DEPS_PATH}." + setVar "LIB_${LIBVAR}_PRESENT" 0 + setVar "LIB_${LIBVAR}_CFLAGS" "-F${DEPS_PATH} -I${FRAMEWORK_PATH}/Headers" + setVar "LIB_${LIBVAR}_LDFLAGS" "-F${DEPS_PATH} -framework ${LIB}" + return 0 + fi + build_message "${TEMP_LIBNAME} not found in ${DEPS_PATH}." + return 1 +} + +# Description: check if a symbol is defined +# Arguments: $1 - the name of the symbol +# $2 - the C code that does the actual checking +have_symbol_generic() { + local CODE DETECT EXTRA + + DETECT=`evalVar "SYMBOL_${1}_DETECT"` + if [ -n "$DETECT" ]; then + $DETECT + return $? + fi + + EXTRA=`evalVar "SYMBOL_${1}_EXTRA"` + CODE=`evalVar "SYMBOL_${1}_CODE"` + if [ -z "$CODE" ]; then + CODE=$2 + fi + + try_compile_c "$CFLAGS $TEMP_CFLAGS" "$LDFLAGS $TEMP_LDFLAGS" << EOF > /dev/null 2>&1 +#include <sys/types.h> +$EXTRA + +$CODE +EOF +} + +# Description: check if a symbol is defined. +# Arguments: $1 - the name of the symbol +have_symbol() { + local SYMBOL TEMP_PRESENT CODE + SYMBOL=$1 + + TEMP_PRESENT=`getVar "SYMBOL_${SYMBOL}_PRESENT"` + if [ -n "$TEMP_PRESENT" ]; then + return "$TEMP_PRESENT" + fi + + CODE=`cat << EOF +int main(void) { + (void) $SYMBOL; + return 0; +} +EOF +` + + have_symbol_generic "$SYMBOL" "$CODE" + if [ $? -gt 0 ]; then + build_message "Symbol '$SYMBOL' not found." + setVar "SYMBOL_${SYMBOL}_PRESENT" 1 + return 1 + fi + build_message "Symbol '$SYMBOL' found." + setVar "SYMBOL_${SYMBOL}_PRESENT" 0 + return 0 +} + +# Description: check if a type is present. +# Arguments: $1 - the name of the symbol +have_type() { + local TYPE TEMP_PRESENT CODE + TYPE=$1 + + TEMP_PRESENT=`getVar "TYPE_${TYPE}_PRESENT"` + if [ -n "$TEMP_PRESENT" ]; then + return "$TEMP_PRESENT" + fi + + CODE=`cat << EOF +int main(void) { + $TYPE var; + (void) var; + return 0; +} +EOF + ` + + have_symbol_generic "$TYPE" "$CODE" + if [ $? -gt 0 ]; then + build_message "Type '$TYPE' not found." + setVar "TYPE_${TYPE}_PRESENT" 1 + return 1 + fi + build_message "Type '$TYPE' found." + setVar "TYPE_${TYPE}_PRESENT" 0 + return 0 +} + +# Description: check if a symbol is defined. +# sets HAVE_<NAME> accordingly, where <NAME> is the capitalized +# name of the symbol. +# Arguments: $1 - the name of the symbol +define_have_symbol() { + local NAME VALUE DEFNAME + + DEFNAME=`getVar "SYMBOL_${1}_DEFNAME"` + if [ -z "$DEFNAME" ]; then + # Why not "tr [:lower:] [:upper:]"? Because the capital "i" is not + # "I" in Turkish... An alternative would be setting LC_CTYPE to POSIX. + NAME=`$TR "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + << EOF +$1 +EOF + ` + DEFNAME="HAVE_$NAME" + fi + + if have_symbol "$1"; then + add_symbol "$DEFNAME" "#define $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 1 + else + add_symbol "$DEFNAME" "#undef $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 0 + fi +} + +# Description: check if a type is present. +# set HAVE_<NAME> accordingly, where <NAME> is the capitalized +# name of the symbol. +# Arguments: $1 - the name of the symbol +define_have_type() { + local NAME VALUE DEFNAME + + DEFNAME=`getVar "TYPE_${1}_DEFNAME"` + if [ -z "$DEFNAME" ]; then + # Why not "tr [:lower:] [:upper:]"? Because the capital "i" is not + # "I" in Turkish... An alternative would be setting LC_CTYPE to POSIX. + NAME=`$TR "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + << EOF +$1 +EOF + ` + DEFNAME="HAVE_$NAME" + fi + + if have_type "$1"; then + add_symbol "$DEFNAME" "#define $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 1 + else + add_symbol "$DEFNAME" "#undef $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 0 + fi +} + +# Description: check if a header is available. +# Arguments: $1 - the name of the header file +have_header() { + local HEADER NAME EXTRA + HEADER=$1 + + NAME=${HEADER%.h} + EXTRA=`evalVar "HEADER_${NAME}_EXTRA"` + + try_compile_c "$CFLAGS $TEMP_CFLAGS" "$LDFLAGS $TEMP_LDFLAGS" << EOF > /dev/null 2>&1 +$EXTRA +#include <$HEADER> +int main(void) { + return 0; +} +EOF + if [ $? -gt 0 ]; then + build_message "Header '$HEADER' not found." + return 1 + fi + build_message "Header '$HEADER' found." + return 0 +} + +# Description: check if a header is available. +# sets HAVE_<NAME> accordingly, where <NAME> is the capitalized +# name of the header file. "sys/time.h" becomes "SYS_TIME_H". +# Arguments: $1 - the name of the header file +define_have_header() { + local NAME VALUE DEFNAME + + DEFNAME=`getVar "HEADER_${1%.h}_DEFNAME"` + if [ -z "$DEFNAME" ]; then + # Why not "tr [:lower:] [:upper:]"? Because the capital "i" is not + # "I" in Turkish... An alternative would be setting LC_CTYPE to POSIX. + NAME=`$TR "/.abcdefghijklmnopqrstuvwxyz" \ + "__ABCDEFGHIJKLMNOPQRSTUVWXYZ" << EOF +$1 +EOF + ` + DEFNAME="HAVE_$NAME" + fi + + if have_header "$1"; then + add_symbol "$DEFNAME" "#define $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 1 + else + add_symbol "$DEFNAME" "#undef $DEFNAME" + add_symbol "${DEFNAME}_FLAG" 0 + fi +} + +# Description: check if a macro is available. +# Arguments: $1 - the name of the macro +have_macro() { + local MACRO EXTRA + MACRO=$1 + + EXTRA=`evalVar "MACRO_${NAME}_EXTRA"` + + try_compile_c "$CFLAGS $TEMP_CFLAGS" "$LDFLAGS $TEMP_LDFLAGS" << EOF > /dev/null 2>&1 +$EXTRA +#ifndef $MACRO +# error +#endif +int main(void) { + return 0; +} +EOF + if [ $? -gt 0 ]; then + build_message "Preprocessor macro '$MACRO' not found." + return 1 + fi + build_message "Preprocessor macro '$MACRO' found." + return 0 +} + +# Description: check if a macro is defined +# sets MACRO_<NAME> to a non-empty string if the macro with +# the specified name is defined, and to an empty string if it +# is not. +# Arguments: $1 - the name of the symbol +define_have_macro() { + local NAME + + NAME=$1 + + if have_macro "$1"; then + add_symbol "MACRO_$NAME" "1" + else + add_symbol "MACRO_$NAME" "" + fi +} + +# Description: Add a symbol to be replaced by substitute_vars +# $HAVE_SYMBOLS will contain the variable names of all +# symbols added by define_have_symbol and should be passed to +# substitute_vars for the file you want them in. +# Arguments: $1 - the symbol to add +# $2 - the value of the symbol +add_symbol() { + local NAME + + eval NAME="$1" + eval "$NAME"=\"\$2\" + HAVE_SYMBOLS="$HAVE_SYMBOLS $NAME" +} + +check_endianness() { + local ENDIAN + + if [ "$BUILD_SYSTEM" '!=' "$HOST_SYSTEM" ]; then + case "$BUILD_HOST_ENDIAN" in + "") + build_message "Cross-compiling - assuming little-endian host." + ENDIAN=little + ;; + big) + build_message "Cross-compiling for a big-endian host." + ENDIAN=big + ;; + little) + build_message "Cross-compiling for a little-endian host." + ENDIAN=little + ;; + *) + build_message "Bad endianness specified. Use \"little\" or \"big\"" + exit 1 + ;; + esac + else + # Detect endianness + try_compile_and_run_c "$CFLAGS" "$LDFLAGS" << EOF +int main(void) { + int i; + + i = 1; + return *((unsigned char *) &i); +} +EOF + if [ $? -eq 0 ]; then + build_message "Big-endian machine detected." + ENDIAN=big + else + build_message "Little-endian machine detected." + ENDIAN=little + fi + fi + + case "$ENDIAN" in + big) + add_symbol WORDS_BIGENDIAN "#define WORDS_BIGENDIAN" + add_symbol "WORDS_BIGENDIAN_FLAG" 1 + ;; + little) + add_symbol WORDS_BIGENDIAN "#undef WORDS_BIGENDIAN" + add_symbol "WORDS_BIGENDIAN_FLAG" 0 + ;; + esac +} + + +# Description: If pkg-config is installed, check if there's a pkg-config +# entry for some binary dependency. +# If successful, it sets the appropriate BIN_xxx_VERSION. +# Arguments: $1 - The name of the program as it is known in +# config_proginfo after "BIN_" +# $2 - The name of the dependency as it would be known to +# pkg-config. +try_pkgconfig_prog() { + have_program pkgconfig || return 1 + + local PROG PKG_NAME TEMP_NAME + PROG=$1 + PKG_NAME=$2 + + TEMP_NAME=`evalVar "PROG_${PROG}_NAME"` + if [ -z "$TEMP_NAME" ]; then + echo "Fatal: Program '$PROG' is not defined!" >&2 + exit 1 + fi + + if $PROG_pkgconfig_FILE --exists "$PKG_NAME"; then + local TEMP_VERSION + TEMP_VERSION=$($PROG_pkgconfig_FILE --modversion "$PKG_NAME") + setVar "PROG_${PROG}_VERSION" "$TEMP_VERSION" + return 0 + else + return 2 + fi +} + + +# Description: If pkg-config is installed, check if there's a pkg-config +# entry for some dependency. +# If successful, it sets the appropriate LIB_xxx_VERSION, +# LIB_xxx_CFLAGS and LIB_xxx_LDFLAGS. +# Arguments: $1 - The name of the library as it is known in +# config_proginfo after "LIB_" +# $2 - The name of the dependency as it would be known to +# pkg-config. +try_pkgconfig_lib() { + have_program pkgconfig || return 1 + + local LIB PKG_NAME TEMP_NAME + LIB=$1 + PKG_NAME=$2 + + TEMP_NAME=`evalVar "LIB_${LIB}_NAME"` + if [ -z "$TEMP_NAME" ]; then + echo "Fatal: Library '$LIB' is not defined!" >&2 + exit 1 + fi + + if $PROG_pkgconfig_FILE --exists "$PKG_NAME"; then + local TEMP_VERSION TEMP_CFLAGS TEMP_LDFLAGS + TEMP_VERSION=$($PROG_pkgconfig_FILE --modversion "$PKG_NAME") + TEMP_CFLAGS=$($PROG_pkgconfig_FILE --cflags "$PKG_NAME") + TEMP_LDFLAGS=$($PROG_pkgconfig_FILE --libs "$PKG_NAME") + setVar "LIB_${LIB}_VERSION" "$TEMP_VERSION" + setVar "LIB_${LIB}_CFLAGS" "$TEMP_CFLAGS" + setVar "LIB_${LIB}_LDFLAGS" "$TEMP_LDFLAGS" + return 2 # Force testing using the new CFLAGS and LDFLAGS + #return 0 + else + return 2 + fi +} + + +# Description: substitute variables in files. +# Every supplied variable name found between @'s in the +# supplied files, is replaced by its value. +# Arguments: $1 - The name of the variable which contains a list of +# variables to substitute in the files. +# $2 - The name of the variable which contains a list of +# files to substitute variables in. +# If a filename ends on .in, that filename is used as +# source, and the filename without .in as target. +# If a filename doesn't end on .in, that filename is used +# as target, and the filename with .in attached as source. +# $3 - A path to which the input file names are relative +# $4 - A path to which the output file names are relative +substitute_vars() { + local VARS VAR VALUE FILES FILE SRC_PATH DST_PATH + + eval VARS=\"\$$1\" + eval FILES=\"\$$2\" + SRC_PATH="$3" + DST_PATH="$4" + + for VAR in $VARS; do + # Escape all / in VAR so that we can use / as seperator char for sed + eval VALUE=\"\$$VAR\" + VALUE=$(echo "$VALUE" | $SED -e 's,\([\&/]\),\\\1,g') + cat << EOF +s/@${VAR}@/${VALUE}/g +EOF + done > "${TEMPFILE}.sed" + + for FILE in $FILES; do + FILE="${FILE%.in}" + cp -p -- "$SRC_PATH/$FILE".in "$DST_PATH/$FILE" + # The copy is done so that the file modes are equal. + $SED -f "${TEMPFILE}.sed" < "$SRC_PATH/$FILE".in > "$DST_PATH/$FILE" + done + deleteTempFiles "${TEMPFILE}.sed" +} + +# Define the build system type. +set_build_system() { + BUILD_SYSTEM=`uname -s` +} + +# Define the host system type. +set_host_system() { + local UHOST + + if [ -z "$BUILD_HOST" ]; then + HOST_SYSTEM=$BUILD_SYSTEM + else + case "$BUILD_HOST" in + *-*-*) + HOST_SYSTEM="${BUILD_HOST#*-}" + HOST_SYSTEM="${HOST_SYSTEM%-*}" + ;; + esac + + # Use a single capitalization. + # What is used is whatever 'uname -s' would give on such a platform. + case "$BUILD_HOST" in + [Ll][Ii][Nn][Uu][Xx]) + HOST_SYSTEM="Linux" ;; + [Ff][Rr][Ee][Ee][Bb][Ss][Dd]) + HOST_SYSTEM="FreeBSD" ;; + [Oo][Pp][Ee][Nn][Bb][Ss][Dd]) + HOST_SYSTEM="OpenBSD" ;; + [Mm][Ii][Nn][Gg][Ww]|[Mm][Ii][Nn][Gg][Ww]32) + HOST_SYSTEM="MINGW32" ;; + [Cc][Yy][Gg][Ww][Ii][Nn]*) + HOST_SYSTEM="CYGWIN" ;; + [Dd][Aa][Rr][Ww][Ii][Nn]) + HOST_SYSTEM="Darwin" ;; + [Ss][Uu][Nn][Oo][Ss]) + HOST_SYSTEM="SunOS" ;; + [Qq][Nn][Xx]) + HOST_SYSTEM="QNX" ;; + [Cc][Ee][Gg][Cc][Cc]) + HOST_SYSTEM="cegcc" ;; + [Ww][Ii][Nn][Ss][Cc][Ww]) + HOST_SYSTEM="WINSCW" ;; + [Aa][Rr][Mm][Vv]5) + HOST_SYSTEM="ARMV5" ;; + [Gg][Cc][Cc][Ee]) + HOST_SYSTEM="GCCE" ;; + *) + build_message "Warning: host type '$BUILD_HOST' unknown. Using defaults." + ;; + esac + fi + +} + +set_system() { + set_build_system + set_host_system +} + +prepare_build_system() { + # Include information about programs we can detect for the build system. + . build/unix/config_proginfo_build +} + +prepare_host_system() { + # Include information about programs we can detect for the host system. + . build/unix/config_proginfo_host +} + +# Some initialisations +HAVE_SYMBOLS="" + +config_requirements() { + # Requirements for the config program itself + have_program echon || exit 1 + ECHON="$PROG_echon_FILE" + have_program sed || exit 1 + SED="$PROG_sed_FILE" + have_program tr || exit 1 + TR="$PROG_tr_FILE" + have_program make || exit 1 + MAKE="$PROG_make_FILE" +} + |