1. 前言
在使用 CMake 构建 C++ 项目时,链接第三方库往往会碰到一些"链接失败"的问题,尤其在 Linux 环境下比较常见。最近我在编译一个涉及 JSON 解析功能的项目时,遇到如下错误:
bash
/usr/bin/ld: 找不到 -ljsoncpp: 没有那个文件或目录
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/run_intrinsic_calibration.dir/build.make:113: ../bin/run_intrinsic_calibration] 错误 1
make[1]: *** [CMakeFiles/Makefile2:111: CMakeFiles/run_intrinsic_calibration.dir/all] 错误 2
make: *** [Makefile:91: all] 错误 2
很明显,链接器找不到 jsoncpp
相关的库文件。通过在 CMakeLists.txt 中把对 jsoncpp.a
的静态库链接改成链接 jsoncpp.so
(动态库),最终成功解决了问题。本文就把这个过程分享给大家,供遇到类似问题的同学参考。
2. 问题背景
在项目的 CMakeLists.txt 中,原先有这样的链接语句:
cmake
target_link_libraries(
${PROJECT_NAME}
jsoncpp.a
${OpenCV_LIBS}
${Boost_SYSTEM_LIBRARY}
)
这表示显式地去链接名为 jsoncpp.a
的静态库。但是在实际环境中,系统安装的只是 libjsoncpp.so
(动态库),并不存在对应的 jsoncpp.a
(静态库)。因此,链接器自然找不到 jsoncpp.a
文件,就会报类似 "找不到 -ljsoncpp" 或 "无法打开 jsoncpp.a" 这样的错误。
2.1 为什么只安装了 .so
而没有 .a
?
在大多数 Linux 发行版上,默认安装的 libjsoncpp-dev
(或同名开发包)只会提供共享库(libjsoncpp.so
)和头文件,而不一定会提供静态库(libjsoncpp.a
)。这是因为静态库往往需要额外维护,并且在普通场景中使用动态库更方便、可维护性更高。
3. 解决思路
要想解决这个报错,无非两种方案:
- 改用动态库:如果只是想让项目能正常编译和运行,直接链接动态库就可以了。
- 自行安装/编译静态库 :如果明确需要静态链接(比如某些嵌入式场景、需要单文件发布等),就得手动编译并安装
jsoncpp.a
。
在这里,我的需求只是能让程序正常编译、运行,不依赖完全的静态链接。因此,选择了 最简单的 方案 ------ 把 ".a" 改成 ".so" ,或者更常见的是 直接写 "jsoncpp" 让 CMake 自动去查找共享库和头文件。
4. 改动一行,链接成功
我只需要在 CMakeLists.txt 中,把原先的
cmake
target_link_libraries(
${PROJECT_NAME}
jsoncpp.a
${OpenCV_LIBS}
${Boost_SYSTEM_LIBRARY}
)
改成:
cmake
target_link_libraries(
${PROJECT_NAME}
jsoncpp.so
${OpenCV_LIBS}
${Boost_SYSTEM_LIBRARY}
)
或者:
cmake
target_link_libraries(
${PROJECT_NAME}
jsoncpp
${OpenCV_LIBS}
${Boost_SYSTEM_LIBRARY}
)
然后重新 cmake .. && make -j
,就可以看到编译顺利通过。因为系统在 /usr/lib/x86_64-linux-gnu/
(不同发行版可能略有差异)下找到了 libjsoncpp.so
这个文件,满足了链接要求。
5. 动态库与静态库的区别
简单科普一下:
- 动态库(
.so
) :程序运行时需要依赖外部的共享库文件,升级库时不需要重新编译所有应用,发布体积小,但需要在环境中保留.so
文件。 - 静态库(
.a
):编译时将第三方库的代码直接打包进可执行文件,发布时无需再携带库文件,更独立,但是体积变大,且若库有更新,需要重新编译可执行文件。
常见情况下,如果你没有特殊需求,使用动态库更方便。
6. 总结
- 问题核心 :CMake 链接阶段找不到
jsoncpp.a
,因为系统并没有安装静态库。 - 解决方法 :直接改用已经安装的动态库
jsoncpp.so
,或者在链接指令里只写jsoncpp
让 CMake 自动匹配到共享库。 - 经验教训 :
- 安装
libjsoncpp-dev
一类的开发包后,大多数情况下只会得到.so
文件而不是.a
文件。 - 如果想要静态库
.a
,通常要自己编译或者额外安装静态库包。 - 若非必要,动态库
.so
更常用。
- 安装
希望这篇文章对同样遇到 "找不到 -ljsoncpp
" 链接错误的朋友有所帮助。如果对你有用,欢迎点赞、收藏或关注。我们下篇文章再见!
参考gpt share:https://chatgpt.com/share/67760c04-d638-8010-84a6-9bcaa52e5144