I've been testing my C libraries by compiling them into ruby extensions and then using ruby's unit testing to test them. Under Windows I had it all running nicely and I could run a main test script that would invoke all the other test scripts. Sweet.
Then it came to getting it running under linux (the target system) and while the unit tests ran fine individually, when I tried my main test script I was getting weird errors from my test extensions, including segment violations (!).
It took me a while to track down the problem but it turned out to be due to the behaviour of gcc and the linux program loader. All my test libraries were loaded into one ruby process and because they all contained functions with similar names it became a bit of a lottery as to which function in which library was called. I am used to the behaviour of windows dll's where all functions are by default hidden from the outside world unless you explicity export them. gcc/elf/whatever seems to export everything from shared libraries (linux equivalent of a dll) by default with hilarious results.
In version 4 of gcc they have added a facility for hiding these internal functions. I solved my problem as follows:
- Add '-fvisibility=hidden' to the gcc arguments to cause all functions to be hidden by default.
-
Add this code to my stddefs.h:
1 #ifdef _MSC_VER 2 #ifdef BUILDING_DLL 3 #define DLLEXPORT __declspec(dllexport) 4 #else 5 #define DLLEXPORT __declspec(dllimport) 6 #endif 7 #define DLLLOCAL 8 #else 9 #define DLLEXPORT __attribute__ ((visibility("default"))) 10 #define DLLLOCAL __attribute__ ((visibility("hidden"))) 11 #endif
-
Change the functions that ruby calls to load the ruby extension to the following form (i.e. add DLLEXPORT):
1 /* 2 * Initialise the test class. 3 */ 4 DLLEXPORT void Init_testtimer( void) 5 { 6 VALUE oMyClass = rb_define_class( "TestTimer", rb_cObject); 7 rb_define_method( oMyClass, "initialize", test_initialise, 1); 8 rb_define_method( oMyClass, "TimerSet", test_TimerSet, 1); 9 rb_define_method( oMyClass, "TimerUpdate", test_TimerUpdate, 1); 10 rb_define_method( oMyClass, "TimerStart", test_TimerStart, 1); 11 rb_define_method( oMyClass, "TimerTest", test_TimerTest, 0); 12 }
These functions are the only ones that need to be visible outside the library.
Results:


