pythoncwindowsdlllinker

Calling simple "Hello World!" function from a compiled C DLL from Python results in OSError: exception: access violation


The C code:

// my_module.c

#include <stdio.h>

__declspec(dllexport)
void hello() {
    printf("Hello World!\n");
}

__declspec(dllexport)
int add_numbers(int a, int b) {
    return a + b;
}

// entry point
int main() {
    return 0;
}

The build script:

# build.py

from setuptools._distutils.ccompiler import new_compiler

compiler = new_compiler()
compiler.compile(["my_module.c"])
compiler.link_shared_lib(["my_module.obj"], "my_module")

The main script:

# main.py

import ctypes

my_module = ctypes.CDLL("./my_module.dll")

my_module.add_numbers.argtypes = ctypes.c_int, ctypes.c_int
my_module.add_numbers.restype = ctypes.c_int

my_module.hello.argtypes = ()
my_module.hello.restype = None

result = my_module.add_numbers(3, 4)
print(type(result), result)

my_module.hello()

After running python build.py , the dll is created without issues. However, when running python main.py , the "add_numbers" function works, but calling the "hello" function results in "OSError: exception: access violation writing 0x0000000000002C44".

Am I missing something? Do I somehow need to tell the compiler to include the "stdio.h" header?


Solution

  • it seems distutils is linking the msvc CRT incorrectly.

    you shouldn't import anything with an underscore such as _distutils, as it is not a part of the public API and you shouldn't use it.

    since this is a simple windows dll you could call cl.exe directly and compile it. (make sure you open x64 Native Tools Command Prompt for VS 2022 command prompt before you do)

    cl.exe /LD my_module.c
    

    which will work, but if you have more files then you should probably create a cmake project for it and use it to build your C dll from python.

    a quick look at the dependencies of the one generated from distutils.

    enter image description here

    vs the one from just cl.exe directly.

    enter image description here

    copying all extra dependencies from the windows sdk to the dll folder should get it to work, but this is not the correct approach.