#!/usr/bin/env bash
CONFIG="config.mk"
PREFIX="/usr/local"
DEBUG=
LIQSRCDIR=./lib
LIQCONFIGURE=(--quiet)
SSE=auto
OPENMP=
LIBPNG_DIR=.
LCMS2=auto
EXTRA_CFLAGS=
EXTRA_LDFLAGS=
# make gcc default compiler unless CC is already set
CC=${CC:-gcc}
SKIP_CC_CHECK=0
help() {
printf "%4s %s\n" "" "$1"
}
for i in "$@"; do
case $i in
--help|-h)
echo
help "--prefix=
installation directory [$PREFIX]"
help "--extra-cflags= append to CFLAGS"
help "--extra-ldflags= append to LDFLAGS"
echo
help "--enable-debug"
help "--enable-sse/--disable-sse enable/disable SSE instructions"
echo
help "--with-libimagequant= external libimagequant (lib/ default)"
help "--with-openmp=static compile with multicore support"
help "--with-lcms2/--without-lcms2 compile with color profile support"
if [[ "$OSTYPE" =~ "darwin" ]]; then
help "--with-cocoa/--without-cocoa use Cocoa framework to read images"
fi
help "--with-libpng= search for libpng in directory"
echo
help "CC= use given compiler command"
help "CFLAGS= pass options to the compiler"
help "LDFLAGS= pass options to the linker"
echo
exit 0
;;
# Can be set before or after configure. Latter overrides former.
CC=*)
CC=${i#*=}
SKIP_CC_CHECK=1
LIQCONFIGURE+=("$i")
;;
CFLAGS=*)
CFLAGS=${i#*=}
LIQCONFIGURE+=("$i")
;;
LDFLAGS=*)
LDFLAGS=${i#*=}
LIQCONFIGURE+=("$i")
;;
--enable-debug)
DEBUG=1
LIQCONFIGURE+=("$i")
;;
--enable-sse)
SSE=1
LIQCONFIGURE+=("$i")
;;
--disable-sse)
SSE=0
LIQCONFIGURE+=("$i")
;;
--with-openmp)
OPENMP=1
LIQCONFIGURE+=("$i")
;;
--with-openmp=static)
OPENMP=static
LIQCONFIGURE+=("$i")
;;
--with-lcms2)
LCMS2=1
;;
--without-lcms2)
LCMS2=0
;;
--with-cocoa)
LCMS2=auto
;;
--without-cocoa)
LCMS2=auto
;;
--with-libpng=*)
LIBPNG_DIR=${i#*=}
;;
--with-libimagequant=*)
LIQSRCDIR=${i#*=}
;;
--with-libimagequant)
LIQSRCDIR=""
;;
--prefix=*)
PREFIX=${i#*=}
LIQCONFIGURE+=("$i")
;;
# can be used multiple times or in quotes to set multiple flags
--extra-cflags=*)
EXTRA_CFLAGS="$EXTRA_CFLAGS ${i#*=}"
LIQCONFIGURE+=("$i")
;;
--extra-ldflags=*)
EXTRA_LDFLAGS="$EXTRA_LDFLAGS ${i#*=}"
LIQCONFIGURE+=("$i")
;;
*)
echo "warning: unknown switch ${i%%=*} (see $0 --help for the list)"
;;
esac
done
# If someone runs sudo make install as very first command, and configure later,
# $CONFIG cannot be overwritten, and must be deleted before continuing.
if [[ -f "$CONFIG" && ! -w "$CONFIG" ]]; then
echo "Cannot overwrite file $CONFIG! Please delete it."
exit 1
fi
cflags() {
CFLAGS="$CFLAGS $1"
}
lflags() {
LDFLAGS="$LDFLAGS $1"
}
status() {
printf "%10s: %s\n" "$1" "$2"
}
# Append to CFLAGS if compiler supports flag, with optional prerequisite.
# Fails on errors and warnings.
conditional_cflags() {
if [ -z "$(echo | "$CC" -xc -S -o /dev/null $2 $1 - 2>&1)" ]; then
cflags "$1"
fi
}
# returns first matching file in directory
find_f() {
echo $(find "$1" -not -path '*/.git/*' -not -type d -name "$2" -print -quit 2> /dev/null)
}
# returns first matching file in directory (no symlinks)
find_h() {
echo $(find "$1" -not -path '*/.*/*' -type f -name "$2" -print -quit 2> /dev/null)
}
find_pkgconfig() {
local LIBNAME=$1
PKG_CONFIG=${PKG_CONFIG:-pkg-config}
if $PKG_CONFIG --exists "$LIBNAME" &> /dev/null; then
cflags "$($PKG_CONFIG --cflags "$LIBNAME")"
lflags "$($PKG_CONFIG --libs "$LIBNAME")"
LIBRARY_FOUND_VERSION=$($PKG_CONFIG --modversion "$LIBNAME")
status "$LIBNAME" "shared ($LIBRARY_FOUND_VERSION)"
return 0
fi
return 1
}
find_static() {
local LIBNAME=$1
local HEADERPATTERN=$2
local STATICPATTERN=$3
local HPATH=$(find_h . "$HEADERPATTERN")
if [ -n "$HPATH" ]; then
local APATH=$(find_f . "$STATICPATTERN")
if [ -n "$APATH" ]; then
LIBRARY_FOUND_HEADER=$HPATH
cflags "-I${HPATH%/*}"
lflags "${APATH}"
status "$LIBNAME" "static ($APATH)"
return 0
fi
fi
return 1
}
find_dynamic() {
local LIBNAME=$1
local HEADERPATTERN=$2
local DYNAMICPATTERN=$3
local HEADERDIR=$4
local LIBDIR=$5
local HPATH=$(find_h "$HEADERDIR" "$HEADERPATTERN")
if [ -n "$HPATH" ]; then
local SOPATH=$(find_f "$LIBDIR" "$DYNAMICPATTERN")
if [ -n "$SOPATH" ]; then
LIBRARY_FOUND_HEADER=$HPATH
cflags "-I${HPATH%/*}"
lflags "-L${SOPATH%/*} -l$DYNAMICLIBNAME"
status "$LIBNAME" "shared ... $SOPATH"
return 0
fi
fi
return 1
}
find_library() {
local LIBNAME=$1
local DYNAMICLIBNAME=$2
local HEADERPATTERN=$3
local STATICPATTERN=$4
local DYNAMICPATTERN=$5
# other functions will overwrite it
LIBRARY_FOUND_HEADER=
LIBRARY_FOUND_VERSION=
LIBRARY_FOUND_BUILD=
if [ "imagequant" = "$LIBNAME" -a -n "$LIQSRCDIR" -a -f "$LIQSRCDIR"/"$HEADERPATTERN" ]; then
status "$LIBNAME" "build static"
cflags "-I$LIQSRCDIR"
lflags "$LIQSRCDIR/libimagequant.a"
LIBRARY_FOUND_HEADER="$LIQSRCDIR"/"$HEADERPATTERN"
LIBRARY_FOUND_BUILD="$LIQSRCDIR"
return 0;
fi
# try static in current directory first
if find_static "$LIBNAME" "$HEADERPATTERN" "$STATICPATTERN"; then
return 0;
fi
# try shared
if find_pkgconfig "$LIBNAME"; then
return 0
fi
for i in "${DIRS[@]}"; do
DIR=($i)
if find_dynamic "$LIBNAME" "$HEADERPATTERN" "$DYNAMICPATTERN" "${DIR[0]}" "${DIR[1]}"; then
return 0
fi
done
return 1
}
# returns full png.h version string
pngh_string() {
echo "$(grep -m1 "define PNG_LIBPNG_VER_STRING" "$1" | \
grep -Eo '"[^"]+"' | grep -Eo '[^"]+')"
}
# returns major minor version numbers from png.h
pngh_majmin() {
local MAJ=$(grep -m1 "define PNG_LIBPNG_VER_MAJOR" "$1" | grep -Eo "[0-9]+")
local MIN=$(grep -m1 "define PNG_LIBPNG_VER_MINOR" "$1" | grep -Eo "[0-9]+")
echo "${MAJ}${MIN}"
}
error() {
status "$1" "error ... $2"
echo
exit 1
}
echo
# /tmp, because mingw has problems opening /dev/null and gives false negative
if ! echo "int main(){}" | "$CC" -xc -std=c99 -o pngquant-gcccheck - > /dev/null; then
rm -f pngquant-gcccheck
if [ "$SKIP_CC_CHECK" -eq 1 ]; then
status "Compiler" "$CC failed to compile anything (make sure it's installed and supports C99)"
else
error "Compiler" "$CC failed to compile anything (make sure it's installed and supports C99)"
fi
fi
rm -f pngquant-gcccheck
status "Compiler" "$CC"
# init flags
CFLAGS=${CFLAGS:--fno-math-errno -funroll-loops -fomit-frame-pointer -Wall}
cflags "-std=c99 -I."
# DEBUG
if [ -z "$DEBUG" ]; then
cflags "-O3 -DNDEBUG"
status "Debug" "no"
else
cflags "-O1 -g"
status "Debug" "yes"
fi
# SSE
if [ "$SSE" = 'auto' ]; then
SSE=0
if type uname > /dev/null; then
if [[ "$(uname -m)" =~ "amd64" || "$(uname -m)" =~ "x86_64" ||
"$(grep -E -m1 "^flags" /proc/cpuinfo)" =~ "sse" ]]; then
SSE=1
fi
fi
fi
if [ "$SSE" -eq 1 ]; then
status "SSE" "yes"
cflags "-DUSE_SSE=1"
cflags "-msse"
# Silence a later ICC warning due to -msse working slightly different.
conditional_cflags "-wd10121"
# Must be set explicitly for GCC on x86_32. Other compilers imply it.
conditional_cflags "-mfpmath=sse" "-msse"
elif [ "$SSE" -eq 0 ]; then
status "SSE" "no"
cflags "-DUSE_SSE=0"
fi
# OpenMP
if [ -n "$OPENMP" ]; then
if [ "static" = "$OPENMP" ]; then
OPENMPFLAGS="-static-libgcc -Bstatic -fopenmp -Bdynamic"
else
OPENMPFLAGS="-fopenmp"
fi
if [[ "$("$CC" -xc -E $OPENMPFLAGS <(echo "#ifdef _OPENMP
#include
#endif") 2>&1)" =~ "omp_get_thread_num" ]]; then
cflags "$OPENMPFLAGS"
lflags "$OPENMPFLAGS"
status "OpenMP" "yes"
else
error "OpenMP" "not supported by compiler (please install a compiler that supports OpenMP (e.g. gcc) and specify it with the CC= argument)"
fi
else
# silence warnings about omp pragmas
cflags "-Wno-unknown-pragmas"
conditional_cflags "-wd3180" # ICC
status "OpenMP" "no"
fi
# Cocoa
if [[ "$OSTYPE" =~ "darwin" ]]; then
cflags "-mmacosx-version-min=10.7"
lflags "-mmacosx-version-min=10.7"
fi
# pairs of possible *.h and lib*.so locations
DIRS=()
if command -v >/dev/null libpng-config; then
DIRS+=("$(libpng-config --prefix) $(libpng-config --libdir)")
fi
if [ -n $"LIQSRCDIR" ]; then
DIRS+=("$LIQSRCDIR" "$LIQSRCDIR") # local libimagequant
fi
DIRS+=(
"/usr/local/include /usr/local/lib"
"/usr/include /usr/lib64"
"/usr/include /usr/lib"
"/opt/local/include /opt/local/lib" # macports
)
if [[ "$OSTYPE" =~ "darwin" ]]; then
SOLIBSUFFIX=dylib
# Search Developer SDK paths, since Apple seems to have dropped the standard Unixy ones
XCODE_CMD="xcode-select"
XCODE_PATH=$($XCODE_CMD -p)
DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib")
DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/lib")
elif [[ "$OSTYPE" =~ "msys" ]]; then
SOLIBSUFFIX=dll
else
SOLIBSUFFIX=so
fi
# libimagequant
if [ "./lib" = "$LIQSRCDIR" -a -d ".git" -a ! -f "lib/Cargo.toml" ]; then
git submodule init && git submodule update;
fi
if find_library "imagequant" "imagequant" "libimagequant.h" "libimagequant.a" "libimagequant.$SOLIBSUFFIX*"; then
if [ -n "$LIBRARY_FOUND_VERSION" ]; then
VERSION=$LIBRARY_FOUND_VERSION
elif [ -n "$LIBRARY_FOUND_HEADER" ]; then
VERSION=$(grep LIQ_VERSION_STRING "$LIBRARY_FOUND_HEADER" | grep -Eo "2\.[0-9.]+")
else
VERSION=unknown
fi
if [ -n "$LIBRARY_FOUND_BUILD" ]; then
STATICLIBDEPS="$LIBRARY_FOUND_BUILD/libimagequant.h $LIBRARY_FOUND_BUILD/libimagequant.a"
LIQSRCDIR="$LIBRARY_FOUND_BUILD"
fi
else
if [ -n "$LIQSRCDIR" -a ! -f "$LIQSRCDIR"/libimagequant.h ]; then
echo "If you're using git, do clone with --recursive, or download from https://github.com/ImageOptim/libimagequant"
error "imagequant" "libimagequant.h not found in $LIQSRCDIR/"
else
error "imagequant" "not found. Get it from https://github.com/ImageOptim/libimagequant and build it in ./lib/"
fi
fi
# libpng
# try if given flags are enough
HAS_LIBPNG=0
if echo "#include \"png.h\"
int main(){
return !png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
}" | "$CC" -xc -std=c99 -o /dev/null $CFLAGS $LDFLAGS - &> /dev/null; then
status "libpng" "custom flags"
HAS_LIBPNG=1
fi
if [ "$HAS_LIBPNG" -eq 0 ]; then
# try static in the given directory
PNGH=$(find_h "$LIBPNG_DIR" "png.h")
if [ -n "$PNGH" ]; then
PNGH_STRING=$(pngh_string "$PNGH")
PNGH_MAJMIN=$(pngh_majmin "$PNGH")
if [[ -n "$PNGH_STRING" && -n "$PNGH_MAJMIN" ]]; then
LIBPNGA=$(find_f "$LIBPNG_DIR" "libpng${PNGH_MAJMIN}.a")
if [ -z "$LIBPNGA" ]; then
LIBPNGA=$(find_f "$LIBPNG_DIR" "libpng.a")
fi
if [ -n "$LIBPNGA" ]; then
cflags "-I${PNGH%/*}"
lflags "${LIBPNGA}"
status "libpng" "static (${PNGH_STRING})"
HAS_LIBPNG=1
fi
fi
fi
fi
# try shared
if [ "$HAS_LIBPNG" -eq 0 ]; then
if find_pkgconfig libpng; then
HAS_LIBPNG=1
else
for i in "${DIRS[@]}"; do
DIR=($i)
PNGH=$(find_h "${DIR[0]}" "png.h")
if [ -n "$PNGH" ]; then
PNGH_STRING=$(pngh_string "$PNGH")
PNGH_MAJMIN=$(pngh_majmin "$PNGH")
if [[ -n "$PNGH_STRING" && -n "$PNGH_MAJMIN" ]]; then
LIBPNGSO=$(find_f "${DIR[1]}" "libpng${PNGH_MAJMIN}.$SOLIBSUFFIX*")
if [ -n "$LIBPNGSO" ]; then
cflags "-I${PNGH%/*}"
lflags "-L${LIBPNGSO%/*} -lpng${PNGH_MAJMIN}"
status "libpng" "shared (${PNGH_STRING})"
HAS_LIBPNG=1
break
fi
fi
fi
done
fi
fi
if [ "$HAS_LIBPNG" -eq 0 ]; then
if [[ "$OSTYPE" =~ "darwin" ]]; then
LIBPNG_CMD='`brew install libpng`'
else
LIBPNG_CMD='`apt-get install libpng16-dev` or `apt-get install libpng-dev` or `yum install libpng-devel`'
fi
error "libpng" "not found (try: $LIBPNG_CMD)"
fi
# zlib
if ! find_library "zlib" "z" "zlib.h" "libz.a" "libz.$SOLIBSUFFIX*"; then
error "zlib" "not found (please install zlib-devel package)"
fi
# lcms2
if [ "$LCMS2" != 0 ]; then
if find_library "lcms2" "lcms2" "lcms2.h" "liblcms2.a" "liblcms2.$SOLIBSUFFIX*"; then
cflags "-DUSE_LCMS=1"
else
if [ "$LCMS2" = 'auto' ]; then
status "lcms2" "no"
else
error "lcms2" "not found (please install libcms2-devel package)"
fi
fi
else
status "lcms2" "no"
fi
echo
# As of GCC 4.5, 387 fp math is significantly slower in C99 mode without this.
# Note: CPUs without SSE2 use 387 for doubles, even when SSE fp math is set.
conditional_cflags "-fexcess-precision=fast"
# Intel C++ Compiler
# ICC does usually only produce fast(er) code when it can optimize to the full
# capabilites of the (Intel) CPU. This is equivalent to -march=native for GCC.
conditional_cflags "-xHOST"
# Disable unsafe fp optimizations and enforce fp precision as set in the source.
conditional_cflags "-fp-model source"
# Silence a gold linker warning about string misalignment.
conditional_cflags "-falign-stack=maintain-16-byte"
lflags "-lm" # Ubuntu requires this library last, issue #38
if [ -n "$EXTRA_CFLAGS" ]; then
cflags "$EXTRA_CFLAGS"
fi
if [ -n "$EXTRA_LDFLAGS" ]; then
lflags "$EXTRA_LDFLAGS"
fi
# Overwrite previous configuration.
echo "
# auto-generated by configure
PREFIX = $PREFIX
VERSION = $VERSION
CC = $CC
CFLAGS = $CFLAGS
LDFLAGS = $LDFLAGS
SOLIBSUFFIX = $SOLIBSUFFIX
STATICLIBDEPS = $STATICLIBDEPS
LIQSRCDIR = $LIQSRCDIR
LIQCONFIGUREFLAGS = $(printf "'%s' " "${LIQCONFIGURE[@]}")
" > "$CONFIG"