Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: lib import/export macros #480

Open
OgreTransporter opened this issue Nov 9, 2022 · 13 comments
Open

Windows: lib import/export macros #480

OgreTransporter opened this issue Nov 9, 2022 · 13 comments
Labels
enhancement New feature or request Windows Related to Windows backend

Comments

@OgreTransporter
Copy link

#define HID_API_EXPORT __declspec(dllexport)

This does not make sense. dllexport is normally always used in combination with dllimport (https://learn.microsoft.com/en-us/cpp/cpp/dllexport-dllimport).

@Youw
Copy link
Member

Youw commented Nov 9, 2022

"does not make" doesn't mean it is broken.
I remember 0 complains about this part. UPD: there are issues - more details below.
And I personally use HDIAPI both as a shared and as a static library on multiple platforms, including Windows.

Please share a specific use-case where the old behavior has compilation/runtime issues. If there is such - we'll try to find a backward-compatible solution for all build systems.

@Youw Youw added enhancement New feature or request Windows Related to Windows backend labels Nov 9, 2022
@Youw Youw changed the title Windows: lib import/export Windows: lib import/export macros Nov 9, 2022
@OgreTransporter
Copy link
Author

I never claimed that errors occur. But I can also argue the other way around, that just because you haven't had an error yet, it doesn't always have to work. After all, the Windows API provides for the combination of dllimport and dllexport. This is a general improvement suggestion to make the code cleaner. Many libraries like Boost (https://github.com/boostorg/system/blob/develop/include/boost/system/config.hpp) use this kind of macro mechanism to implement the Windows API correctly.

@Youw
Copy link
Member

Youw commented Nov 10, 2022

You're perfectly right about how things should be in the ideal world.
And I'm definitely considering making it right for HIDAPI v1+.

But right now - my strong position is: "don't try to fix what is not broken". And the #480 breaks all windows builds on our CI.
And our CI is the kind of "golden sample" for those who seek to start using HIDAPI or a reflection of how HIDAPI is already used by many others.

@YgorSouza
Copy link

"does not make" doesn't mean it is broken. I remember 0 complains about this part. And I personally use HDIAPI both as a shared and as a static library on multiple platforms, including Windows.

Please share a specific use-case where the old behavior has compilation/runtime issues. If there is such - we'll try to find a backward-compatible solution for all build systems.

For what it's worth, I did have problems with that. I linked HIDAPI statically into my DLL, and then noticed that all of its functions were accessible and visible with for example dumpbin /exports. Then I looked at the header and saw that there was no way to disable that, so I just copied the header to my project and edited out the dllexport. Now I am planning on using the hidapi Rust crate, which uses this repo as a submodule, and I realized I'll have to fork this repo and then fork the crate repo to make this same change. That #ifndef HIDAPI_STATIC guard would simplify this a lot.

As for the dllimport, Microsoft says it's optional, and only serves to make the compiler generate "more efficient" code, whatever that means (source). So maybe it's not worth it if it is a breaking change. Maybe change the ifdef to an ifndef? Then for most people it changes nothing, and people who want to get that "more efficient" code can just define the symbol.

@Youw
Copy link
Member

Youw commented Feb 13, 2023

all of its functions were accessible and visible with for example dumpbin /exports. Then I looked at the header and saw that there was no way to disable that

That is a very good case.

To be able to workaround cases like that I suggest:

 #ifdef _WIN32
+   #ifndef HID_API_EXPORT
       #define HID_API_EXPORT __declspec(dllexport)
+   #endif
       #define HID_API_CALL
 #else
+   #ifndef HID_API_EXPORT
       #define HID_API_EXPORT /**< API export macro */
+   #endif
       #define HID_API_CALL /**< API call macro */
 #endif

and a corresponding define for CMake build of the static library


that is not perfect (not even close) but should be good-enough for v0

@YgorSouza
Copy link

Maybe not the most intuitive, but at least it gives users more flexibility to do what they need without having to change the code itself, and doesn't break anything that currently works. I'd say it's a decent enough compromise.

Youw added a commit that referenced this issue Feb 22, 2023
Don't mark API functions with __declspec(dllexport) when building a static library on Windows.
Enforced by CMake builds.
For other builds a compile definition is available.

Related: #480
@SamuelC0507
Copy link

Hi @Youw ,
I have a similar use case of HIDAPI as @YgorSouza 's.

On my end, target_compile_definitions(hidapi_winapi PUBLIC HID_API_EXPORT) in \windows\CMakeLists.txt results in HID_API_EXPORT being defined as 1, causing every function declaration in hidapi.h resulting in error C2059: syntax error : 'constant' during compilation. Not sure if you guys ever ran into this problem?

Maybe something like target_compile_definitions(hidapi_winapi PUBLIC HID_API_STATIC) in \windows\CMakeLists.txt, and

#if defined(_WIN32) && !defined(HID_API_STATIC)
    #define HID_API_EXPORT __declspec(dllexport)
    #define HID_API_CALL
#else
    #define HID_API_EXPORT /**< API export macro */
    #define HID_API_CALL /**< API call macro */
#endif

in hidapi.h would be nice?

@Youw
Copy link
Member

Youw commented Feb 24, 2023

HID_API_EXPORT being defined as 1

Very interesting. I haven't seen a compiler that would do somehting like that.
And one of the onces on our CI behaves that way.

And only now I took attention into CMake documentation that actually describes that behavior:

Note that many compilers treat -DFOO as equivalent to -DFOO=1...

Care to share your compiler and its version?
Just out of my curiosity.


&& !defined(HID_API_STATIC)

Yes, I guess that should work.
Maybe a little less flexible solution (as it doesn't give the ability to define HID_API_EXPORT to something else (e.g. __attribute__((visibility("default")))), but as a solution to this problem - more than acceptible.

@OgreTransporter
Copy link
Author

Have a look at https://github.com/OGRECave/ogre-next/blob/master/OgreMain/include/OgrePlatform.h as a full example for static and dynamic with export and import.

A summary is available at https://github.com/Framstag/libosmscout/blob/master/libosmscout/include/osmscout/CoreImportExport.h.

Even in the GCC documentation the usage is documented like this https://gcc.gnu.org/wiki/Visibility.

The original idea of the proposal was to adapt the import-export API correctly for all cases (static, export, import). Since the simple macro solution is apparently still very unpopular, there is a second way. Simply remove the macro completely and supply a module definition file (https://learn.microsoft.com/en-us/cpp/build/reference/module-definition-dot-def-files?view=msvc-170) for Windows. In CMake it is then relatively simple, everything is identical, only under the Windows DLL this file must be passed to the compiler. The disadvantage of this way is that it only works with Visual Studio and clang under Windows. GCC cannot do this. If you really want to support all compilers in all directions, then you should implement the macro variant.

@Youw
Copy link
Member

Youw commented Feb 25, 2023

I am aware of the the "perfect" solution using macros.
My position about this stands: until v1 - all changes has to be backward compatible with existing usages of HIDAPI (current CI maybe not perfect - but good-enough example of such).

And no changes to autotools - those are deprecated, and should stay untouched until removed in v1 (unless obvious bugs, which I'm not aware of).

@SamuelC0507
Copy link

SamuelC0507 commented Feb 26, 2023

@Youw , my cl version is 14.29.30133, came with Visual Studio 2019 Professional.

Maybe a little less flexible solution (as it doesn't give the ability to define HID_API_EXPORT to something else

My bad I was just thinking of a quick fix and didn't give it a thorough enough thought, I'm sure you would come up with a better way to handle this issue at V1 release, looking forward to it!

@YgorSouza
Copy link

Hi @Youw , I have a similar use case of HIDAPI as @YgorSouza 's.

On my end, target_compile_definitions(hidapi_winapi PUBLIC HID_API_EXPORT) in \windows\CMakeLists.txt results in HID_API_EXPORT being defined as 1, causing every function declaration in hidapi.h resulting in error C2059: syntax error : 'constant' during compilation. Not sure if you guys ever ran into this problem?

Maybe something like target_compile_definitions(hidapi_winapi PUBLIC HID_API_STATIC) in \windows\CMakeLists.txt, and

#if defined(_WIN32) && !defined(HID_API_STATIC)
    #define HID_API_EXPORT __declspec(dllexport)
    #define HID_API_CALL
#else
    #define HID_API_EXPORT /**< API export macro */
    #define HID_API_CALL /**< API call macro */
#endif

in hidapi.h would be nice?

I hadn't tested until now, since I haven't touched this part of my code in a while, but indeed I got the same problem. One solution is to define the macro to something explicitly, so it doesn't get implicitly set to 1. This is done in the other empty definitions in the header file itself.

target_compile_definitions(hidapi PUBLIC HID_API_EXPORT=/**/)

@Youw
Copy link
Member

Youw commented Mar 6, 2023

The only thing I don't like about this aproach, that the /**/ would have to be escaped for a specific command prompt/terminal later for compiler to be executed.
CMake usually does a decent job doing so, but it has to be done carefully and tested in all environmnets.

I prefer not to pass "weird" symbols into command-line when I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Windows Related to Windows backend
Projects
Status: To do
Development

No branches or pull requests

4 participants