L'aggiunta di Boost fa sì che la compilazione del debug dipenda dalle DLL di runtime MSVC "non-D"

StackOverflow https://stackoverflow.com/questions/222778

Domanda

Ho un fastidioso problema che potrei essere in grado di eludere in qualche modo, ma d'altra parte preferirei essere al di sopra di esso e capire cosa sta succedendo esattamente, dal momento che sembra che questa roba sia davvero qui per rimanere.

Ecco la storia: ho una semplice app OpenGL che funziona benissimo: mai un grosso problema nella compilazione, collegamento o esecuzione. Ora ho deciso di provare a spostare alcuni dei calcoli più intensivi in ??un thread di lavoro, al fine di rendere la GUI ancora più reattiva & # 8212; usando Boost.Thread, ovviamente.

In breve, se aggiungo il seguente frammento all'inizio del mio file .cpp:

#include <boost/thread/thread.hpp>

void dummyThreadFun() { while (1); }    

boost::thread p(dummyThreadFun);

, quindi inizio a ottenere " Impossibile avviare questa applicazione perché MSVCP90.dll non è stato trovato " quando si tenta di avviare la build di debug. (La modalità di rilascio funziona bene.)

Ora guardando l'eseguibile usando Dependency Walker, che non trova questa DLL (che è prevedibile suppongo), potrei vedere che lo stiamo cercando per poter chiamare le seguenti funzioni:

?max@?$numeric_limits@K@std@@SAKXZ
?max@?$numeric_limits@_J@std@@SA_JXZ
?min@?$numeric_limits@K@std@@SAKXZ
?min@?$numeric_limits@_J@std@@SA_JXZ

Successivamente, ho provato a convertire tutte le istanze di min e max per utilizzare le macro, ma probabilmente non sono riuscito a trovare tutti i riferimenti a esse, poiché ciò non ha aiutato . (Sto usando alcune librerie esterne per le quali non ho il codice sorgente disponibile. Ma anche se potessi farlo & # 8212; Non penso che sia davvero il modo giusto.)

Quindi, le mie domande & # 8212; Suppongo & # 8212; sono:

  1. Perché cerchiamo una DLL non di debug anche se funziona con la build di debug?
  2. Qual è il modo corretto di risolvere il problema? O anche uno veloce e sporco?

L'ho avuto prima in un'installazione praticamente vaniglia di Visual Studio 2008. Quindi ho provato a installare Feature Pack e SP1, ma non hanno aiutato neanche. Naturalmente ho anche provato a ricostruire più volte.

Sto usando i binari predefiniti per Boost (v1.36.0). Questa non è la prima volta che utilizzo Boost in questo progetto, ma potrebbe essere la prima volta che utilizzo una parte basata su una fonte separata.

La disabilitazione del collegamento incrementale non aiuta. Il fatto che il programma sia OpenGL non sembra essere rilevante neanche & # 8212; Ho avuto un problema simile quando ho aggiunto le stesse tre righe di codice in un semplice programma console (ma lì si lamentava di MSVCR90.dll e _mkdir , e quando ho sostituito quest'ultimo con boost: : create_directory , il problema è scomparso !!). E in realtà è solo la rimozione o l'aggiunta di quelle tre righe che rende il programma funzionare correttamente, o non eseguire affatto, rispettivamente.

Non posso dire di capire Side-by-Side (non so nemmeno se questo è correlato, ma è quello che presumo per ora), e ad essere sincero, non sono neanche super interessato & # 8212; finché posso solo creare, eseguire il debug e distribuire la mia app ...


Modifica 1: Durante il tentativo di creare un esempio ridotto che riproduca comunque il problema, ho scoperto che il problema ha a che fare con Spread Toolkit , il cui utilizzo è un fattore comune a tutti i miei programmi con questo problema. (Tuttavia, non ho mai avuto questo prima di iniziare a creare collegamenti tra i contenuti di Boost.)

Ora ho escogitato un programma minimo che mi consente di riprodurre il problema. Si compone di due unità di compilazione, A.cpp e 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>

Alcune osservazioni:

  1. Se commento la riga SP_join di A.cpp, il problema scompare.
  2. Se commento la singola riga di B.cpp, il problema scompare.
  3. Se sposto o copio la riga singola di B.cpp all'inizio o alla fine di A.cpp, il problema scompare.

(Negli scenari 2 e 3, il programma si arresta in modo anomalo quando si chiama SP_join , ma è solo perché la cassetta postale non è valida ... questo non ha nulla a che fare con il problema a portata di mano.)

Inoltre, la libreria principale di Spread è collegata e fa sicuramente parte della risposta alla mia domanda n. 1, dal momento che non esiste una build di debug di quella lib nel mio sistema.

Attualmente, sto cercando di trovare qualcosa che renda possibile riprodurre il problema in un altro ambiente. (Anche se rimarrò piuttosto sorpreso se in realtà può essere ripetuto fuori dai miei locali ...)


Modifica 2: Ok, quindi qui noi ora ho un pacchetto con il quale sono stato in grado di riprodurre il problema su un'installazione quasi vanilla di WinXP32 + VS2008 + Boost 1.36.0 (ancora file binari predefiniti di BoostPro Computing ).

Il colpevole è sicuramente la libreria Spread, la cui build richiede in qualche modo una versione piuttosto arcaica di STLPort per MSVC 6 ! Tuttavia, trovo ancora i sintomi relativamente divertenti. Inoltre, sarebbe bello sapere se riesci davvero a riprodurre il problema & # 8212; compresi gli scenari 1-3 sopra. Il pacchetto è piuttosto piccolo e dovrebbe contenere tutti i pezzi necessari.

A quanto pare, il problema in realtà non aveva nulla a che fare con Boost. In particolare, poiché questo esempio ora utilizza la libreria Boost Filesystem. Inoltre, ora si lamenta di MSVCR90.dll, non di P come in precedenza.

È stato utile?

Soluzione

Boost.Thread ha alcune possibili combinazioni di build per cercare di soddisfare tutte le differenze nei possibili scenari di collegamento con MSVC. Innanzitutto, è possibile collegarsi staticamente a Boost.Thread oppure a Boost.Thread in una DLL separata. È quindi possibile collegarsi alla versione DLL del runtime MSVC o al runtime della libreria statica. Infine, puoi collegarti al runtime di debug o al runtime di rilascio.

Le intestazioni Boost.Thread provano a rilevare automaticamente lo scenario di compilazione utilizzando le macro predefinite generate dal compilatore. Per eseguire il collegamento con la versione che utilizza il runtime di debug, è necessario definire _DEBUG . Questo viene automaticamente definito dalle opzioni del compilatore / MD e / MDd, quindi dovrebbe essere OK, ma la descrizione del problema suggerisce diversamente.

Da dove hai preso i binari predefiniti? Stai selezionando esplicitamente una libreria nelle impostazioni del tuo progetto o stai permettendo al meccanismo di collegamento automatico di selezionare il file .lib appropriato?

Altri suggerimenti

Credo di aver avuto lo stesso problema con Boost in passato. Dalla mia comprensione capita perché le intestazioni Boost usano un'istruzione preprocessore per collegarsi contro la lib corretta. Se le librerie di debug e di rilascio si trovano nella stessa cartella e hanno nomi diversi, il "collegamento automatico" la funzione non funzionerà correttamente.

Quello che ho fatto è stato definire BOOST_ALL_NO_LIB per il mio progetto (che impedisce alle intestazioni di " auto linking ") e quindi utilizzare le impostazioni del progetto VC per collegarle alle librerie corrette.

Sembra che altre persone abbiano risposto al lato Boost del problema. Ecco un po 'di informazioni di base sul lato MSVC delle cose, che potrebbero salvare ulteriori mal di testa.

Esistono 4 versioni dei runtime C (e C ++) possibili:

  • / MT: libcmt.lib (C), libcpmt.lib (C ++)
  • / MTd: libcmtd.lib, libcpmtd.lib
  • / MD: msvcrt.lib, msvcprt.lib
  • / MDd: msvcrtd.lib, msvcprtd.lib

Le versioni DLL richiedono ancora il collegamento a quella lib statica (che in qualche modo fa tutto il setup per collegarsi alla DLL in fase di esecuzione - non conosco i dettagli). Si noti in tutti i casi che la versione di debug ha il suffisso d . Il runtime C utilizza l'infisso c e il runtime C ++ utilizza l'infisso cp . Vedi lo schema? In qualsiasi applicazione, dovresti sempre e solo collegarti alle librerie in una di quelle righe.

A volte (come nel tuo caso), ti ritrovi a collegarti alla libreria statica di qualcun altro che è configurata per utilizzare la versione sbagliata dei runtime C o C ++ (tramite il terribilmente fastidioso #pragma comment (lib) ). Puoi rilevarlo alzando la verbosità del tuo linker, ma è una vera PITA da cacciare. L '"uccide un roditore con un bazooka" la soluzione è utilizzare l'impostazione del linker / nodefaultlib: ... per escludere le 6 librerie C e C ++ che sai di non aver bisogno. L'ho usato in passato senza problemi, ma non sono sicuro che funzionerà sempre ... forse qualcuno uscirà dalla falegnameria dicendomi come questa "soluzione". può far sì che il tuo programma mangi i bambini il martedì pomeriggio.

Questo è un classico errore di collegamento. Sembra che tu stia collegandoti a Boost DLL che si collega al runtime C ++ errato (c'è anche questa pagina , esegui una ricerca testuale per " discussioni "). Sembra anche che la libreria boost :: posix :: time si colleghi alla DLL corretta.

Sfortunatamente, non sto trovando la pagina che discute su come scegliere la DLL Boost correttamente costruita (anche se ho trovato un email di tre anni che sembra indicare BOOST_THREAD_USE_DLL e BOOST_THREAD_USE_LIB ).


Guardando di nuovo la tua risposta, sembra che tu stia utilizzando i binari predefiniti. La DLL a cui non è possibile collegarsi è parte del feature pack TR1 (seconda domanda in quella pagina). Questo pacchetto di funzionalità è disponibile sul sito Web di Microsoft . Oppure avrai bisogno di un binario diverso per il collegamento. Apparentemente la libreria boost :: posix :: time si collega al runtime C ++ senza patch.

Dato che hai già applicato il feature pack, penso che il prossimo passo che farei sarebbe costruire Boost a mano. Questo è il percorso che ho sempre seguito, ed è molto semplice: scarica il binario di BJam , ed esegui lo script Boost Build nell'origine della libreria. Questo è tutto.

Ora questo è diventato ancora un po 'più interessante ... Se lo aggiungessi da qualche parte nella fonte:

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

(insieme al corrispondente #include ), quindi funziona di nuovo bene. Quindi questa è una soluzione rapida e nemmeno troppo sporca, ma hey & # 8212; cosa sta succedendo qui, davvero?

Dalla memoria, varie parti delle librerie boost richiedono la definizione di alcuni flag di preprocessore per poter essere compilati correttamente. Cose come BOOST_THREAD_USE_DLL e così via.

Il BOOST_THREAD_USE_DLL non sarà ciò che causa questo particolare errore, ma potrebbe aspettarsi che tu definisca _DEBUG o qualcosa del genere. Ricordo che alcuni anni fa nei nostri progetti C ++ boost avevamo alcune definizioni extra di preprocessore BOOST_XYZ dichiarate nelle opzioni del compilatore di Visual Studio (o makefile)

Controlla il file config.hpp nella directory del thread boost. Quando si inserisce il ptime , è possibile che includa un file config.hpp diverso, che può quindi definire diversamente tali elementi del preprocessore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top