1140 lines
30 KiB
Plaintext
1140 lines
30 KiB
Plaintext
# 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"
|
|
}
|
|
|