Skip to content

Add workaround for MSVC specific C++ issue #451

@samansmink

Description

@samansmink

Please describe why this is necessary.

To be able to compile the DuckDB Delta extension, a C++ based project linking against the delta kernel through the FFI, I currently need to manually patch the delta_kernel_ffi.hpp header with the following struct:

struct im_an_unused_struct_that_tricks_msvc_into_compilation {
    ExternResult<KernelBoolSlice> field;
    ExternResult<bool> field2;
    ExternResult<EngineBuilder*> field3;
    ExternResult<Handle<SharedExternEngine>> field4;
    ExternResult<Handle<SharedSnapshot>> field5;
    ExternResult<uintptr_t> field6;
    ExternResult<ArrowFFIData*> field7;
    ExternResult<Handle<SharedScanDataIterator>> field8;
    ExternResult<Handle<SharedScan>> field9;
    ExternResult<Handle<ExclusiveFileReadResultIterator>> field10;
    ExternResult<KernelRowIndexArray> field11;
};

I've taken this trickery from mozilla/cbindgen#402 (comment)

While this seems to work fine, this is a little impractical because it requires manually regenerating and patching the ffi header on every update. Furthermore, it makes it a little finnicky to set up a CI job in the kernel which tests kernel against the DuckDB Delta extension automatically.

First of all, this doesn't appear to be a compiler bug:

Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved (see https://stackoverflow.com/questions/8948443/interface-to-c-objects-through-extern-c-functions)

Note that while msvc throw an error, clang is also not super happy and throws a warning

There seem to be two solutions:

I've chosen the latter because it seemed to cause less potential side effects. Explicit instantiation would be allowed to include the header once in the entire program.

Tbh I think explicit instantiation might work but is probably not really user-friendly compared to the struct approach

Describe the functionality you are proposing.

I think the best approach is to let the kernel generate this workaround automatically. It seems pretty harmless compared to explicit instantiation.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions