You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Linker Error with Clang on Windows linking against Boost built with MSVC #1212
We are building Boost with MSVC and define BOOST_LIB_TOOLSET to compile some project with clang and link statically against Boost.
This does work fine with other Boost libraries.
We want to use Boost.JSON now, but unfortunately we get the following linker error in this situation:
When compiling with MSVC, BOOST_JSON_NO_DESTROY is not set, when compiling with clang, it is.
So different variants of the instance_ member are selected in the two cases.
If I remove the cited block from the config.hpp, everything compiles and links fine.
We could also work around this by building Boost with clang also, obviously.
But I do consider this a bug in Boost.JSON.
I am unsure, how to best prevent this error from within you codebase, however. Do you see a way?
At least an escape hatch macro like BOOST_JSON_AVOID_NO_DESTROY would be nice.
So, to be clear, you build Boost with MSVC, and it compiles Boost.Json a certain way. Then you compiled another project with clang, and it expects Boost.Json to have been built a certain different way.
This doesn't sound to me like a bug in Boost.Json in any way. You're actually lucky you've got a linking error and not some kind of impossible to track down runtime error due to the ODR violation.
I can suggest defining BOOST_JSON_NO_DESTROY when building with clang. That should disable the code that causes the linking error.
So, to be clear, you build Boost with MSVC, and it compiles Boost.Json a certain way. Then you compiled another project with clang, and it expects Boost.Json to have been built a certain different way.
Yes, that is correct. Although that is not as weird as you make it sound, this usually works very well. Clang on Windows aims to be compatible with MSVC, see https://clang.llvm.org/docs/MSVCCompatibility.html
Clang also defines all sorts of MSVC-specific macros on windows. So the only obvious way to break this is by using Clang-specific macros, which is what happens here.
I can suggest defining BOOST_JSON_NO_DESTROY when building with clang. That should disable the code that causes the linking error.
No, that does not work. I need BOOST_JSON_NO_DESTROY to not be defined in default_ressource.hpp, for the ifdefs to select the correct member definition.
Yes, that is correct. Although that is not as weird as you make it sound, this usually works very well. Clang on Windows aims to be compatible with MSVC, see https://clang.llvm.org/docs/MSVCCompatibility.html
I'm not saying it's weird, I'm saying it is fundamentally brittle and subject to arbitrary promises of compatibility between the two compilers.
Clang also defines all sorts of MSVC-specific macros on windows. So the only obvious way to break this is by using Clang-specific macros, which is what happens here.
When building with Clang we use features provided by Clang. It would have been a bug to try to use them if they were not provided, but the opposite is not a bug. Luckily, the use of this specific feature can be disabled by defining BOOST_JSON_NO_DESTROY.
No, that does not work. I need `BOOST_JSON_NO_DESTROY` to not be defined in `default_ressource.hpp`, for the `ifdefs` to select the correct member definition.
Can you elaborate on that? You want the macro not to be defined (manually), so that the static data member is declared. But then you will get a linking error, because that member is not defined anywhere. So, why do you want the member to be declared?
I'm not saying it's weird, I'm saying it is fundamentally brittle and subject to arbitrary promises of compatibility between the two compilers.
Well, the promises are very much not arbitrary. One may even compare it to compiling with a newer version of one compiler, and linking it against Boost that is built with an older version of the same compiler that guarantees binary forward compatibility. Would you argue that one should not do that?
(Even though, I agree that my situation is a bit more unique than this one.)
When building with Clang we use features provided by Clang. It would have been a bug to try to use them if they were not provided, but the opposite is not a bug
Depending on a macro to be set to an identical value when compiling the library and when consuming the library can very well be considered a bug. This is in general a dangerous source of errors. In this particular case with __clang__ etc., this is more debatable.
So if you do not consider it a bug, that is your choice, fair enough.
Can you elaborate on that? You want the macro not to be defined (manually), so that the static data member is declared. But then you will get a linking error, because that member is not defined anywhere. So, why do you want the member to be declared?
Without BOOST_JSON_NO_DESTROY the data member is static holder instance_.
With it, it is static default_resource instance_.
With MSVC, the macro is not defined. With clang, it is set to [[clang::no_destroy]].
If i define the macro (empty) with clang, it keeps its empty value in config.hpp, but is still defined.
So i still get static default_resource instance_, which the linker does not find.
I was persuaded that your specific situation—compatibility of binaries built with MSVC and clang-cl— should work. So, I disabled usage of no_destroy attribute in clang-cl. Can you test #1213, so that I know if it does eliminate the problem?
Can you test #1213, so that I know if it does eliminate the problem?
I did, works as expected :) Both, with only the first commit and setting the macro and with the second commit without an additional macro.
Thanks a lot and sorry for the late reply, I did not get to this during the weekend.
Activity
grisumbras commentedon Oct 21, 2026
So, to be clear, you build Boost with MSVC, and it compiles Boost.Json a certain way. Then you compiled another project with clang, and it expects Boost.Json to have been built a certain different way.
This doesn't sound to me like a bug in Boost.Json in any way. You're actually lucky you've got a linking error and not some kind of impossible to track down runtime error due to the ODR violation.
I can suggest defining
BOOST_JSON_NO_DESTROYwhen building with clang. That should disable the code that causes the linking error.jens-diewald commentedon Oct 21, 2026
Thank you for your answer.
Yes, that is correct. Although that is not as weird as you make it sound, this usually works very well. Clang on Windows aims to be compatible with MSVC, see https://clang.llvm.org/docs/MSVCCompatibility.html
Clang also defines all sorts of MSVC-specific macros on windows. So the only obvious way to break this is by using Clang-specific macros, which is what happens here.
No, that does not work. I need
BOOST_JSON_NO_DESTROYto not be defined indefault_ressource.hpp, for theifdefsto select the correct member definition.grisumbras commentedon Oct 21, 2026
I'm not saying it's weird, I'm saying it is fundamentally brittle and subject to arbitrary promises of compatibility between the two compilers.
When building with Clang we use features provided by Clang. It would have been a bug to try to use them if they were not provided, but the opposite is not a bug. Luckily, the use of this specific feature can be disabled by defining
BOOST_JSON_NO_DESTROY.Can you elaborate on that? You want the macro not to be defined (manually), so that the static data member is declared. But then you will get a linking error, because that member is not defined anywhere. So, why do you want the member to be declared?
jens-diewald commentedon Oct 21, 2026
Well, the promises are very much not arbitrary. One may even compare it to compiling with a newer version of one compiler, and linking it against Boost that is built with an older version of the same compiler that guarantees binary forward compatibility. Would you argue that one should not do that?
(Even though, I agree that my situation is a bit more unique than this one.)
Depending on a macro to be set to an identical value when compiling the library and when consuming the library can very well be considered a bug. This is in general a dangerous source of errors. In this particular case with
__clang__etc., this is more debatable.So if you do not consider it a bug, that is your choice, fair enough.
Without
BOOST_JSON_NO_DESTROYthe data member isstatic holder instance_.With it, it is
static default_resource instance_.With MSVC, the macro is not defined. With clang, it is set to
[[clang::no_destroy]].If i define the macro (empty) with clang, it keeps its empty value in
config.hpp, but is still defined.So i still get
static default_resource instance_, which the linker does not find.grisumbras commentedon Oct 22, 2026
Right! Sorry, I misread the code. I'll add a macro to disable the feature.
grisumbras commentedon Oct 23, 2026
I was persuaded that your specific situation—compatibility of binaries built with MSVC and clang-cl— should work. So, I disabled usage of
no_destroyattribute in clang-cl. Can you test #1213, so that I know if it does eliminate the problem?jens-diewald commentedon Oct 26, 2026
I did, works as expected :) Both, with only the first commit and setting the macro and with the second commit without an additional macro.
Thanks a lot and sorry for the late reply, I did not get to this during the weekend.
grisumbras commentedon Oct 26, 2026
Thanks for checking.