Ориентация как на 32, так и на 64 бита с помощью Visual Studio в одном решении / проекте - PullRequest
108 голосов
/ 28 сентября 2008

У меня есть небольшая дилемма о том, как настроить сборки Visual Studio для мульти-таргетинга.

Справочная информация: c # .NET v2.0 с p / вызовом сторонних 32-битных DLL, SQL compact v3.5 SP1, с проектом установки. Прямо сейчас цель платформы установлена ​​на x86, поэтому она может быть запущена на Windows x64.

Сторонняя компания только что выпустила 64-битные версии своих DLL, и я хочу создать специальную 64-битную программу.

Это поднимает некоторые вопросы, на которые у меня пока нет ответов. Я хочу иметь точно такую ​​же кодовую базу. Я должен строить со ссылками на 32-битный набор DLL или 64-битных DLL. (Как сторонний, так и SQL Server Compact)

Можно ли это решить с помощью 2 новых наборов конфигураций (Debug64 и Release64)?

Должен ли я создать 2 отдельных проекта установки (стандартные проекты Visual Studio, без Wix или любой другой утилиты), или это можно решить с помощью того же MSI?

Любые идеи и / или рекомендации будут приветствоваться.

Ответы [ 8 ]

81 голосов
/ 28 сентября 2008

Да, вы можете использовать как x86, так и x64 с одной и той же кодовой базой в одном проекте. В общем, все будет работать просто, если вы создадите правильные конфигурации решений в VS.NET (хотя P / Invoke для полностью неуправляемых DLL-библиотек, скорее всего, потребует некоторого условного кода): элементы, которые я обнаружил, требующие особого внимания:

  • Ссылки на внешние управляемые сборки с тем же именем, но с собственным битом (это также относится к сборкам взаимодействия COM)
  • Пакет MSI (который, как уже отмечалось, должен быть нацелен либо на x86, либо на x64)
  • Любые пользовательские действия на основе классов .NET Installer в вашем пакете MSI

Проблема со ссылкой на сборку не может быть полностью решена в VS.NET, поскольку она позволит вам добавить ссылку с заданным именем в проект только один раз. Чтобы обойти это, отредактируйте файл проекта вручную (в VS щелкните правой кнопкой мыши файл проекта в обозревателе решений, выберите «Выгрузить проект», затем снова щелкните правой кнопкой мыши и выберите «Изменить»). После добавления ссылки, скажем, на версию сборки x86, ваш файл проекта будет содержать что-то вроде:

<Reference Include="Filename, ..., processorArchitecture=x86">
  <HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>

Оберните этот тег Reference в тег ItemGroup, указывающий конфигурацию решения, к которой он применяется, например:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
   <Reference ...>....</Reference>
</ItemGroup>

Затем скопируйте и вставьте весь тег ItemGroup и отредактируйте его, чтобы он содержал сведения о вашей 64-битной DLL, например ::

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
  <Reference Include="Filename, ..., processorArchitecture=AMD64">
     <HintPath>C:\path\to\x64\DLL</HintPath>
   </Reference>
</ItemGroup>

После перезагрузки вашего проекта в VS.NET диалоговое окно "Ссылка на сборку" будет немного смущено этими изменениями, и вы можете столкнуться с некоторыми предупреждениями о сборках с неверным целевым процессором, но все ваши сборки будут работать нормально.

Следующим будет решение проблемы MSI, и, к сожалению, для этого потребуется не-VS.NET-инструмент: для этой цели я предпочитаю Advanced Installer от Caphyon, так как он выполняет базовый прием (создание общего MSI, а также 32-битных и 64-битных MSI и использование установщика .EXE для извлечения нужной версии и выполнения необходимых исправлений во время выполнения) очень и очень хорошо.

Вероятно, вы можете достичь тех же результатов, используя другие инструменты или набор инструментов Windows Installer XML (WiX) , но Advanced Installer делает вещи настолько простыми (и в то же время вполне доступными), что я никогда по-настоящему посмотрел на альтернативы.

Одна вещь, которую вам может по-прежнему требуется WiX, хотя, даже при использовании расширенного установщика, это для пользовательских действий .NET Installer Class. Хотя указывать определенные действия, которые должны выполняться только на определенных платформах (тривиально с использованием условий выполнения VersionNT64 и NOT VersionNT64, соответственно), тривиально, встроенные пользовательские действия AI будут выполняться с использованием 32-разрядной платформы даже на 64-разрядных компьютерах. .

Это может быть исправлено в будущем выпуске, но сейчас (или при использовании другого инструмента для создания ваших MSI с такой же проблемой) вы можете использовать управляемую поддержку настраиваемых действий WiX 3.0 для создания DLL-файлов действий с правильная битность, которая будет выполнена с использованием соответствующей Framework.


Редактировать: начиная с версии 8.1.2, Advanced Installer правильно поддерживает 64-битные пользовательские действия. Со времени моего первоначального ответа, к сожалению, его цена немного выросла, хотя по сравнению с InstallShield и ему подобным он все еще остается очень хорошим ...


Редактировать: Если ваши DLL зарегистрированы в GAC, вы также можете использовать стандартные ссылочные теги таким образом (например, SQLite):

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>

Условие также сводится ко всем типам сборки, выпуска или отладки, и просто указывает архитектуру процессора.

27 голосов
/ 28 сентября 2008

Допустим, у вас есть библиотеки DLL для обеих платформ, и они находятся в следующем месте:

C:\whatever\x86\whatever.dll
C:\whatever\x64\whatever.dll

Вам просто нужно отредактировать ваш файл .csproj из этого:

<HintPath>C:\whatever\x86\whatever.dll</HintPath>

К этому:

<HintPath>C:\whatever\$(Platform)\whatever.dll</HintPath>

После этого вы сможете создать свой проект, ориентированный на обе платформы, и MSBuild найдет правильный каталог для выбранной платформы.

1 голос
/ 28 сентября 2008

Не уверен в полном ответе на ваш вопрос - но подумал, что я бы указал на комментарий в разделе «Дополнительная информация» на странице загрузки SQL Compact 3.5 с пакетом обновления 1 , увидев, что вы смотрите на x64 - надеюсь, это поможет .

Из-за изменений в SQL Server Compact SP1 и дополнительная 64-битная версия поддержка, централизованно установленная и смешанная Режим среды 32-битной версии SQL Server Compact 3.5 и 64-разрядный версия SQL Server Compact 3.5 с пакетом обновления 1 может создать то, что кажется неустойчивые проблемы. Чтобы минимизировать потенциал для конфликтов, а также для Платформа нейтрального развертывания управляемого клиентские приложения, централизованно установка 64-битной версии SQL Server Compact 3.5 SP1 с использованием Файл установщика Windows (MSI) также требует установки 32-битной версии SQL Server Compact 3.5 с пакетом обновления 1 (SP1) MSI файл. Для приложений, которые только требуется родной 64-битный, приватный развертывание 64-битной версии SQL Server Compact 3.5 SP1 может быть используется.

Я читаю это как «включаю 32-битные файлы SQLCE , а также 64-битные файлы» при распространении для 64-битных клиентов.

Делает жизнь интересной, я думаю ... должен сказать, что мне нравится строка "проблемы, которые кажутся непостоянными" ... звучит немного как "вы воображаете вещи, но на всякий случай сделайте это ..."

0 голосов
/ 03 августа 2018

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

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

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

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

Шаги:

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

    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 в сценарии после сборки

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

0 голосов
/ 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>
0 голосов
/ 27 июля 2012

Вы можете генерировать два решения по-разному и объединить их впоследствии! Я сделал это для VS 2010. и это работает. У меня было 2 разных решения, сгенерированных CMake, и я объединил их

0 голосов
/ 26 ноября 2008

Если вы используете пользовательские действия, написанные в .NET, как часть вашего установщика MSI, у вас возникает другая проблема.

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

Дополнительная информация и некоторые движения ниндзя, чтобы обойти (в основном измените MSI, чтобы использовать 64-битную версию этой прокладки)

Создание MSI в Visual Studio 2005/2008 для работы в SharePoint 64

64-разрядные управляемые настраиваемые действия с Visual Studio

0 голосов
/ 28 сентября 2008

Относительно вашего последнего вопроса. Скорее всего, вы не можете решить это внутри одного MSI. Если вы используете папки реестра / системы или что-либо связанное с этим, сам MSI должен знать об этом, и вы должны подготовить 64-битный MSI для правильной установки на 32-битной машине.

Существует вероятность того, что вы можете установить продукт как 32-разрядное приложение и при этом запустить его как 64-битное, но я думаю, что это может быть довольно сложно достичь.

при этом я думаю, что вы должны иметь единую кодовую базу для всего. На моем нынешнем рабочем месте нам это удалось. (но для того, чтобы все играть вместе, потребовалось некоторое жонглирование)

Надеюсь, это поможет. Вот ссылка на некоторую информацию, связанную с 32/64 битными проблемами: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

...