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

运行make遇多重定义错误,修复后又现未定义引用问题求助

问题描述

项目结构

ProjectX
├── Module1
│   ├── Module2
│   │   ├── CMakeLists.txt
│   │   ├── src
│   │   │   └── Module2.cpp // 包含 #include "Common.h"
│   │   └── include
│   ├── CMakeLists.txt
│   ├── src
│   │   └── Class1.cpp  // 包含 #include "Common.h"
│   │   └── Class2.cpp // 包含 #include "Common.h"
│   └── include
│       └── Class1.h  // 包含 #include "Class2.h"  ** 注意 **
├── Module3
│   ├── CMakeLists.txt
│   ├── src
│   │   └── Class3.cpp // 包含 #include "Common.h"
│   └── include
├── src
│   └── NewClass.cc // 新增文件
├── include
│   ├── NewClass.h // 新增文件
│   └── Common.h // 新增文件
└── CMakeLists.txt

Common.h 代码

Common.h 定义了供所有模块使用的NewClass实例:

#ifndef GLOBALS_H
#define GLOBALS_H

#include "NewClass.h"

namespace ProjectX {
    extern NewClass instance1 = NewClass();
    extern NewClass instance2 = NewClass();
    extern NewClass instance3 = NewClass();
}

#endif // GLOBALS_H

CMake配置

ProjectX/CMakeLists.txt

add_library(${PROJECT_NAME} SHARED 
src/NewClass.cc
include/NewClass.h
include/Common.h
)

ProjectX/Module1/CMakeLists.txt 及 ProjectX/Module2/CMakeLists.txt

set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)

ProjectX/Module3/CMakeLists.txt

set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../../)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)

注意:项目中有5处#include "Common.h"的引用(对应结构中标注的文件)。

初始编译错误

运行make时出现以下链接错误:

/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x10): multiple definition of `ProjectX::instance1'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x10): first defined here
/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x20): multiple definition of `ProjectX::instance2'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x20): first defined here
/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x0): multiple definition of `ProjectX::instance3'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x0): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x20): multiple definition of `ProjectX::instance2'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x20): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x0): multiple definition of `ProjectX::instance3'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x0): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x10): multiple definition of `ProjectX::instance1'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x10): first defined here
collect2: error: ld returned 1 exit status

添加NewClass.cc、NewClass.h和Common.h之前项目运行正常,现在想新增可在所有模块复用的工具功能,修改后出现上述错误,求修复方案及更佳实现方式。


更新:修改后新错误

按照建议修改后,初始错误消失,但出现新的链接错误:

/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::instance1'
/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::NewClass::method(double, double)'
/usr/bin/ld: Module3/libModule3.so: undefined reference to `ProjectX::NewClass::method(std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, double)'
/usr/bin/ld: Module3/libModule3.so: undefined reference to `ProjectX::instance3'
/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::instance2'
collect2: error: ld returned 1 exit status

解决方案

1. 修复全局变量重复定义问题

核心问题是全局变量的声明与定义混淆:extern在头文件中是声明变量,告诉编译器“这个变量在别处定义”,但你直接在extern后加初始化(= NewClass()),这就变成了定义。每个包含Common.h的源文件都会生成一份变量定义,链接时必然报重复定义错误。

修正步骤:

  • 修改Common.h:仅保留extern声明,去掉初始化:
#ifndef GLOBALS_H
#define GLOBALS_H

#include "NewClass.h"

namespace ProjectX {
    // 仅声明,不定义
    extern NewClass instance1;
    extern NewClass instance2;
    extern NewClass instance3;
}

#endif // GLOBALS_H
  • 新增src/Common.cc:在其中实际定义并初始化全局变量:
#include "Common.h"

namespace ProjectX {
    // 实际定义并初始化
    NewClass instance1 = NewClass();
    NewClass instance2 = NewClass();
    NewClass instance3 = NewClass();
}
  • 更新根目录CMakeLists.txt:把Common.cc加入库文件列表:
add_library(${PROJECT_NAME} SHARED 
src/NewClass.cc
src/Common.cc  # 新增该文件
include/NewClass.h
include/Common.h
)

2. 修复未定义引用错误

新错误是因为各个模块没有链接根目录的ProjectX库,导致找不到NewClass的实现和全局实例。

修正步骤:

在每个模块的CMakeLists.txt中,添加对根目录ProjectX库的链接:

  • Module1/CMakeLists.txt 和 Module2/CMakeLists.txt:
set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../)
# 查找根目录构建生成的ProjectX库(需根据实际构建路径调整PATHS)
find_library(PROJECTX_LIB ${PROJECT_NAME} PATHS ${PROJECTX_DIR}/build)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)
# 链接ProjectX库
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECTX_LIB})
  • Module3/CMakeLists.txt:
set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../../)
find_library(PROJECTX_LIB ${PROJECT_NAME} PATHS ${PROJECTX_DIR}/build)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECTX_LIB})

更规范的做法是在根目录CMake中用install或export配置,让子模块可以通过find_package(ProjectX)自动找到库文件和头文件路径。

3. 更佳实现方式(替代全局变量)

全局变量容易引发依赖混乱、线程安全等问题,推荐以下两种方案:

  • 单例模式:把NewClass设计成单例,通过静态方法获取实例,避免全局变量:
// NewClass.h
class NewClass {
public:
    static NewClass& getInstance1() {
        static NewClass instance;
        return instance;
    }
    static NewClass& getInstance2() {
        static NewClass instance;
        return instance;
    }
    static NewClass& getInstance3() {
        static NewClass instance;
        return instance;
    }
    // ... 其他成员方法
private:
    NewClass() {} // 私有构造,禁止外部实例化
    ~NewClass() {}
    NewClass(const NewClass&) = delete;
    NewClass& operator=(const NewClass&) = delete;
};

各模块直接调用NewClass::getInstance1()即可获取实例,无链接问题。

  • 依赖注入:模块需要NewClass实例时,通过构造函数或参数传递,而非直接依赖全局变量,提升代码可测试性和灵活性。

内容的提问来源于stack exchange,提问作者MsA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:29:55