/*************************************************************************** gbx_library.c (c) 2000-2017 Benoît Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #define __GBX_LIBRARY_C #ifdef HAVE_CONFIG_H #include #endif #include "gb_common.h" #include "gb_common_buffer.h" #include "gb_common_case.h" #include "gb_error.h" #include "gb_alloc.h" #include "gb_replace.h" #include "gb_magic.h" #include #include #include #include #include #include "gb_error.h" #include "gbx_class.h" #include "gbx_exec.h" #include "gbx_event.h" #include "gbx_stack.h" #include "gb_file.h" #include "gbx_archive.h" #include "gbx_project.h" #include "gbx_api.h" #include "gbx_string.h" #include "gbx_object.h" #include "gbx_component.h" #include "gb.jit.h" #include "gbx_library.h" //#define DEBUG //#define DEBUG_PRELOAD // Maximum size of a project or startup file // This avoids reading too much in the archive file! #define MAX_SIZE 2048 int _bytes_read = 0; #if 0 static lt_ptr library_malloc(size_t size) { lt_ptr ptr; ALLOC(&ptr, size, "library_malloc"); printf("library_malloc: %d -> %p\n", size, ptr); return ptr; } static void library_free(lt_ptr ptr) { printf("library_free -> %p\n", ptr); FREE(&ptr, "library_free"); } #endif static void *get_symbol(LIBRARY *lib, const char *symbol, bool err) { void *sym; sym = lt_dlsym(lib->handle, symbol); if (sym == NULL && err) { strcpy(COMMON_buffer, lt_dlerror()); lt_dlclose(lib->handle); lib->handle = NULL; THROW(E_LIBRARY, lib->name, COMMON_buffer); } return sym; } static void copy_interface(void **src, void **dst) { for(;;) { if (!*src) return; *dst++ = *src++; } } void LIBRARY_init(void) { /*if (putenv("LD_BIND_NOW=true")) ERROR_panic("Cannot set LD_BIND_NOW: &1", strerror(errno)); if (putenv("KDE_MALLOC=0")) ERROR_panic("Cannot set KDE_MALLOC: &1", strerror(errno));*/ /*lt_dlmalloc = library_malloc; lt_dlfree = library_free;*/ #ifndef DONT_USE_LTDL if (lt_dlinit()) ERROR_panic("Cannot initialize plug-in management: %s", lt_dlerror()); #endif } void LIBRARY_exit(void) { #ifndef DONT_USE_LTDL lt_dlexit(); #endif } void LIBRARY_get_interface(LIBRARY *lib, int version, void *iface) { char symbol[32]; int i, len; char c; len = strlen(lib->name); for (i = 0; i < len; i++) { c = toupper(lib->name[i]); if (!isalnum((unsigned char)c)) c = '_'; symbol[i] = c; } sprintf(&symbol[len], "_%d", version); copy_interface((void **)get_symbol(lib, symbol, TRUE), iface); } bool LIBRARY_get_interface_by_name(const char *name, int version, void *iface) { COMPONENT *comp; comp = COMPONENT_find(name); if (!comp || !comp->library) return TRUE; LIBRARY_get_interface(comp->library, version, iface); return FALSE; } LIBRARY *LIBRARY_create(const char *name) { LIBRARY *lib; ALLOC_ZERO(&lib, sizeof(LIBRARY)); lib->handle = NULL; lib->name = name; /*if (name) { lib->persistent = FALSE; lib->preload = FALSE; } else { lib->persistent = TRUE; lib->preload = TRUE; }*/ return lib; } void LIBRARY_delete(LIBRARY *lib) { LIBRARY_unload(lib); FREE(&lib); } static void init_interface(LIBRARY *lib, const char *sym, const char *sym_ptr, void **api) { void **iface; iface = get_symbol(lib, sym_ptr, FALSE); if (iface) { *((void **)iface) = api; return; } iface = get_symbol(lib, sym, FALSE); if (iface) copy_interface(api, iface); } int LIBRARY_load(LIBRARY *lib) { int (*func)(); GB_DESC **desc; char *path; int order = 0; if (lib->handle) return 0; #ifdef DEBUG clock_t t = clock(); fprintf(stderr, "Loading library %s\n", lib->name); #endif path = FILE_buffer(); sprintf(path, LIB_PATTERN, COMPONENT_path, lib->name); //if (!FILE_exist(path)) // sprintf(path, LIB_PATTERN, COMPONENT_user_path, lib->name); #ifndef DONT_USE_LTDL /* no more available in libltld ? lt_dlopen_flag = RTLD_LAZY; */ lib->handle = lt_dlopenext(path); #else lib->handle = dlopen(path, RTLD_LAZY); #endif if (lib->handle == NULL) THROW(E_LIBRARY, lib->name, lt_dlerror()); func = get_symbol(lib, LIB_INIT, TRUE); /* Interface de Gambas */ init_interface(lib, LIB_GAMBAS, LIB_GAMBAS "_PTR", GAMBAS_Api); init_interface(lib, LIB_JIT, LIB_JIT "_PTR", GAMBAS_JitApi); /* Signal function */ lib->signal = (void(*)())get_symbol(lib, LIB_SIGNAL, FALSE); lib->info = (int(*)())get_symbol(lib, LIB_INFO, FALSE); /* Initialisation */ order = (*func)(); /* Déclaration des classes */ desc = get_symbol(lib, LIB_CLASS, FALSE); if (desc) LIBRARY_declare(desc); #ifdef DEBUG fprintf(stderr, "Library %s loaded ", lib->name); fprintf(stderr, "in %g s\n", ((double)(clock() - t) / CLOCKS_PER_SEC)); #endif return order; } void LIBRARY_after_init(LIBRARY *lib) { void (*func)(); func = get_symbol(lib, LIB_AFTER_INIT, FALSE); if (func) (*func)(); } void LIBRARY_exec(LIBRARY *lib, int argc, char **argv) { void (*func)(); func = get_symbol(lib, LIB_MAIN, FALSE); if (func) (*func)(argc, argv); } void LIBRARY_declare_one(GB_DESC *desc) { CLASS_find_global(desc->name); if (CLASS_register(desc) == NULL) THROW(E_REGISTER, desc->name); } void LIBRARY_declare(GB_DESC **desc) { GB_DESC **p; p = desc; while (*p != NULL) { CLASS_find_global((*p)->name); p++; } p = desc; while (*p != NULL) { if (CLASS_register(*p) == NULL) THROW(E_REGISTER, (*p)->name); p++; } } void LIBRARY_unload(LIBRARY *lib) { void (*gambas_exit)(); if (lib->handle == NULL) return; /* Pas de lib�ation des classes pr�harg� ! */ /* V�ification qu'aucune classe de la librairie n'est instanci� ! */ gambas_exit = lt_dlsym(lib->handle, LIB_EXIT); if (gambas_exit != NULL) (*gambas_exit)(); if (lib->persistent) { gambas_exit = lt_dlsym(lib->handle, "_fini"); if (gambas_exit != NULL) (*gambas_exit)(); } else { lt_dlclose(lib->handle); } lib->handle = NULL; #ifdef DEBUG printf("Unloading library %s\n", lib->name); #endif }