base64: Build of 0.5.1 broken with MinGW

Build of 0.5.1 with MinGW11.0.0/GCC13 fails (it was working fine in 0.5.0):

[7/15] Building C object CMakeFiles/base64-bin.dir/bin/base64.c.obj
FAILED: CMakeFiles/base64-bin.dir/bin/base64.c.obj
D:\Programmes\mingw64\bin\gcc.exe  -IC:/Users/spaceim/.conan2/p/b/base6763a9b6f78112/b/src/include -m64 -O3 -DNDEBUG -MD -MT CMakeFiles/base64-bin.dir/bin/base64.c.obj -MF CMakeFiles\base64-bin.dir\bin\base64.c.obj.d -o CMakeFiles/base64-bin.dir/bin/base64.c.obj -c C:/Users/spaceim/.conan2/p/b/base6763a9b6f78112/b/src/bin/base64.c
C:/Users/spaceim/.conan2/p/b/base6763a9b6f78112/b/src/bin/base64.c:11:10: fatal error: sys/uio.h: No such file or directory
   11 | #include <sys/uio.h>
      |          ^~~~~~~~~~~

sys/uio.h is not provided by MinGW.

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

@sergeevabc It does work. The reason why it’s throwing an error is because the command adds a newline, which is not part of the base64 alphabet. Try it like this:

$ echo -n Z2l0aHVi | base64.exe -d

The newline thing is a known issue, see #126. I plan to fix it soon by discarding newlines in the input.

@sergeevabc, because the flags changed, be sure to clean out the old build first: make clean.

probably something to do with incorrect use of __declspec(dllexport) and __declspec(dllimport)

Correct, the declaration is marked with dllimport, so it’s expecting to import it from a DLL and decorates the name accordingly, but then it’s statically linked into the same module. This invocation works:

make SSSE3_CFLAGS=1 CFLAGS='-Ilib -O3 -mssse3 -DBASE64_STATIC_DEFINE'

This builds everything as though it were a static library, which is in essence the intention when building the command line program. However, that build command isn’t ideal:

  • The -Ilib is necessary because it’s not set properly in the Makefile, nor is there a way to extend it with extras like the -D option. At the top level, Make is a declarative language — resolving all those += before actually building anything — and there isn’t a sense that definitions like CFLAGS are scoped to a particular target or recipe. If you want different flags at different times, use different names and a custom recipe. Example:

    lib/arch/ssse3/codec.o:
        $(CC) -c $(CFLAGS) $(SSSE3_CFLAGS) -o $@ $<
    

    Since -Ilib is so essential, I’d just bake it into the recipe generally, so that CFLAGS can be more freely overridden/extended:

    %.o: %.c
        $(CC) -c -Ilib $(CFLAGS) -o $@ $<
    
    lib/arch/ssse3/codec.o:
        $(CC) -c -Ilib $(CFLAGS) $(SSSE3_CFLAGS) -o $@ $<
    
  • SSSE3_CFLAGS similarly doesn’t work as intended per above. It needs to be set to nonempty for lib/config.h, but otherwise it’s not actually used, so I put -mssse3 in CFLAGS as well.

I suspect -DBASE64_STATIC_DEFINE should be in the default CFLAGS for the root Makefile since it exists just to build the command line program.

@sergeevabc Thanks for giving it a try and for posting the full compilation output.

What I think is happening is that the compiler/linker is mangling the names of the functions for some reason. For example, base64_stream_decode_init seems to be renamed internally to __imp_base64_stream_decode_init, and that function is then not found when linking the binary with the library.

My hypothesis: the reason that function is not found is because objcopy is called with this argument: --keep-global-symbols=lib/exports.txt. The file lib/exports.txt contains a hand-curated list of functions that should be exported globally. You can perhaps experiment either by removing that argument to objcopy, or by adding those __imp_* functions to lib/exports.txt by hand.

The real problem is probably something to do with incorrect use of __declspec(dllexport) and __declspec(dllimport). That deserves a closer look, but I think it should be in another ticket.