You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 15:55:33