Problem with coupling shared object symbol visibility with protection

Benjamin Thaut via Digitalmars-d digitalmars-d at puremagic.com
Tue Jan 20 04:23:31 PST 2015


I'm currently working on Windows DLL support which has stronger rules 
than linux shared objects for which symbols actually get exported from a 
shared library. But as we want to replicate the same behaviour on linux 
using symbol visibility (e.g. gcc 4 -fVisibility=hidden) this issue also 
applies to linux once implemented.

Currently export means two things:
- the symbol is publicy accessible (same as public)
- the symbol will be accisble across shared library boundaries


This has the following issue:

export void templateFunc(T)()
{
   someHelperFunc();
}

private void someHelperFunc()
{

}

And you don't even have to go into phobos to hit this problem. It is 
already in druntime see core.time.FracSec._enforceValid

This works with the current linux shared objects because they simply 
export all symbols. But once only symbols with export get exported this 
breaks.

The problem here is that you don't want to make someHelperFunc() export 
because that would mean users could call it directly, but you want it to 
be available for cross shared library calls. The cross shared library 
call happens if a template is instanced from a different shared library 
/ executable than the module it was originally located in.

There are two solutions for this.

1) Given that export is transitive (that means if a struct or class is 
declared export every member that is _not_ private will be accessible 
across shared library boundaries. This behaviour is required to make the 
export protection level work on windows)

You can now do the following:

export struct SomeStruct
{
   static public void templateFunc(T)()
   {
     someHelperFunc();
   }

   static package void someHelperFunc()
   {

   }
}

Because of the transitivity someHelperFunc will be exported but still 
not be callable by the user directly. This can be used to fix the issue 
in core.time but may not be so well suited if you want the template to 
be on module level instead of nesting it into a struct.

2) Make export an attribute. If export is no longer an protection level 
but instead an attribute this issue can easily be solved by doing.

export public void templateFunc(T)()
{
   someHelperFunc();
}

export private void someHelperFunc()
{

}

But this would require grammar changes. Which are generally avoided if 
possible.

There would be a third option, which I rather avoid. Doing a 
"pramga(forceExport)" or something like that.

My implementation, which I ran into this issue with, currently usses 
approach 1. What do you think how this sould be solved?

Walter: What was the general idea behind export when you designed it, 
and how can it be used to solve this problem?

Kind Regards
Benjamin Thaut


More information about the Digitalmars-d mailing list