Sử dụng có điều kiện tham chiếu 32/64 bit khi xây dựng trong Visual Studio


124

Tôi có một dự án xây dựng trong 32/64-bit và có các phụ thuộc 32/64-bit tương ứng. Tôi muốn có thể chuyển đổi cấu hình và sử dụng tham chiếu chính xác, nhưng tôi không biết làm thế nào để nói với Visual Studio sử dụng phụ thuộc phù hợp với kiến ​​trúc.

Có thể tôi đang đi sai hướng này, nhưng tôi muốn có thể chuyển đổi giữa x86 và x64 trong trình đơn thả xuống cấu hình và có DLL được tham chiếu là bitness đúng.


Rất không rõ ràng, đây là ngôn ngữ gì? Là dự án DLL trong giải pháp?
Hans Passant

Xin lỗi, đây là .NET, tôi đang viết bằng C #.
Jonathan Yee

4
Ok, tôi đã giải quyết nó bằng một giải pháp ngu ngốc: Tạo một tệp csproj bổ sung chỉ tham chiếu DLL x64 (và xóa cấu hình x86 khỏi csproj). Nó hoạt động, nhưng nếu bất cứ ai có một giải pháp thanh lịch hơn mà không liên quan đến một csproj bổ sung, tôi rất muốn thấy nó.
Jonathan Yee

Câu trả lời:


99

Dưới đây là những gì tôi đã thực hiện trong một dự án trước đó, sẽ yêu cầu phiên bản thủ công của tệp .csproj. Bạn cũng cần các thư mục riêng cho các nhị phân khác nhau, anh chị em lý tưởng của nhau và có cùng tên với nền tảng bạn đang nhắm mục tiêu.

Sau khi thêm các tham chiếu của một nền tảng vào dự án, hãy mở .csproj trong trình soạn thảo văn bản. Trước <ItemGroup>phần tử đầu tiên trong <Project>phần tử, hãy thêm đoạn mã sau, điều này sẽ giúp xác định nền tảng nào bạn đang chạy (và xây dựng).

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

Sau đó, đối với các tham chiếu cụ thể cho nền tảng của bạn, bạn thực hiện các thay đổi như sau:

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

Lưu ý việc sử dụng $(CurrentPlatform)tài sản, mà chúng tôi đã xác định ở trên. Thay vào đó, bạn có thể sử dụng các điều kiện để lắp ráp cho nền tảng nào. Bạn cũng có thể cần phải:

  • Thay thế $(PROCESSOR_ARCHITEW6432)$(PROCESSOR_ARCHITECTURE)bằng $(Platform)cách xem xét CHỈ nền tảng mục tiêu của các dự án
  • Thay đổi logic xác định nền tảng để phù hợp với máy hiện tại, do đó bạn không xây dựng / tham chiếu nhị phân 64 bit để thực thi trên nền tảng 32 bit.

Tôi đã viết nó ban đầu cho một Wiki nội bộ tại nơi làm việc, tuy nhiên, tôi đã sửa đổi nó và đăng toàn bộ quá trình lên blog của mình , nếu bạn quan tâm đến các hướng dẫn từng bước chi tiết.


1
Đẹp. Tôi đã sử dụng một điều kiện trên Itemgroup theo đề xuất bên dưới nhưng sử dụng $ (PROCESSOR_ARCHITEW6432) và $ (PROCESSOR_ARCHITECTURE) cho các điều kiện như ở đây. Một lưu ý là tôi thấy $ (PROCESSOR_ARCHITECTURE) trả về x86 trên cả hai nền tảng 32 và 64 bit nhưng $ (PROCESSOR_ARCHITEW6432) chỉ trả về AMD64 trên 64 bit. Một vài điều cần lưu ý nếu bạn thử kiểm tra x86 (vì AMD64 là một dẫn xuất của x86 tôi giả sử).
tjmoore

Cảm ơn thông tin đó @tjmoore. Trên đó O / S bạn đã nhận thấy điều này? Tôi vừa kiểm tra lại của tôi (Win7SP1) và nói AMD64 cho $ (PROCESSOR_ARCHITECTURE), nhưng chắc chắn muốn có thông tin đầy đủ và kỹ lưỡng nhất có thể.
Hugo

7
Thật buồn cười, tìm kiếm của tôi mang tôi đến đây và tôi chỉ cần điều này vì tôi cũng đang sử dụng LeadTools ... +1
Ed S.

Giải pháp hoạt động cho cấu hình mặc định, nhưng không phải từ thử nghiệm của tôi, nếu bạn không thay đổi cấu hình từ cấu hình từ Visual Studio (2012 trong trường hợp của tôi) danh sách thả xuống Cấu hình Giải pháp.
Sarah Weinberger

Thay vì sử dụng $ (PROCESSOR_ARCHITEW6432) tôi đã sử dụng $ (Nền tảng) vì một số lý do $ (PROCESSOR_ARCHITEW6432) không hoạt động.
Dzyann

60

AFAIK, nếu dự án của bạn yêu cầu các tài liệu tham khảo cụ thể 32 bit hoặc 64 bit (nghĩa là các cụm COM-interop) và bạn không quan tâm đến việc chỉnh sửa thủ công tệp .csproj, thì bạn sẽ phải tạo 32 bit riêng biệt và Dự án 64 bit.

Tôi nên lưu ý rằng các giải pháp sau đây chưa được kiểm tra, nhưng nên hoạt động. Nếu bạn sẵn sàng chỉnh sửa thủ công tệp .csproj, thì bạn sẽ có thể đạt được kết quả mong muốn với một dự án duy nhất. Tệp .csproj chỉ là tập lệnh MSBuild, vì vậy để tham khảo đầy đủ, hãy xem tại đây . Khi bạn mở tệp .csproj trong trình chỉnh sửa, hãy xác định vị trí các <Reference>thành phần. Bạn có thể chia các thành phần này thành 3 nhóm mục riêng biệt : tài liệu tham khảo không phải là nền tảng cụ thể, tài liệu tham khảo cụ thể x86 và tài liệu tham khảo cụ thể x64.

Dưới đây là một ví dụ giả định rằng dự án của bạn được cấu hình với các nền tảng đích có tên là "x86" và "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>

Bây giờ, khi bạn đặt cấu hình xây dựng dự án / giải pháp của mình để nhắm mục tiêu nền tảng x86 hoặc x64, nó sẽ bao gồm các tham chiếu thích hợp trong từng trường hợp. Tất nhiên, bạn sẽ cần phải chơi xung quanh với các <Reference>yếu tố. Bạn thậm chí có thể thiết lập các dự án giả trong đó bạn thêm các tham chiếu x86 và x64, sau đó chỉ cần sao chép các <Reference>phần tử cần thiết từ các tệp dự án giả đó vào tệp dự án "thực" của bạn.


Chỉnh sửa 1
Đây là một liên kết đến các mục dự án MSBuild phổ biến mà tôi vô tình bỏ quên khỏi bài đăng gốc: http://msdn.microsoft.com/en-us/l Library / bb629388.aspx


Câu trả lời tuyệt vời !! Cứu ngày của tôi! Cảm ơn rất nhiều.
địa ngục

20

Bạn có thể sử dụng một điều kiện cho một Itemgroup cho các tham chiếu dll trong tệp dự án.
Điều này sẽ khiến phòng thu trực quan kiểm tra lại điều kiện và tham chiếu mỗi khi bạn thay đổi cấu hình hoạt động.
Chỉ cần thêm một điều kiện cho mỗi cấu hình.

Thí dụ:

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

1
Điều này là rất tốt, cảm ơn bạn! Đây chắc chắn là giải pháp được chấp nhận!
ManicBlowfish

Nghiêm túc mà nói, câu trả lời này tốt hơn và đơn giản hơn nhiều so với câu trả lời.
Yandros

1
Có phải là bình thường để có các mục trùng lặp trong Tài liệu tham khảo sau khi làm điều này?
natenho

7

Tôi đang tham khảo các DLL x86, nằm trong ví dụ \ thành phần \ v3_NET4, trong dự án của tôi. Các DLL cụ thể cho x86 / x64 được đặt trong các thư mục con có tên "x86" và "x64" resp.

Sau đó, tôi đang sử dụng tập lệnh dựng sẵn sao chép các tệp DLL phù hợp (x86 / x64) vào thư mục được tham chiếu, dựa trên $ (PlatformName).

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

Làm việc cho tôi.


3

Một bản dựng .Net với Phụ thuộc x86 / x64

Mặc dù tất cả các câu trả lời khác cung cấp cho bạn một giải pháp để tạo các Bản dựng khác nhau theo nền tảng, tôi cung cấp cho bạn một tùy chọn chỉ có cấu hình "AnyCPU" và tạo bản dựng hoạt động với các dll x86 và x64 của bạn.

Độ phân giải của x86 / x64-dll chính xác khi chạy

Các bước:

  1. Sử dụng AnyCPU trong csproj
  2. Quyết định xem bạn chỉ tham chiếu các dll x86 hoặc x64 trong csprojs của bạn. Điều chỉnh cài đặt UnitTests cho cài đặt kiến ​​trúc bạn đã chọn. Điều quan trọng là gỡ lỗi / chạy thử nghiệm bên trong VisualStudio.
  3. Trên Tham chiếu-Thuộc tính được đặt Sao chép Phiên bản cục bộ & cụ thể thành sai
  4. Loại bỏ các cảnh báo kiến ​​trúc bằng cách thêm dòng này vào Thuộc tính nhóm đầu tiên trong tất cả các tệp csproj của bạn nơi bạn tham chiếu x86 / x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Thêm tập lệnh postbuild này vào dự án khởi động của bạn, sử dụng và sửa đổi đường dẫn của tập lệnh này để nó sao chép tất cả các dll x86 / x64 của bạn trong các thư mục con tương ứng của bản dựng 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

    -> Khi bạn sẽ bắt đầu ứng dụng ngay bây giờ, bạn sẽ nhận được một ngoại lệ là không thể tìm thấy lắp ráp.

  6. Đăng ký sự kiện AssociationResolve ngay khi bắt đầu điểm đăng ký ứng dụng của bạn

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;

    với phương pháp này:

    /// <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. Nếu bạn có các bài kiểm tra đơn vị, hãy tạo một TestClass với một Phương thức có một AssociationInitializeAttribution và cũng đăng ký TryResolveArch architectureDependency-Handler ở trên. (Điều này đôi khi sẽ không được thực thi nếu bạn chạy thử nghiệm đơn trong phòng thu trực quan, các tham chiếu sẽ được giải quyết không phải từ thùng UnitTest. Do đó, quyết định trong bước 2 là quan trọng.)

Những lợi ích:

  • Một cài đặt / Xây dựng cho cả hai nền tảng

Hạn chế: - Không có lỗi tại thời gian biên dịch khi các dll x86 / x64 không khớp. - Bạn vẫn nên chạy thử nghiệm ở cả hai chế độ!

Tùy chọn tạo tệp thực thi thứ hai dành riêng cho kiến ​​trúc x64 với Corflags.exe trong tập lệnh postbuild

Các biến thể khác để thử: - Bạn sẽ không cần trình xử lý sự kiện hộiResolve nếu bạn đảm bảo nếu không các dll sẽ được sao chép trong thư mục nhị phân của bạn khi bắt đầu (Đánh giá kiến ​​trúc quy trình -> di chuyển các dll tương ứng từ x64 / x86 sang thư mục bin và quay lại.) - Trong Trình cài đặt đánh giá kiến ​​trúc và xóa nhị phân cho kiến ​​trúc sai và di chuyển đúng vào thư mục bin.


2

Tôi đã đối mặt với cùng một vấn đề và mất khá nhiều thời gian để tìm kiếm một giải pháp tốt. Hầu hết mọi người cung cấp chỉnh sửa thủ công các tệp giải pháp Visual Studio, điều này khá tẻ nhạt, dễ bị lỗi và khó hiểu khi khám phá các tệp đã chỉnh sửa này trong Visual Studio GUI sau đó. Khi tôi đã từ bỏ, giải pháp tự đưa ra. Nó rất giống với những gì Micke đề xuất trong câu trả lời của mình ở trên.

Trong trình quản lý tài khoản, tôi đã tạo hai mục tiêu xây dựng riêng cho nền tảng x86 và x64, như thường lệ. Tiếp theo, tôi đã thêm một tham chiếu đến x86 lắp ráp vào dự án của tôi. Về điểm này, tôi tin rằng dự án chỉ được cấu hình cho bản dựng x86 và sẽ không bao giờ xây dựng cho cấu hình x64, trừ khi tôi sẽ thực hiện chỉnh sửa thủ công cho nó theo đề xuất của Hugo ở trên.

Sau một thời gian, cuối cùng tôi đã quên giới hạn và vô tình bắt đầu xây dựng x64. Tất nhiên, việc xây dựng thất bại. Nhưng quan trọng là thông báo lỗi tôi nhận được. Thông báo lỗi cho biết lắp ráp có tên chính xác như lắp ráp x86 được tham chiếu của tôi bị thiếu trong thư mục dự định là mục tiêu xây dựng x64 cho giải pháp của tôi.

Nhận thấy điều này, tôi đã sao chép thủ công lắp ráp x64 vào thư mục này. Vinh quang! Bản dựng x64 của tôi đã thành công một cách kỳ diệu với sự lắp ráp đúng được tìm thấy và liên kết ngầm. Chỉ cần vài phút để sửa đổi giải pháp của tôi để đặt thư mục đích xây dựng cho x64 lắp ráp vào thư mục này. Sau các bước này, giải pháp sẽ tự động xây dựng cho cả x86 và x64 mà không cần chỉnh sửa thủ công các tệp MSBuild.

Tóm lại:

  1. Tạo các mục tiêu x86 và x64 trong một dự án
  2. Thêm tất cả các tham chiếu dự án thích hợp vào các cụm x86
  3. Đặt một thư mục đích xây dựng chung cho tất cả các cụm x64
  4. Trong trường hợp bạn đã sẵn sàng x64, chỉ cần sao chép chúng một lần vào thư mục đích xây dựng x64 của bạn

Sau khi hoàn thành các bước này, giải pháp của bạn sẽ được xây dựng chính xác cho cả cấu hình x86 và x64.

Điều này làm việc cho tôi trong dự án Visual Studio 2010 .NET 4.0 C #. Rõ ràng, đây là một loại hành vi nội bộ không có giấy tờ của Visual Studio, có thể là đối tượng thay đổi trong các phiên bản 2012, 2013 và 2015. Nếu ai đó sẽ thử trên các phiên bản khác, xin vui lòng chia sẻ kinh nghiệm của bạn.


-1

Tôi đã kết thúc bằng cách sử dụng những gì tôi coi là một giải pháp dễ dàng hơn đó là sự đảo ngược của Micke. Dự án là một ứng dụng biểu mẫu C #, Visual Studio 2015, với các mục tiêu x86 và x64. Tôi đã tham chiếu một trong các hội đồng .NET, tôi đã sử dụng 32 bit một. Trong thuộc tính tham chiếu, tôi đặt "Sao chép cục bộ" thành false. Sau đó, tôi chỉ cần đặt thủ công (32 hoặc 64 bit) .Net lắp ráp trong mỗi thư mục đích. Độ bit tham chiếu thực tế là không liên quan, giả sử chúng có cùng khả năng, vì nó chỉ xác định giao diện bên ngoài. Bạn cũng có thể đặt một bước sao chép bài đăng nếu bạn muốn có được sự ưa thích. Lưu ý dự án này cũng có một tài liệu tham khảo COM, điều tương tự hoạt động. Tham chiếu xác định các đối tượng / giao diện để bitness của DLL tham chiếu là không liên quan. Nếu cả hai DLL COM 32 bit và 64 bit được đăng ký, ứng dụng sẽ tìm ở vị trí thích hợp trong sổ đăng ký và tạo đối tượng COM 32 hoặc 64 bit chính xác. Làm việc cho tôi!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.