2008-10-21 53 views
5

我有一個令人討厭的問題,我可能會以某種方式規避,但另一方面,將更重要的是它的頂部,並明白究竟是什麼繼續,因爲它看起來像這個東西真的留在這裏。添加Boost使調試版本依賴於「非D」MSVC運行時DLL

下面是故事:我有一個簡單的OpenGL應用程序,它工作正常:在編譯,鏈接或運行它時從未遇到過大問題。現在我決定嘗試將一些更密集的計算轉移到工作線程中,以便可能使GUI更加響應 - 當然使用Boost.Thread。

總之,如果我在.cpp文件的開頭添加下面的代碼片段:

#include <boost/thread/thread.hpp> 

void dummyThreadFun() { while (1); }  

boost::thread p(dummyThreadFun); 

,然後我開始變得「​​這個應用程序未能啓動,因爲MSVCP90.dll未找到」的時候試圖啓動Debug版本。 (發佈模式工作正常。)

現在看着使用Dependency Walker的可執行文件,誰也沒有找到這個DLL(這是我預期的),我可以看到我們正在尋找它以便能夠調用以下功能:

[email protected][email protected]@[email protected]@SAKXZ 
[email protected][email protected][email protected]@@SA_JXZ 
[email protected][email protected]@[email protected]@SAKXZ 
[email protected][email protected][email protected]@@SA_JXZ 

接下來,我想每一個實例轉換的minmax使用宏來代替,但可能找不到給他們的所有引用,因爲這並沒有幫助。 (我正在使用一些外部庫,但是我沒有可用的源代碼,但即使我能做到這一點 - 我不認爲這是真的。)

所以,我的問題 - 我猜 - 是:

  1. 爲什麼我們尋找一個非調試DLL,即使使用調試版本?
  2. 解決此問題的正確方法是什麼?甚至是一個快速和骯髒的?

我曾在Visual Studio 2008的一個非常香草的安裝中首次嘗試安裝此功能包和SP1,但它們都沒有幫助。當然也試圖重建好幾次。

我爲Boost(v1.36.0)使用預先構建的二進制文件。這不是我第一次在這個項目中使用Boost,但這可能是我第一次使用基於單獨源的部分。

禁用增量鏈接無濟於事。該程序是OpenGL的事實似乎也不相關 - 當我在一個簡單的控制檯程序中添加相同的三行代碼時,我遇到了類似的問題(但那裏是抱怨MSVCR90.dll和_mkdir,當我用boost::create_directory替換後者,問題就消失了!!)。這實際上只是刪除或添加這三行,這使得程序運行正常,或者根本不運行。

我不能說我理解並排(甚至不知道這是否相關,但這是我現在假設的),並且說實話,我也沒有超級感興趣 - 只要因爲我可以構建,調試和部署我的應用程序......


編輯1:在試圖建立一個精簡的例子,反正重現問題,我發現這個問題與the Spread Toolkit做的,它的使用是共同的一個因素我所有的有這個問題的程序。 (但是,在開始鏈接Boost之前,我從來沒有這樣做過。)

我現在想出了一個最小化的程序,可以讓我重現問題。它由兩個編譯單元A.cpp和B.cpp組成。

A.cpp:

#include "sp.h" 

int main(int argc, char* argv[]) 
{ 
    mailbox mbox = -1; 
    SP_join(mbox, "foo"); 

    return 0; 
} 

B.cpp:

#include <boost/filesystem.hpp> 

一些觀察:

  1. 如果我註釋掉線A.cpp的SP_join,問題消失遠。
  2. 如果我註釋掉B.cpp的單行,問題就會消失。
  3. 如果我將B.cpp的單行移動或複製到A.cpp的開頭或結尾,問題就會消失。

(在方案2和3,程序崩潰調用SP_join時,但這只是因爲郵箱是無效...這無關手頭的問題。)

另外,Spread的核心庫被鏈接進來,這肯定是我的問題#1的答案的一部分,因爲在我的系統中沒有該庫的調試版本。

目前,我試圖想出一些能夠在另一個環境中重現問題的東西。 (雖然我會非常驚訝,如果它實際上可以重複我的處所外...)


編輯2:好了,所以here我們現在有利用這點我是能夠重現一個包問題幾乎香草安裝的WinXP32 + VS2008 +升壓1.36.0(仍然pre-built binaries from BoostPro Computing)。

罪魁禍首肯定是Spread lib,我的內部版本不知何故需要一個相當古老的STLPort版本,用於MSVC 6!儘管如此,我仍然覺得這些症狀比較有趣。另外,如果你真的能夠重現這個問題 - 包括上面的情況1-3,這將非常令人高興。包很小,它應該包含所有必要的部分。

事實證明,這個問題並沒有真正與Boost.Thread有關,因爲這個例子現在使用了Boost Filesystem庫。此外,它現在抱怨MSVCR90.dll,而不是像以前那樣。

回答

2

Boost.Thread爲了儘量滿足在連接的情況可能與MSVC的所有分歧有不少可能構建的組合。首先,您可以靜態鏈接到Boost.Thread,或者鏈接到單獨的DLL中的Boost.Thread。然後,您可以鏈接到MSVC運行時的DLL版本或靜態庫運行時。最後,您可以鏈接到調試運行時或發佈運行時。

的Boost.Thread頭嘗試自動檢測使用編譯器生成預定義宏構建方案。爲了鏈接到使用調試運行時的版本,您需要定義_DEBUG。這是由/ MD和/ MDd編譯器開關自動定義的,所以它應該是可以的,但是你的問題描述是另外的。

你從哪裏得到預構建的二進制文件?你是否明確地在項目設置中選擇了一個庫,還是讓自動鏈接機制選擇適當的.lib文件?

+0

我確實有_DEBUG定義...預構建的二進制文件來自BoostPro Computing(http://www.boostpro.com/products/free),我讓自動鏈接機制完成它的工作。 – Reunanen 2008-10-22 14:26:16

+0

這是最離奇的。我現在很難過。你可以在一個完整的程序中重現問題,你可以發佈? – 2008-10-22 14:37:01

+0

現在很難說,但我必須考慮這種可能性。 – Reunanen 2008-10-22 16:00:22

0

現在,這得到了甚至有點更有趣...如果我只是添加此某處來源:(與相應的#include東西一起)

boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time(); 

,然後再次工作正常。所以這是一個快速,甚至不太骯髒的解決方案,但嘿 - 這裏發生了什麼,真的嗎?

0

從內存Boost庫的各個部分需要你,以便能夠正確編譯定義一些預處理標誌。東西像BOOST_THREAD_USE_DLL等。

BOOST_THREAD_USE_DLL不會是什麼導致這個特定的錯誤,但它可能會期望您定義_DEBUG或類似的東西。我記得幾年前在我們的C++ boost項目中,我們在visual studio編譯器選項(或makefile)中聲明瞭額外的BOOST_XYZ預處理器定義。

檢查boost線程目錄中的config.hpp文件。當你拉動ptime的東西時,它可能會包含一個不同的config.hpp文件,然後它可能會以不同的方式定義這些預處理器的東西。

1

這是一個經典的鏈接錯誤。它看起來像你自己鏈接到錯誤的C++運行時(this page,做一個「線程」的文本搜索)的linking to a Boost DLL。它也看起來像boost::posix::time庫鏈接到正確的DLL。

不幸的是,我沒有找到討論如何選擇正確構建的Boost DLL的頁面(雖然我的確發現了一個似乎指向BOOST_THREAD_USE_DLLBOOST_THREAD_USE_LIBthree-year-old email)。


再次查看您的答案,看起來您使用的是預構建的二進制文件。您無法鏈接到的DLL是part of the TR1 feature pack(該頁面的第二個問題)。 That feature pack is available on Microsoft's website。或者你需要一個不同的二進制文件來鏈接。顯然,boost::posix::time庫與未打補丁的C++運行庫鏈接。

既然你已經應用了功能包,我想下一步我想借此將手工編譯升壓。這是我一直採用的路徑,非常簡單:download the BJam binary,並在庫源代碼中運行Boost Build腳本。而已。

1

我相信我曾與在過去的升壓此相同的問題。根據我的理解,這是因爲Boost頭文件使用預處理器指令來鏈接正確的lib。如果您的調試和發佈庫位於相同的文件夾中並且名稱不同,則「自動鏈接」功能將無法正常工作。

我所做的就是定義BOOST_ALL_NO_LIB爲我的項目(防止頭從「自動連接」),然後使用VC項目設置以對正確的庫鏈接。

1

看起來像其他人已經回答了問題的提振方面。這裏有一些關於MSVC方面的背景信息,這可能會進一步減少頭痛。

有4個版本的C(和C++)的運行時會可能:

  • /MT:LIBCMT.LIB(C),libcpmt.lib(C++)
  • /MTD:libcmtd.lib, libcpmtd.lib
  • /MD:MSVCRT.LIB,msvcprt.lib
  • /MDD:MSVCRTD.LIB,msvcprtd.lib

的DLL版本仍然需要鏈接到靜態庫(這在某種程度上d在運行時鏈接到DLL的所有設置 - 我不知道細節)。注意在所有情況下調試版本都有d後綴。 C運行時使用c中綴,而C++運行時使用cp中綴。看到模式?在任何應用程序中,您只能鏈接到其中一行中的庫。

有時(和你的情況一樣),你會發現自己鏈接到其他人的靜態庫,它被配置爲使用錯誤版本的C或C++運行時(通過非常惱人的#pragma comment(lib))。你可以通過鏈接器詳細的方式來檢測,但它是一個真正的PITA尋找。 「用火箭筒殺死一個齧齒動物」解決方案是使用/nodefaultlib:...鏈接器設置來排除你知道你不需要的6個C和C++庫。我過去沒有用過這個問題,但我不積極,它會一直工作......也許有人會從木製作品中告訴我,這個「解決方案」如何導致您的程序在週二下午吃掉嬰兒。