Langages informatiques permettant de faire des pilotes de type "bibliothèques dynamiques"
Ces logiciels sont toujours des langages compilés, permettant d'obtenir des exécutables. Ils sont classés par ordre alphabétique (B, C, P), en commençant dans chaque catégorie par les logiciels libres.
Les exemples de code sont volontairement réduits, car pour faire un "vrai" pilote, il faut plusieurs dizaines de ligne de code, ce qui aurait été trop long dans ce document. L'important est de savoir qu'on peut faire des bibliothèques dynamiques avec les logiciels cités ci-dessous. Pour une réalisation pratique, le plus simple est de télécharger les exemples disponibles sur Internet (http://sciencexp.free.fr/index.php?perma=pilotes_demonstration), et de les modifier pour les adapter à votre appareil de mesure ou votre dispositif expérimental.
Langages de type "Basic"
Contrairement au Pascal (voir plus bas), l'en-tête du fichier-source ne contient pas d'indication de ce que doit être le fichier compilé. Pour que ce soit une bibliothèque dynamique, il faut l'indiquer dans des options de compilation.
FreeBasic (logiciel libre pour Linux et Windows
Site internet : http://fbide.freebasic.net/, et http://sourceforge.net/projects/fbc/
Sous Linux comme sous Windows, on peut utiliser le compilateur en ligne de commande, après avoir rédigé le programme-source avec un éditeur de texte.
Sous Windows, il existe un environnement de développement intégré, qui peut rendre la rédaction des programmes beaucoup plus agréable. Cet environnement de développement peut être configuré en diverses langues par "Voir | Paramètres".
Lorsqu'on utilise la compilation en ligne de commande, il faut indiquer que la destination est une bibliothèque dynamique par "-dll" avant le nom du fichier à compiler.
Par exemple fbc monprog.bas va compiler le fichier monprog.bas et faire un fichier exécutable monprog.exe sous Windows et monprog sous Linux. Au contraire, fbc -dll mabib.bas va compiler le fichier mabib.bas pour faire une bibliothèque dynamique mabib.dll sous Windows (ou son équivalent .so sous Linux).
public function cead cdecl alias "cead" (byval n as integer) as double export
function = ead(n)
end function
public function cnead cdecl alias "cnead" (byval n as integer) as zstring pointer export
function = nead(n)
end function
Sous Windows, dans l'environnement de programmation FBIDE, dans le menu "Voir | Paramètres | FreeBasic", on peut aussi indiquer au compilateur que le fichier compilé devra être une bibliothèque dynamique, là encore par le mot -dll. ("<$fbc>" -dll "<$file>")
Attention !
Lorsqu'on déclare une fonction "stdcall", FreeBasic ajoute automatiquement à son nom une "décoration" sous la forme d'un suffixe du type @8, ou @4, ou autre. Ce suffixe est une indication pour certains logiciels du type des paramètres à utiliser, mais ça pose problème aux logiciels utilisateurs qui ne trouvent pas la fonction avec le nom qu'ils ont demandé.
Pour les fonctions sans paramètre, ou avec un seul paramètre, la solution est de déclarer la fonction de type "pascal" au lieu de "stdcall" : il n'y a aucun suffixe ajouté, et tout se passe bien (voir l'exemple ci-dessus).. Par contre, pour les fonctions avec deux paramètres (fonctions de sortie sa, sad, sb), cela aboutit à un mélange dans les paramètres,et ces fonctions ne sont pas utilisables.
Il n'y a pas de problème pour les fonctions déclarées "cdecl", où aucun suffixe n'est ajouté.
OxygenBasic (pour Windows)
Voir www.oxygenbasic.org
Spontanément, ce langage fait un fichier exécutable (.exe), de très petite taille, mais qui doit pouvoir accéder à une bibliothèque dynamique spéciale, oxygen.dll. Il n'a pas beaucoup de fonctions intégrées, mais il peut accéder facilement à des bibliothèques dynamiques, en particulier celles de l'API du système d'exploitation, ce qui lui donne alors beaucoup plus de puissance.
Si on veut que le résultat de la compilation soit une bibliothèque dynamique, il faut l'indiquer en début de programme par
$dll
et pour donner le nom du fichier résultant, on indique par une ligne du type :
#File "nom_de_la_bibliotheque.dll".
On déclare ensuite les diverses fonctions que l'on veut utiliser à partir de fichiers extérieurs (en particulier du système d'exploitation), par des instructions du type :
declare function GetTickCount lib "kernel32.dll" alias "GetTickCount" as long
Ceci permet ensuite de faire des fonctions exportables du type :
function stdead stdcall alias "stdead" (byval n as dword) as double export
select n
case 0 : return gettickcount()
case else : return n*1.1 +3
end select
end function
function stdnead stdcall alias "stdnead" (byval n as dword) as zstring export
select n
case 0 : return @"gettickcount"
case else : return @""
end select
end function
PowerBasic (pour Windows)
PowerBasic provient de l'évolution de TurboBasic, autrefois commercialisé par Borland. Cette famille de logiciels est vendue sur www.powerbasic.com. On peut en obtenir une version gratuite sur https://shop.powerbasic.com/pages/powerbasic-product-catalog mais il faut l'activer par une clé d'identification que l'on reçoit en s'inscrivant et donnant son adresse. Le développement semble arrêté à la suite du décès du fondateur.
La version « Classic PowerBASIC for Windows » permet de faire des bibliothèques dynamiques et de les utiliser ; la version « Classic PowerBASIC Console Compiler » permet seulement de les utiliser.
#DIM ALL
#COMPILE DLL "bibdynsyst_powerbasic2016b.DLL"
#INCLUDE "WIN32API.INC"
FUNCTION stdead SDECL ALIAS "stdead"(BYVAL n AS LONG)EXPORT AS DOUBLE
DIM result AS DOUBLE
IF n= 0 THEN
result=TIMER MOD 60
ELSEIF n=1 THEN
result=11.03
ELSE
result=-777.03
END IF
FUNCTION=result
END FUNCTION
FUNCTION cead CDECL ALIAS "cead" (BYVAL n AS LONG) EXPORT AS DOUBLE
FUNCTION=stdead(n) : END FUNCTION
FUNCTION stdnead SDECL ALIAS "stdnead" (BYVAL n AS LONG)EXPORT AS STRING
IF n=0 THEN
FUNCTION="EAD 0:s dans min"+CHR$(0)
ELSEIF n=1 THEN
FUNCTION="EAD 1" +CHR$(0)
ELSE
FUNCTION="" +CHR$(0)
END IF
END FUNCTION
FUNCTION cnead CDECL ALIAS "cnead" (BYVAL n AS LONG) EXPORT AS STRING
FUNCTION=stdnead(n):END FUNCTION
FUNCTION stdtitre SDECL ALIAS "stdtitre" EXPORT AS DWORD
DIM chloc AS STRING
chloc="bibdynsyst PowerBasic"
FUNCTION=STRPTR(chloc)
END FUNCTION
FUNCTION ctitre CDECL ALIAS "ctitre" EXPORT AS DWORD
FUNCTION=stdtitre : END FUNCTION
FUNCTION LIBMAIN (BYVAL hInstance AS LONG, BYVAL fwdReason AS LONG, BYVAL lpvReserved AS LONG) AS LONG
SELECT CASE fwdReason
CASE %DLL_PROCESS_ATTACH : FUNCTION = 1 'success!
CASE %DLL_PROCESS_DETACH : FUNCTION = 1 'success!
CASE %DLL_THREAD_ATTACH : FUNCTION = 1 'success!
CASE %DLL_THREAD_DETACH : FUNCTION = 1 'success!
END SELECT
END FUNCTION
PureBasic (pour Linux et Windows)
Contrairement à FreeBasic, PureBasic n'est pas un logiciel libre. Il est vendu par Fantaisie Software. Une version d'essai est téléchargeable sur internet (www.purebasic.fr, ou .com, ou .de). La version d'essai ne permet pas de compiler des bibliothèques dynamiques, mais seulement de les utiliser : pour faire des bibliothèques dynamiques, il faut la version commerciale complète.
Aussi bien sous Linux que sous Windows, PureBasic fonctionne par un environnement de développement intégré, en diverses langues : français, anglais, allemand ou espagnol.
Par défaut, lorsqu'on utilise l'option la plus évidente (Compilateur | Compiler-Exécuter), la compilation ne fait pas de fichier exécutable créé sur disque. Pour créer un fichier exécutable sur disque (donc ici un fichier de bibliothèque dynamique), il faut utiliser l'option Compilateur | Créer un exécutable.
Pour que la compilation soit faite sous forme de bibliothèque dynamique, il faut le préciser dans les options de compilation (Compilateur | Options du compilateur) la première fois que l'on compile le programme-source. Ensuite, ces réglages seront mémorisés dans le fichier-source, à la fin du programme lui-même (ils n'apparaissent pas dans l'éditeur de PureBasic, mais on peut les voir facilement en éditant le programme avec un autre éditeur).
ProcedureCDLL .d cead(n .i)
ProcedureReturn(ead(n))
EndProcedure
ProcedureCDLL .s cnead(n .i)
ProcedureReturn(nead(n))
EndProcedure
PureBasic n'a pas d'option spéciale pour pouvoir utiliser des paramètres par référence (= par variable) dans les fonctions, mais on peut utiliser des pointeurs, ce qui aboutit au même résultat (même si le programme-source est moins clair) :
ProcedureCDLL ceadref(*n.INTEGER,*x.DOUBLE) :
*x\d=cead(*n\i)
EndProcedure
Changement important à partir de la version 5.50 : les chaînes de caractères sont codées en Unicode.
Le codage Unicode correspond à 2 octets par caractère, or les fonctions de nommage du système Mensura sont codées en ASCII-ANSI, avec un seul octet par caractère. Ceci pose des problèmes aux logiciels Mensura (MGW32, Mensurasoft-LZ, Mensurasoft-PB...), qui interprètent mal ces séries de caractères dont la moitié sont des caractères nuls : les chaînes de caractères sont tronquées, et de longueur nulle ou quasi-nulle.
Une solution est de forcer les fonctions de nommage à donner des chaînes ASCII-ANSI :
Procedure .s chaineascii(ch$)
*tableau=@ch$
souschaine$=""
For i =1 To Len(ch$)
souschaine$=souschaine$+Chr(Asc(Mid(ch$,i,1)))
Next i
PokeS(*tableau,souschaine$,Len(souschaine$),#PB_Ascii)
ProcedureReturn(ch$)
EndProcedure
Ensuite, pour chaque fonction de nommage, au lieu de renvoyer une chaîne normale (procedurereturn(chdetail$)), on renvoie le résultat de la transformation par la fonction chaineascii (procedurereturn(chaineascii(chdetail$))).
Dans le futur, une autre solution sera d'utiliser consciemment des fonctions de nommage codées en Unicode-UTF8 : cUTF8detail, cUTF8titre, cUTF8nead, cUTF8nsad, cUTF8neb, cUTF8nsb...
Langages de type C/C++
On donne d'abord la liste des fonctions à exporter, avec leurs caractéristiques.
Ensuite, le reste du programme-source contient les fonctions en question.
Les langages C et C++ sont très puissants, et permettent de très nombreux réglages, parfois trop nombreux pour être pratiques.
Ils permettent souvent de faire deux types de compilation : "release" qui aboutit à un fichier compilé compact, mais peu analysable, et "debug", qui est moins compact, mais parfois plus utile lors de la mise au point d'un programme. Ici, il faut prendre l'option "release", car l'option "debug" aboutit souvent à un plantage du programme.
Les compilateurs C et C++ ont souvent l'habitude de "décorer" les noms des fonctions, par exemple une fonction déclarée comme "mafonction" pourra être nommée comme "__mafonction@8" (dans le fichier compilé). Pour éviter ça (pour que les noms de fonctions soient conservés dans les fichiers compilés), il y a plusieurs techniques : d'une part déclarer que ce sont des fonctions C par les mots extern "C" (car les fonctions C sont moins décorées que les fonctions C++), et d'autre part indiquer la correspondance des noms dans un fichier .def, où l'on trouve des lignes du type "mafonction=mafonction", qui signifient que la fonction "mafonction" ne doit pas changer de nom (ne pas être décorée).
Code::Blocks (logiciel libre, pour Linux et Windows)
(http://www.codeblocks.org)
Par défaut, cet environnement de développement utilise le compilateur gcc. Il faut choisir l'option de compilation en mode "Release".
Sous Windows, on a le choix du langage (C ou C++), mais sous Linux on doit utiliser C. En conséquence, sous Linux, on ne peut pas faire de fonctions stdcall, mais seulement des fonctions cdecl.
//les fonctions suivantes sont en langage C
double cead( int n)
{return n*3.33 ;}
char cnead( int n)
{ char *chloc;
if (n==0) chloc="entrée analogique 0\0";
if (n==1) chloc="EA 1 (volts)\0";
if (n==2) chloc="température °C\0";
if (n>2) chloc="\0";
return chloc ;}*
Dev-C++ (Bloodshed, pour Windows)
http://www.bloodshed.net/devcpp.html
Il utilise le compilateur libre GCC, et fournit un environnement de développement intégré.
Pour faire une bibliothèque dynamique, il faut choisir l'option Fichier | Nouveau | Projet | DLL.
Le logiciel demandera de sauvegarder le projet avec un nouveau nom (extension .dev), puis fera apparaître le squelette d'un programme-source (extension .cpp), qu'il faudra ensuite remplir avec les fonctions désirées.
extern "C" __declspec(dllexport) __stdcall double stdead( int n);
extern "C" __declspec(dllexport) __stdcall LPTSTR stdnead( int n);
double __stdcall stdead( int n)
{
double varloc;
if (n<3) {varloc= n*3.33;}else{varloc= -777;}
return varloc;
}
LPTSTR __stdcall stdnead( int n)
{
LPTSTR chloc;
chloc=LPTSTR("");
if (n==0) chloc=LPTSTR("entrée analogique fictive 0\0");
if (n==1) chloc=LPTSTR("EA fictive 1 (volts)\0");
if (n==2) chloc=LPTSTR("température fictive°C\0");
return chloc; }
C++Builder (Borland-Embarcadero, pour Windows)
Pour créer une nouvelle bibliothèque dynamique, il faut prendre l'option Fichier | Nouveau | DLL.
Un squelette de programme-source est créé, et il suffit ensuite de le remplir avec les fonctions souhaitées.
extern "C" __declspec(dllexport) __cdecl double cead( int n) ;
extern "C" __declspec(dllexport) __cdecl LPTSTR cnead( int n) ;
double __cdecl cead( int n)
{return stdead(n) ;}
LPTSTR __cdecl cnead( int n)
{ return stdnead(n);}
3.2.4 Visual C++ (Microsoft, pour Windows)
Là aussi, il faut choisir l'option "Release", et ne pas prendre l'option "Debug".
extern "C" double __stdcall stdead(int n)
{
double varloc;
if (n<3) {varloc= n*3.33;}else{varloc= -777;}
return varloc;
}
LPTSTR __stdcall stdnead(int n)
{
LPTSTR chloc;
if (n==0) chloc=LPTSTR("entrée analogique 0\0");
if (n==1) chloc=LPTSTR("EA 1 (volts)\0");
if (n==2) chloc=LPTSTR("température °C\0");
if (n>2) chloc=LPTSTR("\0");
return chloc; }
Langages de type Pascal
Pour réaliser une bibliothèque dynamique à la compilation, il faut que les fichiers-sources commencent par le mot "library" (alors que pour faire un programme exécutable, il faut qu'ils commencent par le mot "program").
Chaque fonction destinée à être exportée doit se terminer par "export".
Malheureusements, certains compilateurs (Lazarus/FreePascal) peuvent décorer les noms de fonctions par un tiret de soulignement avant le nom de la fonction. La solution est la même qu'en Basic : mettre après le mot "alias" le nom correct de la fonction, par exemple
function cead(x:longint):double;cdecl;export; alias : 'cead';
Pour que ces fonctions soient bien exportées, il faut l'indiquer par le mot réservé « exports », en principe à la fin de la bibliothèque.
FreePascal (logiciel libre pour Linux et Windows)
http://www.freepascal.org/
Il existe plusieurs environnement de développement, soit en mode texte (FreePascal IDE) soit en mode graphique (Lazarus : http://www.lazarus.freepascal.org/). Sous Windows, on peut aussi utiliser Bloodshed Dev-Pas (http://www.bloodshed.net/devpascal.html).
Le compilateur est très (trop?) adaptable, et on peut changer un très (trop ?) grand nombre de réglages.
Dans "FreePascal EDI", on peut effectuer ces réglages par le menu «Options Compiler».
Pour Lazarus, il faut aller dans "Projet | Options du compilateur"
Pour Dev-Pas, il faut choisir "Options | Compiler options".
Pour que FreePascal soit «vraiment» compatible avec Delphi ou TurboPascal, il faut lui en donner l’ordre en cochant les cases correspondantes dans la boite de dialogue.
De même, il y a plusieurs options pour l’utilisation d’instructions en assembleur. Apparemment, le mieux est de choisir le style «Intel».
Enfin, pour que les DLL compilées par FreePascal soient utilisables par d'autres programmes, il faut prendre le mode «normal» et non «debug».
function stdnead(x:longint):pchar;stdcall; export;
begin stdnead:=nead(x);end;
function stdead(x:longint):double;stdcall;export;
begin stdead:=ead(x); end;
//et à la fin :
exports
stdead, stdnead;
Dans la pratique, il arrive que Lazarus mette un tiret de soulignement avant le nom de fonctions, en particulier avant le nom des fonctions de type "cdecl", ce qui rend ces fonctions inutilisables par les logiciels cherchant une telle fonction sans le tiret de soulignement. Il faut donc forcer le nom correct par l'emploi du mot "alias", par exemple :
function cead(x:longint):double;cdecl;export; alias : 'cead';
begin cead:=ead(x); end;
FreePascal/Lazarus permet de faire assez simplement des pilotes mixtes, ayant à la fois des fonctions de nommage ASCII-ANSI et UTF8. Il faut d'une part utiliser l'unité lazutf8, et d'autre part indiquer dans l'en-tête du fichier que l'on utilisera UTF8 :
{$codepage utf8}
function stdnead(n:longint):pchar;
begin
case n of
0 : stdnead:=pchar('seconde dans min');
1 : stdnead:=pchar('seconde dans jour');
2 : stdnead:=pchar('date (fraction de jour)');
3 : stdnead:=pchar('nombre 333.33');
else stdnead:=pchar('');
end;
end;
function stdUTF8nead(n:longint):pwidechar;
begin
case n of
0 : stdUTF8nead:=pwidechar('seconde dans min');
1 : stdUTF8nead:=pwidechar('seconde dans jourαβγδεζηθ');
2 : stdUTF8nead:=pwidechar('date (fraction de jour)αβγδεζηθ');
3 : stdUTF8nead:=pwidechar('αβγδεζηθnombre 333.33');
else stdUTF8nead:=pwidechar('');
end;
end;
Delphi (Borland-Embarcadero, pour Windows)
Ce logiciel non-libre a eu de nombreuses versions depuis 1996, qui sont toutes capables de faire des bibliothèques dynamiques et de les utiliser. L'aspect et le fonctionnement sont semblables à Lazarus.
On peut le télécharger par exemple en http://delphi.developpez.com/telecharger/gratuit/
Dernière modification le 10/03/2018