Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com X-Originating-IP: [64.229.109.49] From: "Glen Ozymok" To: cygwin AT cygwin DOT com Subject: Run time linking a .dll into a .exe Date: Tue, 04 Dec 2001 19:42:57 -0500 Mime-Version: 1.0 Content-Type: text/plain; format=flowed Message-ID: X-OriginalArrivalTime: 05 Dec 2001 00:42:57.0555 (UTC) FILETIME=[C894EE30:01C17D25] I want to create some plugins for an executable. The problem is that when I create a plugin (.dll, shared object, or whatever you want to call it), it sucks in code that is already in the executable. In other words, I link the executable with some static library, libfoo.a, and the executable gets routines from libfoo.a. I then link the dll, and it gets some of the same routines. Normally this would be annoying since you have code duplication, but would work. However, if the code contains static variables, then the executable and the dll have their own versions of the static, which get out of sync. Is there a way to link the dll so that it uses the code inside the executable? Here's a simple example of my problem. I have a Foo class which contains a static to the class. I create a static library (libfoo.a) out of the class code. I create a dll which calls the routines in libfoo.a. I also create an application which also calls routines in libfoo.a, and calls routines in the dll via dlopen() and dlsym() which in turn call routines from libfoo.a. The result is that different versions of the Foo static get set. ============== my_app.cpp ================== #include #include #include "foo_cls.hpp" int main() { cout << "Foo::get_val() = " << Foo::get_val() << endl; cout << "Calling Foo::set_val(7)" << endl; Foo::set_val(7); cout << "Foo::get_val() = " << Foo::get_val() << "\n\n"; void *handle = ::dlopen("bar.dll", RTLD_NOW); if (!handle) { cout << "Unable to open bar.dll.\n"; return(1); } int (*get_val)(void) = (int (*)())::dlsym(handle, "get_val"); void (*set_val)(int) = (void (*)(int))::dlsym(handle, "set_val"); cout << "::get_val() = " << get_val() << endl; cout << "Calling ::set_val(13)" << endl; set_val(13); cout << "::get_val() = " << get_val() << "\n\n"; ::dlclose(handle); cout << "Foo::get_val() = " << Foo::get_val() << endl; return(0); } ============== foo_cls.hpp ================== #ifndef _FOO_CLS_HPP_ #define _FOO_CLS_HPP_ class Foo { public: static void Foo::set_val(int new_val); static int Foo::get_val(); private: static int Foo::_val; }; #endif // _FOO_CLS_HPP_ ============== foo_cls.cpp ================== #include "foo_cls.hpp" int Foo::_val = 0; void Foo::set_val(int new_val) { Foo::_val = new_val; } int Foo::get_val() { return(Foo::_val); } ============== bar.hpp ================== #ifndef _BAR_HPP_ #define _BAR_HPP_ extern "C" { void set_val(int new_val); int get_val(); }; #endif // _BAR_HPP_ ============== bar.cpp ================== #include "bar.hpp" #include "foo_cls.hpp" void set_val(int new_val) { Foo::set_val(new_val); } int get_val() { return(Foo::get_val()); } /************************************************************************/ /* Under Cygwin, we can use the dl family of calls, but we need to jump */ /* through some hoops first. Specifically, we need to include */ /* and we need to use the DECLARE_CYGWIN_DLL() */ /* macro. During the link phase, we must use __cygwin_dll_entry AT 12 as */ /* the entry point. See http://sources.redhat.com/cygwin/dl-docs.html. */ /************************************************************************/ #if defined(__CYGWIN__) #include DECLARE_CYGWIN_DLL(dll_entry); int WINAPI dll_entry( HANDLE , DWORD reason, void *) { switch (reason) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return 1; } #endif /* defined(__CYGWIN__) */ ============== Makefile ================== CYGWIN_DIR = D:/Apps/Cygwin DLL_DIR = . TARGET = my_app.exe LIB = libfoo.a DLL = bar.dll EXE_OBJS = my_app.o DLL_OBJS = bar.o LIB_OBJS = foo_cls.o DLL_DEF_FILE = dll.def DLL_EXP_FILE = dll.exp DLL_BASE_FILE = dll.base CYGWIN_ENTRY_PT = __cygwin_dll_entry AT 12 LIBS = \ -L"$(CYGWIN_DIR)/lib" \ -L"$(CYGWIN_DIR)/lib/gcc-lib/i686-pc-cygwin/2.95.3-4" \ -L"$(CYGWIN_DIR)/lib/w32api" \ -lstdc++ -lgcc -lc -lkernel32 all: $(TARGET) $(DLL) $(TARGET) : $(EXE_OBJS) $(LIB) g++ $(EXE_OBJS) $(LIB) -o $@ --export-dynamic -W -Wall $(LIB) : $(LIB_OBJS) ar ruv $@ $(LIB_OBJS) ranlib $@ $(DLL_DIR)/$(DLL): $(DLL_OBJS) echo EXPORTS > $(DLL_DEF_FILE) nm $(DLL_OBJS) | grep '^........ [BCDT] _' | sed 's/[^_]*_//' \ >> $(DLL_DEF_FILE) ld --base-file $(DLL_BASE_FILE) --dll -o dummy $(DLL_OBJS) $(LIB) \ $(LIBS) -e $(CYGWIN_ENTRY_PT) dlltool --as=as --dllname $(DLL_DIR)/$(DLL) --def $(DLL_DEF_FILE) \ --base-file $(DLL_BASE_FILE) --output-exp $(DLL_EXP_FILE) ld --base-file $(DLL_BASE_FILE) $(DLL_EXP_FILE) --dll \ -o $(DLL_DIR)/$(DLL) $(DLL_OBJS) $(LIB) $(LIBS) -e $(CYGWIN_ENTRY_PT) dlltool --as=as --dllname $(DLL_DIR)/$(DLL) --def $(DLL_DEF_FILE) \ --base-file $(DLL_BASE_FILE) --output-exp $(DLL_EXP_FILE) ld $(DLL_EXP_FILE) --dll -o $(DLL_DIR)/$(DLL) $(DLL_OBJS) $(LIB) \ $(LIBS) -e $(CYGWIN_ENTRY_PT) rm dummy clean: -rm $(EXE_OBJS) $(LIB_OBJS) $(LIB) $(DLL_OBJS) $(DLL_DEF_FILE) \ $(DLL_BASE_FILE) $(DLL_EXP_FILE) clean_all: clean -rm $(DLL_DIR)/$(DLL) $(TARGET) %.o : %.cpp g++ -c $*.cpp -o $*.o -I$(CYGWIN_DIR)/usr/include -W -Wall ============== End of code ================== The output from this is: Foo::get_val() = 0 Calling Foo::set_val(7) Foo::get_val(7) ::get_val() = 0 <-- I want this to be 7. Calling ::set_val(13) ::get_val() = 13 Foo::get_val() = 7 <--I want this to be 13. Under the --export-dynamic option in the ld man page, it says: ". . . If you use dlopen to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself." So it seems what I want to do should be possible. Thanx. - glen _________________________________________________________________ Get your FREE download of MSN Explorer at http://explorer.msn.com/intl.asp -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Bug reporting: http://cygwin.com/bugs.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/