Utilisez conditionnellement une référence 32/64 bits lors de la construction dans Visual Studio

J'ai un projet qui construit en 32/64 bits et a des dépendances 32/64 bits correspondantes. Je veux pouvoir changer de configuration et avoir la référence correcte utilisée, mais je ne sais pas comment dire à Visual Studio d'utiliser la dépendance appropriée à l'architecture.

Peut-être que je vais à ce sujet dans le mauvais sens, mais je veux être en mesure de basculer entre x86 et x64 dans la liste déroulante de configuration, et que la DLL référencée soit le bon bitness.

115
demandé sur Holf 2010-09-30 20:08:53

6 réponses

Voici ce que j'ai fait dans un projet précédent, qui nécessitera l'édition manuelle de la .fichier (s) csproj. Vous avez également besoin de répertoires séparés pour les différents binaires, idéalement frères et sœurs les uns des autres, et avec le même nom que la plate-forme que vous ciblez.

Après avoir ajouté les références d'une plate-forme unique au projet, ouvrez le .csproj dans un éditeur de texte. Avant le premier élément <ItemGroup> dans l'élément <Project>, ajoutez le code suivant, ce qui aidera à déterminer quelle plate-forme vous courez (et construisez) sur.

<!-- Properties group for Determining 64bit Architecture -->
<PropertyGroup>
  <CurrentPlatform>x86</CurrentPlatform>
  <CurrentPlatform Condition="'$(PROCESSOR_ARCHITECTURE)'=='AMD64' or '$(PROCESSOR_ARCHITEW6432)'=='AMD64'">AMD64</CurrentPlatform>
</PropertyGroup>

Ensuite, pour vos références spécifiques à la plate-forme, vous apportez des modifications telles que:

<ItemGroup>
  <Reference Include="Leadtools, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.Codecs, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.Codecs.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.ImageProcessing.Core, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.ImageProcessing.Core.dll</HintPath>
  </Reference>
  <Reference Include="System" />
  <Reference Include="System.Core" />
  <Reference Include="System.Data.Entity" />
  <!--  Other project references -->
</ItemGroup>

Notez l'utilisation de la propriété $(CurrentPlatform), que nous avons définie ci-dessus. Vous pouvez, à la place, utiliser des conditions pour quels assemblys inclure pour quelle plate-forme. Vous pourriez également avoir besoin de:

  • remplacez les $(PROCESSOR_ARCHITEW6432) et $(PROCESSOR_ARCHITECTURE) par $(Platform) pour ne considérer que la plate-forme cible des projets
  • Modifier la logique de détermination de la plate-forme dans l'ordre pour être approprié à la machine actuelle, de sorte que vous ne construisez pas / référençant un binaire 64 bits à exécuter sur une plate-forme 32 bits.

J'ai écrit ceci à l'origine pour un Wiki interne au travail, cependant, je l'ai modifié et posté le processus complet sur mon blog , si vous êtes intéressé par les instructions détaillées étape par étape.

94
répondu Hugo 2018-03-28 15:20:41

AFAIK, si votre projet nécessite des références spécifiques à 32 bits ou 64 bits (c'est-à-dire des assemblages COM-interop), et que vous n'avez aucun intérêt à éditer manuellement le .fichier csproj, alors vous devrez créer des projets 32 bits et 64 bits séparés.

Je devrais noter que la solution suivante n'est pas testée, mais devrait fonctionner. Si vous êtes prêt à modifier manuellement .fichier csproj, alors vous devriez être en mesure d'atteindre le résultat souhaité avec un seul projet. Le .le fichier csproj est juste un MSBuild script, donc pour une référence complète, regardez ici . Une fois que vous ouvrez le .fichier csproj dans un éditeur, recherchez les éléments <Reference>. Vous devriez pouvoir diviser ces éléments en 3 groupes d'éléments distincts : références qui ne sont pas spécifiques à la plate-forme, références spécifiques à x86 et références spécifiques à x64.

Voici un exemple qui suppose que votre projet est configuré avec des plates-formes cibles nommées "x86"et" x64 "

<!-- this group contains references that are not platform specific -->
<ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <!-- any other references that aren't platform specific -->
</ItemGroup>

<!-- x86 specific references -->
<ItemGroup Condition=" '$(Platform)' == 'x86' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x86\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x86 specific references -->
</ItemGroup>

<!-- x64 specific referneces -->
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x64\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x64 specific references -->
</ItemGroup>

Maintenant, lorsque vous définissez votre projet / solution build configuration pour cibler la plate-forme x86 ou x64, elle doit inclure les références appropriées dans chaque cas. Bien sûr, vous devrez jouer avec les éléments <Reference>. Vous pouvez même configurer des projets fictifs où vous ajoutez les références x86 et x64, puis copiez simplement les éléments <Reference> nécessaires de ces fichiers de projet fictifs dans votre fichier de projet "réel".


Modifier 1
Voici un lien vers les éléments communs du projet MSBuild, que j'ai accidentellement omis du message d'origine: http://msdn.microsoft.com/en-us/library/bb629388.aspx

52
répondu Justin Holzer 2015-01-27 22:32:37

Vous pouvez utiliser une condition pour un ItemGroup pour la dll références dans le fichier de projet.
Cela entraînera visual studio à revérifier la condition et les références chaque fois que vous modifiez la configuration active.
Il suffit d'ajouter une condition pour chaque configuration.

Exemple:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <Reference Include="DLLName">
      <HintPath>..\DLLName.dll</HintPath>
    </Reference>
    <ProjectReference Include="..\MyOtherProject.vcxproj">
      <Project>{AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT}</Project>
      <Name>MyOtherProject</Name>
    </ProjectReference>
  </ItemGroup>
19
répondu Yochai Timmer 2013-09-11 14:22:07

Je fais référence aux DLL x86, situées par exemple dans \component \ v3_NET4, dans mon projet. Les DLL spécifiques pour x86 / x64 sont situées dans des sous-dossiers nommés" x86 "et" x64 " resp.

Ensuite, j'utilise un script de pré-construction qui copie des dll appropriées(x86/x64) dans le dossier référencé, basé sur $(PlatformName).

xcopy /s /e /y "$(SolutionDir)..\component\v3_NET4\$(PlatformName)\*" "$(SolutionDir)..\component\v3_NET4"

Fonctionne pour moi.

7
répondu Micke 2012-05-14 10:09:50

J'ai fait face au même problème et j'ai passé un bon moment à chercher une solution décente. La plupart des gens offrent l'édition manuelle des fichiers de solution Visual Studio, ce qui est assez fastidieux, sujet aux erreurs et déroutant lors de l'exploration de ces fichiers édités dans L'interface graphique Visual Studio par la suite. Quand j'ai déjà abandonné, la solution est venue elle-même. C'est très similaire à ce que Micke recommande dans sa réponse ci-dessus.

Dans account manager, j'ai créé deux cibles de construction distinctes pour les plates-formes x86 et x64, comme d'habitude. Ensuite, j'ai ajouté une référence à l'assemblage x86 à mon projet. Sur ce point, j'ai cru que le projet est configuré pour la construction x86 seulement et ne construira jamais pour la configuration x64, à moins que je ne fasse l'édition manuelle de celui-ci comme suggéré par Hugo ci-dessus.

Après un certain temps, j'ai finalement oublié la limitation et accidentellement commencé version x64. Bien sûr, la compilation a échoué. Mais important était le message d'erreur que j'ai reçu. Message d'erreur dit que l'assembly nommé exactement comme mon assembly x86 référencé est manquant dans le dossier prévu comme cible de construction x64 pour ma solution.

Ayant remarqué cela, j'ai copié manuellement l'assemblage x64 approprié dans ce répertoire. Gloire! Ma construction x64 a miraculeusement réussi avec un assemblage correct trouvé et lié implicitement. Il a fallu quelques minutes pour modifier ma solution pour définir un répertoire cible de construction pour l'assemblage x64 dans ce dossier. Après ces étapes, la solution se construit automatiquement pour x86 et x64 sans aucune édition manuelle des fichiers MSBuild.

À résumé:

  1. créez des cibles x86 et x64 dans un seul projet
  2. ajoute toutes les références de projet appropriées aux assemblys x86
  3. définissez un répertoire cible de compilation commun pour tous les assemblys x64
  4. Si vous avez des assemblys x64 prêts, copiez-les une fois dans votre répertoire cible de compilation x64

Après l'achèvement de ces étapes, votre solution sera correctement construite pour les configurations x86 et x64.

Cela a fonctionné pour moi sur Projet Visual Studio 2010. net 4.0 c#. Évidemment, il s'agit d'une sorte de comportement interne non documenté de Visual Studio, qui pourrait faire l'objet de changements dans les versions 2012, 2013 et 2015. Si quelqu'un va essayer d'autres versions, veuillez partager votre expérience.

2
répondu Boris Zinchenko 2015-09-04 08:33:46

Une construction. net avec des dépendances x86/x64

Alors que toutes les autres réponses vous donnent une solution pour faire différentes Builds en fonction de la plate-forme, je vous donne une option pour n'avoir que la configuration "AnyCPU" et faire une build qui fonctionne avec vos DLL x86 et x64.

Vous devez écrire un code de plomberie pour cela. Je ne pouvais pas faire fonctionner cela avec l'application.config. Si quelqu'un d'autre connaît un moyen de le résoudre via l'application.config je voudrais vraiment savoir.

Résolution des dll x86/x64 correctes à l'exécution

Étapes:

  1. utiliser AnyCPU dans csproj
  2. décidez si vous référencez uniquement les DLL x86 ou x64 dans vos csprojs. Adaptez les paramètres UnitTests aux paramètres d'architecture que vous avez choisis. C'est important pour le débogage/l'exécution des tests dans VisualStudio.
  3. Sur la Référence-Propriétés de l'ensemble Copie Locale & Version Spécifique à false
  4. débarrassez-vous des avertissements d'architecture en ajoutant ceci ligne vers le premier PropertyGroup dans tous vos fichiers csproj où vous référencez x86/x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Ajoutez ce script postbuild à votre projet de démarrage, utilisez et modifiez les chemins de ce script sp qu'il copie toutes vos DLL x86/x64 dans les sous-dossiers correspondants de votre build bin\x86 \ bin \ x64 \

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86 xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    -- > Lorsque vous démarrez l'application maintenant, vous obtenez une exception que l'assemblée n'a pas pu être trouvé.

  6. Enregistrer le AssemblyResolve événement juste au début de votre point d'entrée de l'application

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    Avec cette méthode:

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs)
    {
        var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(","));
    
        var anyCpuAssemblyPath = $".\\{dllName}.dll";
    
        var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86";
    
        var assemblyPath = $".\\{architectureName}\\{dllName}.dll";
    
        if (File.Exists(assemblyPath))
        {
            return Assembly.LoadFrom(assemblyPath);
        }
    
        return null;
    }
    
  7. Si vous avez des tests unitaires, créez une classe de test avec une méthode qui a un AssemblyInitializeAttribute et enregistrez également le Gestionnaire tryresolvearchitecturedependency-Handler ci-dessus. (Cela ne sera pas exécuté parfois si vous exécutez des tests uniques dans visual studio, les références seront résolues pas à partir de la corbeille UnitTest. Par conséquent la décision à l'étape 2 est important.)

Avantages:

  • une Installation / Construction pour les deux plates-formes

Inconvénients: - Aucune erreur au moment de la compilation lorsque les DLL x86 / x64 ne correspondent pas. - Vous devriez toujours exécuter test dans les deux modes!

Créez éventuellement un second exécutable exclusif pour l'architecture x64 avec Corflags.exe dans le script postbuild

Autres Variantes à essayer: - Vous n'auriez pas besoin du gestionnaire D'événements AssemblyResolve si vous assurez autrement que les DLL obtiennent copié dans votre dossier binaire au démarrage (évaluer L'architecture du processus - > déplacer les DLL correspondantes de x64 / x86 vers le dossier bin et retour.) - Dans le programme D'installation, évaluez l'architecture et supprimez les binaires pour une mauvaise architecture et déplacez les bons dans le dossier bin.

0
répondu Felix Keil 2018-08-03 09:54:13