混合使用 C 和 C++ 时出现重复符号
Duplicate Symbols when Mixing C and C++
我正在尝试学习如何使用 repo 中提供的 SDL2 KISS project/toolkit/library-thing, via the example provided in the manual (found on page 4). Whenever I link it, however, it fails, citing duplicate symbol errors. The two example files 构建、编译和正常工作。
我的假设是,因为我试图将手册中的示例代码写入 C++ 文件,而库是纯 C89,所以内部编译器发生了一些愤怒的爆炸。如果我用相同的代码转发声明一个 C 函数,一切似乎都很好,但我真的不希望有一堆纯粹作为调用 C 函数的委托存在的 C++ 文件。
它确实在项目 readme 中说(在第一段的末尾)一切都是 C++ 兼容的,并且实际上是用与 SDL2 库相同的方式编写的——我可以使用没有问题。 SDL2 KISS header 似乎已正确设置为与 C++ 一起使用,使用:
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
};
#endif
就 Undefined symbols for architecture x86_64
链接器错误的可能原因而言,我有三个嫌疑人:我对混合纯 C 和 C++ 的无知,我为项目编写的 CMakeLists,或者库本身的问题(我认为这是极不可能的)。几天来我一直在研究不同的潜在解决方案,但没有遇到比前瞻性声明更好的东西(我不想这样做)。您会在下面找到确切的错误,我的 main.cpp
文件,其中仅包含手册中的代码,以及我编写的 CMakeLists
文件。代码 posted 不 为我构建,但我可以 post 工作的 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})
如果我可以提供更多信息来帮助您,请告诉我!
谢谢!
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.
换句话说,密码被破坏了。
现已修复。 extern "C" 虽然意味着它下面的声明就像C++,其余代码像C一样编译,比如我的是C89。如果用 C 编译器编译,并且文件扩展名为 c。正确理解这是解决问题的原因。
用于 SDL2 https://github.com/actsl/kiss_sdl 的简单通用 GUI 小部件工具包,由我编写。
我正在尝试学习如何使用 repo 中提供的 SDL2 KISS project/toolkit/library-thing, via the example provided in the manual (found on page 4). Whenever I link it, however, it fails, citing duplicate symbol errors. The two example files 构建、编译和正常工作。
我的假设是,因为我试图将手册中的示例代码写入 C++ 文件,而库是纯 C89,所以内部编译器发生了一些愤怒的爆炸。如果我用相同的代码转发声明一个 C 函数,一切似乎都很好,但我真的不希望有一堆纯粹作为调用 C 函数的委托存在的 C++ 文件。
它确实在项目 readme 中说(在第一段的末尾)一切都是 C++ 兼容的,并且实际上是用与 SDL2 库相同的方式编写的——我可以使用没有问题。 SDL2 KISS header 似乎已正确设置为与 C++ 一起使用,使用:
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
};
#endif
就 Undefined symbols for architecture x86_64
链接器错误的可能原因而言,我有三个嫌疑人:我对混合纯 C 和 C++ 的无知,我为项目编写的 CMakeLists,或者库本身的问题(我认为这是极不可能的)。几天来我一直在研究不同的潜在解决方案,但没有遇到比前瞻性声明更好的东西(我不想这样做)。您会在下面找到确切的错误,我的 main.cpp
文件,其中仅包含手册中的代码,以及我编写的 CMakeLists
文件。代码 posted 不 为我构建,但我可以 post 工作的 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})
如果我可以提供更多信息来帮助您,请告诉我!
谢谢!
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.
换句话说,密码被破坏了。
现已修复。 extern "C" 虽然意味着它下面的声明就像C++,其余代码像C一样编译,比如我的是C89。如果用 C 编译器编译,并且文件扩展名为 c。正确理解这是解决问题的原因。
用于 SDL2 https://github.com/actsl/kiss_sdl 的简单通用 GUI 小部件工具包,由我编写。