Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure: Enable FULLY static builds #368

Open
bdkjones opened this issue Nov 21, 2020 · 12 comments
Open

Configure: Enable FULLY static builds #368

bdkjones opened this issue Nov 21, 2020 · 12 comments

Comments

@bdkjones
Copy link
Contributor

The INSTALL documentation lists a procedure for ensuring that pngquant statically links to libpng (put the source for libpng as subfolder of pngquant's source, configure it with the static flag, then make it.)

However, zlib is still linked dynamically, no matter what the hell I try to do to change that. It would be very handy to have baked-in support for statically linking zlib as well.

I tried this, but had no luck: https://stackoverflow.com/questions/35582138/compile-a-static-version-of-pngquant

@bdkjones
Copy link
Contributor Author

Ok, finally noticed that the patch at the SO link above used zlib.a instead of libz.a, which is why it failed. Here is the new, patched Configure file.

To ensure a fully static build, you need only follow the existing directions in INSTALL: download libpng and libz. Build each project, then drop their source folders inside pngquant's source folder. Run ./configure on pngQuant and you'll see both libraries are now linked statically.

#!/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=<dir>                installation directory [$PREFIX]"
        help "--extra-cflags=<flags>        append to CFLAGS"
        help "--extra-ldflags=<flags>       append to LDFLAGS"
        echo
        help "--enable-debug"
        help "--enable-sse/--disable-sse    enable/disable SSE instructions"
        echo
        help "--with-libimagequant=<dir>    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=<dir>           search for libpng in directory"
        help "--with-zlib=<dir>             search for zlib in directory"
        echo
        help "CC=<compiler>                 use given compiler command"
        help "CFLAGS=<flags>                pass options to the compiler"
        help "LDFLAGS=<flags>               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=""
        ;;
    --with-zlib=*)
        ZLIB_DIR=${i#*=}
        ;;
    --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
    if ! type "$PKG_CONFIG" &> /dev/null; then
        echo "warning: pkg-config is not installed, can't search for libraries. Please install pkg-config."
    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}"
}

# returns full zlib.h version string
zlibh_string() {
    echo "$(grep -m1 "define ZLIB_VERSION" "$1" | \
            grep -Eo '"[^"]+"' | grep -Eo '[^"]+')"
}

# returns major minor version numbers from png.h
zlibh_majmin() {
    local MAJ=$(grep -m1 "define ZLIB_VER_MAJOR" "$1" | grep -Eo "[0-9]+")
    local MIN=$(grep -m1 "define ZLIB_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 -DDEBUG"
    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 <omp.h>
           #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

# try if given flags are enough for zlib
HAS_ZLIB=0
if echo "#include \"zlib.h\"
    int main(){
    uLong test = zlibCompileFlags();
    return 0;
}" | "$CC" -xc -std=c99 -o /dev/null $CFLAGS $LDFLAGS - &> /dev/null; then
    status "zlib" "custom flags"
    HAS_ZLIB=1
fi

if [ "$HAS_ZLIB" -eq 0 ]; then
    # try static in the given directory
    ZLIBH=$(find_h "$ZLIB_DIR" "zlib.h")
    if [ -n "$ZLIBH" ]; then
        ZLIBH_STRING=$(zlibh_string "$ZLIBH")
        ZLIBH_MAJMIN=$(zlibh_majmin "$ZLIBH")
        if [[ -n "$ZLIBH_STRING" && -n "$ZLIBH_MAJMIN" ]]; then
            ZLIBA=$(find_f "$ZLIB_DIR" "libz${ZLIBH_MAJMIN}.a")
            if [ -z "$ZLIBA" ]; then
                ZLIBA=$(find_f "$ZLIB_DIR" "libz.a")
            fi
            if [ -n "$ZLIBA" ]; then
                cflags "-I${ZLIBH%/*}"
                lflags "${ZLIBA}"
                status "zlib" "static (${ZLIBH_STRING})"
                HAS_ZLIB=1
            fi
        fi
    fi
fi
# zlib
if ! find_library "zlib" "z" "zlib.h" "libz.a" "zlib.$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"

@kornelski
Copy link
Owner

Ugh, zlib vs libz name seems to vary between platforms.

@kornelski
Copy link
Owner

Does 9d8f968 work for you?

@bdkjones
Copy link
Contributor Author

bdkjones commented Nov 21, 2020 via email

@kornelski
Copy link
Owner

It searches for libz.* first, and then searches for zlib.*

@dpanic
Copy link

dpanic commented May 10, 2023

I just tested on 2.x branch. All works out of the box.

Steps:

  • Download and place into root of pngquant src dir
    • libpng
    • zlib
    • lcms2
  • Statically compile libpng, zlib and lcms2
  • Configure and build pngquant

End result:
image

Which is good for me!

@kornelski
Copy link
Owner

The latest version on the main branch:

cargo build --release --features=lcms2-static,png-static,z-static

or 100% static:

rustup target add x86_64-unknown-linux-musl
# install musl build utils if needed
cargo build --release --features=lcms2-static,png-static,z-static --target=x86_64-unknown-linux-musl

@dpanic
Copy link

dpanic commented May 10, 2023

The latest version on the main branch:

cargo build --release --features=lcms2-static,png-static,z-static

or 100% static:

rustup target add x86_64-unknown-linux-musl
# install musl build utils if needed
cargo build --release --features=lcms2-static,png-static,z-static --target=x86_64-unknown-linux-musl

Amazing. Thank you!

Will this work for target Darwin and Windows as well?

And is latest 3.x stable enough for usage? I saw on your website that stable is 2.x branch.

@kornelski
Copy link
Owner

kornelski commented May 10, 2023

MUSL target is specifically for the Linux kernel only. Darwin does not support 100% static executables — you're required to use libSystem. I don't know what Windows supports in theory, but in practice Rust just has msvc and gnu targets that require some runtime libraries. In all cases you can have static 3rd party deps like zlib/png/lcms2.

@kornelski
Copy link
Owner

I've updated the site. The current status is:

  • libimagequant 4.x in Rust is now stable production ready. Use it if you can. The 2.x C version is in maintenance mode and isn't getting new features.

  • pngquant v3 is a combination of 2.x CLI executable and 4.x Rust library. It's technically fine and stable, but it's a bit of a Frankenstein multi-language executable. I suspect it's annoying to package in distros, so I'm not pushing for it.

  • pngquant v4, a pure-Rust rewrite from scratch is a work in progress. There's a branch for it, but it's not feature-complete.

@dpanic
Copy link

dpanic commented May 10, 2023

MUSL target is specifically for the Linux kernel only. Darwin does not support 100% static executables — you're required to use libSystem. I don't know what Windows supports in theory, but in practice Rust just has msvc and gnu targets that require some runtime libraries. In all cases you can have static 3rd party deps like zlib/png/lcms2.

Thank you for clarification!

@dpanic
Copy link

dpanic commented May 10, 2023

I've updated the site. The current status is:

  • libimagequant 4.x in Rust is now stable production ready. Use it if you can. The 2.x C version is in maintenance mode and isn't getting new features.
  • pngquant v3 is a combination of 2.x CLI executable and 4.x Rust library. It's technically fine and stable, but it's a bit of a Frankenstein multi-language executable. I suspect it's annoying to package in distros, so I'm not pushing for it.
  • pngquant v4, a pure-Rust rewrite from scratch is a work in progress. There's a branch for it, but it's not feature-complete.

I am waiting for v4 than. I am using statically built for Linux v2. And v2 for Windows and MacOS which I downloaded from your website. I am developing desktop app which is multi OS, and it's written in Go Lang.

I know that it would be better to create Go Lang bindings for libpngquant, but I don't have time now for that. I am willing to pay "price" for fork-exec :-)

6t8k added a commit to 6t8k/nixpkgs that referenced this issue Nov 16, 2023
https://github.com/kornelski/pngquant/blob/3.0.3/CHANGELOG

Since 3.0.0, pngquant uses libimagequant 4.x, which is a Rust rewrite,
and and switches the build system from make to Cargo. The `pngquant`
executable is now a Rust wrapper around `pngquant.c`, which in turn
interfaces with libimagequant via the `imagequant_sys` crate, which
exports a C API.[1] The CLI seems unchanged.

Upstream lacks a Cargo.lock[2], so I generated one and patched it in.

Set `doCheck = false;` as there are no Rust-based tests. `test/` was
previously part of the make-based workflow (which is gone with pngquant
3.x) and looks like it isn't meant for pngquant 3.x anyway (as `test.sh`
executes `$BIN --version 2>&1 | fgrep 2.`).

`$ nix build .#pkgsCross.raspberryPi.pngquant` succeeds[3]; remove the
workaround originally introduced in [4].

Notes on dependencies:

- While nixpkgs package libimagequant on its own, pngquant depends on a
  specific vendored version

- pngquant 3.x depends on the libpng-sys and lcms2-sys crates, which
  provide bindings to the respective C libraries. If those are not
  provided by the system at build time, vendored versions of them will
  be built and statically linked; libpng 1.6.37 and LCMS 2.15,
  respectively

[1] See also: kornelski/pngquant#368 (comment)
[2] See also: kornelski/pngquant#347
[3] New SSE flag decision logic: https://github.com/kornelski/pngquant/blob/3.0.3/rust/build.rs#L31
[4] NixOS#145672
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants