yourWaifu / sleepy-discord

C++ library for the Discord chat client. Please use Rust for new bots
https://yourWaifu.github.io/sleepy-discord/
MIT License
707 stars 92 forks source link

Build fails when using Clang-Cl (Windows) #219

Closed TheDreamsWind closed 3 years ago

TheDreamsWind commented 3 years ago

Today was trying to migrate my project from msvc compiler to clang-cl but unfortunately found that the library fails to build with such configuration. Was using Visual Studio Community 2019, version 16.9.5 under Windows.

yourWaifu commented 3 years ago

can you give me the console output from the compiler?

TheDreamsWind commented 3 years ago

Here is the last lines of build output:

[2/6] Building CXX object libs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\voice_connection.cpp.obj
  FAILED: libs/sleepy-discord/sleepy_discord/CMakeFiles/sleepy-discord.dir/voice_connection.cpp.obj 
  C:\PROGRA~2\MIB055~1\2019\COMMUN~1\VC\Tools\Llvm\bin\clang-cl.exe  /nologo -TP -DCURL_STATICLIB -DEXISTENT_ASIO -DEXISTENT_CPR -DEXISTENT_WEBSOCKETPP -DNONEXISTENT_OPUS -DNONEXISTENT_SODIUM -DNONEXISTENT_UWEBSOCKETS -DNONEXISTENT_ZLIB_NG -DSLEEPY_DISCORD_CMAKE -I..\..\..\libs\sleepy-discord\include -I..\..\..\libs\sleepy-discord\deps\include -I..\..\..\libs\sleepy-discord\include\sleepy_discord -I..\..\..\libs\sleepy-discord\deps\asio\asio\include -I..\..\..\libs\sleepy-discord\deps\websocketpp -I..\..\..\libs\sleepy-discord\deps\cpr\include -imsvc D:\Documents\Joe\Projects\VCPkg\vcpkg\installed\x64-windows\include -m64 -fdiagnostics-absolute-paths  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1   -w -Wall /showIncludes /Folibs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\voice_connection.cpp.obj /Fdlibs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\sleepy-discord.pdb -c -- ..\..\..\libs\sleepy-discord\sleepy_discord\voice_connection.cpp
  In file included from ..\..\..\libs\sleepy-discord\sleepy_discord\voice_connection.cpp:1:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord\voice_connection.h:10:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/snowflake.h:8:
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,108): error : too few arguments provided to function-like macro invocation
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                                                                                                             ^
  C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\minwindef.h(193,9): note: macro 'max' defined here
  #define max(a,b)            (((a) > (b)) ? (a) : (b))
          ^
  In file included from ..\..\..\libs\sleepy-discord\sleepy_discord\voice_connection.cpp:1:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord\voice_connection.h:10:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/snowflake.h:8:
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,70): error : cannot initialize return object of type 'nonstd::sv_lite::basic_string_view::size_type' (aka 'unsigned long long') with an lvalue of type 'unsigned long long () noexcept'
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,30): error : no return statement in constexpr function
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                               ^
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(552,54): error : expected unqualified-id
          return basic_string_view( data() + pos, std::min( n, size() - pos ) );
                                                       ^
  C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\minwindef.h(197,29): note: expanded from macro 'min'
  #define min(a,b)            (((a) < (b)) ? (a) : (b))
                              ^
  4 errors generated.
  [3/6] Building CXX object libs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\asio_udp.cpp.obj
  FAILED: libs/sleepy-discord/sleepy_discord/CMakeFiles/sleepy-discord.dir/asio_udp.cpp.obj 
  C:\PROGRA~2\MIB055~1\2019\COMMUN~1\VC\Tools\Llvm\bin\clang-cl.exe  /nologo -TP -DCURL_STATICLIB -DEXISTENT_ASIO -DEXISTENT_CPR -DEXISTENT_WEBSOCKETPP -DNONEXISTENT_OPUS -DNONEXISTENT_SODIUM -DNONEXISTENT_UWEBSOCKETS -DNONEXISTENT_ZLIB_NG -DSLEEPY_DISCORD_CMAKE -I..\..\..\libs\sleepy-discord\include -I..\..\..\libs\sleepy-discord\deps\include -I..\..\..\libs\sleepy-discord\include\sleepy_discord -I..\..\..\libs\sleepy-discord\deps\asio\asio\include -I..\..\..\libs\sleepy-discord\deps\websocketpp -I..\..\..\libs\sleepy-discord\deps\cpr\include -imsvc D:\Documents\Joe\Projects\VCPkg\vcpkg\installed\x64-windows\include -m64 -fdiagnostics-absolute-paths  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1   -w -Wall /showIncludes /Folibs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\asio_udp.cpp.obj /Fdlibs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\sleepy-discord.pdb -c -- ..\..\..\libs\sleepy-discord\sleepy_discord\asio_udp.cpp
  In file included from ..\..\..\libs\sleepy-discord\sleepy_discord\asio_udp.cpp:4:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord\client.h:14:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/message.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/user.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/discord_object_interface.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/json_wrapper.h:17:
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,108): error : too few arguments provided to function-like macro invocation
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                                                                                                             ^
  C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\minwindef.h(193,9): note: macro 'max' defined here
  #define max(a,b)            (((a) > (b)) ? (a) : (b))
          ^
  In file included from ..\..\..\libs\sleepy-discord\sleepy_discord\asio_udp.cpp:4:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord\client.h:14:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/message.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/user.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/discord_object_interface.h:3:
  In file included from ..\..\..\libs\sleepy-discord\include\sleepy_discord/json_wrapper.h:17:
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,70): error : cannot initialize return object of type 'nonstd::sv_lite::basic_string_view::size_type' (aka 'unsigned long long') with an lvalue of type 'unsigned long long () noexcept'
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(481,30): error : no return statement in constexpr function
      nssv_constexpr size_type max_size() const nssv_noexcept { return std::numeric_limits< size_type >::max(); }
                               ^
D:\Documents\Joe\Projects\DSBot\libs\sleepy-discord\include\sleepy_discord\nonstd\string_view.hpp(552,54): error : expected unqualified-id
          return basic_string_view( data() + pos, std::min( n, size() - pos ) );
                                                       ^
  C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\minwindef.h(197,29): note: expanded from macro 'min'
  #define min(a,b)            (((a) < (b)) ? (a) : (b))
                              ^
  4 errors generated.
  [4/6] Building CXX object libs\sleepy-discord\sleepy_discord\CMakeFiles\sleepy-discord.dir\websocketpp_websocket.cpp.obj
  ninja: build stopped: subcommand failed.
yourWaifu commented 3 years ago

Oh this is a common issue with compiling c++ code on Windows. max is a standard C++ function and a Windows macro. So compilers often get confused on which is being used.

yourWaifu commented 3 years ago

https://stackoverflow.com/a/11544154/9106075

TheDreamsWind commented 3 years ago

I believe this could be part of the library source code, if I'm not mistaken there is quite accurate way of checking for clang-cl compiler by looking at both __clang__ and _MSC_VER macros

yourWaifu commented 3 years ago

This is a separate library that's part of this library. Defining the compiler define NOMINMAX in the cmake arguments should do the trick. You can also try compiling with c++17 or higher, I believe that also fixes it. Even then, I don't see how looking for the macros is going to help as the library doesn't do any header includes to Windows, so I don't see where a check for it would actually work for all cases. It's better to just set it using command line arguments or during the configuration. But I personally it's better for the user to set it as some Windows header files use it and as such the user would need control over this. A cmake option would be a decent middle ground but I'll have to recreate this issue first for testing related reasons.

Adding

-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} /DNOMINMAX"

into your cmake arguments setting would work Or

target_compiler_definitions(replace-me PUBLIC NOMINMAX)
#or
add_compile_definitions(NOMINMAX)

in cmake

I believe this also works if you can use c++ 17 or higher.

-DCMAKE_CXX_STANDARD=17

or

set_property(TARGET replace-me PROPERTY CXX_STANDARD 17)
TheDreamsWind commented 3 years ago

Thanks for the clarification, I didn't realize it was part of a different library. What you suggested definitely resolves the issue, however I just don't like the fact of altering target-wide configuration in order to make one little peace of code work... I think setting C++ standard to 17 is more neutral because it doesn't add extra definition which is not needed, however Cmake probably just ignores this parameter for clang-cl. I ended up with adding it like this:

if(WIN32)
  add_compile_options(-Xclang -std=c++17)
endif()

However as you can see this option for clang-cl looks very specific and violates principle of compiler-agnostic configuration. I'll file an issue on string-view lite repo and hopefully they can resolve it on their side

yourWaifu commented 3 years ago

I believe they already fixed it, updating that library should fix it.