Agregar Boost hace que la construcción de depuración dependa de las DLL de tiempo de ejecución de MSVC "no D"

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

Pregunta

Tengo un problema molesto que podría evitar de alguna manera, pero, por otro lado, preferiría estar encima de él y entender qué es exactamente lo que está pasando, ya que parece que estas cosas realmente están aquí para quedarse.

Aquí está la historia: tengo una aplicación OpenGL simple que funciona bien: nunca es un problema importante al compilarlo, enlazarlo o ejecutarlo. Ahora decidí intentar mover algunos de los cálculos más intensivos a un subproceso de trabajo, para posiblemente hacer que la GUI sea aún más receptiva & # 8212; usando Boost.Thread, por supuesto.

En resumen, si agrego el siguiente fragmento al principio de mi archivo .cpp:

#include <boost/thread/thread.hpp>

void dummyThreadFun() { while (1); }    

boost::thread p(dummyThreadFun);

, luego comienzo a recibir " Esta aplicación no pudo iniciarse porque no se encontró MSVCP90.dll " al intentar iniciar la compilación de depuración. (El modo de liberación funciona bien).

Ahora, mirando el ejecutable con Dependency Walker, que tampoco encuentra este DLL (que se espera que suponga), puedo ver que lo estamos buscando para poder llamar a las siguientes funciones:

?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

A continuación, intenté convertir cada instancia de min y max para usar macros, pero probablemente no encontré todas las referencias a ellas, ya que esto no ayudó . (Estoy usando algunas bibliotecas externas para las que no tengo el código fuente disponible. Pero incluso si pudiera hacer esto & # 8212; realmente no creo que sea la forma correcta).

Entonces, mis preguntas & # 8212; Supongo que & # 8212; son:

  1. ¿Por qué buscamos una DLL sin depuración 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 simple de Visual Studio 2008. Luego intenté instalar Feature Pack y SP1, pero tampoco me ayudaron. Por supuesto, también trató de 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.

Deshabilitar el enlace incremental no ayuda. El hecho de que el programa sea OpenGL no parece ser relevante tampoco & # 8212; Obtuve un problema similar al agregar las mismas tres líneas de código en un programa de consola simple (pero ahí se quejaba de MSVCR90.dll y _mkdir , y cuando reemplacé este último con un impulso de : : create_directory , el problema desapareció !!). Y realmente es solo eliminar o agregar esas tres líneas lo que hace que el programa se ejecute bien, o no se ejecute, respectivamente.

No puedo decir que entiendo lado a lado (ni siquiera sé si esto está relacionado pero eso es lo que supongo por ahora), y, para ser sincero, tampoco estoy muy interesado & # 8212; siempre que pueda compilar, depurar e implementar mi aplicación ...


Edición 1: Al intentar crear un ejemplo simplificado que reproduzca el problema, he descubierto que el problema tiene que ver con Spread Toolkit , cuyo uso es un factor común a todos mis programas que tienen este problema. (Sin embargo, nunca tuve esto antes de comenzar a enlazar en el contenido de Boost).

Ahora he creado un programa mínimo que me permite reproducir el problema. Se compone 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 la línea SP_join de A.cpp, el problema desaparece.
  2. Si comento la única línea de B.cpp, el problema desaparece.
  3. Si muevo o copio la línea única de B.cpp al principio o al final de A.cpp, el problema desaparece.

(En los escenarios 2 y 3, el programa se bloquea al llamar a SP_join , pero eso se debe a que el buzón no es válido ... esto no tiene nada que ver con el problema en cuestión.)

Además, la biblioteca central de Spread está vinculada, y eso seguramente es parte de la respuesta a mi pregunta # 1, ya que no hay una versión de depuración de esa biblioteca en mi sistema.

Actualmente, estoy tratando de encontrar algo que permita reproducir el problema en otro entorno. (Aunque me sorprenderá bastante si realmente se puede repetir fuera de mis instalaciones ...)


Edit 2: Ok, entonces aquí nosotros ahora tengo un paquete con el que pude reproducir el problema en una instalación casi falsa de WinXP32 + VS2008 + Boost 1.36.0 (todavía binarios precompilados desde BoostPro Computing ).

El culpable es seguramente el Spread lib, ¡mi compilación de la cual 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 puede reproducir el problema & # 8212; incluyendo los escenarios 1-3 anteriores. El paquete es bastante pequeño y debe contener todas las piezas necesarias.

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

¿Fue útil?

Solución

Boost.Thread tiene bastantes combinaciones de compilaciones posibles para intentar satisfacer todas las diferencias en los escenarios de vinculación posibles con MSVC. En primer lugar, puede enlazar 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 el tiempo de ejecución de la biblioteca estática. Finalmente, puede enlazar con el tiempo de ejecución de depuración o el tiempo de ejecución de lanzamiento.

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

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

Otros consejos

Creo que he tenido este mismo problema con Boost en el pasado. Según tengo entendido, esto sucede porque los encabezados de Boost usan una instrucción del preprocesador para vincularse con la biblioteca adecuada. Si sus bibliotecas de depuración y versión están en la misma carpeta y tienen nombres diferentes, " auto-link " La función no funcionará correctamente.

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

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

Hay 4 versiones de los tiempos de ejecución de C (y C ++) posibles:

  • / 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 aún requieren enlaces a esa biblioteca estática (que de alguna manera hace que toda la configuración se vincule a la DLL en tiempo de ejecución, no conozco los detalles). Observe que en todos los casos, la versión de depuración tiene el sufijo d . El tiempo de ejecución de C utiliza el infijo c , y el tiempo de ejecución de C ++ utiliza el infijo cp . ¿Ves el patrón? En cualquier aplicación, solo debes vincular a las bibliotecas en una de esas filas.

A veces (como en su caso), se encuentra enlazando a la biblioteca estática de otra persona que está configurada para usar la versión incorrecta de los tiempos de ejecución de C o C ++ (a través del comentario ). Puede detectar esto al aumentar la verbosidad de su enlazador, pero es un verdadero PITA para buscar. El " mata a un roedor con una bazuca " la solución es utilizar la configuración del enlazador / nodefaultlib: ... para descartar las bibliotecas 6 C y C ++ que sabe que no necesita. He usado esto en el pasado sin problemas, pero no estoy seguro de que siempre funcionará ... quizás alguien saldrá de la madera y me dirá cómo esta " solución " puede causar que su programa coma bebés los martes por la tarde.

Este es un error de enlace clásico. Parece que estás enlazando a un Boost DLL que a su vez enlaza con el tiempo de ejecución de C ++ incorrecto (también hay esta página , haga una búsqueda de texto para " hilos "). También parece que los enlaces de la biblioteca boost :: posix :: time a la DLL correcta.

Lamentablemente, no encuentro la página que explica cómo elegir el archivo DLL Boost correctamente creado (aunque sí encontré un correo electrónico de tres años que parece apuntar a BOOST_THREAD_USE_DLL y BOOST_THREAD_USE_LIB ).


Mirando tu respuesta de nuevo, parece que estás usando binarios pre-construidos. La DLL a la que no puede enlazar es parte del paquete de características TR1 (segunda pregunta en esa página). Ese paquete de características está disponible en el sitio web de Microsoft . O necesitarás un binario diferente para enlazar. Al parecer, la biblioteca boost :: posix :: time se vincula con el tiempo de ejecución de C ++ sin parches.

Ya que has aplicado el paquete de características, creo que el siguiente paso que daría sería construir Boost a mano. Ese es el camino que siempre he tomado, y es muy simple: descargue el binario BJam , y ejecute el script Boost Build en la fuente de la biblioteca. Eso es todo.

Ahora esto se volvió un poco más interesante ... Si simplemente agrego esto en algún lugar de la fuente:

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

(junto con el correspondiente #include ), entonces nuevamente funciona bien. Así que esta es una solución rápida y ni siquiera demasiado sucia, pero hey & # 8212; ¿Qué está pasando aquí, realmente?

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

El BOOST_THREAD_USE_DLL no será la causa de este error en particular, pero puede estar esperando que definas _DEBUG o algo por el estilo. Recuerdo que hace unos años, en nuestros proyectos de C ++ boost, tuvimos unas cuantas definiciones de preprocesador de BOOST_XYZ adicionales declaradas en las opciones del compilador de estudio visual (o makefile)

Verifique el archivo config.hpp en el directorio de subprocesos boost. Cuando introduce el código ptime , es posible que incluya un archivo diferente config.hpp , que luego puede definir esas cosas del preprocesador de manera diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top