Closed JakeSmarter closed 1 year ago
Is there a specific issue you're having?
The binary API is essentially frozen, there would a lot of reluctance to change this.
I am not requesting to change the binary API. I am just saying that there is neither need for dllimport
nor GLEW_STATIC
, especially when you build GLEW as a static library. Because when you compile an app for Windows to consume GLEW, by default (without GLEW_STATIC
defined) you get __imp_
prefixed external symbols. And, when you try to link your app to GLEW statically you get unresolved symbols. At the same time, you do not need dllimport
when writing code which is going to access symbols in a DLL. dllimport
is a relic of Cygwin. Some will argue that it enables application developers to select on a per symbol level the source of a symbol in the source code when linking to static and dynamic libraries at the same time. However, this decision should and can still be made by the application developer (GLEW’s consumer) in their own code, not in GLEW’s headers.
My perception of dllimport
is that it's rather more conventional than being a "relic of Cygwin". But I do follow your reasoning and think it has technical merit. The practical problem is that if I get this wrong and widespread breakage results, I will likely get flooded with nasty outrage, the internet being how it is. I don't think using and requiring GLEW_STATIC is such a burden, but I admit that I just expect Windows development to be needlessly "annoying" like this.
I guess one thing for me to revise is the implications of having the __imp_
prefix, or not. I do regard that as an ABI change, but what is the risk of that change more broadly?
Using declspec(dllimport) is optional on function declarations, but the compiler produces more efficient code if you use this keyword. However, you must use declspec(dllimport) for the importing executable to access the DLL's public data symbols and objects. Note that the users of your DLL still need to link with an import library.
https://learn.microsoft.com/en-us/cpp/build/importing-and-exporting?view=msvc-170
Use the keywords declspec(dllimport) or declspec(dllexport) in a function definition in the main application
dllexport
is meant for and still used by library authors. dllimport
is/was meant for application authors, especially in the days before import libraries (like WinNT 3.51 and earlier). Application authors should decide which symbol and which not to import from a DLL. This decision should not be made by library headers. Today, this decision is usually made at link‑time by choosing either a static library or an import library (hence the word import in the name :wink:). GLEW produces an import library by default. So yes, technically libraries can make this decision (as GLEW does) but by convention they do not and should not, especially when they provide an import library. In legacy toolchains, I think in pre‑MSVC 6.0, you had to use dllimport
at least on data symbols (this is probably also a reason why dllimport
s have been added throughout GLEW). However, I think since MSVC 6.0, you do not have to do even this anymore. The linkers of all toolchains have been upgraded to do this automatically long time ago. All extern
symbols are just resolved at link‑time, no matter whether they are found in a DLL or a static library. Furthermore, I think since MSVC 7.0 or maybe even earlier, Microsoft has stopped adding __imp_
prefixed symbols to their import library releases.
This is the only hint of that transition I could find now. Argh, if I could only find a properly archived MSDN somewhere… There was a nice article about this.
For example, the Windows SDK headers do not use virtually all symbols in the headers can only be found in DLLs, and at link‑time in import libraries.dllimport
although
dllimport
should also enable you to link to a DLL, in other words import a symbol, if you do not have an import library of that particular DLL. But, since GLEW produces an import library there is no need for doubling the effort (and creating confusion).
…, but doing so allows the compiler to generate better code. …, but the compiler produces more efficient code if you use this keyword.
This claim in the docs is basically unsubstantiated and I am not even sure where this may be coming from. Maybe symbol lookup at link‑time can happen a bit faster? But, the compiler does not really have much to do with that.
My perception of
dllimport
is that it's rather more conventional than being a “relic of Cygwin”.
It is a “relic of Cygwin” in that sense that Cygwin kept using this explicit symbol importing mechanism when Microsoft and other toolchain makers have already moved on long time ago to import libraries.
what is the risk of that change more broadly?
You should not break much because all modern toolchains do not need dllimport
to work properly. People using ancient toolchains may need this but then :thinking: who would want to use obsolete toolchains and the artifacts they produce? In this case people can still add dllimport
to the symbols they need in their code.
the compiler generates slightly different code when it needs to reference an imported function, since the compiler is aware of the special way imported functions are implemented.
https://devblogs.microsoft.com/oldnewthing/20060724-00/?p=30403
If you forget to declare a function as dllimport, then you’re basically making the compiler act like a naive compiler that doesn’t understand dllimport. When the linker goes to resolve the external reference for the function, it will use the stub from the import library, and everything will work as before. You do miss out on the optimization that dllimport enables, but the code will still run. You’re just running in naive mode.
https://devblogs.microsoft.com/oldnewthing/20060726-00/?p=30363
The fact that names in import libraries are decorated means that it is doubly crucial that you use the official import library for the DLL you wish to use rather than trying to manufacture one with an import library generation tool. As we noted earlier, the tool won’t know whether the ordinal assigned to a named function was by design or merely coincidental.
https://devblogs.microsoft.com/oldnewthing/20060727-00/?p=30343
Although these are not the articles I had in mind they are also definitely enlightening. Thank you for digging these up. :+1:
So, I guess we learn that dllimport
reduces one level of indirection, which does result in less binary code produced by the compiler, however the gains are minuscule. This reminds me that I might have read about dllimport
’s obsolescence in the context of Microsoft’s LTCG or GCC’s LTO. Because like the name says, there is code generation involved when linking. So, maybe it was in that context. Because if my memory serves me right, during LTCG or LTO the linker effectively creates __imp_
prefixed symbols before finally linking which has exactly the same effect Raymond Chen describes. I will have to search more on LTO.
Though, much of what Raymond Chen talks about there is often closely related to x86 (only). So, I guess one has to be careful when dealing with other architectures.
Interestingly, he says something about that I have also observed and mentioned this:
:hand_over_mouth: I guess his hopes have been in vain to this day. The Platform SDK (now renamed to the Windows SDK) headers still have not been attributed with , probably due to the linker upgrades over time.dllimport
. So, apparently it has been deemed not as important as things may seem
Anyhow, having dllimport
declarations in a header does not do any harm per se, it is just that you have to basically guard those symbols with a macro and define it when you want to link them statically. I guess, it is an inconvenience one can live with but with the downside that you always have to dig up the exact static guarding macro’s name while at the same time this problem has been solved in modern linkers.
I'm sincere in saying that I didn't intend to tour this particular rabbit-hole, but a bit glad to have had a look and a conversation.
So far I'm leaning towards status-quo. Some reasoning:
Having said all that, I'm not sure dllimport is completely obsolete, but probably still appropriate for such an entrenched and old-school software module.
Yeah, everything you are saying sounds reasonable und I fully understand that you want to minimize any chances of braking something.
I have opened this issue because GLEW was the only dependency in the project I am currently working on that requires you to define a macro at compile‑time when you intend to link statically later, which in my humble experience is quite unusual. It took me more than a day to figure out what was going on. Maybe I should have looked into GLEW’s documentation and source code a little bit earlier but since it is a kind of inherited project there was seemingly no reason for me to look more closely into this particular dependency than others. Anyhow, I have solved the issue in the project and have learned something new about dllimport
. :smile:
This should close #385. Thank you for your assistance. :+1:
The Platform SDK (now renamed to the Windows SDK) headers still have not been attributed with
dllimport
.
Just FYI, the function declarations in the Windows SDK headers have been indeed specified with dllimport
. I must have missed something the first time or have been only looking at the WINAPI
macro. The WINBASEAPI
and DECLSPEC_IMPORT
macros are substituted with dllimport
specifiers.
I wonder however how do they handle function declarations that can be linked dynamically and statically without the need for an additional macro because the Windows SDK ships with a (though obsolete but nevertheless existing) static C runtime library. And, I do not recall defining one just in order to link statically later. Well, it was long time ago. :grinning:
https://github.com/nigels-com/glew/blob/ef7d12ecb7f1f336f6d3a80cebd6163b2c094108/auto/src/glew_head.h#L118-L126
and has only applied to ancient versions of Cygwin, maybe also ancient MinGW32 but never to MSVC or ICC.Binutil’sld
is capable of linking to import libs and DLLs with or without the__imp_
symbol prefix since August 2nd, 2001! Please, remove the use ofdllimport
from the headers. It causes more harm and confusion then good. If someone really wants to prefix GLEW’s symbols with__imp_
then they can configure their compiler or linker to do so, though I doubt anybody would want this. Hence, there is also no need for theGLEW_STATIC
macro to exist.