[Cython] Fwd: Question about how best require compiler options for C sources

Nathaniel Smith njs at vorpus.org
Mon Apr 11 13:05:49 EDT 2016


On Apr 11, 2016 06:23, "Erik Bray" <erik.m.bray at gmail.com> wrote:
>
> On Mon, Apr 11, 2016 at 2:51 PM, Nathaniel Smith <njs at vorpus.org> wrote:
> > Now, back to your example: Here the caller and callee are both compiled
into
> > the same shared library, so you don't want dllexport/dllimport at all,
you
> > just want a shared-library-internal symbol, which as we see is much
easier.
>
> Sorry, I'll respond more to your (helpfully detailed and precise)
> message in a second.  But something I wanted to point out is that my
> example is incomplete and I should have arranged a more complete
> example.  In this case I really do want the symbol "hello" to be
> exported by the DLL, as well as be understood between translation
> units making up the same library.  A more complete example would have
> shown a separate library which links with "foo" and uses the "hello"
> function in it.
>
> Yes, it's arguable that exporting anything more than then initmodule
> function from a Python extension module is not best practice, but the
> possibility should not be ruled out either.
>
> So I think later on you hit correctly on the deeper problem, which is
> that Cython currently doesn't have a great way to distinguish between
> intra-library visibility and *inter*-library visibility.
>
> And if both are needed then some DL_IMPORT-like macro is needed that
> sets the visibility for a symbol correctly depending on the context in
> which it's being used. (And yes, this is not a problem on *nix, but it
> is on Windows due to the way __declspec(dllimport) causes name
> mangling :(

This is highly tangential to the main conversation, but FYI and in the
general interests of demystifying this stuff: the reason for all this
rigmarole on Windows is that dllimport doesn't just cause name mangling, it
causes *type* mangling. The way windows symbol relocations work, is that
you can only import pointers. So code like

  __declspec(dllimport) extern void f(...);
  __declspec(dllimport) extern int myvalue;

is syntactic sugar for something like:

  // pointer that will be filled in by loader
  void (*__imp_f)(...);
  // desugar direct calls into indirect calls
  #define f(...) (*__imp_f)(...)

  // similar
  int *__imp_myint;
  #define myint (*__imp_myint)

...except that (a) instead of using the preprocessor to perform the
substitution, it happens in the compiler frontend, so it can correctly
follow scoping rules and things that the preprocessor can't, and (b) the
linker will also automagically generate a function like

  void f(...) {
      return (*__imp_f)(...);
  }

So there shouldn't still be any mentions of 'f' in the resulting file --
they should all be replaced by mentions of (*__imp_f) -- but just in case
we missed any your code will still work, albeit at the cost of some icache
pollution and an extra indirect jump at every call.

Note in particular that this __imp_ nonsense *isn't* an approximation on my
part, there really will be a shared-library-internal symbol called
__imp_whatever whose value is a pointer that gets filled in my the loader.
(Except possibly I got my underscores wrong -- on phone so too lazy to
check.) You could literally write the code I wrote above with the #define's
and it would actually work on windows...

-n
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cython-devel/attachments/20160411/d7fd0ab5/attachment.html>


More information about the cython-devel mailing list