2010-09-14 30 views
1

J'utilise plusieurs P/Invokes sous .NET. Cependant, je veux que ma bibliothèque fonctionne à la fois sous Windows et Linux, de préférence avec les mêmes binaires.DllImport noms incomplets

Étant donné que la bibliothèque native dont je dépend est disponible sur plusieurs plates-formes, j'espérais juste les avoir avec les binaires de ma bibliothèque gérée.

En ce moment je suis en utilisant quelque chose comme ceci:

[DllImport("/usr/lib/libMYLIBNAME.so.1")] 

Mais cela fonctionne évidemment que pour Linux. Je considérais que je pourrais peut-être copier ce binaire de/usr/lib et distribuer en même temps que ma demande, je réduiraient les ci-dessus pour:

[DllImport("libMYLIBNAME.so")] 

Mais cela est encore Linux uniquement.

Y a-t-il un moyen de changer la chaîne de nom de la bibliothèque afin qu'elle recherche libMYLIBNAME.so sous Linux et MYLIBNAME.dll sous Windows, ou quelque chose de très similaire?

Je voudrais éviter tout ce qui nécessite recompilation pour chaque plate-forme supportée ...

(Note: Il serait encore mieux une solution qui regarderait pour MYLIBNAME.dll sous Windows et/usr/lib/libMYLIBNAME .so.1 sous Linux, mais cette amélioration est facultative)

Répondre

7

Deux choses

1- DllImport sans l'extension Ceci est pris en charge sur Windows, Linux et MAC et importer la bibliothèque appropriée pour la plate-forme cible.

[DllImport("libMYLIBNAME")] - 

2- L'option preffered est d'utiliser le <dllmap/> qui vous permet de mapper un nom de bibliothèque d'importation au nom de la bibliothèque de plate-forme cible. Donc, si sous Windows, vous avez une dll appelé mylib.dll et correspondant Linux donc est mylinuxlib.so.3.6.1 vous pouvez importer cela en utilisant les fenêtres nom de la DLL

[DllImport("mylib.dll")] 

Et ajouter une configuration à la configuration pour mapper ce nom au nom de la bibliothèque Linux

<configuration> 
    <dllmap dll="mylib.dll" target="mylinuxlib.so.3.6.1" /> 
</configuration> 

en savoir plus Here

+2

Laisser l'extension éteint ne fonctionne pas, j'ai essayé cela. –

+0

Je vais avec l'option dllmap. Je le savais mais je ne savais pas qu'il pouvait être spécifié par assemblage. – luiscubal

+0

@Hans, c'est étrange, je l'ai testé et cela a fonctionné pour moi. Avez-vous eu le '.donc dans le même répertoire que le '.exe'? J'ai testé avec Mono 2.4.4 sur Ubuntu 10.04. –

2

Une solution que j'ai vue est de créer une classe wrapper abstraite autour de vos P/Invoke et de générer celle qui convient en fonction de l'environnement.

public abstract class Wrapper 
{ 
    public void SomeMethod() 
    { 
     WrappedMethod(); 
    } 

    public static Wrapper GetWrapper() 
    { 
     //TODO: write some method to determine OS 
     return IsLinux() ? new LinuxWrapper() : new WindowsWrapper(); 
    } 

    public abstract void WrappedMethod(); 
} 

public class WindowsWrapper : Wrapper 
{ 
    //windows dll imports go here 

    public override void WrappedMethod() 
    { 
     //p/invokes go here 
    } 
} 

public class LinuxWrapper : Wrapper 
{ 
    //linux dll imports go here 
    public override void WrappedMethod() 
    { 
    //p/invokes go here 
    } 
} 
2

Windows est pas pointilleux sur l'extension de nom de fichier pour une DLL. Les changer n'est pas inhabituel, .ocx pour les contrôles ActiveX, .scr pour les économiseurs d'écran par exemple. Mais toujours une DLL régulière. Le chargeur Windows vérifie l'identité du fichier à partir du contenu, l'en-tête PE32 est ce qui en fait une vraie DLL.

Il vous suffit donc de renommer votre version Windows du fichier .dll en .so. Modifiez le paramètre Nom de sortie de l'éditeur de liens ou renommez simplement le fichier.

+1

Si je renommer la DLL Windows en * .so, je ne serai pas en mesure d'expédier une version Linux dans le même paquet ... – luiscubal

+0

Vous ne savez pas ce que signifie un "paquet". Un autre répertoire me vient à l'esprit. –

+0

Je voulais dire le même fichier ZIP dans lequel je pourrais distribuer mon assembly. – luiscubal