Условно используйте 32/64 битную ссылку при сборке в Visual Studio - PullRequest
119 голосов
/ 30 сентября 2010

У меня есть проект, который строит в 32/64-битных и имеет соответствующие 32/64-битные зависимости.Я хочу иметь возможность переключать конфигурации и использовать правильную ссылку, но я не знаю, как сказать Visual Studio использовать зависимую от архитектуры зависимость.

Возможно, я поступаю неправильно, но я хочу иметь возможность переключаться между x86 и x64 в раскрывающемся списке конфигурации и иметь правильную битность указанной библиотеки DLL.

Ответы [ 6 ]

97 голосов
/ 24 ноября 2010

Вот что я сделал в предыдущем проекте, для которого потребуется ручная редакция файла .csproj.Вам также нужны отдельные каталоги для разных двоичных файлов, в идеале родных и близких друг другу, и с тем же именем, что и целевая платформа.

После добавления ссылок на одну платформу в проект откройте .csproj вТекстовый редактор.Перед первым элементом <ItemGroup> в элементе <Project> добавьте следующий код, который поможет определить, на какой платформе вы работаете (и строите).

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

Затем для конкретной платформыссылки, вы вносите изменения, такие как следующее:

<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>

Обратите внимание на использование свойства $(CurrentPlatform), которое мы определили выше.Вместо этого вы могли бы использовать условные обозначения, какие сборки включить для какой платформы.Вам также может понадобиться:

  • Заменить $(PROCESSOR_ARCHITEW6432) и $(PROCESSOR_ARCHITECTURE) на $(Platform), чтобы рассматривать ТОЛЬКО целевую платформу проектов
  • Изменить логику определения платформы в порядкечтобы соответствовать текущей машине, так что вы не создаете / не ссылаетесь на 64-битный двоичный файл для выполнения на 32-битной платформе.

Я изначально написал это для внутренней Wiki на работеоднако я изменил его и опубликовал полный процесс в своем блоге , если вас интересуют подробные пошаговые инструкции.

57 голосов
/ 30 сентября 2010

AFAIK, если ваш проект требует ссылок, которые являются 32-битными или 64-битными (то есть сборками COM-взаимодействия), и вы не заинтересованы в ручном редактировании файла .csproj, то вам придется создать отдельный 32и 64-битные проекты.

Следует отметить, что следующее решение не проверено, но должно работать.Если вы хотите вручную редактировать файл .csproj, то вы сможете достичь желаемого результата с помощью одного проекта.Файл .csproj - это всего лишь скрипт MSBuild, поэтому для полной информации смотрите здесь .Открыв файл .csproj в редакторе, найдите элементы <Reference>.Вы должны быть в состоянии разделить эти элементы на 3 отдельные группы элементов : ссылки, которые не зависят от платформы, ссылки для x86 и ссылки для x64.

Вотпример, который предполагает, что ваш проект настроен с целевыми платформами с именами "x86" и "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>

Теперь, когда вы устанавливаете конфигурацию сборки вашего проекта / решения для целевой платформы x86 или x64, она должна включатьправильные ссылки в каждом конкретном случае.Конечно, вам нужно поиграться с элементами <Reference>.Вы даже можете настроить фиктивные проекты, в которых вы добавляете ссылки на x86 и x64, а затем просто копируете необходимые элементы <Reference> из этих фиктивных файлов проекта в ваш "настоящий" файл проекта.

Редактировать 1 Вот ссылка на общие элементы проекта MSBuild, которые я случайно пропустил из исходного поста: http://msdn.microsoft.com/en-us/library/bb629388.aspx

19 голосов
/ 11 сентября 2013

Вы можете использовать условие для ItemGroup для ссылок dll в файле проекта.
Это заставит Visual Studio перепроверить условие и ссылки при каждом изменении активной конфигурации.
Просто добавьте условие для каждой конфигурации.

Пример:

 <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>
7 голосов
/ 14 мая 2012

Я ссылаюсь на библиотеки x86, расположенные, например, в \ component \ v3_NET4, в моем проекте.Специальные библиотеки DLL для x86 / x64 находятся в подпапках с именами «x86» и «x64» соответственно.

Затем я использую сценарий предварительной сборки, который копирует соответствующие DLL (x86 / x64) в указанную папку на основе $ (PlatformName).

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

У меня работает.

2 голосов
/ 04 сентября 2015

Я столкнулся с той же проблемой и провел довольно много времени в поисках достойного решения.Большинство людей предлагают ручное редактирование файлов решений Visual Studio, что довольно утомительно, подвержено ошибкам и приводит к путанице при последующем исследовании этих отредактированных файлов в графическом интерфейсе Visual Studio.Когда я уже сдался, решение пришло само собой.Это очень похоже на то, что Микке рекомендует в своем ответе выше.

В менеджере аккаунтов я, как обычно, создал две отдельные цели сборки для платформ x86 и x64.Затем я добавил ссылку на сборку x86 в свой проект.На этом этапе я полагал, что проект настроен только для сборки x86 и никогда не будет собираться для конфигурации x64, если я не буду выполнять его ручное редактирование, как это было предложено Хьюго выше.

Через некоторое время я в конце концов забылограничение и случайно начал x64 build.Конечно, сборка не удалась.Но важным было сообщение об ошибке, которое я получил.Сообщение об ошибке говорит о том, что сборка, названная точно так, как моя сборка x86, на которую ссылаются, отсутствует в папке, предназначенной как цель сборки x64 для моего решения.

Заметив это, я вручную скопировал правильную сборку x64 в этот каталог.Слава!Моя сборка x64 чудесным образом преуспела, и надлежащая сборка была обнаружена и неявно связана.Было несколько минут, чтобы изменить мое решение, чтобы установить в эту папку целевой каталог сборки для сборки x64.После этих шагов решение автоматически собирается для x86 и x64 без какого-либо ручного редактирования файлов MSBuild.

Подводя итог:

  1. Создание целей x86 и x64 в одном проекте
  2. Добавить все правильные ссылки проекта для сборок x86
  3. Установить один общий целевой каталог сборки для всех сборок x64
  4. Если у вас есть готовые сборки x64, просто скопируйте их один раз в свойцелевой каталог сборки x64

После выполнения этих шагов ваше решение будет правильно построено для конфигураций x86 и x64.

Это помогло мне в Visual Studio 2010 .NET 4.0C # проект.Очевидно, это своего рода недокументированное внутреннее поведение Visual Studio, которое может быть изменено в версиях 2012, 2013 и 2015 гг.Если кто-то попробует другие версии, поделитесь своим опытом.

1 голос
/ 25 июля 2018

Одна сборка .Net с зависимостями x86 / x64

В то время как все остальные ответы дают вам решение для создания различных сборок в соответствии с платформой, я даю вам возможность иметь толькоНастройте AnyCPU и создайте сборку, которая будет работать с вашими библиотеками x86 и x64.

Для этого вы должны написать некоторый код для подключения.Я не мог заставить это работать с app.config.Если кто-то еще знает способ решить эту проблему через app.config, мне бы очень хотелось знать.

Разрешение правильных x86 / x64-dll во время выполнения

Шаги:

  1. Использовать AnyCPU в csproj
  2. Решите, будете ли вы ссылаться только на dll x86 или x64 в ваших csprojs.Адаптируйте настройки UnitTests к выбранным вами настройкам архитектуры.Это важно для отладки / запуска тестов внутри VisualStudio.
  3. При задании свойств ссылок Копировать локальную & Специальная версия в false
  4. Избавьтесь от архитектурных предупреждений, добавив эту строку в первый PropertyGroup во всех ваших файлах csproj, где вы ссылаетесь на x86 / x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Добавьте этоСценарий postbuild для вашего запускаемого проекта, используйте и измените пути этого сценария sp, чтобы он копировал все ваши dll x86 / x64 в соответствующие подпапки вашего 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

    -> Когда вы запускаете приложение сейчас, вы получаете исключение, что сборка не может быть найдена.

  6. Зарегистрируйте событие AssemblyResolve в самом начале вашей записи приложения.point

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    с помощью этого метода:

    /// <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. Если у вас есть модульные тесты, создайте TestClass с методом, который имеет AssemblyInitializeAttribute, а также зарегистрируйте вышеупомянутый TryResolveArchitectureDependency-Handler есть.(Это не будет выполняться иногда, если вы запускаете одиночные тесты в Visual Studio, ссылки будут разрешаться не из бункера UnitTest. Поэтому решение на шаге 2 важно.)

Преимущества:

  • Одна установка / сборка для обеих платформ

Недостатки: - Нет ошибок во время компиляции, когда не совпадают dll x86 / x64.- Вы по-прежнему должны запускать тест в обоих режимах!

При необходимости создайте второй исполняемый файл, предназначенный исключительно для архитектуры x64, с Corflags.exe в сценарии postbuild

Другие варианты, чтобы опробовать: - Вы бы не сталинужен обработчик события AssemblyResolve, если в противном случае вы гарантируете, что библиотеки dll будут скопированы в вашу двоичную папку при запуске (архитектура Evaluate Process -> переместите соответствующие библиотеки dll из x64 / x86 в папку bin и обратно.)и переместите нужные в папку bin.

...