Націлювання на 32-бітну та 64-бітну версію Visual Studio в одному і тому ж рішенні / проекті


111

У мене є невелика дилема щодо того, як налаштувати мої візуальні студії для багатоцільового націлювання.

Передумови: c # .NET v2.0 з p / викликом в сторонні 32-бітні DLL, SQL compact v3.5 SP1, з проектом Setup. Зараз цільова платформа встановлена ​​на x86, тому її можна запустити на Windows x64.

Компанія третьої партії щойно випустила 64-бітні версії своїх DLL, і я хочу створити спеціалізовану 64-бітну програму.

Це викликає деякі питання, на які я ще не отримав відповіді. Я хочу мати саме таку базу коду. Я повинен будувати з посиланнями або на 32-бітний набір DLL, або на 64-бітні DLL. (І сторонні, і SQL Server Compact)

Чи можна це вирішити за допомогою двох нових наборів конфігурацій (Debug64 та Release64)?

Потрібно створити 2 окремих програми налаштування (студійні проекти візуальної студії, без Wix чи будь-якої іншої утиліти), або це можна вирішити в межах одного .msi?

Будь-які ідеї та / або рекомендації будуть вітатися.


@Magnus Johansson: ви можете використовувати дві конфігурації для досягнення половини своєї мети. MSI трохи складніше.
user7116

Відповіді:


83

Так, ви можете націлити на 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 є наступним, і , до жаль , це буде вимагати non-VS.NET інструменту: Я віддаю перевагу Caphyon в Advanced Installer для цієї мети, так як він витягає основний трюк залученого (створити загальну MSI, а також 32-бітові і 64-бітні специфічні MSI, і використовувати пусковий інструмент налаштування .EXE, щоб витягти потрібну версію і зробити потрібні виправлення під час виконання) дуже і дуже добре.

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

Одне, що вам може знадобитися для WiX, хоча навіть при використанні розширеного інсталятора - це власні дії .NET Installer Class. Хоча тривіально вказати певні дії, які повинні виконуватись лише на певних платформах (відповідно відповідно до умов виконання VersionNT64 та NOT VersionNT64), вбудовані спеціальні дії AI виконуватимуться за допомогою 32-бітного Framework навіть на 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>

Ця умова також зменшується до всіх типів збірки, випуску чи налагодження, і просто вказує архітектуру процесора.


У Visual Studio 2008 я виявив, що <ItemGroup> s не можна вкладати. Це рішення спрацювало чудово, коли я зробив нові <ItemGroup> s під групою решту <Reference> s. Я також повинен був змінити x86 на AnyCPU, що, мабуть, стосується історії мого конкретного проекту.
Олівер Бок

Цей розширений інсталятор виглядає досить приголомшливо.
Пт

Це може бути тупим питанням, але як дістатися до файлу, щоб відредагувати його вручну?
ч

1
Щоб відредагувати файл у VS, клацніть правою кнопкою миші на проект у Провіднику рішень та знайдіть «Розвантажити проект». Після того, як проект буде завантажено, клацніть правою кнопкою миші ще раз та натисніть "Редагувати <ім'я файлу проекту>". Після того як ви відредагували файл проекту, збережіть його та ще раз клацніть правою кнопкою миші на файл проекту та завантажте його. Якщо помилок чи помилок не буде, вони знову завантажуватимуться. Якщо ні, VS скаже вам, в чому проблема з файлом. Сподіваюся, що це допомагає!
Джон Бафман

Чудова відповідь! Дякую!
Джон Бафман

27

Скажімо, у вас є побудова 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 буде шукати у правильному каталозі обраної платформи.


Це було б геніально, якби це працювало, але це не так. Принаймні не для мене.
Джон Шихан

10
Хіба це не повинно бути: <HintPath> C: \ what \ $ (Платформа) \ what.dll </HintPath>
Андреас

Для мене працював нормально на Visual Studio 2008, але не копіював DLL автоматично в цільовий каталог збірки, як це робить звичайний <Reference>. Рішення mdb працювало краще для мене.
Олівер Бок

1

Не впевнений у повній відповіді на ваше запитання, але подумав, що я хотів би зазначити коментар у розділі Додаткова інформація на сторінці завантаження SQL Compact 3.5 SP1, коли ви дивитесь на x64 - сподіваюся, це допоможе.

Завдяки змінам у SQL Server Compact SP1 та додатковій підтримці 64-розрядної версії, централізовано встановлені та змішані середовища 32-бітної версії SQL Server Compact 3.5 та 64-розрядної версії SQL Server Compact 3.5 SP1 можуть створювати те, що видається переривчастим проблеми. Щоб мінімізувати потенціал для конфліктів та увімкнути розгортання керованих клієнтських програм на нейтральній платформі, централізована установка 64-розрядної версії SQL Server Compact 3.5 SP1 за допомогою файла інсталятора Windows (MSI) також потребує встановлення 32-бітної версії SQL Server Компактний файл SPI MSI 3,5 SP1. Для додатків, які потребують лише 64-розрядної назви, можна використовувати приватне розгортання 64-розрядної версії SQL Server Compact 3.5 SP1.

Я читаю це як "включати 32-бітні файли SQLCE , а також 64-бітні файли", якщо поширює 64-бітних клієнтів.

Я думаю, що життя стає цікавим. Я мушу сказати, що я люблю рядок "те, що, як видається, є переривчасті проблеми" ... трохи схоже на "ви уявляєте речі, але про всяк випадок зробіть це ..."


1

Одна .Net збірка із залежностями x86 / x64

Хоча всі інші відповіді дають вам рішення робити різні збірки відповідно до платформи, я даю вам можливість мати лише конфігурацію "AnyCPU" та зробити збірку, яка працює з вашими d86 x86 та x64.

Для цього потрібно написати якийсь сантехнічний код.

Дозвіл правильних x86 / x64-dlls під час виконання

Кроки:

  1. Використовуйте AnyCPU в csproj
  2. Вирішіть, чи посилаєтесь лише на x86 або x64 dlls у своєму csprojs. Адаптуйте параметри UnitTests до вибраних вами параметрів архітектури. Це важливо для налагодження / запуску тестів всередині VisualStudio.
  3. У розділі Довідкові властивості встановіть значення Копіювати локальну та конкретну версію в хибну
  4. Позбавтеся від попереджень архітектури, додавши цей рядок до першої PropertyGroup у всіх своїх файлах csproj, де ви посилаєтеся на x86 / x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Додайте цей сценарій після збирання до свого запуску проекту, використовуйте та змінюйте шляхи цього сценарію, щоб він копіював усі ваші x86 / x64 dlls у відповідні підпапки вашого накопичувача \ 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. (Це не буде виконуватися іноді, якщо ви запускаєте одиночні тести у візуальній студії, посилання вирішуватимуться не з відрізка UnitTest. Тому рішення на кроці 2 є важливим.)

Переваги:

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

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

За бажанням створіть другий виконуваний файл, ексклюзивний для архітектури x64 за допомогою Corflags.exe в сценарії після побудови

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


0

Щодо вашого останнього запитання. Швидше за все, ви не можете вирішити це всередині одного MSI. Якщо ви використовуєте папки реєстру / системи або що-небудь подібне, сам MSI повинен знати про це, і ви повинні підготувати 64-бітний MSI для правильної установки на 32-бітній машині.

Є ймовірність, що ви можете зробити так, щоб продукт був встановлений як додаток 32, і все-таки зможете змусити його працювати як 64-бітний, але я думаю, що це може бути дещо важко досягти.

але, як кажуть, я думаю, ви повинні мати можливість зберегти єдину базу коду для всього. На моєму робочому місці нам це вдалося зробити. (але знадобилося трохи жонглювання, щоб змусити все грати разом)

Сподіваюся, це допомагає. Ось посилання на деякі відомості, пов’язані з проблемами 32/64 біт: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


0

Якщо ви використовуєте власні дії, написані в .NET, як частину свого інсталятора MSI, тоді у вас є інша проблема.

'Shim', який виконує ці власні дії, завжди 32-бітний, тоді ваша власна дія також буде виконуватись 32-бітну, незважаючи на те, яку ціль ви вказали.

Додаткову інформацію та деякі ніндзя рухається, щоб обійти (в основному змінити MSI, щоб використовувати 64-бітну версію цього лайфу)

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

64-бітні керовані користувацькі дії за допомогою Visual Studio


0

Ви можете генерувати два рішення по-різному і зливати їх згодом! Я зробив це для VS 2010. і це працює. У мене було 2 різних рішення, створених CMake, і я їх об'єднав


0

Ви можете використовувати умову до ItemGroup для посилань на DLL у файлі проекту.
Це призведе до того, що візуальна студія повторно перевірятиме стан та посилання, коли ви змінюєте активну конфігурацію.
Просто додайте умову для кожної конфігурації.

Приклад:

 <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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.