代码之家  ›  专栏  ›  技术社区  ›  Kyohei Kaneko

cgo:当使用cgo在包中包含C头文件时,如何防止“多重定义…”错误?

  •  0
  • Kyohei Kaneko  · 技术社区  · 1 年前

    我正在编写一个本地库,它使用cgo提供了一个C api。我有一个C头文件,其中包括一个常量定义,但当我使用cgo将其包含在一个包中,然后在go中将该包导入main时,我会得到一个 multiple definition... 生成时出现链接器错误:

    C:\Users\danie\AppData\Local\Temp\go-link-1146178960\000011.o:C:\Temp\cgo-error\mypackage/errors.h:29: multiple definition of `MYMODULE_ERROR_STRS'; C:\Users\danie\AppData\Local\Temp\go-link-1146178960\000010.o:C:/Temp/cgo-error/mypackage/errors.h:29: first defined here    
    collect2.exe: error: ld returned 1 exit status
    

    下面的示例代码使用了此答案中给出的错误处理示例: https://stackoverflow.com/a/59221452/1324919

    main.go:

    package main
    
    import "C"
    import "example.com/cgo-error/mypackage"
    
    func main() {}
    
    //export exported_function
    func exported_function() {
        mypackage.CallCFunction()
    }
    

    mypackage.go(包括C头文件):

    package mypackage
    
    // #include "errors.h"
    import "C"
    
    func CallCFunction() {
        _ = C.mymodule_func1()
    }
    

    错误。h:

    #ifndef ERRORS_H_
    #define ERRORS_H_
    
    /// @brief Error codes for library "mymodule"
    typedef enum mymodule_error_e
    {
        /// No error
        MYMODULE_ERROR_OK = 0,
        MYMODULE_ERROR_INVARG,
        MYMODULE_ERROR_NOMEM,
        MYMODULE_ERROR_MYERROR,
        MYMODULE_ERROR_COUNT,
    } mymodule_error_t;
    
    // Array of strings to map enum error types to printable strings
    const char *const MYMODULE_ERROR_STRS[] =
        {
            "MYMODULE_ERROR_OK",
            "MYMODULE_ERROR_INVARG",
            "MYMODULE_ERROR_NOMEM",
            "MYMODULE_ERROR_MYERROR",
    };
    
    // To get a printable error string
    const char *mymodule_error_str(mymodule_error_t err);
    
    // Other functions in mymodule
    mymodule_error_t mymodule_func1(void);
    mymodule_error_t mymodule_func2(void);
    mymodule_error_t mymodule_func3(void);
    
    #endif
    

    错误。c:

    #include "errors.h"
    #include <stdio.h>
    
    /// @brief      Function to get a printable string from an enum error type
    /// @param[in]  err     a valid error code for this module
    /// @return     A printable C string corresponding to the error code input above, or NULL if an invalid error code
    ///             was passed in
    const char *mymodule_error_str(mymodule_error_t err)
    {
        const char *err_str = NULL;
    
        // Ensure error codes are within the valid array index range
        if (err >= MYMODULE_ERROR_COUNT)
        {
            goto done;
        }
    
        err_str = MYMODULE_ERROR_STRS[err];
    
    done:
        return err_str;
    }
    
    // Let's just make some empty dummy functions to return some errors; fill these in as appropriate for your
    // library module
    
    mymodule_error_t mymodule_func1(void)
    {
        return MYMODULE_ERROR_OK;
    }
    
    mymodule_error_t mymodule_func2(void)
    {
        return MYMODULE_ERROR_INVARG;
    }
    
    mymodule_error_t mymodule_func3(void)
    {
        return MYMODULE_ERROR_MYERROR;
    }
    

    在我看来,将头文件包含在 mypackage.go 并将其包含在 errors.c 导致go链接器导入它两次,当 mypackage 在中导入 main . 有什么办法绕过这个吗?

    1 回复  |  直到 1 年前
        1
  •  1
  •   gulpr    1 年前

    不要 定义 变量,因为您将在每个编译单元中创建这些变量的新实例 #include 这个.h文件这是你的问题的根源。将它们放在C文件中。

    错误。h 文件:

    extern const char *const MYMODULE_ERROR_STRS[];
    

    以及中的实际定义 错误。c: 文件:

    const char *const MYMODULE_ERROR_STRS[] =
        {
            "MYMODULE_ERROR_OK",
            "MYMODULE_ERROR_INVARG",
            "MYMODULE_ERROR_NOMEM",
            "MYMODULE_ERROR_MYERROR",
    };
    
    推荐文章