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

supported clang-cl #595

Closed
wants to merge 1 commit into from
Closed

supported clang-cl #595

wants to merge 1 commit into from

Conversation

durswd
Copy link

@durswd durswd commented Nov 6, 2019

This PR makes tests and compile passed on clang-cl (clang on Windows)

@@ -286,7 +286,7 @@ namespace cereal
void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }

public:
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(__clang__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you'd want to do this, clang-cl has the same integer sizes as MSVC, so we'd want the unsigned long overload as well here, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to suppress this error

call to member function 'saveValue' is ambiguous

in json.hpp

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok correction: in our org we never came across this even though our json.hpp looks the same. We're using clang-cl version 8.0.0. I wonder if @durswd has a different configuration whereby sizeof(long) is coming out as 8?

@@ -44,7 +44,7 @@
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt) */

#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(__clang__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-cl supports declspecs, so I'd imagine this is useful as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declspec causes this error on clang9

cereal::detail::StaticObject<cereal::detail::bind_to_archives<PolyDerivedLA, cereal::detail::(anonymous namespace)::polymorphic_binding_tag> >' must have external linkage when declared 'dllexport'

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this error can be reproduced on test_polymorphic

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We (myself + @fnabulsi + @bmcdb) got the identical error and had to make the same change, although I acknowledge this may warrant more investigation.

We are testing cereal only with static linking so it wouldn't surprise me if there's more work to ensure that clang-cl can properly build Cereal as a DLL.

@jdonald
Copy link

jdonald commented Nov 13, 2019

I was about to file a pull request then found this. We came up with byte-for-byte identical changes so fully approve here. @fnabulsi @bmcdb. Edit: Okay our changes are not identical, please see other comments.

We also were running an older version that lacked the defined(__clang__) && defined(_MSC_VER) case around line 560 of rapidjson.h, but what's in trunk is sufficient there now, so apparently rapidjson was ahead on clang-cl support while cereal just needs these three additional fixes.

@jdonald
Copy link

jdonald commented Nov 13, 2019

Edit: this line 719 in polymorphic_impl.hpp seems to be fine, not requiring any __clang__ qualification.

      #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)

The CEREAL_BIND_TO_ARCHIVES() errors we were getting earlier were due to a different local change while testing one of the other three.

(Unedited) Overall any reason we get different results compared to @durswd is a combination of issues: using a different version of clang-cl, have an older fork of of cereal, and we use different features of the library which affects which templates get exercised.

You can take a look at our comparable changes here: master...jdonald:clang-cl

@AzothAmmo
Copy link
Contributor

So what's the verdict here? Is this PR sufficient for supporting clang? Apparently we can build against clang on appveyor, if anyone wants to figure that out.

Copy link

@jdonald jdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two unresolved concerns were:

  1. The saveLong(unsigned long) part
  2. CEREAL_DLL_EXPORT

For 1) I just did a test with the saveLong part conditioned in our own codebase, and I can confirm it at least doesn't hurt. I suspect this one not specifically about a long being 4 or 8 bytes, but some other MSVC cl.exe-specific weirdness.

For 2) I think it would take more work to validate if Cereal builds and runs properly as a DLL with clang-cl, but it would still be an improvement if we got the static lib clang-cl build working alone. Overall this PR only makes things better for clang-cl while changing nothing with cl, so I recommend merging it as.

@durswd
Copy link
Author

durswd commented Nov 18, 2019

saveLong error causes when it is compiled as 64bit. it is no problem when it is compiled as 32bit.

Instead of it

this changes uppresses this error

//! MSVC only long overload to current node
void saveValue( unsigned long lu ){ saveLong( lu ); };

->

//! MSVC only long overload to current node
void saveValue( unsigned long lu ){ saveLong( lu ); };
void saveValue( long lu ) { saveLong(lu); };

It seem that Overloading is failed on clang-cl with x64

@InBetweenNames
Copy link
Contributor

InBetweenNames commented Oct 17, 2020

The main issue with DLL support is that a tag in an anonymous namespace polymorphic_binding_tag is used as the template argument for StaticObject, which means internal linkage. So, that it works on MSVC at all is actually a compiler bug -- unless MSVC treats all anonymous namespaces as actually having the same "name" internally in the compiler, which would permit exporting.

Think about it: each TU gets it's own polymorphic_binding_tag that is different from the tag in all other TU's, yet this class is marked dllexport, which also appears in each TU. You'd effectively have a bunch of dllexported symbols that you couldn't actually access.

@InBetweenNames
Copy link
Contributor

On thinking about this more: is it actually necessary to maintain the StaticObject as a dllexport?

@InBetweenNames
Copy link
Contributor

OK -- I found a solution for this. It requires C++17, but essentially the following changes are made:

  • polymorphic_type_impl no longer resides in an anonymous namespace
  • CEREAL_BIND_TO_ARCHIVES now uses a static inline variable:

#define CEREAL_BIND_TO_ARCHIVES(...)                                     \
    namespace cereal {                                                   \
    namespace detail {                                                   \
    template<>                                                           \
    struct init_binding<__VA_ARGS__> {                                   \
        static inline bind_to_archives<__VA_ARGS__> const & b=           \
        ::cereal::detail::StaticObject<                                  \
            bind_to_archives<__VA_ARGS__>                                \
        >::getInstance().bind();                                         \
        CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION                          \
    };                                                                   \
    }} /* end namespaces */

The StaticObject template is still marked dllexport.

This enables the following:

  • Each TU only accesses ONE StaticObject across the entire DLL
  • Each DLL receives it's own StaticObject, but these are identical with correct usage of the Cereal macros (as documented)

I didn't realize this, but the reason dllexport is even used is to prevent the linker from optimizing away the static object.
It's not actually used for linkage purposes.

This change also reduces code size, as the inline static merges the definition across all TUs.

@InBetweenNames
Copy link
Contributor

InBetweenNames commented Oct 18, 2020

The same approach could be used to get the CEREAL_CLASS_VERSION macro working on MSVC 2017, where right now you can get a multiple definition error. That macro could be changed as follows (again requiring C++17)

  #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
  namespace cereal { namespace detail {                                          \
    template <> struct Version<TYPE>                                             \
    {                                                                            \
      static std::uint32_t registerVersion()                                     \
      {                                                                          \
        ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
             std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
        return VERSION_NUMBER;                                                   \
      }                                                                          \
      static inline const std::uint32_t version = registerVersion();             \
      CEREAL_UNUSED_FUNCTION                                                     \
    }; /* end Version */                                                         \
  } } // end namespaces

InBetweenNames added a commit to InBetweenNames/cereal that referenced this pull request Oct 20, 2020
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643
@InBetweenNames
Copy link
Contributor

I have a proposed patch to fix this and a few other small linker-related annoyances on Windows in #657.

InBetweenNames added a commit to InBetweenNames/cereal that referenced this pull request Oct 20, 2020
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643
InBetweenNames added a commit to InBetweenNames/cereal that referenced this pull request Oct 28, 2020
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643
AzothAmmo pushed a commit that referenced this pull request May 5, 2021
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix #595
Fix #652
Fix #582
Fix #643
arximboldi pushed a commit to arximboldi/cereal that referenced this pull request Sep 7, 2021
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643
AzothAmmo pushed a commit to AzothAmmo/cereal that referenced this pull request Nov 28, 2021
This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643
julianharbarth added a commit to motis-project/cereal that referenced this pull request Mar 14, 2023
* Fix json.hpp compilation issue when int32_t is a long (USCiLab#621)

When testing whether or not to define a saveValue() overload
for long, test the actual set of types implemented.

* [cpp20] explicitly capture 'this' as copy (USCiLab#640)

implicit 'this' capture is deprecated in C++20

* Fix rapidjson for Clang 10 (USCiLab#645)

Based on Tencent/rapidjson#1679
Addresses USCiLab#631

* Fixes to prevent clang-diagnostic errors (USCiLab#643)

* Fixes to prevent clang-diagnostic when running clang-tidy with Microsoft Visual Studio cmake projects.

* Used boolean rather than bitwise operator.

* cleanup cmake files to be a little more moderen (USCiLab#659)

* cleanup cmake files to be a little more moderen

keep the source tree free of build artifacts
cmakelint the cmake files too

* fix cmake setup errors on CI

fix APPLE clang builds too

* CI needs support for realy history cmake V3.6

fix typo in cmake files using add_test() commnds

* One step more to use modern cmake

Prevent to modifiy compile and linker FLAGS and to set global includes
pathes

* fix CI build problems with older cmake versions

prepare cleanup cmake list file

* final cleanup

use Config.cmake.in and install hole cmake config files

* Fix cpp17 PORTABILITY_TEST linker problem

add missed target_link_libraries()

* hopefully prevent windows test problems

* Store a copy of each serialized shared_ptr within the archive to prevent the shared_ptr to be freed to early. (USCiLab#667)

The archives use the memory address pointed by the shared_ptr as a
unique id which must not be reused during lifetime of the archive.
Therefore, the archives stores a copy of it.
This problem was also reported as CVE-2020-11105.

* add license files for components of cereal

Signed-off-by: Adam Miartus <[email protected]>

* Update README.md

Fix link to main website

* Catch short documents in JSON input

When reading unnamed fields from JSON input, the member/value iterators
are incremented blind without checking if the end of the iterator has
been reached.

Record the size so that this can be checked against the current position
to ensure reading doesn't walk off the end of the iterator.

* C++17: use inline globals for StaticObjects

This prevents multiple definition errors in Clang,
and also stops dllexporting functions with internal
linkage.  Degrades gracefully when C++17 is not
present.

Fix USCiLab#595
Fix USCiLab#652
Fix USCiLab#582
Fix USCiLab#643

* Use std::variant::emplace when loading

* Use std::optional::emplace() when loading to construct and load the contained value directly in place

* Fix itsNextName not clearing when not found

An issue exists when loading vectors of objects where, if the last nvp of
the previous object does not exist in the json file, the itsNextName
variable within the json serializer is not cleared. This causes the vector
serializer to search for that name next (when it should be searching for a
nameless object.) The json serializer then throws during the named search.

Mild reworking of itsNextName solution

* Add github actions workflow

use docker containers
remove sudo
install software-properties-common
update before trying install
install wget
cmake and make
install cmake from pip
add apt-transport-https
Use llvm xenial
Fix clang package name
Fix boost with gcc<5
verbose compile
skip boost for gcc<5
macos test
skip boost for macos
test different xcode compilers
use new cmake syntax for selecting platform
no xcode 10 installed
Rename tests

* Update doctest to 2.4.6 dev + local fixes slated for upstream

* Update appveyor to build with MSVC 2022 and fix boost

* Fixed loading of std::vector<bool>

We should use auto && instead of auto if we want to modify v inside the for loop.

* Update license to match BSD template

* Update doctest to 2.4.7, update CI, add badges

Updates doctest and fixes issues with g++4.7 and MSVC2013 doctest
builds.

Adds new CI targets for g++ 9 and 10, clang 9 through 12.

Adds CI badges for github actions.

* Use GNUInstallDirs instead of hard wiring install directories

On a multilib setup cmake files should go into lib64.

* Update version to 1.3.1

* Make doxygen docs reproducible

* Add CMake options for building doc and sandbox

relates USCiLab#739

* Correct patch version for 1.3.2

* Fix long long json serialization (USCiLab#728)

* Fix long long json serialization

* Update pod.hpp

* Update .gitignore

`.vs/` folder is created by Visual Studio and it is not needed.

* `ST` renamed to `AlignedStorage`

* Remove extra ; after member function definition

Triggered by -Wextra-semi.

* add string_view to json archive

---------

Signed-off-by: Adam Miartus <[email protected]>
Co-authored-by: Bernard Blackham <[email protected]>
Co-authored-by: Łukasz Gemborowski <[email protected]>
Co-authored-by: groscoe2 <[email protected]>
Co-authored-by: John Alexander <[email protected]>
Co-authored-by: Claus Klein <[email protected]>
Co-authored-by: Michael Walz <[email protected]>
Co-authored-by: Adam Miartus <[email protected]>
Co-authored-by: Shane Grant <[email protected]>
Co-authored-by: John Keeping <[email protected]>
Co-authored-by: Shane Peelar <[email protected]>
Co-authored-by: logan <[email protected]>
Co-authored-by: Gary Heckman <[email protected]>
Co-authored-by: Isuru Fernando <[email protected]>
Co-authored-by: Darred <[email protected]>
Co-authored-by: Anton Blanchard <[email protected]>
Co-authored-by: Michael R. Crusoe <[email protected]>
Co-authored-by: CHP <[email protected]>
Co-authored-by: Luca Ciucci <[email protected]>
Co-authored-by: Jan Niklas Hasse <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants