使用ARM工具链的CMake项目链接时出现多个未定义引用问题
解决arm-none-eabi工具链编译时_sbrk等未定义引用问题
问题原因
_sbrk是Newlib C标准库依赖的系统调用接口,嵌入式裸机环境没有操作系统提供这些接口,必须手动实现syscalls相关函数。即便使用nosys.specs,部分核心接口仍需自行实现才能满足链接需求。
具体解决步骤
1. 添加syscalls实现文件
在arch/目录下创建syscalls/文件夹,新增syscalls.c文件,实现必要的系统调用接口,示例代码如下:
#include <errno.h> #include <stdint.h> #include <sys/stat.h> // 需根据硬件内存配置调整堆内存起始/结束地址(通常在链接脚本中定义) extern uint8_t _HeapStart[]; extern uint8_t _HeapEnd[]; static uint8_t* current_heap_ptr = _HeapStart; // 实现内存分配依赖的_sbrk void* _sbrk(int incr) { uint8_t* prev_heap_ptr = current_heap_ptr; if ((current_heap_ptr + incr) > _HeapEnd) { errno = ENOMEM; return (void*)-1; } current_heap_ptr += incr; return prev_heap_ptr; } // 其他避免链接错误的空实现 int _close(int file) { return -1; } int _fstat(int file, struct stat* st) { st->st_mode = S_IFCHR; return 0; } int _isatty(int file) { return 1; } int _lseek(int file, int ptr, int dir) { return 0; } int _read(int file, char* ptr, int len) { return 0; } int _write(int file, char* ptr, int len) { // 若需要串口输出,可在此添加UART发送逻辑 return len; }
2. 修改arch目录下的CMakeLists.txt
将syscalls.c加入编译源文件,确保被链接到最终目标:
# 原有arch库配置基础上添加 add_library(arch STATIC # 原有文件... syscalls/syscalls.c ) target_include_directories(arch PUBLIC include/ # 其他已包含的头文件目录... )
3. 调整工具链配置(可选)
在cmake/toolchain-samd51.cmake中明确指定链接参数,确保nosys.specs生效:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -specs=nosys.specs -specs=nano.specs" CACHE INTERNAL "")
注:nano.specs用于启用精简版Newlib,可根据项目需求选择是否添加。
4. 确认链接顺序
在应用的CMakeLists.txt中,确保arch库在标准库之前链接,避免符号解析顺序问题:
add_executable(test_app src/main.c # 其他应用源文件... ) target_link_libraries(test_app PRIVATE arch # 其他依赖库... )
关键说明
- 堆内存的
_HeapStart和_HeapEnd需要在链接脚本(如linker.ld)中定义,必须与硬件实际内存布局匹配。 - 如果使用
printf等输出函数,需在_write中实现串口发送逻辑,否则输出会被静默丢弃。 - 若仍出现其他未定义引用,可根据错误信息补充对应的syscalls函数空实现或实际逻辑。
内容的提问来源于stack exchange,提问作者Gaspar S.
相关产品推荐
相关产品推荐

