【问题标题】:Duplicate Symbols when Mixing C and C++混合 C 和 C++ 时重复符号
【发布时间】:2016-05-20 15:28:16
【问题描述】:

我正在尝试通过example provided in the manual(位于第 4 页)学习如何使用SDL2 KISS 项目/工具包/库的东西。但是,每当我链接它时,它都会失败,并引用重复的符号错误。 repo 中提供的两个example files 构建,编译,工作正常。

我的假设是,因为我试图将手册中的示例代码写入 C++ 文件,并且库是纯 C89,所以内部编译器会发生一些愤怒的爆炸。如果我用相同的代码转发声明一个 C 函数,一切似乎都很好,但我真的不希望有一堆纯粹作为调用 C 函数的委托而存在的 C++ 文件。

它确实在项目readme(在第一段的末尾)中说所有内容都与 C++ 兼容,并且实际上以与 SDL2 库相同的方式编写——我可以毫无问题地使用它。 SDL2 KISS 标头似乎已正确设置为与 C++ 一起使用,使用:

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
};
#endif

对于Undefined symbols for architecture x86_64 链接器错误的可能原因,我有三个嫌疑人:我对将纯 C 与 C++ 混合的无知、我为项目编写的 CMakeLists 或库本身的问题(我认为难以置信)。几天来,我一直在弄乱不同的潜在解决方案,但没有遇到比前向声明更好的方法(同样,我不想这样做)。下面你会发现确切的错误,我的main.cpp 文件,它只包含手册中的代码,以及我编写的CMakeLists 文件。发布的代码不是为我构建的,但我可以发布工作的 C++ 文件,该文件前向声明 C 函数,如果有帮助的话。

从终端出错

Scanning dependencies of target Test_KISS
[ 16%] Linking CXX executable bin/Test_KISS
duplicate symbol _kiss_border in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_green in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_progress_interval in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_click_interval in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_black in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_slider_padding in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_spacing in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_textfont_size in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_buttonfont_size in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_lightblue in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_blue in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_white in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
duplicate symbol _kiss_edge in:
    CMakeFiles/Test_KISS.dir/src/main.cpp.o
    CMakeFiles/Test_KISS.dir/include/kiss_draw.c.o
ld: 13 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [bin/Test_KISS] Error 1
make[1]: *** [CMakeFiles/Test_KISS.dir/all] Error 2
make: *** [all] Error 2

main.cpp

#include "kiss_sdl.h"


void button_event(kiss_button *button, SDL_Event *e, int *draw, int *quit)
{
    if (kiss_button_event (button, e, draw))
        *quit = 1;
}

int main (int argc, char *argv[])
{

    SDL_Renderer *renderer;
    SDL_Event e;

    kiss_array objects;
    kiss_window window;
    kiss_label label;
    kiss_button button;

    char message[KISS_MAX_LENGTH];
    int draw = 1;
    int quit = 0;

    kiss_array_new (&objects);
    renderer = kiss_init ("Test KISS SDL", &objects, 320, 120);
    kiss_window_new (&window, NULL, 0, 0, 0, kiss_screen_width, kiss_screen_height);
    strcpy (message, "Hello, world!");

    kiss_label_new (&label, &window, message, window.rect.w / 2 - strlen (message) * kiss_textfont.advance / 2, window.rect.h / 2 - (kiss_textfont.fontheight + 2 * kiss_normal.h) / 2);
    label.textcolor.r = 255;

    kiss_button_new (&button, &window, "Okay", window.rect.w / 2 - kiss_normal.w / 2, label.rect.y + kiss_textfont.fontheight + kiss_normal.h);
    window.visible = 1;

    while (!quit)
    {

        SDL_Delay (10);
        while (SDL_PollEvent (&e))
        {

             if (e.type == SDL_QUIT)
                 quit = 1;

             kiss_window_event (&window, &e, &draw);
             button_event (&button, &e, &draw, &quit);
        }

        if (!draw)
            continue;

        SDL_RenderClear (renderer);
        kiss_window_draw (&window, renderer);
        kiss_label_draw (&label, renderer);
        kiss_button_draw (&button, renderer);
        SDL_RenderPresent (renderer);
        draw = 0;
    }

    kiss_clean (&objects);
    return 0;
}

CMakeLists

cmake_minimum_required(VERSION 3.3)
project(Test_KISS)


set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Test_KISS_SOURCE_DIR}/cmake")
set(BIN_DIR ${Test_KISS_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)


#Define Preprocessor Macros (RESDIR found in include/kiss_sdl.h)
add_definitions(-DRESDIR=\"../../resources/\")


find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIR})

find_package(SDL2_ttf REQUIRED)
include_directories(${SDL2_TTF_INCLUDE_DIR})

find_package(SDL2_image REQUIRED)
include_directories(${SDL2_IMAGE_INCLUDE_DIR})

include_directories(include)


add_executable(Test_KISS src/main.cpp include/kiss_draw.c include/kiss_general.c include/kiss_posix.c include/kiss_widgets.c)


target_link_libraries(Test_KISS ${SDL2_LIBRARY} ${SDL2_TTF_LIBRARY} ${SDL2_IMAGE_LIBRARY})
install(TARGETS Test_KISS RUNTIME DESTINATION ${BIN_DIR})

如果我可以提供更多信息来提供帮助,请告诉我!

谢谢!

【问题讨论】:

    标签: c++ c cmake linker-errors sdl-2


    【解决方案1】:

    kiss_sdl.h 实际上定义了很多变量:

    double kiss_spacing;
    int kiss_textfont_size, kiss_buttonfont_size;
    int kiss_click_interval, kiss_progress_interval;
    int kiss_slider_padding;
    int kiss_border, kiss_edge;
    int kiss_screen_width, kiss_screen_height;
    

    这些变量在 #include 所在的每个 C/C++ 文件中定义。因此,您会得到重复的符号 - 因为有 个重复的符号。

    解决办法?修复代码,使其正确declares the variables instead of defining them

    换句话说,代码被破坏了。

    【讨论】:

    • 感谢您的回答!我会对此进行更多调查,但我应该向图书馆的创建者报告,还是我做错了什么?另外,应该修复什么代码,头文件还是不同的文件?
    • @MichaelBethke - 用于包含在使用库的多个文件中的头文件不应定义 那样的变量。如果不深入研究库代码及其文档,我真的不能说如何最好地修复它 - 无论如何这只是我的意见。如果您按照文档所述使用它,那么让它工作的唯一方法是使用链接时选项来接受重复的符号,或者以包含该头文件的方式更改代码仅在您的一个源文件中。
    • 好的,感谢您的意见!我将联系库创建者,看看他们对审查标头定义的看法。谢谢!
    【解决方案2】:

    现在已经修复了。 extern "C" 虽然意味着它下面的声明就像 C++ 一样,其余的代码都像 C 一样编译,就像我的是 C89。如果使用 C 编译器编译,并且文件具有 c 扩展名。正确理解这一点可以解决问题。

    SDL2 https://github.com/actsl/kiss_sdl 的简单通用 GUI 小部件工具包,由我编写。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-18
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      相关资源
      最近更新 更多