2013-04-15 5 views
2

Это мой первый пост, и я стараюсь придерживаться правил форума. Я знаю, что этот вопрос задавался несколько раз раньше, но предоставленные решения не работают для меня. Я не совсем понимаю, почему это так, наверное, я что-то упустил.символы доступа внутри приложения из общего объекта Windows/MinGW

Я хочу получить доступ из общих модулей (.so) символов (переменных и функций), которые находятся внутри основного приложения. Я всегда получаю ошибки ссылок («неопределенная ссылка»).

Сценарий подобно тому, как описано здесь, с одной expection, что я использую обычный C вместо C++:

shared object can't find symbols in main binary, C++

Может быть, эта разница является причиной, что предлагаемое решение не работает. Я использую 32-битную MinGW, версию 4.6.2 под 32-разрядной Windows (если это имеет значение, XP).

Я также читал эти сообщения:

Receive "undefined symbol" error when loading library with dlopen

Dynamic loading and symbols sharing

Can I access to symbols of the host proccess from a shared object loaded in runtime? Any alternative?

Последнее решение будет работать, я думаю, но это не вариант, потому что это перенесение проект от Linux со 100 + символами. Это плагиновая система, и я не хочу ограничивать возможности, доступные для плагинов.

Я пробовал несколько переключателей командной строки при связывании основного приложения, например -rdynamic (по-видимому, не поддерживается в MinGW), --export-all-symbols, --export-dynamic. Я также пробовал различные параметры командной строки при связывании разделяемой библиотеки, например, --allow-shlib-undefined, --enable-auto-import, --enable-runtime-pseudo-reloc

Приложение представляет собой приложение для Linux и там хорошо работает; Мне удалось заставить его работать под Mac OSX (Дарвин). Там я не должен разделять основной исполняемый файл приложения во время ссылки и указывать имя приложения «-bundle -bundle_loader» при связывании общих объектов.

Большое спасибо заранее!

Johannes

ответ

0

Ну, я обнаружил себя с некоторой помощью CodeGuru форума (см http://forums.codeguru.com/showthread.php?536343-RESOLVED-accessing-symbols-in-appllication-from-within-dynamic-library-MinGW).

Решение не так, как я думал сначала - некоторый вариант для компоновщика; по-видимому, автоматическая обратная связь невозможна в Windows. Вы должны вручную загрузить символы, которые хотите использовать из основного приложения во время выполнения; аналогично тому, когда вы вручную загружаете DLL.

Я сделал небольшой тест и демонстрационный проект:

файл "my_app.c":

#include <stdio.h> 
#include <stdlib.h> 

#include "my_app.h" 
#include "plugins.h" 

int a; 
int b; 
Plugin *P; 

void hello() 
{ 
    printf ("Hello World!\n"); 
} 

int main() 
{ 
    char choice; 
    char buf[BUFLEN]; 
    char *plugin_name=NULL; 
    Plugin *p=NULL; 

    do 
    { 
    printf ("\n --- Menu items ---\n"); 
    printf (" '1' .. select plugin\n"); 
    printf (" '2' .. load plugin\n"); 
    printf (" '3' .. execute plugin function\n"); 
    printf (" '4' .. unload plugin\n"); 
    printf (" 'x' .. exit\n"); 
    printf ("\n Your choice: "); 

    fgets (buf, sizeof(buf), stdin); 
    putchar ('\n'); 
    choice = buf[0]; 
    switch (choice) 
    { 
     case '1': 
     plugin_name = plugin_select(); 
     break; 
     case '2': 
     if (plugin_name) 
     { 
      p = plugin_load (plugin_name); 
      if (p) 
      printf ("Plugin '%s' loaded successfully\n", plugin_name); 
      P = p; 
     } else 
      printf ("No plugin selected\n");  
     break; 
     case '3': 
     if (p) 
     { 
      printf ("Enter the 1st number: "); 
      fgets (buf, sizeof(buf), stdin); 
      a = atoi (buf); 
      printf ("Enter the 2nd number: "); 
      fgets (buf, sizeof(buf), stdin); 
      b = atoi (buf); 
      printf ("\nExecuting the plugin '%s' ...\n", plugin_name); 
      plugin_action (p); 
     } else 
      printf ("No plugin loaded\n"); 
     break; 
     case '4': 
     if (p) 
     { 
      plugin_destroy (p); 
      p = NULL; 
      P = NULL; 
     } else 
      printf ("No plugin loaded\n"); 
     break; 
    } 
    } while (choice != 'x'); 

    return 0; 
} 

файл "my_app.h":

#ifndef __MYAPP_H 
#define __MYAPP_H 

#include "plugins.h" 

#define TRUE 1 
#define FALSE 0 

#define BUFLEN 120 

extern int a; 
extern int b; 

extern void hello (void); 

extern Plugin *P; 

#endif /* __MYAPP_H */ 

файл «плагинов.с ":

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <dlfcn.h> 

#include "my_app.h" 
#include "plugins.h" 

Plugin *plugin_load (const char *filename) 
{ 
    Plugin *p; 
    int (*init)(Plugin *); 

    p = malloc (sizeof(Plugin)); 
    if (p == NULL) 
    { 
    printf ("Couldn't allocate Plugin object\n"); 
    return NULL; 
    } 
    strncpy (p->filename, filename, sizeof(p->filename)); 
    if ((p->module = dlopen(p->filename, RTLD_LAZY)) == NULL) 
    { 
    printf ("%s\n", dlerror()); 
    free (p); 
    return NULL; 
    } 

    init = dlsym (p->module, "init_plugin"); 
    if (init == NULL) 
    { 
    printf ("%s\n", dlerror()); 
    free (p); 
    return NULL; 
    } 

    if (!init(p)) 
    { 
    perror ("Couldn't initialize plugin"); 
    free (p); 
    return NULL; 
    } 

    p->load = TRUE; 
    return p; 
} 

void plugin_action (Plugin *p) 
{ 
    if (p == NULL) 
    { 
    printf ("Plugin not found!\n"); 
    return; 
    } 
    p->plugin_cb(); 
} 

char *plugin_select() 
{ 
    DIR *dp; 
    struct dirent *e; 
    static char buf[BUFLEN]; 
    char *p; 
    size_t len; 
    char *suffix; 

    dp = opendir ("."); 
    if (dp == NULL) 
    { 
    perror ("Cannot open '.'"); 
    return NULL; 
    } 
    printf ("\nFollowing plugins are available:\n"); 
    while ((e=readdir(dp)) != NULL) 
    { 
    suffix = strrchr (e->d_name, '.'); 
    if (suffix) 
    { 
     if (strcmp (suffix, PLUGIN_SUFFIX) == 0) 
     printf (" %s\n", e->d_name); 
    } 
    } 
    closedir (dp); 
    printf ("Your choice: "); 
    buf[0] = '.'; 
    buf[1] = '/'; 
    p = &buf[2]; 
    fgets (p, sizeof(buf)-2, stdin); 
    len = strlen (buf); 
    if (len > 0) 
    len --; 
    buf[len] = '\0'; 
    if (strchr(p, '.') == NULL) 
    strcat (buf, PLUGIN_SUFFIX); 

    return buf; 
} 

void plugin_destroy (Plugin *p) 
{ 
    void (*unload)(Plugin *); 

    unload = dlsym (p->module, "unload_plugin"); 
    if (unload != NULL) 
    unload (p); 

    dlclose (p->module); 
    free (p); 
} 

файл "plugins.h":

#ifndef __PLUGINS_H 
#define __PLUGINS_H 

#include <limits.h>   /*PATH_MAX */ 

#define PLUGIN_SUFFIX ".so" 

typedef struct _Plugin 
{ 
    char filename[PATH_MAX]; 
    char *name; 
    char *description; 
    unsigned int show_in_menu; 
    unsigned int load; 
    void *module; 
    void (*plugin_cb)(); 
} Plugin; 

Plugin *plugin_load (const char *filename); 
void plugin_action (Plugin *p); 
char *plugin_select (void); 
void plugin_destroy (Plugin *p); 

#endif /* __PLUGINS_H */ 

Теперь плагины:

Скрыть противные объявления указателя функции и т.д .: "plugin_macros.h":

#ifndef __PLUGIN_MACROS_H 
#define __PLUGIN_MACROS_H 

#ifdef WIN32 
#include <windows.h> 

#define DECLARE_FUNC(type,name,par) typedef type (WINAPI *name ## _t)par; static name ## _t name; 
#define DECLARE_VAR(type,name) static type * p ## name; 
#define DECLARE_PTR(type,name) static type *name; 

#define LOAD_FUNCC(name) if((name=(name ## _t)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0 
#define LOAD_FUNC(name) (name=(name ## _t)GetProcAddress(GetModuleHandle(NULL),#name)) 

#define LOAD_VARC(type,name) if((p ## name=(type *)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0 
#define LOAD_VAR(type,name) (name=(type *)GetProcAddress(GetModuleHandle(NULL),#name)) 

#define LOAD_PTRC(type,name) if((name=*(type **)GetProcAddress(GetModuleHandle(NULL),#name))==NULL) return 0 
#define LOAD_PTR(type,name) (name=*(type **)GetProcAddress(GetModuleHandle(NULL),#name)) 

#else 
/* not WIN32 */ 
#define DECLARE_FUNC(type,name,par) 
#define DECLARE_VAR(type,name) 
#define DECLARE_PTR(type,name) 

#define LOAD_FUNCC(name) 
#define LOAD_FUNC(name) 

#define LOAD_VARC(type,name) 
#define LOAD_VAR(type,name) 

#define LOAD_PTRC(type,name) 
#define LOAD_PTR(type,name) 
#endif 

#endif /* __PLUGIN_MACROS_H */ 

файл "add.c":

#include <stdio.h> 

#include "plugins.h" 
#include "plugin_macros.h" 

#ifdef WIN32 
#include <windows.h> 

DECLARE_FUNC(void, hello, (void)); 
DECLARE_VAR(int, a); 
DECLARE_VAR(int, b); 
DECLARE_PTR(Plugin, P); 

#define a (*pa) 
#define b (*pb) 

#else 
#include "my_app.h" 
#endif 


static void add() 
{ 
    hello(); 
    LOAD_PTR(Plugin, P); 
    printf ("name=%s\n", P->name); 
    printf ("description=%s\n\n", P->description); 
    printf ("%d + %d = %d\n", a, b, a+b); 
} 

int init_plugin (Plugin *p) 
{ 
    LOAD_FUNCC(hello); 
    LOAD_VARC(int, a); 
    LOAD_VARC(int, b); 

    p->name = "Add"; 
    p->description = "Add two integers."; 
    p->plugin_cb = add; 
    P = p; 

    return TRUE; 
} 

файл "multiply.c":

#include <stdio.h> 

#include "plugins.h" 
#include "plugin_macros.h" 

#ifdef WIN32 
#include <windows.h> 

DECLARE_VAR(int, a); 
DECLARE_VAR(int, b); 
DECLARE_PTR(Plugin, P); 

#define a (*pa) 
#define b (*pb) 

#else 
#include "my_app.h" 
#endif 

static void multiply() 
{ 
    LOAD_PTR(Plugin, P); 
    printf ("name=%s\n", P->name); 
    printf ("description=%s\n\n", P->description); 
    printf ("%d * %d = %d\n", a, b, a*b); 
} 

int init_plugin (Plugin *p) 
{ 
    LOAD_VARC(int, a); 
    LOAD_VARC(int, b); 

    p->name = "Multiply"; 
    p->description = "Multiply two integers."; 
    p->plugin_cb = multiply; 
    P = p; 

    return TRUE; 
} 

... и Makefile:

ifeq ($(OS), Windows_NT) 
    TARGET = plugintest.exe 
    CC = $(MINGW)\bin\gcc.exe 
    LDFLAGS = -Wl,--export-all-symbols 
    STRIP = -s 
    SHARED = -shared 
    RM = del 
else 
    TARGET = plugintest 
    UNAME := $(shell uname -s) 
    ifeq ($(UNAME),Linux) 
    LDFLAGS = -Wl,--export-dynamic 
    STRIP = -s 
    SHARED = -shared 
    endif 
    ifeq ($(UNAME),Darwin) 
    LDFLAGS = 
    STRIP = 
    SHARED = -bundle -bundle_loader plugintest 
    endif 
    RM = rm -f 
endif 

PLUGINS = add.so multiply.so 
OBJS = my_app.o plugins.o 
LIBS = -ldl 
CFLAGS = -Wall 

all: $(TARGET) my_plugins 

$(TARGET): $(OBJS) 
    $(CC) $(OBJS) $(LIBS) $(LDFLAGS) -o $(TARGET) 

my_app.o: my_app.c my_app.h plugins.h 
    $(CC) $(CFLAGS) -c my_app.c -o my_app.o 

plugins.o: plugins.c my_app.h plugins.h 
    $(CC) $(CFLAGS) -c plugins.c -o plugins.o 

my_plugins: $(PLUGINS) 

add.so: add.c my_app.h plugin_macros.h 
    $(CC) $(CFLAGS) $(SHARED) add.c -o add.so 

multiply.so: multiply.c my_app.h plugin_macros.h 
    $(CC) $(CFLAGS) $(SHARED) multiply.c -o multiply.so 

clean: 
    $(RM) *.o *.so $(TARGET) 

Проект использует POSIX динамической загрузки функции dlopen() и т.д. Они не являются частью установки MinGW, но вы можете скачать здесь:

http://code.google.com/p/dlfcn-win32/

Я надеюсь, что т он помогает другим, которые сталкиваются с одной и той же проблемой. Любые комментарии и вопросы приветствуются!

Johannes

 Смежные вопросы

  • Нет связанных вопросов^_^