Search code examples
pythoncwindowsgcccffi

Handling C2016 error on Windows using Visual Studio Code


I have to use someone else's C header files, which include empty structs. I have no control over these headers or I would change them as empty structs are not conventional C. The structs are throwing C2016 errors, as expected with the standard compiler in Visual Studio Code (on Windows). The original author of the headers is using some other compiler, which allows empty structs.

Here is an example of the error I'm receiving:

message_definitions.h(45): error C2016: C requires that a struct or union have at least one member

Here is an example of the structs:

typedef struct {
} Controller_Do_Graceful_Shutdown_t;

According to what I've read you are permitted empty structs using other compilers, such as gcc. I have installed gcc and have verified it exists:

gcc -v
Using built-in specs.
COLLECT_GCC=C:\msys64\ucrt64\bin\gcc.exe
COLLECT_LTO_WRAPPER=C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../gcc-13.2.0/configure --prefix=/ucrt64 --with-local-prefix=/ucrt64/local --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --with-native-system-header-dir=/ucrt64/include --libexecdir=/ucrt64/lib --enable-bootstrap --enable-checking=release --with-arch=nocona --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++,jit --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts --enable-libstdcxx-time --disable-libstdcxx-pch --enable-lto --enable-libgomp --disable-libssp --disable-multilib --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-libiconv --with-system-zlib --with-gmp=/ucrt64 --with-mpfr=/ucrt64 --with-mpc=/ucrt64 --with-isl=/ucrt64 --with-pkgversion='Rev3, Built by MSYS2 project' --with-bugurl=https://github.com/msys2/MINGW-packages/issues --with-gnu-as --with-gnu-ld --disable-libstdcxx-debug --with-boot-ldflags=-static-libstdc++ --with-stage1-ldflags=-static-libstdc++
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.2.0 (Rev3, Built by MSYS2 project)

The hard part

I'm using cffi in Python to "import" the C headers, so the C compiler being used is whatever the ffibuilder decides to use. Out of the box it uses the Microsoft C compiler, which throws the C2016 errors. :-(

Here is the cffi code:

from cffi import FFI
ffibuilder = FFI()

ffibuilder.set_source("_message_definitions",  # name of the output C extension
"""
    #include "message_definitions.h"
""",
    sources=['message_definitions.c'],
    libraries=[])

if __name__ == "__main__":
    ffibuilder.compile(verbose=True)

Is there a way to tell cffi to use gcc instead, or suppress the C2016 errors being thrown?


Solution

  • Visual studio will refuse to compile that, as it doesn't allow zero size structs in C, you need to use gcc instead to build that library. if you must use MSVC then you need to modify those structs to contain a simple char which is what gcc does, and hope that no one is depending on their size in the code.

    typedef struct {
    char unused;
    } some_struct;
    

    to get cffi to use mingw when compiling you need to create a file named setup.cfg in the same folder of your cffi python file with the following content.

    [build]
    compiler=mingw32
    

    there is no documentation for this, but cffi uses distutils, if this answer fails in the future then you can check this answer edit history for a complex way to hack distutils,