CMake构建库与可执行文件时链接错误及重定义问题求助
问题描述
我正在学习CMake,目标是创建库并编译对应的示例程序。项目结构如下:
/home/username/project/--| |-- CMakeLists.txt |-- example/--| | |-- CMakeLists.txt | |-- main.cpp | |--fraction/--| | |--CMakeLists.txt | |--include/--| | | |--fraction.h | | | |--src/------| | | |--fraction.cpp | |--operation/-| | |--CMakeLists.txt | |--include/--| | | |--operation.h | | | |--src/------| | | |--operation.cpp
执行编译命令后出现链接错误(undefined reference),若在main.cpp中添加#include "fraction.h"又会触发重定义错误,需要解决模块链接问题。
解决方案
1. 修复示例程序的CMake配置(链接依赖库)
当前example/CMakeLists.txt仅添加了头文件路径,但未链接依赖的库,导致链接阶段找不到函数实现。修改如下:
add_executable(example1 main.cpp) # 直接链接operation库,CMake会自动处理其依赖的fraction库 target_link_libraries(example1 PRIVATE operation)
无需手动设置头文件路径,因为operation库会通过CMake的目标依赖自动传递头文件信息。
2. 修复operation库的CMake配置(正确暴露依赖)
operation库当前使用include_directories设置头文件路径,这是全局设置,应改用target_include_directories并设为PUBLIC,让依赖它的目标自动获取头文件路径:
set(target operation) set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include") set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src") file(GLOB_RECURSE sources ${source_path}/*.cpp) file(GLOB_RECURSE headers ${include_path}/*.h) add_library(${target} ${sources}) # 设为PUBLIC,让依赖operation的目标自动继承fraction库的依赖 target_link_libraries(${target} PUBLIC fraction) # 改用target_include_directories并设为PUBLIC target_include_directories(${target} PUBLIC ${include_path}) install(FILES ${headers} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${target}) install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
3. 修复fraction.h的重定义问题
fraction.h中直接定义了least_common_multiple函数,多个源文件包含该头文件会触发重定义错误,需将函数声明与定义分离:
- 修改
fraction.h,仅保留函数声明:
#ifndef FRACTION_H #define FRACTION_H #include <iostream> using namespace std; // 仅声明函数 int least_common_multiple(int d1, int d2); class fraction { private: int numerator, denominator; public: fraction(int numr = 1, int denomr = 1); fraction operator+(fraction &frac); ~fraction(); }; #endif // FRACTION_H
- 将
least_common_multiple的实现移到fraction.cpp中:
#include "fraction.h" // 实现函数 int least_common_multiple(int d1, int d2) { int large = d1 > d2 ? d1 : d2; int small = large == d1 ? d2 : d1; for (int i = 1; ; i++) { if ((large*i) % small == 0) { large = large*i; break; } } return large; } fraction::fraction(int numr, int denomr) : numerator(numr), denominator(denomr) {} fraction fraction::operator+(fraction &frac) { fraction sum; sum.numerator = denominator*frac.numerator + numerator*frac.denominator; sum.denominator = least_common_multiple(denominator, frac.denominator); return sum; } fraction::~fraction() {}
4. 添加头文件保护(可选但推荐)
为operation.h也添加头文件保护,避免重复包含:
#ifndef OPERATION_H #define OPERATION_H #include "fraction.h" class operation { public: fraction add(fraction a, fraction b); ~operation(); }; #endif // OPERATION_H
编译验证
重新执行编译流程:
rm -rf build && mkdir build && cd build cmake -DCMAKE_INSTALL_PREFIX=./install .. make
此时可正常完成编译链接,无错误。
内容的提问来源于stack exchange,提问作者user15897459
相关产品推荐
相关产品推荐

