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

使用Clang时共享库入口点创建出现未定义引用链接错误

问题:共享库导出类的析构函数未解析链接错误

当前项目包含供可执行文件调用的共享库Engine,尝试将入口点移至该共享库中,仅让可执行文件包含函数和待创建的类,但编译可执行文件时出现未解析外部符号错误。


可复现项目结构

共享库Engine文件

  • entry.h
  • BaseGame.h
  • Application.cpp

entry.h 代码

#include "BaseGame.h"

extern game* create_game();

int main(int argc, char *argv[])
{
    auto testgame = create_game();
    delete testgame;
    return 0;
}

BaseGame.h 代码

class __declspec(dllexport) game
{
public:
    game() = default;
    virtual ~game();
    virtual bool initialize() =0;
    virtual bool update(float deltaTime) =0;
    virtual bool render(float deltaTime) =0;
    virtual void on_resize() =0;
};

Application.cpp 代码

#include "BaseGame.h"
class __declspec(dllexport) Application
{
public:
    Application()=default;
    ~Application()=default;
};

可执行文件文件

  • entry.cpp(定义create_game)
  • my_game.h(继承game类)
  • my_game.cpp

entry.cpp 代码

#include <entry.h>
#include "my_game.h"

game* create_game()
{
    return new myGame;
}

my_game.h 代码

class myGame : public game
{
public:
    myGame(){};
    ~myGame() override = default;
    bool initialize() override;
    bool update(float deltaTime) override;
    bool render(float deltaTime) override;
    void on_resize() override;
};

my_game.cpp 代码

#include "my_game.h"

bool myGame::initialize()
{
    return true;
}
bool myGame::update(float deltaTime)
{
    return true;
}
bool myGame::render(float deltaTime)
{
    return true;
}
void myGame::on_resize()
{
}

编译命令

共享库Engine编译命令

SET assembly=Engine
SET compilerFlags=-g -shared -Wvarargs -Wall -Werror
SET includeFlags=-Isrc
SET linkerFlags=-luser32
SET defines=-D_DEBUG_EG -DGEXPORT -D_CRT_SECURE_NO_WARNINGS

ECHO "Building %assembly%%..."
clang++ %cFilenames% %compilerFlags% -o ../bin/%assembly%.dll %defines% %includeFlags% %linkerFlags%

可执行文件编译命令

SET assembly=testbed
SET compilerFlags=-g 
REM -Wall -Werror
SET includeFlags=-Isrc -I../Engine/src/
SET linkerFlags=-L../bin/ -lEngine.lib
SET defines=-D_DEBUG_EG -DGIMPORT
clang++ %cFilenames% %compilerFlags% -o ../bin/%assembly%.exe %defines% %includeFlags% %linkerFlags%

链接错误信息

创建库..\bin\testbed.lib和对象..\bin\testbed.exp
entry-3b33f2.o : error LNK2019: 未解析的外部符号"public: virtual __cdecl game::~game(void)" (??1game@@UEAA@XZ),该符号在函数"public: virtual __cdecl myGame::~myGame(void)" (??1myGame@@UEAA@XZ)中被引用
..\bin\testbed.exe : fatal error LNK1120: 1个未解析的外部符号

问题分析与解决

核心问题1:基类game的析构函数只有声明无定义

你在BaseGame.h中声明了virtual ~game();,但未在共享库的源文件中提供实现。子类myGame的析构函数执行时会自动调用基类析构,链接器找不到该实现就会报错。

解决方法:在共享库的源文件(比如Application.cpp或新增BaseGame.cpp)中添加析构函数定义:

#include "BaseGame.h"

game::~game() = default;

核心问题2:导出/导入宏未正确切换

当前直接写__declspec(dllexport),但编译可执行文件时应该用__declspec(dllimport)导入类,否则会导致符号解析异常。

优化方案:修改BaseGame.h,用宏切换导出/导入:

#ifdef GEXPORT
#define GAME_API __declspec(dllexport)
#else
#define GAME_API __declspec(dllimport)
#endif

class GAME_API game
{
public:
    game() = default;
    virtual ~game() = default; // 也可直接在这里默认定义,无需单独写源文件
    virtual bool initialize() =0;
    virtual bool update(float deltaTime) =0;
    virtual bool render(float deltaTime) =0;
    virtual void on_resize() =0;
};

编译共享库时已定义GEXPORT,会自动导出类;编译可执行文件时定义GIMPORT,此时GEXPORT未定义,会自动用dllimport导入类,确保符号正确解析。

额外注意点

  • 确保共享库编译时包含所有必要源文件(比如新增BaseGame.cpp要加入%cFilenames%)。
  • 检查可执行文件编译时的链接路径-L../bin/是否正确,确保能找到Engine.lib。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:27:21