L'ajout de Boost rend la construction de débogage dépendante de & # 8220; non-D & # 8221; DLL d'exécution MSVC

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

Question

J'ai un problème ennuyeux que je pourrais peut-être contourner, mais d'un autre côté, je préférerais de loin être au-dessus et comprendre ce qui se passe exactement, car il semble que ce genre de choses est vraiment là pour rester.

Voici l’histoire: j’ai une application OpenGL simple qui fonctionne bien: jamais un problème majeur lors de la compilation, de la création de liens ou de l’exécution. Maintenant, j'ai décidé d'essayer de déplacer certains des calculs les plus intensifs dans un thread de travail, afin de rendre l'interface graphique encore plus réactive & # 8212; en utilisant Boost.Thread, bien sûr.

En bref, si j'ajoute le fragment suivant au début de mon fichier .cpp:

#include <boost/thread/thread.hpp>

void dummyThreadFun() { while (1); }    

boost::thread p(dummyThreadFun);

, je commence à obtenir "Cette application n'a pas pu démarrer car MSVCP90.dll n'a pas été trouvé" en essayant de lancer la construction Debug. (Le mode de libération fonctionne correctement.)

Maintenant, en regardant l’exécutable à l’aide de Dependency Walker, qui ne trouve pas non plus cette DLL (ce qui est attendu, je suppose), je me suis rendu compte que nous le recherchions pour pouvoir appeler les fonctions suivantes:

?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

Ensuite, j'ai essayé de convertir chaque instance de min et de max pour utiliser des macros à la place, mais je n'ai probablement pas trouvé toutes les références, car cela n'a pas aidé. . (J'utilise des bibliothèques externes pour lesquelles je n'ai pas le code source disponible. Mais même si je pouvais le faire, je ne pense pas que ce soit vraiment le bon moyen.)

Alors, mes questions & # 8212; Je suppose & # 8212; sont:

  1. Pourquoi cherchons-nous une DLL autre que de débogage alors que nous travaillons avec la version de débogage?
  2. Quelle est la bonne façon de résoudre le problème? Ou même un rapide et sale?

Je l’ai d'abord abordé dans une installation quasi-vanille de Visual Studio 2008. Ensuite, j'ai essayé d'installer Feature Pack et SP1, mais cela n'a pas aidé non plus. Bien sûr, nous avons également essayé de reconstruire plusieurs fois.

J'utilise des fichiers binaires prédéfinis pour Boost (v1.36.0). Ce n’est pas la première fois que j’utilise Boost dans ce projet, mais c’est peut-être la première fois que j’utilise une partie basée sur une source distincte.

Désactiver la liaison incrémentielle n'aide pas. Le fait que le programme soit OpenGL ne semble pas être pertinent non plus & # 8212; J'ai eu un problème similaire lors de l'ajout des trois mêmes lignes de code dans un programme de console simple (mais il se plaignait de MSVCR90.dll et de _mkdir , et j'ai remplacé ce dernier par boost: : create_directory , le problème a disparu !!). Et il s’agit simplement de supprimer ou d’ajouter ces trois lignes, ce qui permet au programme de fonctionner correctement ou de ne pas fonctionner du tout.

Je ne peux pas dire que je comprends côte à côte (je ne sais même pas si c'est lié, mais c'est ce que je suppose pour le moment), et pour être honnête, je ne suis pas non plus très intéressé & # 8212; tant que je peux juste construire, déboguer et déployer mon application ...

Modifier 1: Tout en essayant de créer un exemple dépouillé reproduisant le problème, j'ai découvert que le problème concernait Spread Toolkit , dont l’utilisation est un facteur commun à tous mes programmes rencontrant ce problème. (Cependant, je n'ai jamais eu cela avant de commencer à créer un lien dans le contenu Boost.)

Je viens maintenant de concevoir un programme minimal qui me permette de reproduire le problème. Il se compose de deux unités de compilation, A.cpp et 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>

Quelques observations:

  1. Si je commente la ligne SP_join de A.cpp, le problème disparaît.
  2. Si je commente la seule ligne de B.cpp, le problème disparaît.
  3. Si je déplace ou copie la ligne unique de B.cpp au début ou à la fin de A.cpp, le problème disparaît.

(Dans les scénarios 2 et 3, le programme se bloque lors de l'appel de SP_join , mais c'est uniquement parce que la boîte aux lettres n'est pas valide ... cela n'a rien à voir avec le problème actuel.)

De plus, la bibliothèque principale de Spread est liée, et cela fait sûrement partie de la réponse à ma question n ° 1, car il n'y a pas de version de débogage de cette lib dans mon système.

Actuellement, j'essaie de trouver quelque chose qui permettrait de reproduire le problème dans un autre environnement. (Même si je serais assez surpris que cela puisse être répété en dehors de mes locaux ...)

Modifier 2: OK, ici J'ai maintenant un paquet avec lequel j'ai pu reproduire le problème sur une installation presque vanille de WinXP32 + VS2008 + Boost 1.36.0 (toujours binaires pré-construits à partir de BoostPro Computing ).

Le coupable est sûrement la librairie Spread, dont la construction nécessite une version plutôt archaïque de STLPort pour MSVC 6 ! Néanmoins, je trouve toujours les symptômes relativement amusants. En outre, il serait intéressant de savoir si vous pouvez réellement reproduire le problème & # 8212; y compris les scénarios 1 à 3 ci-dessus. Le paquet est assez petit et devrait contenir toutes les pièces nécessaires.

Comme il s’est avéré que le problème n’avait vraiment rien à voir avec Boost.Thread, cet exemple utilise maintenant la bibliothèque Boost Filesystem. De plus, il se plaint maintenant de MSVCR90.dll et non de P comme précédemment.

Était-ce utile?

La solution

Boost.Thread propose un certain nombre de combinaisons de construction possibles pour essayer de prendre en compte toutes les différences de scénarios de liaison possibles avec MSVC. Tout d'abord, vous pouvez soit créer un lien statique vers Boost.Thread ou un lien vers Boost.Thread dans une DLL distincte. Vous pouvez ensuite créer un lien vers la version DLL du runtime MSVC ou le runtime de la bibliothèque statique. Enfin, vous pouvez créer un lien vers le runtime de débogage ou le runtime de version.

Les en-têtes Boost.Thread tentent de détecter automatiquement le scénario de construction à l'aide des macros prédéfinies générées par le compilateur. Pour créer un lien avec la version qui utilise le runtime de débogage, vous devez définir _DEBUG . Ceci est automatiquement défini par les commutateurs / MD et / MDd du compilateur, donc ça devrait aller, mais la description de votre problème suggère le contraire.

Où avez-vous obtenu les fichiers binaires pré-construits? Sélectionnez-vous explicitement une bibliothèque dans les paramètres de votre projet ou laissez-vous le mécanisme de liaison automatique sélectionner le fichier .lib approprié?

Autres conseils

Je pense avoir eu le même problème avec Boost dans le passé. À ma connaissance, cela se produit parce que les en-têtes Boost utilisent une instruction de préprocesseur pour établir une liaison avec la bibliothèque appropriée. Si vos bibliothèques de débogage et de publication se trouvent dans le même dossier et portent des noms différents, l'option "lien automatique". Cette fonctionnalité ne fonctionnera pas correctement.

Ce que j'ai fait est de définir BOOST_ALL_NO_LIB pour mon projet (ce qui empêche les en-têtes de "liaison automatique"), puis d'utiliser les paramètres du projet VC pour établir une liaison avec les bibliothèques appropriées.

On dirait que d'autres personnes ont répondu au problème Boost. Voici quelques informations de fond sur le côté MSVC, qui pourraient vous épargner davantage de maux de tête.

Il existe 4 versions des environnements d’exécution C (et C ++) possibles:

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

Les versions de DLL nécessitent toujours un lien vers cette bibliothèque statique (qui effectue en quelque sorte toute l'installation pour créer un lien vers la DLL au moment de l'exécution - je ne connais pas les détails). Notez que dans tous les cas, la version de débogage a le suffixe d . Le runtime C utilise l'infixe c et le runtime C ++ utilise l'infixe cp . Voir le motif? Dans toutes les applications, vous ne devez jamais créer de lien vers les bibliothèques de l'une de ces lignes.

Parfois (comme dans votre cas), vous vous retrouvez lié à la bibliothèque statique de quelqu'un d'autre configurée pour utiliser la mauvaise version des runtimes C ou C ++ (via le #pragma comment (lib) ). Vous pouvez le détecter en augmentant la verbosité de votre lieur, mais c’est un vrai PITA à chasser. "Tuez un rongeur avec un bazooka" La solution consiste à utiliser le paramètre de l'éditeur de liens / nodefaultlib: ... pour éliminer les 6 bibliothèques C et C ++ dont vous savez qu'elles ne sont pas nécessaires. J'ai déjà utilisé cela sans problème par le passé, mais je ne suis pas certain que cela fonctionnera toujours ... peut-être que quelqu'un sortira de la pièce en me disant comment cette "solution" peut amener votre programme à manger des bébés le mardi après-midi.

Ceci est une erreur de lien classique. Vous semblez créer un lien vers un Boost DLL liée elle-même au mauvais runtime C ++ (il existe également cette page , effectuez une recherche textuelle dans les "discussions"). Il semble également que la bibliothèque boost :: posix :: time relie la DLL correcte.

Malheureusement, je ne trouve pas la page qui explique comment choisir la DLL Boost correctement construite (bien que j'ai trouvé un email de trois ans qui semble pointer vers BOOST_THREAD_USE_DLL et BOOST_THREAD_USE_LIB ).

Si vous examinez de nouveau votre réponse, vous constaterez que vous utilisez des fichiers binaires prédéfinis. La DLL que vous ne pouvez pas lier est fait partie du pack de fonctionnalités TR1 (deuxième question de cette page). Cet ensemble de fonctionnalités est disponible sur le site Web de Microsoft. . Ou vous aurez besoin d'un autre binaire pour faire le lien. Apparemment, la bibliothèque boost :: posix :: time est liée au runtime C ++ non corrigé.

Puisque vous avez déjà appliqué le pack de fonctionnalités, je pense que la prochaine étape que je prendrais serait de créer Boost à la main. C’est le chemin que j’ai toujours emprunté, et c’est très simple: télécharger le fichier binaire BJam , et exécutez le script Boost Build dans la source de la bibliothèque. C'est ça.

Maintenant, cela devient encore un peu plus intéressant ... Si je viens d'ajouter ceci quelque part dans la source:

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

(avec les éléments #include correspondants), cela fonctionne à nouveau correctement. C’est donc une solution rapide et pas trop sale, mais bon, que se passe-t-il vraiment ici?

De mémoire, diverses parties des bibliothèques boost nécessitent que vous définissiez des indicateurs de préprocesseur afin de pouvoir compiler correctement. Des choses comme BOOST_THREAD_USE_DLL et ainsi de suite.

Le BOOST_THREAD_USE_DLL ne sera pas la cause de cette erreur particulière, mais il peut s’attendre à ce que vous définissiez _DEBUG ou quelque chose du genre. Je me souviens qu'il y a quelques années, dans nos projets de boost C ++, nous avions quelques définitions de préprocesseur BOOST_XYZ supplémentaires déclarées dans les options du compilateur Visual Studio (ou le fichier Make)

Vérifiez le fichier config.hpp dans le répertoire du thread boost. Lorsque vous récupérez le fichier ptime , il peut éventuellement inclure un fichier config.hpp différent, qui peut ensuite définir ces éléments de préprocesseur différemment.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top