• C++问题:在共享库 clang 中创建入口点时未定义的引用


    问题描述:

    我有一个我不明白的问题。我的项目现在很简单。我有一个由我的可执行文件调用的共享库引擎。我试图在我的共享库中移动入口点,所以可执行部分只有函数和一些要创建的类。

    为此,我的共享库中有这些文件:

    1. entry.h

    2. BaseGame.h

    3. Application.cpp

    这是entry.h

    1. #include "BaseGame.h"
    2. extern game* create_game();
    3. int main(int argc, char *argv[])
    4. {
    5. auto testgame = create_game();
    6. delete testgame;
    7. return 0;
    8. }

    BaseGame.h

    1. class __declspec(dllexport) game
    2. {
    3. public:
    4. game() = default;
    5. virtual ~game();
    6. virtual bool initialize() =0;
    7. virtual bool update(float deltaTime) =0;
    8. virtual bool render(float deltaTime) =0;
    9. virtual void on_resize() =0;
    10. };

    Application.cpp

    1. #include "BaseGame.h"
    2. class __declspec(dllexport) Application
    3. {
    4. public:
    5. Application()=default;
    6. ~Application()=default;
    7. };

    在我的可执行文件中,我有两个文件 entry.cpp 定义了 create_game 和 my_game.h ,它们继承自游戏。

    entry.cpp

    1. #include
    2. #include "my_game.h"
    3. game* create_game()
    4. {
    5. return new myGame;
    6. }

    and my_game.h:

    1. class myGame : public game
    2. {
    3. public:
    4. myGame(){};
    5. ~myGame() override = default;
    6. bool initialize() override;
    7. bool update(float deltaTime) override;
    8. bool render(float deltaTime) override;
    9. void on_resize() override;
    10. };

    my_game.cpp:

    1. #include "my_game.h"
    2. bool myGame::initialize()
    3. {
    4. return true;
    5. }
    6. bool myGame::update(float deltaTime)
    7. {
    8. return true;
    9. }
    10. bool myGame::render(float deltaTime)
    11. {
    12. return true;
    13. }
    14. void myGame::on_resize()
    15. {
    16. }

    我不明白的是,我在构建我的 exe 时总是遇到链接器错误:

    1. Création de la bibliothèque ..\bin\testbed.lib et de l'objet ..\bin\testbed.exp
    2. entry-3b33f2.o : error LNK2019: symbole externe non résolu "public: virtual __cdecl game::~game(void)" (??1game@@UEAA@XZ) référencé dans la fonction "public: virtual __cdecl myGame::~myGame(void)" (??1myGame@@UEAA@XZ)
    3. ..\bin\testbed.exe : fatal error LNK1120: 1 externes non résolus

    这也是我构建共享库的方式:

    1. SET assembly=Engine
    2. SET compilerFlags=-g -shared -Wvarargs -Wall -Werror
    3. SET includeFlags=-Isrc
    4. SET linkerFlags=-luser32
    5. SET defines=-D_DEBUG_EG -DGEXPORT -D_CRT_SECURE_NO_WARNINGS
    6. ECHO "Building %assembly%%..."
    7. clang++ %cFilenames% %compilerFlags% -o ../bin/%assembly%.dll %defines% %includeFlags% %linkerFlags%

    这是我的可执行文件:

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

    即使游戏被导出。有人看出什么不对了吗?PS:我使用 Clang 作为编译器。

    解决思路一:

    你的例子并不完整。我假设析构函数~game()实际上是在共享库的某个 cpp 文件中定义的。并且my_game.h需要包括BaseGame.h(因为myGame源自game)。所以基本上my_game.cpp在可执行文件中最终会看到game如图所示的定义,包括__declspec(dllexport). 但是,可执行文件不应该看到__declspec(dllexport)(即 exe 不应该 export game),而是应该看到__declspec(dllimport)(即 exe 应该import game)。因此,您想在构建 dll 和构建可执行文件时定义gamewith 。__declspec(dllexport)__declspec(dllimport)

    有条件地拥有一个或另一个的典型方法是使用宏并根据预处理器符号更改其定义,这对于 exe 和 dll 是不同的。例如(改编自官方文档):

    1. // Either in BaseGame.h or in a dedicated header
    2. // that gets included by BaseGame.h.
    3. #ifdef EXPORT_GAME_SYMBOLS
    4. #define GAME_DECLSPEC __declspec(dllexport)
    5. #else
    6. #define GAME_DECLSPEC __declspec(dllimport)
    7. #endif
    8. // BaseGame.h
    9. class GAME_DECLSPEC game
    10. { ... class definition ... };

    在构建 dll 时,您确实EXPORT_GAME_SYMBOLS在预处理器 ( -DEXPORT_GAME_SYMBOLS) 中进行了定义。但是在构建可执行文件时,您没有定义EXPORT_GAME_SYMBOLS.

    链接器仅抱怨析构函数,game因为在您的示例中只有析构函数具有非内联实现。默认构造函数是 inline ( game() = default;,意味着链接器不需要导出来找到实现),其他函数是纯函数(意味着它们没有开始的实现)。因此,这里的替代方法是完全删除导出/导入内容game并定义内联的析构函数(virtual ~game() = default;)。但是当然,如果一切都是内联的,你不需要构建一个共享库开始......

    旁注:

    __declspec(dllexport)on没有意义,Application因为它在.cppdll 的文件中,这意味着可执行文件中的代码永远看不到Application. (除非你#include "Application.cpp",你不应该这样做。)所以不需要导出符号。

    正如其他人所指出的,main()在头文件中包含 是不常见的。您可以将它移动到您的 exe 项目中,例如my_game.cpp或专用main.cpp。

    解决思路二(解决编者问题的思路):

    该类game缺少析构函数定义。我建议这样做default:

    以上仅为部分解决思路介绍,请查看全部内容,请添加下方公众号后回复001,即可查看。

    公众号有许多评分最高的编程书籍和其它实用工具,绝对好用,可以放心使用

    如果您觉得收到帮助,也可以关注公众号——定期发布有用的资讯和资源​

  • 相关阅读:
    行业内口碑好值得信赖的短网址,让你不再选择恐惧
    UE4/5:通过Blender制作BlendShape导入【UE4/5曲线、变形目标,blender形态键】
    day2_QT
    电子元器件销售ERP管理系统哪个比较好?
    Vue项目案例-头条新闻
    制作一个简单HTML静态网页(HTML+CSS)
    求截面面积(vtk)-1
    springboot - 手写spring mvc
    AVL树的插入(C++实现)
    单目标应用:基于白鲨优化算法(WSO)优化极限学习机(ELM)的数据预测(ELM隐藏层神经元可修改,提供MATLAB代码)
  • 原文地址:https://blog.csdn.net/qq_38334677/article/details/126093105