[LLVMdev] Feedback required on proper dllexport/import implementation
Nico Rieck
nico.rieck at gmail.com
Tue Apr 23 13:06:52 PDT 2013
On 23.04.2013 19:10, Gao, Yunzhong wrote:
> I missed the discussion when I implemented dllexport/dllimport for our local tree. I
> essentially implemented your approach#1. I was trying to avoid the various
> external_linkage + some_attribute approaches because it seems that external_linkage
> would imply the external linkage without the dllimport/dllexport semantics, and there
> may be existing compiler codes that rely on this semantics. If I used external_linkage
> + some attribute, then any place in existing codes that uses hasExternalLInkage() will
> have to be modified to check both the linkage type as well as the attribute list, which
> seems a bit fragile to maintain; somebody somewhere will forget to check the attributes
> when writing their new optimization or garbage collection passes.
What problems do you expect with another approach? I have a local
prototype that removes dllimport/export as linkage and uses function
attributes and an extension to globals. I decorate dllexported functions
with the Used attribute and it seems to work fine. This allows such
functions to have linkonce_odr and weak_odr linkage and not be discarded.
> I think dllimport inline functions are more closely related to the available_externally
> linkage than linkonce_odr; no COMDAT is involved and no .linkonce discard directive
> is needed. I would name it dllimport_inline or something similar.
Hm, I don't think so, because dllimported inline functions must never be
instantiated, or else you get duplicated symbols. They are only allowed
to be expanded. At the moment I solve this by checking for definitions
during codegen (this means they survived the inliner) and dropping their
body.
> While it makes sense to mimic MSVC behavior and MSDN doc for C++ codes, it is
> not very clear to me what should be the correct semantics when a C99 inline function
> carries a dllimport/dllexport declspec. [...]
> An alternative is to generate an error message whenever a C99 inline function is used
> with a dllimport/dllexport declspec.
I agree. This should be rejected.
> In a similar manner, I wonder what should be the correct semantics of:
> inline __declspec(dllexport) int foo() { return 100; }
>
> I guess I could let dllexport imply "extern", so that an out-of-line definition always gets
> generated, but is that the expected behavior?
Yes, such a function is always instanciated and exported.
> For the following test case, GCC ignores the dllimport attribute with a warning (similar
> to clang's current behavior)
>
> /* test1.c */
> inline __declspec(dllimport) void foo();
> inline void foo();
> inline void foo() { }
> void foo_user() { foo(); }
> /* end of file */
Generally, MSVC allows a dllimport definition if the first declaration
is specified as inline. This test case should import foo() (or expand it
inline).
> But for the following two cases, GCC produces both an out-of-line definition and also a
> reference to an dllimported symbol foo with no diagnostics. It seems wrong, unless
> there is some problem with my build process.
>
> /* test2.c */
> inline void foo();
> __declspec(dllimport) void foo();
> inline void foo() { }
> void foo_user() { foo(); }
> /* end of file */
Having both seems wrong, as it leads to linker errors. MSVC rejects this
code because it does not allow redeclaring a function and adding dllimport.
> /* test3.c */
> inline void foo();
> __declspec(dllimport) void foo();
> __declspec(dllimport) void foo() { } // clang complains that this is a redeclaration without
> // "dllimport" attribute", which seems wrong...
> void foo_user() { foo(); }
> /* end of file */
Same as above.
> What are your thoughts?
I have one issue in mind where I wonder if it's beneficial to be less
strict than MSVC. As stated before, MSVC requires the inline keyword
together with dllimport. This extends to member functions and prevents
out-of-line definitions with inline:
struct X1 {
inline void foo();
void bar();
};
void X::foo() {} // OK
inline void X::bar() {} // Error
Same goes for class and function templates. I stumbled on this in libc++
where internal class templates are externed.
-Nico
More information about the llvm-dev
mailing list