Skip to content

Link failures in OpenColorIO (MXE) due to unresolved bcrypt and ZSTD symbols from minizip-ng static build #2284

@hkunz

Description

@hkunz

When building OpenColorIO (2.5.1 / master) with MXE (x86_64-w64-mingw32.static), the link step fails due to unresolved references coming from libminizip.a, specifically BCrypt* (WinCNG crypto API) and ZSTD_* (zstd compression). This occurs when minizip-ng is built with Windows crypto and ZSTD support enabled, but its static library configuration does not properly link or propagate required system and third-party dependencies (bcrypt, crypt32, zstd) through its exported CMake targets. Looks like an OpenColorIO build issue.

I have verified that minizip-ng was built correctly using this MXE package

# This file is part of MXE. See LICENSE.md for licensing information.

include src/common/pkgutils.mk

PKG             := minizip-ng
$(PKG)_WEBSITE  := https://github.com/zlib-ng/minizip-ng.git
$(PKG)_DESCR    := Modern fork of minizip providing ZIP archive handling with support for multiple compression backends zlib, bzip2, lzma, zstd
$(PKG)_VERSION  := 4.1.0
$(PKG)_IGNORE   :=
$(PKG)_CHECKSUM := 85417229bb0cd56403e811c316150eea1a3643346d9cec7512ddb7ea291b06f2
$(PKG)_GH_CONF  := zlib-ng/minizip-ng/tags
$(PKG)_DEPS     := cc bzip2 libiconv lzma openssl pkgconf zlib zstd


define $(PKG)_BUILD

	# configure package with cmake
	cd "$(BUILD_DIR)" && "$(TARGET)-cmake" "$(SOURCE_DIR)" \
		-DCMAKE_INSTALL_PREFIX="$(PREFIX)/$(TARGET)" \
		-DCMAKE_PREFIX_PATH="$(PREFIX)/$(TARGET)" \
		-DBUILD_SHARED_LIBS=$(CMAKE_SHARED_BOOL) \
		-DMZ_BUILD_FUZZ_TESTS=OFF \
		-DMZ_BUILD_TESTS=OFF \
		-DMZ_BUILD_UNIT_TESTS=OFF \
		-DMZ_BZIP2=ON \
		-DMZ_CODE_COVERAGE=OFF \
		-DMZ_COMPAT=ON \
		-DMZ_COMPRESS_ONLY=OFF \
		-DMZ_DECOMPRESS_ONLY=OFF \
		-DMZ_FETCH_LIBS=OFF \
		-DMZ_FILE32_API=OFF \
		-DMZ_FORCE_FETCH_LIBS=OFF \
		-DMZ_ICONV=ON \
		-DMZ_LIBBSD=ON \
		-DMZ_LZMA=ON \
		-DMZ_OPENSSL=ON \
		-DMZ_PKCRYPT=ON \
		-DMZ_WZAES=ON \
		-DMZ_ZLIB=ON \
		-DMZ_ZSTD=ON \
		-DCMAKE_BUILD_TYPE=Release

	# build package and install
	$(MAKE) -C "$(BUILD_DIR)" -j $(JOBS)
	$(MAKE) -C "$(BUILD_DIR)" -j 1 install

	# Override minizip.pc because Windows crypto backend (bcrypt) is not exported even though it is required when crypto features are enabled
	$(call GENERATE_PC, \
		$(PREFIX)/$(TARGET), \
		$(PKG), \
		$($(PKG)_DESCR), \
		$($(PKG)_VERSION), \
		, \
		, \
		-lminizip, \
		-lz -lbz2 -llzma -lzstd -lbcrypt, \
		$(PREFIX)/$(TARGET)/include, \
		, \
	)

	# compile a test program to verify the library is usable
	"$(TARGET)-g++" -Wall -Wextra "$(TEST_FILE)" \
		-o "$(PREFIX)/$(TARGET)/bin/test-$(PKG).exe" \
		`"$(TARGET)-pkg-config" "$(PKG)" --cflags --libs`
endef

and thoroughly tested it to work perfectly correctly:

minizip-ng-test.cpp

/*
    Minimal test program for MXE minizip-ng build

    This tests whether libminizip.a is correctly linked
    and whether optional dependencies (bcrypt, lzma, zstd, bzip2)
    are required at link time.

    This test verifies:
    - ZIP archive creation (write support)
    - ZLIB compression backend (-lz)
    - Optional encrypted ZIP entries (crypto backend, e.g. BCrypt/OpenSSL)
    - ZIP archive reading (unzip functionality)
    - File listing and metadata access
    - End-to-end data integrity (write → compress → read → decompress)

    Compile with MXE:

    ./usr/bin/x86_64-w64-mingw32.static-g++ \
        src/minizip-ng-test.cpp \
        -I usr/x86_64-w64-mingw32.static/include \
        -L usr/x86_64-w64-mingw32.static/lib \
        -lminizip \
        -lz \
        -lbz2 \
        -llzma \
        -lzstd \
        -lbcrypt \
        -o usr/x86_64-w64-mingw32.static/bin/test-minizip-ng.exe
*/

#include <cstdio>
#include <cstring>
#include <vector>

#include <minizip/zip.h>
#include <minizip/unzip.h>

static void write_file(zipFile zf,
                       const char* name,
                       const char* content,
                       const char* password = nullptr)
{
    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    int err = zipOpenNewFileInZip3_64(
        zf,
        name,
        &zi,
        nullptr, 0,
        nullptr, 0,
        nullptr,
        Z_DEFLATED,
        Z_DEFAULT_COMPRESSION,
        0,
        -MAX_WBITS,
        DEF_MEM_LEVEL,
        Z_DEFAULT_STRATEGY,
        password,
        0,
        0
    );

    if (err != ZIP_OK) {
        printf("FAIL: write %s\n", name);
        return;
    }

    zipWriteInFileInZip(zf, content, (unsigned int)strlen(content));
    zipCloseFileInZip(zf);

    printf("OK: wrote %s\n", name);
}

static void read_zip(const char* zipname)
{
    unzFile uf = unzOpen(zipname);
    if (!uf) {
        printf("FAIL: unzip open\n");
        return;
    }

    if (unzGoToFirstFile(uf) != UNZ_OK) {
        printf("FAIL: go first file\n");
        unzClose(uf);
        return;
    }

    do {
        char fname[256];
        unz_file_info info;
        memset(&info, 0, sizeof(info));

        if (unzGetCurrentFileInfo(
                uf,
                &info,
                fname,
                sizeof(fname),
                nullptr, 0,
                nullptr, 0) != UNZ_OK)
        {
            printf("FAIL: get file info\n");
            break;
        }

        printf("READ FILE: %s\n", fname);

        int err;

        // IMPORTANT: handle encrypted file properly
        if (strcmp(fname, "encrypted.txt") == 0)
        {
            err = unzOpenCurrentFilePassword(uf, "password123");
        }
        else
        {
            err = unzOpenCurrentFile(uf);
        }

        if (err != UNZ_OK) {
            printf("FAIL: open file %s\n", fname);
            break;
        }

        std::vector<char> buf(info.uncompressed_size + 1);
        int r = unzReadCurrentFile(uf, buf.data(), (unsigned int)buf.size());

        if (r < 0) {
            printf("FAIL: read file\n");
            unzCloseCurrentFile(uf);
            break;
        }

        buf[r] = '\0';

        printf("CONTENT: %s\n", buf.data());

        unzCloseCurrentFile(uf);

    } while (unzGoToNextFile(uf) == UNZ_OK);

    unzClose(uf);
}

int main()
{
    printf("=== MXE minizip-ng FULL VALIDATION TEST ===\n");

    const char* zipname = "test.zip";

    zipFile zf = zipOpen(zipname, 0);
    if (!zf) {
        printf("FAIL: zipOpen\n");
        return 1;
    }

    // -------------------------
    // Normal file (zlib)
    // -------------------------
    write_file(
        zf,
        "zlib.txt",
        "hello from zlib compression"
    );

    // -------------------------
    // Encrypted file (bcrypt path if enabled)
    // -------------------------
    write_file(
        zf,
        "encrypted.txt",
        "secret data inside zip",
        "password123"
    );

    zipClose(zf, nullptr);

    printf("\n=== ZIP CREATED ===\n\n");

    // -------------------------
    // READ BACK
    // -------------------------
    read_zip(zipname);

    printf("\n=== TEST COMPLETE ===\n");
    return 0;
}

Result:

And here's the test result. So I'm fairly confident that this is not a minizip-ng issue anymore but rather an OpenColorIO issue.

.\test-minizip-ng.exe
=== MXE minizip-ng FULL VALIDATION TEST ===
OK: wrote zlib.txt
OK: wrote encrypted.txt

=== ZIP CREATED ===

READ FILE: zlib.txt
CONTENT: hello from zlib compression
READ FILE: encrypted.txt
CONTENT: secret data inside zip

=== TEST COMPLETE ===

But the opencolorio.mk package keeps failing:

# This file is part of MXE. See LICENSE.md for licensing information.

PKG             := opencolorio
$(PKG)_WEBSITE  := https://github.com/AcademySoftwareFoundation/OpenColorIO.git
$(PKG)_DESCR    := A color management framework for visual effects and animation.
$(PKG)_VERSION  := 2.5.1
$(PKG)_IGNORE   :=
$(PKG)_CHECKSUM := 08cb6213ea4edee550ab050509d38204004bee6742c658166b1cf825d0a9381b
$(PKG)_GH_CONF  := AcademySoftwareFoundation/OpenColorIO/tags,v
$(PKG)_DEPS     := cc imath minizip-ng pkgconf expat yaml-cpp bzip2 lzma zstd

define $(PKG)_BUILD

	# apply local patch for bug https://github.com/AcademySoftwareFoundation/OpenColorIO/issues/2283
	FILE="$(SOURCE_DIR)/src/OpenColorIO/transforms/FileTransform.cpp"; \
	$(SED) 's/Platform::filenameToUTF(filepath), mode/Platform::filenameToUTF(filepath).c_str(), mode/g' \
		$$FILE \
		> $$FILE.patched; \
	mv $$FILE.patched $$FILE

	# configure package with cmake
	cd "$(BUILD_DIR)" && "$(TARGET)-cmake" "$(SOURCE_DIR)" \
		-DCMAKE_INSTALL_PREFIX="$(PREFIX)/$(TARGET)" \
		-DCMAKE_PREFIX_PATH="$(PREFIX)/$(TARGET)" \
		-DBUILD_SHARED_LIBS=$(CMAKE_SHARED_BOOL) \
		-DBUILD_TESTING=ON \
		-DOCIO_BUILD_APPS=ON \
		-DOCIO_BUILD_DOCS=OFF \
		-DOCIO_BUILD_GPU_TESTS=ON \
		-DOCIO_BUILD_JAVA=OFF \
		-DOCIO_BUILD_NUKE=OFF \
		-DOCIO_BUILD_OPENFX=OFF \
		-DOCIO_BUILD_PYTHON=OFF \
		-DOCIO_BUILD_TESTS=ON \
		-DOCIO_ENABLE_SANITIZER=OFF \
		-DOCIO_USE_AVX2=ON \
		-DOCIO_USE_AVX512=ON \
		-DOCIO_USE_AVX=ON \
		-DOCIO_USE_F16C=ON \
		-DOCIO_USE_HEADLESS=OFF \
		-DOCIO_USE_OIIO_FOR_APPS=OFF \
		-DOCIO_USE_SIMD=ON \
		-DOCIO_USE_SOVERSION=ON \
		-DOCIO_USE_SSE2=ON \
		-DOCIO_USE_SSE3=ON \
		-DOCIO_USE_SSE42=ON \
		-DOCIO_USE_SSE4=ON \
		-DOCIO_USE_SSSE3=ON \
		-DOCIO_VERBOSE=OFF \
		-DOCIO_WARNING_AS_ERROR=OFF \
		-DCMAKE_BUILD_TYPE=Release

	# build package and install
	$(MAKE) -C "$(BUILD_DIR)" -j $(JOBS)
	$(MAKE) -C "$(BUILD_DIR)" -j 1 install

	# compile a test program to verify the library is usable
	"$(TARGET)-g++" -Wall -Wextra "$(TEST_FILE)" \
		-o "$(PREFIX)/$(TARGET)/bin/test-$(PKG).exe" \
		`"$(TARGET)-pkg-config" "OpenColorIO" --cflags --libs`
endef

Error:

[ 49%] ESC[32mESC[1mLinking CXX executable ociobakelut.exeESC[0m
make[4]: Leaving directory '/home/a/workspace/mxe.git/tmp-opencolorio-x86_64-w64-mingw32.static/OpenColorIO-2.5.1.build_'
make[4]: Entering directory '/home/a/workspace/mxe.git/tmp-opencolorio-x86_64-w64-mingw32.static/OpenColorIO-2.5.1.build_'
[ 49%] ESC[32mBuilding CXX object src/apps/ocioperf/CMakeFiles/ocioperf.dir/main.cpp.objESC[0m
[ 50%] ESC[32mESC[1mLinking CXX executable ociomakeclf.exeESC[0m
[ 50%] ESC[32mESC[1mLinking CXX executable ocioperf.exeESC[0m
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x169): undefined reference to `BZ2_bzDecompressInit'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x199): undefined reference to `BZ2_bzCompressInit'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x1ed): undefined reference to `BZ2_bzDecompressEnd'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x251): undefined reference to `BZ2_bzCompress'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x2a0): undefined reference to `BZ2_bzCompressEnd'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x39a): undefined reference to `BZ2_bzDecompress'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_bzip.c.obj):mz_strm_bzip.c:(.text+0x4fe): undefined reference to `BZ2_bzCompress'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x231): undefined reference to `lzma_stream_decoder'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x25d): undefined reference to `lzma_lzma_preset'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x2f2): undefined reference to `lzma_properties_size'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x31f): undefined reference to `lzma_stream_encoder'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x39d): undefined reference to `lzma_alone_decoder'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x3f1): undefined reference to `lzma_alone_encoder'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x4f6): undefined reference to `lzma_code'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x685): undefined reference to `lzma_end'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x735): undefined reference to `lzma_code'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x781): undefined reference to `lzma_end'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x7ea): undefined reference to `lzma_end'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_lzma.c.obj):mz_strm_lzma.c:(.text+0x8df): undefined reference to `lzma_code'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x121): undefined reference to `ZSTD_createDStream'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x149): undefined reference to `ZSTD_createCStream'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x175): undefined reference to `ZSTD_CCtx_setParameter'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x228): undefined reference to `ZSTD_decompressStream'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x233): undefined reference to `ZSTD_isError'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x32c): undefined reference to `ZSTD_compressStream2'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x34c): undefined reference to `ZSTD_isError'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x45d): undefined reference to `ZSTD_freeDStream'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x4a3): undefined reference to `ZSTD_freeCStream'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_strm_zstd.c.obj):mz_strm_zstd.c:(.text+0x55f): undefined reference to `ZSTD_CCtx_setParameter'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_crypt_winvista.c.obj):mz_crypt_winvista.c:(.text+0xa1): undefined reference to `BCryptDestroyKey'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_crypt_winvista.c.obj):mz_crypt_winvista.c:(.text+0xb8): undefined reference to `BCryptCloseAlgorithmProvider'
/home/a/workspace/mxe.git/usr/bin/x86_64-w64-mingw32.static-ld: /home/a/workspace/mxe.git/usr/x86_64-w64-mingw32.static/lib/libminizip.a(mz_crypt_winvista.c.obj):mz_crypt_winvista.c:(.text+0x158): undefined reference to `BCryptOpenAlgorithmProvider'

This can be tested in my MXE fork, specifically the pkg/openimageio (image not color here hehe) branch: https://github.com/hkunz/mxe/tree/pkg/openimageio. just execute command make opencolorio

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions