You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cython调用外部C代码失败:UserScanInit等函数未定义求助

问题描述

从微软avscan示例中提取用户态代码,尝试将其主函数逻辑迁移到Cython内嵌C代码中实现,编译时出现链接错误,具体信息如下:

代码文件

cythonmod.pyx

cdef extern from *:
    r"""
    #include <windows.h>
    #include <stdio.h>
    #include <fltUser.h>
    #include "..\\avscan\\user\\utility.h"
    #include "..\\avscan\\inc\\avlib.h"
    #include "..\\avscan\\user\\userscan.h"
    
    HRESULT UserScanInit(PUSER_SCAN_CONTEXT pContext);
    
    int usermodeDef(){
        printf("User mode connecting to kernel mode\n");
        UCHAR c;
        HRESULT hr = S_OK;
        USER_SCAN_CONTEXT userScanCtx = {0};
    
    
        hr = UserScanInit(&userScanCtx);
        if (FAILED(hr)) {
            fprintf(stderr, "Failed to initialize user scan data\n");
            DisplayError( hr );
            return 255;
        }
        
        // 读取用户输入直到按下'q'退出
        for(;;) {
        
            printf("press 'q' to quit: ");
            c = (unsigned char) getchar();
            if (c == 'q') {
            
                break;
            }
        }
        
        // 结束扫描线程上下文
        hr = UserScanFinalize(&userScanCtx);
        if (FAILED(hr)) {
            fprintf(stderr, "Failed to finalize the user scan data.\n");
        }
        return 0;
    }
    """

    int usermodeDef()

setup.py

from distutils.core import setup, Extension
from Cython.Build import cythonize

ext_modules = [
    Extension(
        "cythonmod",
        sources=["cythonmod.pyx"],
        include_dirs=["../avscan/inc", "../avscan/user"],
        extra_compile_args=["-include", "../avscan/user/userscan.h"],
    ),
]

setup(
    name="avscanner",
    ext_modules=cythonize(ext_modules),
    compiler_directives={'language_level': 3, "unraisable_tracebacks": True}
)

编译错误信息

c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: build\temp.win-amd64-3.9\Release\commonmodules.o:commonmodules.c:(.text+0x75df5): undefined reference to `UserScanInit'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: build\temp.win-amd64-3.9\Release\commonmodules.o:commonmodules.c:(.text+0x75e1d): undefined reference to `UserScanFinalize'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: build\temp.win-amd64-3.9\Release\commonmodules.o:commonmodules.c:(.text+0x75e5b): undefined reference to `DisplayError'
collect2.exe: error: ld returned 1 exit status
error: command 'C:\\MinGW\\bin\\gcc.exe' failed with exit code 1

生成的GCC编译选项

gcc -mdll -O -Wall -I../avscan/inc -I../avscan/user -IC:\Users\username\AppData\Local\Programs\Python\Python39\include -IC:\Users\username\AppData\Local\Programs\Python\Python39\include -c cythonmod.c -o build\temp.win-amd64-3.9\Release\cythonmod.o -include ../avscan/user/userscan.h

已尝试直接用cdef extern from "../avscan/user/userscan.h"引入头文件,但问题未解决。请问如何在Cython内嵌C代码中正确导入外部C代码?


解决方案

你遇到的是链接错误:编译器能通过头文件找到函数声明,但找不到这些函数的实现代码。UserScanInit/UserScanFinalize的实现在userscan.c中,DisplayError的实现在utility.c中,当前setup.py仅编译了Cython的.pyx文件,未包含这些依赖的C源文件。

步骤1:添加依赖C源文件到setup.py

修改Extension的sources参数,把avscan用户态的C源文件路径加入,同时补充必要的链接库:

ext_modules = [
    Extension(
        "cythonmod",
        sources=[
            "cythonmod.pyx",
            "../avscan/user/userscan.c",
            "../avscan/user/utility.c"
        ],
        include_dirs=["../avscan/inc", "../avscan/user"],
        # MinGW编译需链接fltUser库
        extra_link_args=["-lfltUser"],
    ),
]

步骤2:简化Cython的extern声明

无需手动声明函数,直接从头文件引入类型和函数,代码更规范:

# 从userscan.h引入结构体和函数声明
cdef extern from "../avscan/user/userscan.h":
    ctypedef struct USER_SCAN_CONTEXT:
        pass  # Cython只需知晓结构体类型,无需具体成员
    HRESULT UserScanInit(USER_SCAN_CONTEXT* pContext)
    HRESULT UserScanFinalize(USER_SCAN_CONTEXT* pContext)

# 从utility.h引入DisplayError函数
cdef extern from "../avscan/user/utility.h":
    void DisplayError(HRESULT hr)

# 内嵌主逻辑代码
cdef extern from *:
    r"""
    #include <windows.h>
    #include <stdio.h>
    #include <fltUser.h>
    
    int usermodeDef(){
        printf("User mode connecting to kernel mode\n");
        UCHAR c;
        HRESULT hr = S_OK;
        USER_SCAN_CONTEXT userScanCtx = {0};
    
        hr = UserScanInit(&userScanCtx);
        if (FAILED(hr)) {
            fprintf(stderr, "Failed to initialize user scan data\n");
            DisplayError( hr );
            return 255;
        }
        
        for(;;) {
            printf("press 'q' to quit: ");
            c = (unsigned char) getchar();
            if (c == 'q') {
                break;
            }
        }
    
        hr = UserScanFinalize(&userScanCtx);
        if (FAILED(hr)) {
            fprintf(stderr, "Failed to finalize the user scan data.\n");
        }
        return 0;
    }
    """

int usermodeDef()

步骤3:注意编译环境兼容性

avscan示例是针对MSVC编写的,MinGW编译可能存在Windows API类型定义差异。如果上述步骤仍有问题,建议切换到MSVC编译:

  1. 安装Visual Studio并勾选「Desktop development with C++」组件
  2. 打开VS开发者命令提示符,运行python setup.py build_ext --inplace

内容的提问来源于stack exchange,提问作者Abdul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:44:55