-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
fmt::ostream - aggregate buffer instead of inheriting it #3139
Conversation
Some MSVC-specific behavior: When class fmt::ostream inherits detail::buffer - the last gets implicitly exported when fmt is built as a shared library. Unless os.h is included, the compiler assumes detail::buffer is not externally exported and instantiets a local copy of it, which causes ODR violation. With aggregation - there is no extra exporting of detail::buffer symbols.
Export table of
After:
Diff:
|
CI failure:
Looks like the |
But that would spawn the v-table for stream_buffer in each translation unit it is included (at least as per itanium/clang arch)... |
But the same story with |
Interesting that with the latest change - the amount of export symbols is exactly the same ( |
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.
Thanks for the PR.
Do I understand correctly that this is an alternative to #3132?
include/fmt/os.h
Outdated
/** A fast output stream which is not thread-safe. */ | ||
class FMT_API ostream final : private detail::buffer<char> { | ||
private: | ||
template <typename Char> class file_buffer final : public detail::buffer<Char> { |
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 doesn't need to be a template because file I/O is char-based.
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.
doesn't need to be
That is exactly what I've tried in the previous commit.
But compilers generally are not happy about it.
I simply took the same approach as with memory_buffer
.
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.
You should be able to fix that warning by outlining some virtual method. memory_buffer
is different because it has to be a template.
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.
by outlining some virtual method
That I did and got a different problem - the v-table gets anchored into a shared library but not exported, which makes it unavailable outside of a shared library.
Initially I thought that the only fix would be to export the entire class (to export a v-table) which is the opposite of this entire change. But after giving it a second though - I think it would be enough to outline c-tor and other special functions. Let me try that.
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.
done - it worked
Yes. |
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.
Overall looks good, a few minor comments inline.
file file_; | ||
|
||
void grow(size_t) override; | ||
FMT_MSC_WARNING(suppress : 4251) |
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.
What is this for?
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.
warning C4251: class 'detail::file_buffer' needs to have dll-interface ...
I.e. MSVC doesn't like that ostream
is exported and detail::file_buffer
- is not
|
||
FMT_END_DETAIL_NAMESPACE | ||
|
||
ostream::~ostream() = default; |
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.
Does it need to be outlined?
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.
it guess that's my old habit - always anchor class by its d-tor
otherwise - how would compiler know where to place definition of functions marked with FMT_API
?
maybe that is not the case for this particular class - but that's the case for polymorphic classes
at least I didn't check if it would behave fine w/o it
Thanks |
Some MSVC-specific behavior:
When class fmt::ostream inherits detail::buffer - the last gets implicitly exported when fmt is built as a shared library.
Unless os.h is included, the compiler assumes detail::buffer is not externally exported and instantiets a local copy of it, which causes ODR violation.
With aggregation - there is no compiler assumptions that could cause an ODR violation.
Closes: #3132