ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Clay 在 C++ 多编译单元工程怎么组织?CLAY_IMPLEMENTATION 应放在哪个翻译单元

Clay 在 C++ 多编译单元工程怎么组织?CLAY_IMPLEMENTATION 应放在哪个翻译单元 Clay 在 C 多编译单元工程怎么组织CLAY_IMPLEMENTATION 应放在哪个翻译单元【免费下载链接】clayHigh performance UI layout library in C.项目地址: https://gitcode.com/GitHub_Trending/clay9/clayClay 是一个高性能 2D UI 布局库核心是单个 clay.h 头文件零依赖。把 Clay 接入一个由多个.c/.cpp编译单元组成的 C 工程时最容易踩的坑是在多个文件里都#include clay.h然后不知道该在哪个文件里放#define CLAY_IMPLEMENTATION。规则只有一条——CLAY_IMPLEMENTATION必须且只能在恰好一个翻译单元里、在包含clay.h之前定义。clay.h文件头部注释的原文是/* NOTE: In order to use this library you must define the following macro in exactly one file, _before_ including clay.h: #define CLAY_IMPLEMENTATION #include clay.h See the examples folder for details. */先确认工程满足 Clay 的语言标准要求clay.h开头有硬性编译器检查C 工程需要 C20或使用 MSVC#if !( \ (defined(__cplusplus) __cplusplus 202002L) || \ (defined(__STDC__) __STDC__ 1 defined(__STDC_VERSION__) __STDC_VERSION__ 199901L) || \ defined(_MSC_VER) || \ defined(__OBJC__) \ ) #error Clay requires C99, C20, or MSVC #endifREADME 的 Bindings for non C 一节也说明Clay 可以直接作为.h头文件在 C99 和 C20 工程中使用。CMake 工程对应写法见 examples/cpp-project-example/CMakeLists.txt其中set(CMAKE_CXX_STANDARD 20)就是用来满足上面这条要求的。CLAY_IMPLEMENTATION 应该放在哪个翻译单元组织方式选一个源文件通常是main.cpp或专门的实现文件在里面先#define CLAY_IMPLEMENTATION再包含头文件其余所有翻译单元只包含clay.h不重复定义宏。仓库里的 C 示例 examples/cpp-project-example/main.cpp 就是这样写的#include iostream #define CLAY_IMPLEMENTATION #include ../../clay.h Clay_LayoutConfig layoutElement Clay_LayoutConfig { .padding {5} }; void HandleClayErrors(Clay_ErrorData errorData) { printf(%s, errorData.errorText.chars); } int main(void) { uint64_t totalMemorySize Clay_MinMemorySize(); Clay_Arena clayMemory Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, (char *)malloc(totalMemorySize)); Clay_Initialize(clayMemory, Clay_Dimensions {1024,768}, Clay_ErrorHandler { HandleClayErrors }); Clay_BeginLayout(); CLAY_AUTO_ID({ .layout layoutElement, .backgroundColor {255,255,255,0} }) { CLAY_TEXT(CLAY_STRING(), CLAY_TEXT_CONFIG({ .fontId 0 })); } Clay_EndLayout(0); return 0; }这样做的机制clay.h内部用#ifdef CLAY_IMPLEMENTATION把实现部分包起来宏定义后立即#undef所以只有定义了宏的那个翻译单元会编译出 Clay 的全部函数体其余翻译单元只拿到声明。如果多个文件都定义了该宏实现会重复编译一个文件都没定义则所有Clay_*函数调用无法链接。其他编译单元里怎么用 Clay多编译单元场景下非实现文件照常#include clay.h就可以使用CLAY()系列宏和Clay_*公共函数无需任何额外定义。仓库里的 examples/raylib-sidebar-scrolling-container/multi-compilation-unit.c 就是这个用途的现成样例文件开头的注释直接说明了它的目的#include ../../clay.h // NOTE: This file only exists to make sure that clay works when included in multiple translation units. void SatisfyCompiler(void) { CLAY(CLAY_ID(SatisfyCompiler), { }) { CLAY_TEXT(CLAY_STRING(Test), CLAY_TEXT_CONFIG({ .fontId 0, .fontSize 24 })); } }对应的构建配置在 examples/raylib-sidebar-scrolling-container/CMakeLists.txt注意这一行把实现文件和非实现文件一起编进同一个可执行目标add_executable(clay_examples_raylib_sidebar_scrolling_container main.c multi-compilation-unit.c)其中main.c是定义CLAY_IMPLEMENTATION的文件multi-compilation-unit.c只包含头文件。两个翻译单元属于同一 target链接时公共函数由实现单元提供。如何验证组织方式正确验证就是按示例的 CMake 配置构建并运行两个示例工程都给出了可直接参照的路径C 单编译单元工程examples/cpp-project-exampleCMake 配置为 CXX 项目、CMAKE_CXX_STANDARD 20构建目标clay_examples_cpp_project_example多编译单元工程examples/raylib-sidebar-scrolling-containermain.cmulti-compilation-unit.c同属一个 target。构建成功且程序正常运行布局流程走通Clay_Initialize→Clay_BeginLayout→CLAY_AUTO_ID/CLAY→Clay_EndLayout说明宏只落在了一个翻译单元上、其余单元的声明能正确链接。反过来如果报Clay_Initialize等函数未定义通常是忘记在某个文件里定义CLAY_IMPLEMENTATION如果同一符号出现重复定义则是多个文件都定义了它。边界与注意事项CLAY_IMPLEMENTATION必须写在#include clay.h之前写在包含之后无效宏检查发生在头文件处理时。编译器命令行上也可以统一定义README Preprocessor Directives 一节提到可以用-D之类的方式在编译参数中设置宏但那样做时要确保只有编译实现单元的那个编译任务携带该定义否则会重复实现。需要把 Clay 编译成 DLL 时README 说明应额外定义CLAY_DLL针对 WebAssembly 则需CLAY_WASM。这两个与放哪个翻译单元无关属于独立选项。头文件里有一处 IDE 特例#if __CLION_IDE__下会自动#define CLAY_IMPLEMENTATION这只影响 CLion 的语法分析不影响工程实际构建。README 提醒 Clay 目前不支持多线程同时渲染多个实例多实例要按 README.md 中 Running more than one Clay instance 一节用Clay_Initialize返回的Clay_Context*加Clay_SetCurrentContext切换这与编译单元组织是两回事不要混淆。【免费下载链接】clayHigh performance UI layout library in C.项目地址: https://gitcode.com/GitHub_Trending/clay9/clay创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表