2008-10-21 9 views
5

Tengo un problema molesto que de alguna manera podría eludir, pero por otro lado preferiría estar en la parte superior y entender qué es exactamente pasando, ya que parece que esto realmente está aquí para quedarse.Agregar Boost hace que la compilación de depuración dependa de las DLL de tiempo de ejecución de MSVC "no D"

Aquí está la historia: Tengo una aplicación OpenGL simple que funciona bien: nunca un problema importante en la compilación, vinculación o ejecución. Ahora decidí tratar de mover algunos de los cálculos más intensivos en un hilo de trabajo, para posiblemente hacer que la GUI sea aún más receptiva, usando Boost.Thread, por supuesto.

En resumen, si añado el siguiente fragmento en el comienzo de mi archivo .cpp:

#include <boost/thread/thread.hpp> 

void dummyThreadFun() { while (1); }  

boost::thread p(dummyThreadFun); 

, entonces comienza a recibir "Esta aplicación no pudo iniciar porque no se encontró msvcp90.dll" cuando tratando de lanzar la compilación Debug (El modo de liberación funciona bien)

Ahora, mirando el archivo ejecutable usando Dependency Walker, que tampoco encuentra esta DLL (lo que se espera supongo), pude ver que lo estamos buscando para poder llamar a las siguientes funciones:

[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 

a continuación, traté de convertir todas las instancias de min y max utilizar macros en su lugar, pero probablemente no podría encontrar todas las referencias a ellos, ya que esto no ayuda. (Estoy usando algunas bibliotecas externas para las cuales no tengo el código fuente disponible. Pero incluso si pudiera hacer esto, no creo que sea la manera correcta en realidad.)

Entonces, mis preguntas - I Supongo que son:

  1. ¿Por qué buscamos una DLL sin errores aunque trabajemos con la compilación de depuración?
  2. ¿Cuál es la forma correcta de solucionar el problema? ¿O incluso uno rápido y sucio?

Tuve esto primero en una instalación bastante generalizada de Visual Studio 2008. Luego probé a instalar Feature Pack y SP1, pero tampoco me ayudaron. Por supuesto, también intenté reconstruir varias veces.

Estoy utilizando binarios precompilados para Boost (v1.36.0). Esta no es la primera vez que uso Boost en este proyecto, pero puede ser la primera vez que uso una parte que se basa en una fuente separada.

Desactivar el enlace incremental no ayuda. El hecho de que el programa es OpenGL tampoco parece ser relevante. Obtuve un problema similar al agregar las mismas tres líneas de código en un programa de consola simple (pero allí estaba quejándose de MSVCR90.dll y _mkdir, y cuando reemplazado este último con boost::create_directory, el problema desapareció !!). Y en realidad es solo eliminar o agregar esas tres líneas lo que hace que el programa se ejecute bien o no se ejecute en absoluto, respectivamente.

No puedo decir que entiendo Side-by-Side (ni siquiera sé si esto está relacionado, pero eso es lo que supongo por ahora), y para ser sincero, tampoco estoy muy interesado, siempre y cuando como puedo construir, depurar e implementar mi aplicación ...


Edición 1: Al tratar de construir un ejemplo reducidos al mínimo, que reproduce todos modos el problema, he descubierto que el problema tiene que ver con the Spread Toolkit, cuyo uso es un factor común a todos mi programas que tienen este problema (Sin embargo, nunca tuve esto antes de comenzar a vincular las cosas de Boost).

Ahora he encontrado un programa mínimo que me permite reproducir el problema. Consta de dos unidades de compilación, A.cpp y 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> 

Algunas observaciones:

  1. Si comento hacia fuera de la línea de SP_join a.cpp, el problema va lejos.
  2. Si comento la línea individual de B.cpp, el problema desaparece.
  3. Si muevo o copio la línea individual de B.cpp al principio o al final de A.cpp, el problema desaparece.

(En los escenarios 2 y 3, el programa se bloquea cuando se llama a SP_join, pero eso es sólo porque el buzón no es válida ... esto no tiene nada que ver con el tema en cuestión.)

Además , La biblioteca principal de Spread está vinculada, y eso seguramente forma parte de la respuesta a mi pregunta n. ° 1, ya que no hay una compilación de depuración de esa lib en mi sistema.

Actualmente, estoy tratando de encontrar algo que permita reproducir el problema en otro entorno. (A pesar de que voy a ser muy sorprendido si en realidad se puede repetir fuera de mi local ...)


Edición 2: Ok, así here ahora tenemos un paquete con el que yo era capaz de reproducir el problema en una instalación casi vanilla de WinXP32 + VS2008 + Boost 1.36.0 (todavía pre-built binaries from BoostPro Computing).

El culpable es sin duda el Spread lib, mi versión de la que de alguna manera requiere una versión bastante arcaica de STLPort para MSVC 6! Sin embargo, todavía encuentro los síntomas relativamente divertidos. Además, sería bueno saber si realmente puedes reproducir el problema, incluidos los escenarios 1-3 anteriores. El paquete es bastante pequeño y debe contener todas las piezas necesarias.

Como resultado, el problema en realidad no tenía nada que ver con Boost. Lea específicamente, ya que este ejemplo ahora usa la biblioteca Boost Filesystem. Además, ahora se queja de MSVCR90.dll, no de P como anteriormente.

Respuesta

2

Boost.Thread tiene bastantes combinaciones de construcción posibles para tratar de cubrir todas las diferencias en los escenarios de vinculación posibles con MSVC. En primer lugar, puede vincular estáticamente a Boost.Thread o enlazar a Boost.Thread en una DLL separada. A continuación, puede vincular a la versión DLL del tiempo de ejecución de MSVC o al tiempo de ejecución de la biblioteca estática. Finalmente, puede vincular el tiempo de ejecución de depuración o el tiempo de ejecución de la versión.

Los encabezados Boost.Thread intentan detectar automáticamente el escenario de compilación utilizando las macros predefinidas que genera el compilador. Para establecer un vínculo con la versión que utiliza el tiempo de ejecución de depuración, debe tener definido _DEBUG. Esto se define automáticamente por los modificadores de compilador/MD y/MDd, por lo que debería estar bien, pero la descripción de su problema sugiere lo contrario.

¿De dónde obtuviste los binarios preconstruidos? ¿Está seleccionando explícitamente una biblioteca en la configuración de su proyecto, o está dejando que el mecanismo de enlace automático seleccione el archivo .lib apropiado?

+0

Tengo definido _DEBUG ... Los binarios preconstruidos son de BoostPro Computing (http://www.boostpro.com/products/free), y estoy dejando que el mecanismo de enlace automático haga su trabajo. – Reunanen

+0

Eso es más extraño. Estoy perplejo en este momento. ¿Puedes reproducir el problema en un programa completo que puedes publicar? –

+0

Es difícil de decir en este momento, pero tendré que considerar esa posibilidad. – Reunanen

0

Ahora bien, esto tiene incluso un poco más interesante ... Si tan sólo añadir algún lugar de la fuente:

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

(junto con el material correspondiente #include), a continuación, de nuevo funciona bien. Entonces esta es una solución rápida y no demasiado sucia, pero bueno, ¿qué está pasando aquí realmente?

0

Desde la memoria varias partes de las bibliotecas de impulso necesitan definir algunos indicadores de preprocesador para poder compilar correctamente. Cosas como BOOST_THREAD_USE_DLL y así sucesivamente.

El BOOST_THREAD_USE_DLL no será el causante de este error en particular, pero es posible que espere que defina _DEBUG o algo así. Recuerdo que hace unos años en nuestro impulso C++ proyectos que teníamos bastantes BOOST_XYZ definiciones de preprocesador adicionales declarados en las opciones del compilador de Visual Studio (o makefile)

comprobar el archivo en el directorio config.hpp hilo impulso. Cuando ingresa ptime es posible que incluya un archivo diferente config.hpp, que luego puede definir las cosas del preprocesador de manera diferente.

1

Este es un error de enlace clásico. Parece que eres linking to a Boost DLL que se vincula con el tiempo de ejecución de C++ incorrecto (también hay this page, haz una búsqueda de texto para "hilos"). También parece que la biblioteca boost::posix::time está vinculada a la DLL correcta.

Por desgracia, no estoy encontrando la página que trata sobre cómo elegir el DLL correctamente incorporado Boost (aunque lo hice encontrar un three-year-old email que parece apuntar a BOOST_THREAD_USE_DLL y BOOST_THREAD_USE_LIB).


Al ver su respuesta de nuevo, parece que está utilizando binarios preconstruidos. La DLL a la que no puede vincular es part of the TR1 feature pack (segunda pregunta en esa página). That feature pack is available on Microsoft's website. O necesitarás un binario diferente para enlazar. Aparentemente, la biblioteca boost::posix::time enlaza con el tiempo de ejecución de C++ no parcheado.

Dado que ya ha aplicado el paquete de características, creo que el siguiente paso que tomaría sería construir Boost a mano. Esa es la ruta que siempre he tomado, y es muy simple: download the BJam binary, y ejecutar el script Boost Build en el origen de la biblioteca. Eso es.

1

Creo que he tenido este mismo problema con Boost en el pasado. Según tengo entendido, sucede porque los encabezados de Boost usan una instrucción de preprocesador para enlazar con la lib propia. Si sus bibliotecas de depuración y liberación están en la misma carpeta y tienen diferentes nombres, la característica "auto-link" no funcionará correctamente.

Lo que he hecho es definir BOOST_ALL_NO_LIB para mi proyecto (que impide que los encabezados se vinculen automáticamente) y luego usar la configuración del proyecto de VC para vincular con las bibliotecas correctas.

+0

No estoy seguro de si la respuesta fue útil para el OP, pero seguro que me ayudó. – DevSolar

1

Parece que otras personas han respondido al lado de Boost del problema. Aquí hay un poco de información general sobre el lado MSVC de las cosas, que puede ahorrar más dolor de cabeza.

Hay 4 versiones de la C (y C++) motores de ejecución posible:

  • /MT: LIBCMT.LIB (C), libcpmt.lib (C++)
  • /MTd: LIBCMTD.LIB libcpmtd.lib
  • /MD: msvcrt.lib, MSVCPRT.lib
  • /MDd: MSVCRTD.LIB MSVCPRTD.lib

Las versiones de DLL todavía requieren ligarse a que lib estática (que de alguna manera d Oes toda la configuración para vincular a la DLL en tiempo de ejecución - No sé los detalles). Tenga en cuenta que en todos los casos la versión de depuración tiene el sufijo d. El tiempo de ejecución de C usa el infijo c y el tiempo de ejecución de C++ usa el infijo cp. Ver el patrón? En cualquier aplicación, solo debería vincularse a las bibliotecas en una de esas filas.

A veces (como en su caso), se encuentra vinculando a la biblioteca estática de otra persona que está configurada para usar la versión incorrecta de los tiempos de ejecución C o C++ (a través del muy molesto #pragma comment(lib)). Puede detectar esto al aumentar la verbosidad de su enlazador, pero es un verdadero PITA que debe buscar. La solución "matar a un roedor con una bazooka" es usar la configuración del enlazador /nodefaultlib:... para descartar las 6 bibliotecas C y C++ que usted sabe que no necesita. He usado esto en el pasado sin problemas, pero no estoy seguro de que siempre funcione ... tal vez alguien saldrá de la carpintería y me dirá cómo esta "solución" puede hacer que su programa coman bebés los martes por la tarde. .

+1

El problema con el uso de/nodefaultlib para corregir los errores de enlace es que las definiciones de algunas estructuras de biblioteca de tiempo de ejecución cambian según la configuración del compilador. También las bibliotecas pueden cambiar * sus * estructuras dependiendo de la configuración del compilador. A continuación, puede golpear un comportamiento extraño. –

Cuestiones relacionadas