<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Peter's Blog - Nodes for gcc</title>
    <link>http://www.petersblog.org/</link>
    <description>Nodes containing the tag gcc</description>
    <item>
      <title>Problems with Multiple Ruby Extensions</title>
      <link>http://www.petersblog.org/node/view/1572</link>
      <description>&lt;p&gt;
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. 
&lt;/p&gt;
&lt;p&gt;
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 (!). 
&lt;/p&gt;
&lt;p&gt;
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. 
&lt;/p&gt;
&lt;p&gt;
In version 4 of gcc they have added a facility for hiding these internal functions. I solved my problem as follows: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
Add '-fvisibility=hidden' to the gcc arguments to cause all functions to be hidden by default. 
&lt;/li&gt;
&lt;li&gt;
Add this code to my stddefs.h: 
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; #&lt;span class="Keyword"&gt;ifdef&lt;/span&gt; _MSC_VER
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt;   #&lt;span class="Keyword"&gt;ifdef&lt;/span&gt; BUILDING_DLL
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt;     #&lt;span class="Keyword"&gt;define&lt;/span&gt; &lt;span class="Entity"&gt;DLLEXPORT&lt;/span&gt; &lt;span class="Entity"&gt;__declsp&lt;span class="Entity"&gt;ec&lt;/span&gt;&lt;/span&gt;(dllexport)
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt;   #&lt;span class="Keyword"&gt;else&lt;/span&gt;
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt;     #&lt;span class="Keyword"&gt;define&lt;/span&gt; &lt;span class="Entity"&gt;DLLEXPORT&lt;/span&gt; &lt;span class="Entity"&gt;__declsp&lt;span class="Entity"&gt;ec&lt;/span&gt;&lt;/span&gt;(dllimport)
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;   #&lt;span class="Keyword"&gt;endif&lt;/span&gt;
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;   #&lt;span class="Keyword"&gt;define&lt;/span&gt; &lt;span class="Entity"&gt;DLLLOCAL&lt;/span&gt;
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt; #&lt;span class="Keyword"&gt;else&lt;/span&gt;
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;   #&lt;span class="Keyword"&gt;define&lt;/span&gt; &lt;span class="Entity"&gt;DLLEXPORT&lt;/span&gt; __attribute__ ((visibility(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;default&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)))
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt;   #&lt;span class="Keyword"&gt;define&lt;/span&gt; &lt;span class="Entity"&gt;DLLLOCAL&lt;/span&gt; __attribute__ ((visibility(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;hidden&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)))
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt; #&lt;span class="Keyword"&gt;endif&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
Change the functions that ruby calls to load the ruby extension to the following form (i.e. add DLLEXPORT): 
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt; &lt;span class="Comment"&gt; * Initialise the test class.&lt;/span&gt;
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt; &lt;span class="Comment"&gt; &lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt; DLLEXPORT &lt;span class="Keyword"&gt;void&lt;/span&gt; &lt;span class="Entity"&gt;Init_testtim&lt;span class="Entity"&gt;er&lt;/span&gt;&lt;/span&gt;( &lt;span class="Keyword"&gt;void&lt;/span&gt;)
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt; {
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;     VALUE oMyClass = rb_define_class( &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TestTimer&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, rb_cObject);
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;     rb_define_method( oMyClass, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;initialize&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, test_initialise, &lt;span class="Constant"&gt;1&lt;/span&gt;);
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt;     rb_define_method( oMyClass, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TimerSet&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, test_TimerSet, &lt;span class="Constant"&gt;1&lt;/span&gt;);
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;     rb_define_method( oMyClass, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TimerUpdate&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, test_TimerUpdate, &lt;span class="Constant"&gt;1&lt;/span&gt;);
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt;     rb_define_method( oMyClass, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TimerStart&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, test_TimerStart, &lt;span class="Constant"&gt;1&lt;/span&gt;);
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt;     rb_define_method( oMyClass, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TimerTest&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, test_TimerTest, &lt;span class="Constant"&gt;0&lt;/span&gt;);
&lt;span class="line-numbers"&gt;  12 &lt;/span&gt; }
&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
These functions are the only ones that need to be visible outside the library. 
&lt;/p&gt;
&lt;p&gt;
Results: 
&lt;/p&gt;
&lt;div style="text-align:center"&gt;&lt;img src="/images/TestsDone.gif" alt="images/TestsDone.gif"/&gt;&lt;/div&gt; &lt;p&gt;Related Posts: &lt;a href="/tag/c"&gt;c&lt;/a&gt; &lt;a href="/tag/gcc"&gt;gcc&lt;/a&gt; &lt;a href="/tag/linux"&gt;linux&lt;/a&gt; &lt;a href="/tag/ruby"&gt;ruby&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1572</guid>
      <category domain="http://www.technorati.com/tag">c</category>
      <category domain="http://www.technorati.com/tag">gcc</category>
      <category domain="http://www.technorati.com/tag">linux</category>
      <category domain="http://www.technorati.com/tag">ruby</category>
    </item>
  </channel>
</rss>
