-
Notifications
You must be signed in to change notification settings - Fork 287
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
C++ visibility support #1040
C++ visibility support #1040
Conversation
This is a good start, but I have a few notes:
What I've done in the past is:
This also gives us the opportunity to add documentation to each macro, which may be helpful for end users. I would suggest we consider naming the export macro as And a final note: We need to create a unique export header for each library in the project, which means each of the optional components that aren't part of |
Revising my last comment: Since we would need a bunch of the "manually written" |
Having another layer of export header sounds good to me.
Could you let me know why do we need different configurations for each component? |
The definition of the export macro will be different depending on whether the header is being included by the library that is defining the class or by a library that is using the class. To illustrate how things would go wrong, let's say we use the same export macro for |
@mxgrey That makes sense to me. I have a follow-up question though. Although |
This is not correct. When you use the When |
So the short version is, cmake takes care of your concern automatically. |
@mxgrey Thanks for the explanation! I learned a lot while working on this PR. I've addressed your feedback in the last commits.
|
) | ||
|
||
# Generate final export header | ||
set(header_guard_name ${base_name_upper}_EXPORT_HPP_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would probably be much cleaner if we created a export.hpp.in
and then called configure_file
on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. I wrote this lines because I thought each component requires individual export.hpp.in
, but this is not true.
cmake/DARTMacros.cmake
Outdated
generate_export_header(${target_name} | ||
EXPORT_MACRO_NAME ${base_name_upper}_DETAIL_API | ||
EXPORT_FILE_NAME detail/export.h | ||
DEPRECATED_MACRO_NAME ${base_name_upper}_DETAIL_DEPRECATED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: I like to put the DETAIL
in front of DART
so it gets excluded from autocomplete when users start typing DART...
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, but I thought we use DART_
prefix to avoid possible name conflicts. At the same time, I don't see the possibility of name confliction with DETAIL_DART_~
.
Let me change it to DETAIL_DART_~
as I don't have a strong preference here.
@mxgrey I've fixed build and test errors. Could you do a second review? |
dart/common/Deprecated.hpp
Outdated
@@ -42,7 +43,7 @@ | |||
//============================================================================== | |||
|
|||
#if defined(__GNUC__) || defined(__clang__) | |||
#define DART_DEPRECATED(version) __attribute__ ((deprecated)) | |||
#define DART_DEPRECATED(version) DETAIL_DART_DEPRECATED | |||
#define DART_FORCEINLINE __attribute__((always_inline)) | |||
#elif defined(_MSC_VER) | |||
#define DART_DEPRECATED(version) __declspec(deprecated) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also be redirected to DETAIL_DART_DEPRECATED
to be consistent with the other definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the export macro should not be applied to any templates. It should only be applied to fully-defined classes (which does include explicit template instantiations, but it does not include any templates with unset parameters).
I've marked a few lines with the comment Example
to point out what I mean.
The reason incomplete templates can't be marked as exported is because it prevents a user from instantiating that template with their own custom parameters. Instead of automatically instantiating the template with whatever parameters the user requests, the compiler will assume that a suitable class with those parameters was already instantiated by the DLL that exported the header. This will typically result in a linking error.
It looks like the lines that I marked with |
I haven't fully investigated but without the export macro to the template classes caused test failures of
|
I think that's because this class is never marked as exported. I'm not sure what the correct way to export that would be. Maybe we need to explicitly instantiate the
That might be a trickier issue. It's not immediately clear to me why that would happen. |
Marking a static member of a template class would be also dangerous? |
Yes, I think that would also be dangerous, because the definition is actually given in the implementation header. My understanding of the export macro is that it effectively tells the user's compiler "Don't try to create a definition for this symbol, because the definition will be provided by the library that exported this header", and then it tells the user's linker "Don't look for a definition of this symbol within the library that we just compiled; instead, look for it in one of the libraries that we are linking to". I think if we "export" that static member, then users will get a linking error for it whenever they pass a custom class type into |
This PR implements the control of binary symbols visibility in DART inspired by flexible-collision-library/fcl#233.
DART_EXPORT
preprocessor is added to any class, struct, and function that needs to be exposed publicly to third-party software. I could compile all the tests, examples, and tutorials without any issue, but it would be good to test DART with other third-party software like AIKIDO for sure.DART_HIDE_ALL_SYMBOLS
CMake option is also added, which isOFF
by default, for the case that we want to hide all the symbols as DART is built as static library.Caveat:
There is a preprocessor name conflict between the existing
DART_DEPRECATED(version)
and another preprocessor generated bygenerate_export_header()
, which is necessary to mark visibility of deprecated APIs. To resolve this, I changed the name toDART_DEPRECATED2
so that the preprocessor for deprecated API becomesDART_DEPRECATED2_EXPORT
. I'm open to better workaround.Alternatively, we could remove
DART_DEPRECATED(version)
and use one generated bygenerate_export_header()
. The version information can be provided by using Doxygen comment (e.g.,/// \deprecated Deprecated in <version>. Please use <other_api> instead).
).This PR is related to #1005.
Before creating a pull request
clang-format
Before merging a pull request
CHANGELOG.md