[msvc] Utiliser LINK en ligne de commande

Le
K.
Bonjour, je dois compiler avec Microsoft Visual C++ quelque chose que je
réussis à compiler sous Linux ; or seul un ami peut le faire pour moi.
Mais comme il se trouve à distance et qu'il ne connaît pas bien la
programmation, j'essaie de le guider par messagerie instantanée. Cela a
marché tant que mes projets restaient simples ; là, nous avons passé la
matinée à tester des options sans réussir.

Quelques précisions : je lui ai fait installer Visual C++ Express ; comme
je n'ai pas l'habitude de travailler avec des interfaces de
développement, nous avons pris l'habitude de travailler en ligne de
commande ; je lui envoie un Makefile et il n'a qu'à taper NMAKE. Le tout
premier Makefile provenait d'un projet similaire ; et il marchait bien.

Je compile des plug-ins pour un logiciel, qui doivent se présenter sous
la forme de bibliothèques dynamiques ; dans mon cas il s'agit de fichier
*.so ; je lui fais bien entendu produire des DLL.

Jusqu'à aujourd'hui, je n'utilisais que des fonctions standard sans
appeler de bibliothèque extérieure. Cette fois, ET LA DIFFICULTÉ VIENT DE
LÀ, je souhaite inclure dans mon plug-in une bibliothèque statique (il
s'agit du parser mathématique muParser). De mon côté, tout se passe bien.
Mon propre Makefile appelle les commandes :

g++ -O3 -I ./includes/ -c -o plugin.o plugin.cpp
g++ -O3 -I ./includes/ -shared -o plugin.so plugin.o libmuparser.a

De son côté, le Makefile appelle les commandes CL et LINK. La première
produit bien un fichier de type .OBJ, apparemment sans le moindre
problème. Une fois cela fait, je n'ai pas réussi, malgré près d'une
dizaine de tentatives différentes, à trouver quelles options passer à
LINK pour parvenir au fichier DLL final.

J'ai évidemment pas mal cherché sur le web, mais la plupart des liens
pointent vers des explications concernant l'interface de Visual C++ avec
des concepts qui me sont largement étrangers et qui ne feront que
compliquer la tâche à mon ami ; je présume que la solution n'est pas loin
mais je suis surpris de toutes ces difficultés.

Cordialement, K.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Fabien LE LEZ
Le #18807481
On 02 Mar 2009 19:57:41 GMT, "K."
Bonjour, je dois compiler avec Microsoft Visual C++ quelque chose que je
réussis à compiler sous Linux



Si tu utilises g++ sous Linux, pourquoi ne pas aussi l'utiliser sous
Windows ? Il me semble que ça simplifierait considérablement les
choses.
http://www.mingw.org/
http://www.cygwin.com/
Sylvain Togni
Le #18810691
K. a écrit :

Jusqu'à aujourd'hui, je n'utilisais que des fonctions standard sans
appeler de bibliothèque extérieure. Cette fois, ET LA DIFFICULTÉ VIENT DE
LÀ, je souhaite inclure dans mon plug-in une bibliothèque statique (il
s'agit du parser mathématique muParser). De mon côté, tout se passe bien.
Mon propre Makefile appelle les commandes :

g++ -O3 -I ./includes/ -c -o plugin.o plugin.cpp
g++ -O3 -I ./includes/ -shared -o plugin.so plugin.o libmuparser.a



Je pense que ceci devrait convenir :

LINK /OUT:"plugin.dll" /DLL plugin.obj muparser.lib

Sinon un petit tour ici :

http://msdn.microsoft.com/en-us/library/y0zzbyt4(VS.80).aspx

--
Sylvain
Sylvain Togni
Le #18810681
Fabien LE LEZ a écrit :

Si tu utilises g++ sous Linux, pourquoi ne pas aussi l'utiliser sous
Windows ? Il me semble que ça simplifierait considérablement les
choses.
http://www.mingw.org/
http://www.cygwin.com/



À condition de ne pas avoir besoin de std::wstring, std::wcout, ...
car g++ ne les supporte pas sous Windows, ce qui rend ce compilateur
presque inutilisable dans cet OS où l'UTF-16 règne en maitre.

--
Sylvain
James Kanze
Le #18819001
On Mar 2, 8:57 pm, "K."
Bonjour, je dois compiler avec Microsoft Visual C++ quelque
chose que je réussis à compiler sous Linux ; or seul un ami
peut le faire pour moi. Mais comme il se trouve à distance et
qu'il ne connaît pas bien la programmation, j'essaie de le
guider par messagerie instantanée. Cela a marché tant que mes
projets restaient simples ; là, nous avons passé la matinée à
tester des options sans réussir.



Est-ce que tu n'as pas la possibilité d'installer une version de
Visual Studios dans une partition Windows chez toi ? Parce que
la procédure que tu décris me paraît ajouter des complications
pour rien ; ça serait nettement plus simple et plus rapide que
tu fais des essais toi-même, jusqu'à avoir déterminé exactement
ce qu'il faut.

Quelques précisions : je lui ai fait installer Visual C++
Express ; comme je n'ai pas l'habitude de travailler avec des
interfaces de développement, nous avons pris l'habitude de
travailler en ligne de commande ; je lui envoie un Makefile et
il n'a qu'à taper NMAKE. Le tout premier Makefile provenait
d'un projet similaire ; et il marchait bien.



C'est à peu près comment je travaille sous Windows. Mais
j'installe quand même un toolkit Unix (CygWin ou UWin --
j'expérimente actuellement avec MSys, mais il a des
modifications dans bash qui créent pas mal de problèmes.) Aussi,
je me suis standardisé sur GNU make, quelque soit la
plateforme ; ne pas avoir à s'occuper des problèmes de
portabilité des fichiers make, c'est un problème en moins. Et il
supporte des include et des functions définies par
l'utilisateur, qu'on peut s'arranger faire d'un répertoire qui
dépend de la configuration, ce qui permet à maintenir la partie
qui dépend de la plateforme dans un fichier à part : j'ai par
exemple :
buildExec = $(compile) -o $(1) $(3) $(2) $(addprefix -L,
$(4)) $(addprefix -l,$(5)) $(additionalLibraries)
dans gcc.mk (inclut par toutes les configurations qui utilisent
g++), et
buildExec = $(compile) -Fm$(strip $(6)) -Fd -Fe$(1) $(3)
$(2) $(patsubst %,-link '-libpath(%)',$(4)) $(5)
dans conf/i80x86-win32-vc80/system.mk (le fichier de
configuration pour VC++ 8.0 sous Windows 32 sur un processeur
Intel 32 bits). Je ne connais pas d'autre make qui en permet
autant. (En fait, mes fichiers make ont besoin de la version
3.81, parce qu'ils se servent aussi de $(eval...), une fonction
qui permet la génération dynamique du makefile même. C'est de la
méta-programmation générique en make -- aussi illisible que la
méta-programmation avec templates en C++, mais aussi puissant
aussi.)

Je compile des plug-ins pour un logiciel, qui doivent se
présenter sous la forme de bibliothèques dynamiques ; dans mon
cas il s'agit de fichier *.so ; je lui fais bien entendu
produire des DLL.



Tiens, tiens. C'est exactement le problème dont je m'occupe
depuis une semains.

La façon que fonction les objets chargés dynamiquement sous
Windows et bien différente que sous les Unix. En général, c'est
beaucoup plus robuste et sécure, mais en revanche, un peu plus
compliqué à mettre en oeuvre. Selon la façon que tu travailles,
tu pourrais même être amené à modifier les sources. (Jusqu'ici,
je l'ai évité dans mes utilisations. Mais le tout ne fonctionne
pas encore complètement.)

Jusqu'à aujourd'hui, je n'utilisais que des fonctions standard
sans appeler de bibliothèque extérieure. Cette fois, ET LA
DIFFICULTÉ VIENT DE LÀ, je souhaite inclure dans mon plug-in
une bibliothèque statique (il s'agit du parser mathématique
muParser). De mon côté, tout se passe bien. Mon propre
Makefile appelle les commandes :



g++ -O3 -I ./includes/ -c -o plugin.o plugin.cpp
g++ -O3 -I ./includes/ -shared -o plugin.so plugin.o libmuparser.a



De son côté, le Makefile appelle les commandes CL et LINK. La
première produit bien un fichier de type .OBJ, apparemment
sans le moindre problème. Une fois cela fait, je n'ai pas
réussi, malgré près d'une dizaine de tentatives différentes, à
trouver quelles options passer à LINK pour parvenir au fichier
DLL final.



D'abord, je n'utilise que cl comme commande, comme je n'utilise
que g++ ou CC sous Unix. Le $(compile) dans les exemples
ci-dessus est soit cl, soit g++... soit CC sous Solaris avec Sun
CC. (Dans le cas de VC++, je crois qu'effectivement, on pourrait
très bien se servir de link directement. Mais en général, je
crois que c'est préférable d'invoquer le pilote du compilateur,
avec toutes les options qui ont servies aussi lors des
compilations.)

J'ai évidemment pas mal cherché sur le web, mais la plupart
des liens pointent vers des explications concernant
l'interface de Visual C++ avec des concepts qui me sont
largement étrangers et qui ne feront que compliquer la tâche à
mon ami ; je présume que la solution n'est pas loin mais je
suis surpris de toutes ces difficultés.



Si tu as Visual Studios installé quelque part, la documentation
qui l'accompagne est excellante. Et il y a bien une section
« Building on the Command Line ». (Il y a aussi beaucoup sur
la façon que fonctionne les DLL sous Windows ; je te conseille
fortement de le lire.)

Enfin, la grande différence dans la philosophie des objets
dynamiques, c'est que sous Unix, au moins par défaut, quasiment
tous les symboles publics sont visible par tout. (Ce n'est pas
tout à fait le cas avec l'éditeur de liens GNU, qui sert sous
Linux, où il faut l'option -rdynamic pour qu'il comporte comme
les autres éditeurs de liens Unix.) Sous Windows, rien n'est
visible en dehors de l'objet dynamique par défaut ; il faut
dire explicitement tout ce qu'on veut exporter, soit sur la
ligne de commande, soit dans un fichier de definitions (.def),
soit au moyen d'une extension dans le compilateur, dans les
sources. J'utilise actuellement la deuxième solution ci-dessus,
avec génération automatique du fichier .def (parce qu'il y faut
des noms décorés) ; le noyau du script fait :
dumpbin -section:.text $x | egrep -v 'anonymous namespace' | eval
sed $sedArgs
où $sedArgs est construit à partir des options d'invocation du
script, qui spécifient ce qu'il faut exporter (namespaces,
classes, etc.). Je crois que c'est une bonne solution pour un
plugin, où tu as un nombre très limité de symboles à exporter,
et que et le chargement et la récherche de chaque symbol se fait
explicitement, au moyen de dlopen/dlsym ou
LoadLibrary/GetProcAddress. Il conviendrait certainement moins
bien pour un objet chargé implicitement ; je ne suis même pas
certain qu'il fonctionne dans ce cas-là.

Le deuxième problème que tu vas rencontrer, c'est que les
symboles définis dans la racine (le main) ne sont pas visible.
Ce qui veut dire qu'au moins par défaut, l'objet dynamque ne
peut pas s'en servir. Surtout que par défaut, la bibliothèque
système (l'équivalent de libc) est linké statiquement ; l'objet
dynamque n'y a donc pas accès au malloc qui te sert dans le
main, et incorporera sa propre copie (ce qui veut dire que la
mémoire allouée dans l'objet dynamique ne peut pas être libérée
dans le main et vice versa). Dans l'ensemble, c'est une décision
plus raisonable que la solution Unix ; si l'objet dynamique
compte sur la présence de la fonction xxx dans le main, c'est un
contrait sur le main (et dans l'état, j'ai trouvé pas mal des
cas dans mon code où l'objet dynamique dépendait des fonctions
qui étaient présentes, par hazard, dans mes programmes de test,
mais qui n'étaient pas du tout garantie dans tout main). En ce
qui concerne les fonctions du système, évidemment, la solution
est d'utiliser une version dynamique de la bibliothèque
système ; elle exporte tous les symboles. Et les contient, meme
si le main ne s'en est pas servi ; l'option ici (au moins si tu
invoques par cl), c'est /MDd (ou /MD, pour une version
non-debug). Et si tu as des fonctions à toi qui doivent servir à
la fois dans ton main et dans des objets dynamiques, je crois
qu'il faut les mettre dans un .dll à part (en les exportant),
que tu charges (implicitement ?) dans le main.

Enfin, c'est que j'ai trouvé jusqu'ici. Comme j'ai dit, je n'y
fais que commencer ; il y a donc certainement encore des
problèmes qui m'attendent. Mais ça pourrait te donner quelques
idées pour commencer.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Publicité
Poster une réponse
Anonyme