C共享库问题

标签 c compilation shared dlopen

背景:

我正在尝试用 C 开发一个类似于 Zelda (NES) 的简单游戏,作为学习 C 的一种方式。我得出的结论是将所有游戏数据放在一个文件中并不理想。所以我想做的是将每个“区域”分解成它自己的模块。这个“区域”模块将向主程序描述它的属性,例如瓦片 map 、触发特定事件的函数,以及调用主程序的游戏 API 来操作 Actor /声音/等。屏幕上。因此,这些模块必须在运行时加载/卸载。本质上,主程序是一个状态机,它处理从这个“区域”模块提供给它的任何数据。

我已经尝试创建这些共享模块,但似乎主程序中定义的函数对区域模块不可见(至少不在同一范围内)。我确定这是因为我链接不正确。所以我所做的是尝试提出一个可行的概念证明。以下是我失败的概念证明:

api.h

#ifndef _API_H
#define _API_H

static char *name = 0;

extern int play_sfx(int, int, int);
extern int move_actor(int, int, int);
extern int set_name(char*);
extern char* get_name(void);

#endif

区域.c

#include "api.h"

extern int init(void)
{
    int ret = set_name("area 1");
    return ret;
}

game.c

#include <stdio.h>
#include <dlfcn.h>

#include "api.h"

int main()
{
    void *handle = dlopen("/home/eric/tmp/build_shared5/libarea.so", RTLD_LAZY);
    int (*test)(void) = dlsym(handle, "init");
    (*test)();
    dlclose(handle);
    printf("Name: %s\n", get_name());
    return 0;
}

extern int play_sfx(int id, int times, int volume)
{
    // @todo Execute API call to play sfx
    return 1;
}

extern int move_actor(int id, int x, int y)
{
    // @todo Execute API call to move actor
    return 1;
}

extern int set_name(char *p)
{
    name = p;

    return 1;
}

extern char* get_name(void)
{
    return name;
}

build.sh

#!/bin/bash
gcc -o game.o -c game.c
gcc -fPIC -o area.o -c area.c
#,--no-undefined
gcc -shared -Wl,-soname,libarea.so.1 -o libarea.so game.o area.o
gcc -o game game.o -ldl

构建:

$./build.sh

程序产生:

$./游戏

姓名:(空)

我希望看到:名称:区域 1

我正在尝试做的事情是否可行?如果没有,我有另一个想法,就是将所有 API 调用注册到区域模块……但对我来说,这是理想的。

机器信息:gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3。

最佳答案

您的 .h 文件中有 static char *name = 0;,这会引起混淆。

您的 area.c 包含 app.h 并将获得一个 char *name 仅在其翻译单元中可见,因为它是静态的。

您的 game.c 还包含 app.h 并将获得另一个 char *name 变量。因此 area.c 看到的 name 与 game.c 看到的不一样,并且在它们各自的 .c 文件之外都不可见。 您可以在共享库和主要可执行文件上运行 nm 来验证这一点。两者都应该有一个 provate name symbol

extern char *name; 放在 app.h 中而不是 static char *name; 并将 char *name; 放在文件的某处game.c 中的作用域

(虽然我有点不确定在使用动态加载共享库时是否会正确解析)。

关于C共享库问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3773196/

相关文章:

c - C 是否有任何用于执行字符串添加的工具?

c - 需要扩展库才能使用 PG_MODULE_MAGIC 宏

compilation - 为什么 llvm-build 看不到自定义后端?

vb.net - 声明共享 MustOverride

c++ - 为什么我的 C++ 链接器仅在删除 boost 共享目标文件后才起作用?

c++ - lldb 调试器无法打印结构内容

c - if-else 或 switch-case 的最快替代方案

c - 在编译期间将展开的宏打印到文件

c++ - GCC -flto 更改符号可见性

c++ - 无法在 std::map<std::string,std::shared_ptr<class>> 中设置值