多个仅包含 header 个库导致重新定义错误

Multiple includes of header only library causing redefinition errors

我正在使用名为 Nuklear 的仅 header 库。这是一个 header 唯一的图书馆。使用来自不同文件的多个包含时遇到问题。它returns一个多重定义的例子:

...
obj/main.o:main.c:(.text+0x4a52b): multiple definition of `nk_sdl_font_stash_begin'
obj/components.o:components.c:(.text+0x4a56f): first defined here
obj/main.o:main.c:(.text+0x4a563): multiple definition of `nk_sdl_font_stash_end'
obj/components.o:components.c:(.text+0x4a5a7): first defined here
obj/main.o:main.c:(.text+0x4a5f4): multiple definition of `nk_sdl_handle_event'
obj/components.o:components.c:(.text+0x4a638): first defined here
obj/main.o:main.c:(.text+0x4ac9f): multiple definition of `nk_sdl_shutdown'
obj/components.o:components.c:(.text+0x4ace3): first defined here

我正在尝试将库包含到 2 个文件中。

main.c

#define SDL_MAIN_HANDLED
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_SDL_GL3_IMPLEMENTATION
#include "nuklear.h"
#include "nuklear_sdl_gl3.h"
#include "components.h"
...

components.c

#define SDL_MAIN_HANDLED
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_SDL_GL3_IMPLEMENTATION
#include "nuklear.h"
#include "nuklear_sdl_gl3.h"

Nuklear 库已经包含 header 守卫,所以我不确定为什么会出现此错误。有什么建议吗?

nuklear_sdl_gl3.h 包含数据和函数。它写得非常糟糕。所有定义都应该在 .c 文件中,只有声明、类型定义、外部变量声明和静态内联函数应该在头文件中。

您不能在整个项目中多次包含此文件。守卫在这里不起作用,因为它包含在不同的编译单元中。

你应该只 #define NK_SDL_GL3_IMPLEMENTATION 在你 #include "nuklear_sdl_gl3.h" 之前的一个 .c 源文件中。

nuklear_sdl_gl3.h 文件包含所有函数定义以及函数声明,您只需要将定义放在一个地方,否则,正如您所发现的,您的链接器会报错。

来自 GitHub 的自述文件:

This library is self contained in one single header file and can be used either in header only mode or in implementation mode. The header only mode is used by default when included and allows including this header in other headers and does not contain the actual implementation.

The implementation mode requires to define the preprocessor macro NK_IMPLEMENTATION in one .c/.cpp file before #includeing this file, e.g.:

#define NK_IMPLEMENTATION
#include "nuklear.h"

因此,main.ccomponents.c 中只有一个应该包含 #define NK_IMPLEMENTATION — 但您在两者中都定义了它。

修复

  • components.c 中删除 #define NK_IMPLEMENTATION
  • 除了 nuklear.h 之外,不要包含任何其他 Nuklear header — 说明并没有告诉您这样做(至少,表面上没有;也许其他地方是这样说的,但是……)。

文档还指出:

IMPORTANT: Every time you include "nuklear.h" you have to define the same optional flags. This is very important not doing it either leads to compiler errors or even worse stack corruptions.

可能值得拥有自己的 header — 例如 use_nuklear.h,但我相信您会想到一个更好的名字 — 包含正确的 [=23] =] 选项(除 NK_IMPLEMENTATION 之外的所有选项)。然后 #include "use_nuklear.h" 在你的源文件中。这样一来,如果(当)您更改选项时,您只有一个地方可以更改 — 并且重建将是一致的。