From fff4fb8afa837811d1a5c913bb77fedb488c699d Mon Sep 17 00:00:00 2001 From: Alfred Klomp Date: Wed, 3 Jan 2024 00:21:00 +0100 Subject: [PATCH] #127: bin/base64: fix compilation on MinGW As of v0.5.1, the `base64' demo program no longer compiled under MinGW because MinGW does not emulate the `writev(2)' system call. Fix this by detecting MinGW at compile time and optionally emulating `writev(2)' as a series of `write(2)' calls. Resolves #127. --- Makefile | 19 ++++++++++---- bin/base64.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-- test/Makefile | 4 ++- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index bcb94455..bba3fde4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic +CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE # Set OBJCOPY if not defined by environment: OBJCOPY ?= objcopy @@ -56,6 +56,7 @@ ifdef OPENMP CFLAGS += -fopenmp endif +TARGET := $(shell $(CC) -dumpmachine) .PHONY: all analyze clean @@ -64,9 +65,17 @@ all: bin/base64 lib/libbase64.o bin/base64: bin/base64.o lib/libbase64.o $(CC) $(CFLAGS) -o $@ $^ -lib/libbase64.o: $(OBJS) - $(LD) -r -o $@ $^ - $(OBJCOPY) --keep-global-symbols=lib/exports.txt $@ +# Workaround: mangle exported function names on MinGW32. +lib/exports.build.txt: lib/exports.txt +ifeq (i686-w64-mingw32, $(TARGET)) + sed -e 's/^/_/' $< > $@ +else + cp -f $< $@ +endif + +lib/libbase64.o: lib/exports.build.txt $(OBJS) + $(LD) -r -o $@ $(OBJS) + $(OBJCOPY) --keep-global-symbols=$< $@ lib/config.h: @echo "#define HAVE_AVX512 $(HAVE_AVX512)" > $@ @@ -97,4 +106,4 @@ analyze: clean scan-build --use-analyzer=`which clang` --status-bugs make clean: - rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h $(OBJS) + rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h lib/exports.build.txt $(OBJS) diff --git a/bin/base64.c b/bin/base64.c index 98d6b3cb..6a940749 100644 --- a/bin/base64.c +++ b/bin/base64.c @@ -1,4 +1,19 @@ -#define _XOPEN_SOURCE // IOV_MAX +// Test for MinGW. +#if defined(__MINGW32__) || defined(__MINGW64__) +# define MINGW +#endif + +// Decide if the writev(2) system call needs to be emulated as a series of +// write(2) calls. At least MinGW does not support writev(2). +#ifdef MINGW +# define EMULATE_WRITEV +#endif + +// Include the necessary system header when using the system's writev(2). +#ifndef EMULATE_WRITEV +# define _XOPEN_SOURCE // Unlock IOV_MAX +# include +#endif #include #include @@ -8,7 +23,7 @@ #include #include #include -#include + #include "../include/libbase64.h" // Size of the buffer for the "raw" (not base64-encoded) data in bytes. @@ -50,6 +65,59 @@ struct buffer { char *enc; }; +// Optionally emulate writev(2) as a series of write calls. +#ifdef EMULATE_WRITEV + +// Quick and dirty definition of IOV_MAX as it is probably not defined. +#ifndef IOV_MAX +# define IOV_MAX 1024 +#endif + +// Quick and dirty definition of this system struct, for local use only. +struct iovec { + + // Opaque data pointer. + void *iov_base; + + // Length of the data in bytes. + size_t iov_len; +}; + +static ssize_t +writev (const int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t r, nwrite = 0; + + // Reset the error marker. + errno = 0; + + while (iovcnt-- > 0) { + + // Write the vector; propagate errors back to the caller. Note + // that this loses information about how much vectors have been + // successfully written, but that also seems to be the case + // with the real function. The API is somewhat flawed. + if ((r = write(fd, iov->iov_base, iov->iov_len)) < 0) { + return r; + } + + // Update the total write count. + nwrite += r; + + // Return early after a partial write; the caller should retry. + if ((size_t) r != iov->iov_len) { + break; + } + + // Move to the next vector. + iov++; + } + + return nwrite; +} + +#endif // EMULATE_WRITEV + static bool buffer_alloc (const struct config *config, struct buffer *buf) { diff --git a/test/Makefile b/test/Makefile index c896627e..7ecb893a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic +CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE ifdef OPENMP CFLAGS += -fopenmp endif @@ -6,6 +6,8 @@ endif TARGET := $(shell $(CC) -dumpmachine) ifneq (, $(findstring darwin, $(TARGET))) BENCH_LDFLAGS= +else ifneq (, $(findstring mingw, $(TARGET))) + BENCH_LDFLAGS= else # default to linux, -lrt needed BENCH_LDFLAGS=-lrt