boostorg / thread

Boost.org thread module
http://boost.org/libs/thread
198 stars 162 forks source link

[boost-1.70.0] Linker error with llvm toolset in VS2017 #286

Open thebrandre opened 5 years ago

thebrandre commented 5 years ago

My setup: I use static boost-1.70.0 libraries with PlatformToolset v141 (Visual Studio 2017) and address-model=64 architecture=x86 runtime-link=shared on Windows 7.

When trying to link with PlatformToolset LLVM (clang-cl and lld-link based on clang-8.0), I get a linker error due to undefined symbols because BOOST_THREAD_DECL is resolved to __declspec(dllimport) even though I link statically. The rest of boost is working fine ... if you have doubts about my setup ;-)

The good news is that I already found a workaround: define BOOST_THREAD_USE_LIB globally whenever I use clang-cl. This solves the issue that clang-cl seems to be not detected correctly in lines 471 to 477 of boost/thread/detail/config.hpp

viboes commented 4 years ago

I have Nevers trier clangcl.

Andy pr IS welcome

thebrandre commented 4 years ago

I'll try and have a look into that ... if all the compilers supported in boost/config.hpp don't scare me off. ;-)

But at the very least, I can provide a detailed description:

Boost configuration:

These are more or less the default settings with Visual Studio 2017 64bit:

call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
.\bootstrap.bat
.\b2 -j8 toolset=msvc-14.1 architecture=x86 address-model=64 runtime-link=shared variant=debug,release --without-mpi --without-python --prefix=D:\lib\boost_1_71_0 install

Example program:

(Basically anything that uses boost.thread)

#include <boost/thread.hpp>
#include <iostream>

int main() {
    boost::thread Thread([]() { std::cout << "Hello World!" << std::endl; });
    Thread.join();
}

Compilation with msvc

call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
cl.exe example.cpp /EHsc /MD /DBOOST_ALL_NO_LIB /I D:\lib\boost_1_71_0\include\boost-1_71 /link /LIBPATH:D:\lib\boost_1_71_0\lib libboost_thread-vc141-mt-x64-1_71.lib

Note: autolink would work here but it doesn't with clang-cl when I want to link to the binaries generated by Visual Studio. So for compatibility, I avoid autolink via /DBOOST_ALL_NO_LIB here as well.

Compilation with clang-cl (fails)

When I now try to use clang-cl (version 8.0.1 in my case) as a drop-in replacement for msvc:

set PATH=%PATH%;C:\Program Files\LLVM\bin
clang-cl.exe example.cpp /EHsc /MD /DBOOST_ALL_NO_LIB /I D:\lib\boost_1_71_0\include\boost-1_71 /link /LIBPATH:D:\lib\boost_1_71_0\lib libboost_thread-vc141-mt-x64-1_71.lib

I'll get a lengthy linker_error. Luckily, that's the only issue with boost-1.70 and clang-cl that I had so far.

Compilation with clang-cl (workaround)

The hack I described earlier is to #define BOOST_THREAD_USE_LIB

set PATH=%PATH%;C:\Program Files\LLVM\bin
clang-cl.exe example.cpp /EHsc /MD /DBOOST_ALL_NO_LIB /DBOOST_THREAD_USE_LIB /I D:\lib\boost_1_71_0\include\boost-1_71 /link /LIBPATH:D:\lib\boost_1_71_0\lib libboost_thread-vc141-mt-x64-1_71.lib

Root of the problem

clang-cl defines _MSC_VER by ms-compatibility but BOOST_MSVC will not be set. So there is a subtle difference between the two.

#include <boost/thread.hpp>
#include <iostream>

int main() {
#ifdef _MSC_VER
    std::cout << "_MSC_VER is set to " << _MSC_VER << std::endl;
    std::cout << "_MSC_FULL_VER is set to " << _MSC_FULL_VER << std::endl;
#endif

#ifdef __clang__
    std::cout << "__clang_version__ is set to " << __clang_version__ << std::endl;
#else
    std::cout << "__clang__ is NOT SET!" << std::endl;
#endif

#ifdef BOOST_MSVC
    std::cout << "BOOST_MSVC is set to " << BOOST_MSVC << std::endl;
#else
    std::cout << "BOOST_MSVC is NOT SET!" << std::endl;
#endif
}

Output when compiled with Visual Studio 2017:

_MSC_VER is set to 1916 _MSC_FULL_VER is set to 191627032 __clang__ is NOT SET! BOOST_MSVC is set to 1916

Output when compiled with clang-cl:

_MSC_VER is set to 1922 _MSC_FULL_VER is set to 192227905 __clang_version__ is set to 8.0.1 (tags/RELEASE_801/final) BOOST_MSVC is NOT SET!

dmenendez-gruposantander commented 4 years ago

Hi, Just a reminder, this fix didn't make it into the 1.72.0 release. Could it be merged to the release branch so it gets into 1.73.0 please?

LowLevelMahn commented 4 years ago

Another reminder :)

We also try to use boost and clang-cl in a project its the perfect solution to pepare for a linux port and get rid of unwanted c++ microsoft extensions (warned by clang-cl)

is there anything todo to get that going - tests or something?

pdimov commented 4 years ago

The PR that is referenced above as fixing this issue should be in 1.74. You can download the beta from https://www.boost.org/users/history/version_1_74_0.html and see if the problem persists.

LowLevelMahn commented 4 years ago

tested with 1.74-rc2 - compiles without any problem, but now auto-link wants a different library (using also serialization in my small test, same happens also with regex)

compiler set to clang-cl in VS2017: libboost_serialization-clangw10-mt-gd-x32-1_74.lib

compiler set to microsoft-cl in VS2017: libboost_serialization-vc141-mt-gd-x32-1_74.lib

that was not needed with 1.73 (and nor of my other 10-20 third party libs need special builds) and i don't think that this behavior is correct or wanted - it removes the easy interchangeable feature of clang-cl - what i think was the main reason for building it

it seems that its not 100% clear what clang as a standalone and clang-cl as a MSVC source/binary compatible compiler means, or did i just configured something wrong with 1.74?