[thread] C++/CLI C# mixed code: linking to libthread yields runtime exception
Hi!
I am pretty sure this is an issue beyond boost, rather one of those
numerous pitfalls on the way to the M$-promised land called
CanUseOldCodeAndCppInDotNet.
OTOH I have hope that someone knows about some workaround,
OK, here the facts:
Win32, XP SP3, using Visual Studio 2008 SP1 with boost_1_37_0
I create a solution containing a C++/CLI project and a C# project, which
references the C++/CLI project.
Now if the C++/CLI project simply links to libboost_thread*, either
via autolink or via explicit configuration, the compiler creates an
executable which fails to start in both configurations, Debug and Release.
The debugger catches a System.BadImageFormatException.
Something went plain wrong.
OTOH adding the source files contained in \libs\thread\src\win32
to the project, defining BOOST_ALL_NO_LIB and adding
---
#pragma managed(push, off)
extern "C" void tss_cleanup_implemented(void) {}
#include
In order to add to the headache, here is a "workaround": Add libboost_thread-vc90-mt-1_37.lib to the "Ignore Specific Library" linker property section, add boost_thread-vc90-mt-gd-1_37.lib to the "Additional Dependencies", et voila: after copying its sister boost_thread-vc90-mt-gd-1_37.dll into the directory of the executable, the executable runs fine. Unfortunately ilmerge now fails to work properly ... Q1: Is this workaround safe? regards, Markus
Markus Werle
In order to add to the headache, here is a "workaround":
Add libboost_thread-vc90-mt-1_37.lib to the "Ignore Specific Library" linker property section, add boost_thread-vc90-mt-gd-1_37.lib to the "Additional Dependencies", et voila: after copying its sister boost_thread-vc90-mt-gd-1_37.dll into the directory of the executable, the executable runs fine.
You've forcibly replaced the static library with the DLL here. You're better off defining the right compiler+preprocessor directives to ensure that it is automatically selected. That way you'll ensure that the code in the main EXE is compatible with that in the DLL. Unfortunately, I can't remember what the required settings are at the moment. Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Anthony Williams schrieb:
Markus Werle
writes: In order to add to the headache, here is a "workaround":
Add libboost_thread-vc90-mt-1_37.lib to the "Ignore Specific Library" linker property section, add boost_thread-vc90-mt-gd-1_37.lib to the "Additional Dependencies", et voila: after copying its sister boost_thread-vc90-mt-gd-1_37.dll into the directory of the executable, the executable runs fine.
You've forcibly replaced the static library with the DLL here. You're better off defining the right compiler+preprocessor directives to ensure that it is automatically selected. That way you'll ensure that the code in the main EXE is compatible with that in the DLL.
Unfortunately, I can't remember what the required settings are at the moment.
Maybe you should use BOOST_ALL_DYN_LINK.
Markus Werle
OK, here the facts:
Win32, XP SP3, using Visual Studio 2008 SP1 with boost_1_37_0
I create a solution containing a C++/CLI project and a C# project, which references the C++/CLI project. Now if the C++/CLI project simply links to libboost_thread*, either via autolink or via explicit configuration, the compiler creates an executable which fails to start in both configurations, Debug and Release. The debugger catches a System.BadImageFormatException. Something went plain wrong.
OTOH adding the source files contained in \libs\thread\src\win32 to the project, defining BOOST_ALL_NO_LIB and adding
--- #pragma managed(push, off) extern "C" void tss_cleanup_implemented(void) {} #include
#pragma managed(pop) --- in a cpp file yields a working executable. Scratching my head.
Do you have any hint why linking to libboost_thread leads to this weird behaviour? Any idea what I might try? I can provide a stripped down project solution as zip-file on request.
The problem is that the static boost thread library tries to hook the native win32 PE TLS callbacks in order to ensure that the thread-local data used by boost thread is cleaned up correctly. This is not compatible with a C++/CLI executable. Your workaround explicitly omits the automatic TLS cleanup (and declares that you're doing it yourself by calling on_thread_exit at the appropriate time). Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Anthony Williams
The problem is that the static boost thread library tries to hook the native win32 PE TLS callbacks in order to ensure that the thread-local data used by boost thread is cleaned up correctly. This is not compatible with a C++/CLI executable.
So the auto-link feature should be switched off in C++/CLI, right?
Your workaround explicitly omits the automatic TLS cleanup (and declares that you're doing it yourself by calling on_thread_exit at the appropriate time).
I am lost here. Could you eventually provide some Good (TM) workaround and advice for this? regards, Markus
Markus Werle
Anthony Williams
writes: The problem is that the static boost thread library tries to hook the native win32 PE TLS callbacks in order to ensure that the thread-local data used by boost thread is cleaned up correctly. This is not compatible with a C++/CLI executable.
So the auto-link feature should be switched off in C++/CLI, right?
Maybe. Alternatively, it should force the use of the thread DLL rather than static lib.
Your workaround explicitly omits the automatic TLS cleanup (and declares that you're doing it yourself by calling on_thread_exit at the appropriate time).
I am lost here.
Boost.Thread uses some TLS variables for things like the current thread ID, interruption handles and so forth. In order to ensure that these things are correctly freed when a thread exits, on_thread_exit must be called when a thread exits. For the DLL build of Boost.Thread, this is done in the DLL_THREAD_DETACH handler. For the static lib, it hooks the win32 executable TLS callback to do this. If you provide tss_cleanup_implemented() you are declaring that you are going to do this yourself somehow (e.g. as part of the thread function).
Could you eventually provide some Good (TM) workaround and advice for this?
Link against the Boost.Thread DLL. Build your app with BOOST_THREAD_USE_DLL defined to force the auto-link to choose this, and ensure that the code is compatible. Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Anthony Williams
Link against the Boost.Thread DLL. Build your app with BOOST_THREAD_USE_DLL defined to force the auto-link to choose this, and ensure that the code is compatible.
Many thanks for taking time to clarify the issue. Defining BOOST_THREAD_USE_DLL in the mini demo project helps. (Only ilmerge fails to merge the C++/CLI DLL with the C# executable ...) Alas, for the RealWorld example containing some more spirit parser code this does not help either. The linker now correctly chooses the DLL: Linking... Searching libraries Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\MSVCRT.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\OLDNAMES.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\MSVCMRT.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\MSCOREE.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\msvcprt.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\uuid.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\comsupp.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\oleaut32.lib: Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\boost_thread-vc90-mt-1_37.lib: Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\libboost_date_time-vc90-mt-1_37.lib: but the executable shows the System.BadImageFormatException again. Any further idea? Am I not allowed to mix the static inclusion of date_time with the dynamic version of threads? I also tried BOOST_DYN_LINK, but even then libboost_date_time-vc90-mt-1_37.lib ist used by the linker. Then used BOOST_DATE_TIME_DYN_LINK which should have the same effect, but then linking chooses the correct libs: Searching libraries [...] Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\boost_thread-vc90-mt-1_37.lib: Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\boost_date_time-vc90-mt-1_37.lib: This looks odd to me. Ain't this a bug for DATE_TIME? Anyway, even then System.BadImageFormatException is thrown. I am lost again. regards, Markus
Markus Werle
Alas, for the RealWorld example containing some more spirit parser code this does not help either. The linker now correctly chooses the DLL:
Linking... Searching libraries Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\MSVCRT.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\OLDNAMES.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\MSVCMRT.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\MSCOREE.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\msvcprt.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\uuid.lib: Searching D:\Programme\Microsoft Visual Studio 9.0\VC\lib\comsupp.lib: Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\oleaut32.lib: Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\boost_thread-vc90-mt-1_37.lib: Searching D:\FEV-Data\Sourcen\FEV\TOPexpert\3rdParty\BOOST\boost_1_37_0 \stage\lib\libboost_date_time-vc90-mt-1_37.lib:
but the executable shows the System.BadImageFormatException again.
Any further idea?
Nope. I've never tried it myself; I just knew that TLS usage was a definite problem.
Am I not allowed to mix the static inclusion of date_time with the dynamic version of threads?
That shouldn't be a problem, because the parts of date-time used by threads are all header-only anyway. Sorry, but I have no further suggestions at this time. Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Markus Werle
I also tried BOOST_DYN_LINK, but even then libboost_date_time-vc90-mt-1_37.lib ist used by the linker. [...] This looks odd to me. Ain't this a bug for DATE_TIME?
Use BOOST_ALL_DYN_LINK instead of BOOST_DYN_LINK. http://www.nabble.com/BOOST_DYN_LINK-td18294892.html Markus
Anthony Williams
Link against the Boost.Thread DLL. Build your app with BOOST_THREAD_USE_DLL defined to force the auto-link to choose this, and ensure that the code is compatible.
As I explained in the parallel post, things still fail to run properly. Q: Can I circumvent the linker problem by simply adding a set of files from lib/threads and lib/XX and defining some macro (BOOST_THREAD_BUILD_LIB?)? Which files must be in the set? Which macros? I have to get this up and running and compile time never is my first problem ... regards, Markus P.S.: C++/CLI sucks.
Hi! I summarized the solutions in an exter post with subject "[solved] Using Boost in C++/CLI and C# mixed code environment" See e.g. http://thread.gmane.org/gmane.comp.lib.boost.user/44515 best regards, Markus
participants (3)
-
Anthony Williams
-
Hansi
-
Markus Werle