Я понял, как это сделать. Спасибо всем за ваши предложения! Это в конечном итоге привело меня к конечному результату.
В качестве нападающего я хотел бы упомянуть результаты, которые я получил с предложениями.
@ DarkDust
Я реализовал ваше предложение, в котором модуль "area" дал главной функции указатель на ее методы. Это сработало, но результаты были такими же, как в первом посте. Это привело меня к мысли, что оба скомпилированных файла .c имеют свои собственные экземпляры функций play_sfx, move_actor, set_name и т. Д. Однако ваше предложение привело меня к возможному ответу на мой вопрос.
@ nos & @caf
Ты прав. Не имело никакого смысла компилировать в game.o в общую библиотеку. Все, что было сделано, - это создать два отдельных экземпляра программы ... что, во-первых, не то, что я хотел.
Я также сделал общую библиотеку не связанной с game.o. Когда я запустил программу, она сказала, что не может найти символ set_game.
На диаграмме ниже показано, что я ожидал, что на самом деле произошло и что было сделано для решения проблемы:
How I expected it to work:
+--------------------+ +----------------+
| area.h | | game.h |
| | | |
| call set_name() --------->set_name() |
| | | |
+--------------------+ +----------------+
How it actually happened:
+-------------------------------+ +-----------------------------+
| area.h | | game.h |
| | | |
| call set_name() -->set_name() | | set_name() <-- never called |
| | | |
+-------------------------------+ +-----------------------------+
How I resolved the issue:
+-------------------------------+ +-----------------------------+
| area.h | | game.h |
| | | |
| init(*p) { | | init(*game_api_ref) |
| *api = p; | | |
| api->set_name() ----------------->set_name() |
| } | | |
| | | |
+-------------------------------+ +-----------------------------+
Вот мое последнее доказательство концепции. В идеале мне бы хотелось, чтобы это работало как первый пример, но я отвлекся. То, как я это сделал, на самом деле позволяет очень легко перекомпилировать модули областей, если есть ошибка только в одной из областей. Я не знаю, понесу ли я какие-либо огромные накладные расходы, делая это таким образом.
api.h
#ifndef _API_H
#define _API_H
typedef struct
{
int (*play_sfx)(int, int, int);
int (*move_actor)(int, int, int);
int (*set_name)(char*);
char* (*get_name)(void);
} api_methods;
#endif
area.c
#include <stdlib.h>
#include "api.h"
static api_methods *api = NULL;
int init(api_methods *p)
{
api = p;
api->set_name("area 1");
return 1;
}
game.c
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include "api.h"
/**
* Exposed API methods
*/
int play_sfx(int, int, int);
int move_actor(int, int, int);
int set_name(char*);
char* get_name(void);
/***** State machine variables *****/
// Name of area
static char *name = 0;
int main()
{
// Setup API methods
api_methods *api = (api_methods*) malloc(sizeof(api_methods));
api->play_sfx = &play_sfx;
api->move_actor = &move_actor;
api->set_name = &set_name;
api->get_name = &get_name;
// Load & initialize area file
void *handle = dlopen("./libarea.so", RTLD_LAZY);
int (*init)() = dlsym(handle, "init");
init(api);
printf("Name: %s\n", get_name());
free(api);
dlclose(handle);
return 0;
}
int play_sfx(int id, int times, int volume)
{
// @todo Execute API call to play sfx
return 1;
}
int move_actor(int id, int x, int y)
{
// @todo Execute API call to move actor
return 1;
}
int set_name(char *p)
{
name = p;
return 1;
}
char* get_name(void)
{
return name;
}
build.sh
#!/bin/bash
gcc -fPIC -o area.o -c area.c
gcc -shared -o libarea.so area.o
gcc game.c -o game -ldl
Я не на той же машине, на которой работал, когда впервые создал вопрос, поэтому проверю ответ DarkDust в качестве решения проблемы завтра.
Еще раз спасибо всем! Если у вас есть какие-либо предложения о том, как заставить это работать, как в первом примере, мне все равно было бы интересно услышать ваш ответ. Я подозреваю, что это либо проблема со связыванием, либо я неправильно объявляю прототипы функций. В любом случае это должно работать для того, что мне нужно.