Visual Studio'da derlerken koşullu olarak 32/64 bit başvurusu kullanın


124

32/64-bit inşa eden ve buna karşılık gelen 32/64-bit bağımlılıkları olan bir projem var. Yapılandırmaları değiştirebilmek ve doğru referansın kullanılabilmesini istiyorum, ancak Visual Studio'ya mimariye uygun bağımlılığı kullanmasını nasıl söyleyeceğimi bilmiyorum.

Belki bunu yanlış yoldan yapıyorum, ancak yapılandırma açılır menüsünde x86 ve x64 arasında geçiş yapabilmek ve başvurulan DLL'nin doğru bit olmasını istiyorum.


Çok belirsiz, bu hangi dil? DLL projesi çözümde mi?
Hans Passant

Üzgünüm, bu .NET, C # ile yazıyorum.
Jonathan Yee

4
Tamam, aptalca bir çözümle çözdüm: Yalnızca x64 DLL'ye başvuran (ve x86 yapılandırmasını csproj'dan kaldıran) ek bir csproj dosyası oluşturdum. İşe yarıyor, ancak herhangi birinin ek bir csproj içermeyen daha zarif bir çözümü olsaydı, onu görmeyi çok isterim.
Jonathan Yee

Yanıtlar:


99

İşte önceki bir projede .csproj dosyalarının manuel baskısını gerektiren bir şey. Farklı ikili dosyalar için, ideal olarak birbirlerinin kardeşleri için ve hedeflediğiniz platformla aynı ada sahip ayrı dizinlere de ihtiyacınız var.

Projeye tek bir platformun referanslarını ekledikten sonra, .csproj dosyasını bir metin düzenleyicide açın. <ItemGroup>Öğe içindeki ilk öğeden önce, <Project>hangi platformda çalıştırdığınızı (ve oluşturduğunuzu) belirlemenize yardımcı olacak aşağıdaki kodu ekleyin.

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

Ardından, platforma özel referanslarınız için aşağıdakiler gibi değişiklikler yaparsınız:

<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)Yukarıda tanımladığımız mülkün kullanımına dikkat edin . Bunun yerine, hangi platform için hangi derlemelerin dahil edileceği için koşul ifadeleri kullanabilirsiniz. Ayrıca şunlara da ihtiyacınız olabilir:

  • YALNIZCA projelerin hedef platformunu dikkate almak için $(PROCESSOR_ARCHITEW6432)ve $(PROCESSOR_ARCHITECTURE)ile değiştirin$(Platform)
  • Mevcut makineye uygun olması için platform belirleme mantığını değiştirin, böylece 32 bitlik bir platformda çalıştırmak için 64 bitlik bir ikili dosya oluşturmaz / referans vermezsiniz.

Bunu aslen işteki dahili bir Wiki için yazdım, ancak ayrıntılı adım adım talimatlarla ilgileniyorsanız, onu değiştirdim ve tüm süreci bloguma gönderdim .


1
Güzel. Aşağıdaki öneriye göre ItemGroup üzerinde bir koşul kullanmaya gittim, ancak buradaki koşullar için $ (PROCESSOR_ARCHITEW6432) ve $ (PROCESSOR_ARCHITECTURE) kullandım. Bir not: $ (PROCESSOR_ARCHITECTURE), hem 32 hem de 64 bit platformlarda x86 döndürür, ancak $ (PROCESSOR_ARCHITEW6432), AMD64'ü yalnızca 64 bit'te döndürür. X86'yı test etmeye çalışırsanız dikkat etmeniz gereken bir şey (çünkü AMD64, x86'nın bir türevi olduğunu varsayıyorum).
tjmoore

Bu bilgi için teşekkürler @tjmoore. Bunu hangi O / S'de fark ettiniz? Benimkini tekrar kontrol ettim (Win7SP1) ve AMD64 için $ (PROCESSOR_ARCHITECTURE) diyor, ancak kesinlikle mümkün olduğunca eksiksiz ve eksiksiz bilgi almak istiyorum.
Hugo

7
Komik, araştırmam beni buraya getiriyor ve buna ihtiyacım var çünkü LeadTools'u da kullanıyorum ... +1
Ed S.

Çözüm, varsayılan yapılandırma için çalışır, ancak yapılandırmayı yapılandırmadan Visual Studio (benim durumumda 2012) Çözüm Yapılandırma açılır listesinden değiştirirseniz, benim testimden değil.
Sarah Weinberger

$ (PROCESSOR_ARCHITEW6432) yerine $ (Platform) kullandım, nedense $ (PROCESSOR_ARCHITEW6432) çalışmıyordu.
Dzyann

60

AFAIK, projeniz 32-bit veya 64-bit özel referanslar gerektiriyorsa (yani COM-birlikte çalışma derlemeleri) ve .csproj dosyasını manuel olarak düzenlemekle ilgilenmiyorsanız, ayrı 32 bit ve 64 bit projeler.

Aşağıdaki çözümün test edilmediğini ancak işe yaraması gerektiğini not etmeliyim. .Csproj dosyasını manuel olarak düzenlemeye istekli iseniz, istediğiniz sonucu tek bir projeyle elde edebilmelisiniz. .Csproj dosyası yalnızca bir MSBuild betiğidir, bu nedenle tam bir referans için buraya bakın . .Csproj dosyasını bir düzenleyicide açtığınızda, <Reference>öğeleri bulun . Bu öğeleri 3 farklı öğe grubuna ayırabilmeniz gerekir : platforma özgü olmayan referanslar, x86'ya özgü referanslar ve x64'e özgü referanslar.

Aşağıda, projenizin "x86" ve "x64" adlı hedef platformlarla yapılandırıldığını varsayan bir örnek verilmiştir.

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

Şimdi, proje / çözüm derleme yapılandırmanızı x86 veya x64 platformunu hedefleyecek şekilde ayarladığınızda, her durumda uygun başvuruları içermelidir. Tabii ki, <Reference>öğelerle oynamanız gerekecek . Hatta x86 ve x64 referanslarını eklediğiniz kukla projeler kurabilir ve ardından gerekli <Reference>öğeleri bu kukla proje dosyalarından "gerçek" proje dosyanıza kopyalayabilirsiniz .


Düzenleme 1
İşte, yanlışlıkla orijinal gönderiden çıkardığım yaygın MSBuild proje öğelerine bir bağlantı: http://msdn.microsoft.com/en-us/library/bb629388.aspx


Mükemmel Cevap !! Günümü kurtardım! Çok teşekkürler.
hellodear

20

Proje dosyasındaki dll başvuruları için bir ItemGroup koşulunu kullanabilirsiniz .
Bu, görsel stüdyonun aktif konfigürasyonu her değiştirdiğinizde durumu ve referansları yeniden kontrol etmesine neden olur.
Her konfigürasyon için bir koşul eklemeniz yeterlidir.

Misal:

 <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
Bu harika, teşekkürler! Bu kesinlikle kabul edilen çözüm olmalıdır!
ManicBlowfish

Cidden, bu cevap kabul edilenden çok daha iyi ve daha basit.
Yandros

1
Bunu yaptıktan sonra Referanslarda yinelenen girişlerin olması normal mi?
natenho

7

Projemde örneğin \ component \ v3_NET4 konumunda bulunan x86 DLL'lerine referans veriyorum. X86 / x64 için belirli DLL'ler, "x86" ve "x64" adlı alt klasörlerde bulunur.

Ardından, uygun DLL'leri (x86 / x64) $ (PlatformName) temelinde başvurulan klasöre kopyalayan önceden oluşturulmuş bir komut dosyası kullanıyorum.

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

Benim için çalışıyor.


3

X86 / x64 Bağımlılıkları ile tek .Net derlemesi

Diğer tüm yanıtlar size platforma göre farklı Derlemeler yapmak için bir çözüm sunarken, size yalnızca "AnyCPU" yapılandırmasına sahip olma ve x86 ve x64 dll'lerinizle çalışan bir yapı oluşturma seçeneği sunuyorum.

Çalışma zamanında doğru x86 / x64-dll'lerin çözünürlüğü

Adımlar:

  1. Csproj'da AnyCPU kullanın
  2. Csproj'larınızda yalnızca x86 veya x64 dll'leri referans alıp almadığınıza karar verin. UnitTests ayarlarını seçtiğiniz mimari ayarlarına uyarlayın. VisualStudio içindeki testleri hata ayıklamak / çalıştırmak için önemlidir.
  3. Referans Özelliklerinde Yerel ve Belirli Sürümü Kopyala seçeneğini yanlış olarak ayarlayın
  4. X86 / x64'e başvurduğunuz tüm csproj dosyalarınızda bu satırı ilk PropertyGroup'a ekleyerek mimari uyarılardan kurtulun : <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Bu postbuild komut dosyasını başlangıç ​​projenize ekleyin, bu komut dosyasının yollarını kullanın ve değiştirin, böylece tüm x86 / x64 dll'lerinizi yapı bininizin \ x86 \ bin \ x64 \ alt klasörlerine kopyalar.

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

    -> Uygulamayı şimdi başlattığınızda, derlemenin bulunamadığına dair bir istisna alırsınız.

  6. AssemblyResolve olayını başvuru giriş noktanızın hemen başında kaydedin

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;

    bu yöntemle:

    /// <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. Birim testleriniz varsa, AssemblyInitializeAttribute içeren bir Yöntemle TestClass oluşturun ve ayrıca yukarıdaki TryResolveArchitectureDependency-Handler'ı oraya kaydedin. (Bu bazen visual studio içinde tek testler çalıştırırsanız uygulanmaz, referanslar UnitTest bölmesinden değil çözümlenecektir. Bu nedenle 2. adımdaki karar önemlidir.)

Yararları:

  • Her iki platform için bir Kurulum / Yapı

Dezavantajlar: - x86 / x64 dll'leri eşleşmediğinde derleme sırasında hata oluşmaz. - Yine de her iki modda da test çalıştırmalısınız!

İsteğe bağlı olarak, postbuild komut dosyasında Corflags.exe ile x64 mimarisine özel ikinci bir yürütülebilir dosya oluşturun

Denenecek Diğer Değişkenler: - Aksi takdirde dll'lerin başlangıçta ikili klasörünüze kopyalanacağından emin olursanız AssemblyResolve olay işleyicisine ihtiyacınız olmaz (İşlem mimarisini değerlendirin -> ilgili dll'leri x64 / x86'dan bin klasörüne ve geri taşıyın.) - Yükleyicide mimariyi değerlendirin ve yanlış mimari için ikili dosyaları silin ve doğru olanları bin klasörüne taşıyın.


2

Aynı sorunla karşılaştım ve iyi bir çözüm ararken epey bir zaman geçirdim. Çoğu kişi, daha sonra bu düzenlenmiş dosyaları Visual Studio GUI'de keşfederken oldukça sıkıcı, hataya açık ve kafa karıştırıcı olan Visual Studio çözüm dosyalarının manuel olarak düzenlenmesini sunar. Zaten vazgeçtiğimde çözüm kendi kendine geldi. Micke'nin yukarıdaki cevabında önerdiği şeye çok benziyor.

Hesap yöneticisinde, her zamanki gibi x86 ve x64 platformları için iki ayrı derleme hedefi oluşturdum. Ardından, projeme x86 derlemesine bir başvuru ekledim. Bu noktada, projenin yalnızca x86 yapılandırması için yapılandırıldığına ve yukarıda Hugo'nun önerdiği şekilde manuel olarak düzenlemeyi yapmadığım sürece x64 yapılandırması için oluşturulmayacağına inandım.

Bir süre sonra, sonunda sınırlamayı unuttum ve yanlışlıkla x64 oluşturmaya başladım. Tabii ki, yapı başarısız oldu. Ama önemli olan, aldığım hata mesajıydı. Hata mesajı, tam olarak başvurulan x86 derlemem olarak adlandırılan derlemenin, çözümüm için x64 derleme hedefi olarak tasarlanan klasörde eksik olduğunu söyledi.

Bunu fark ettikten sonra, uygun x64 derlemesini bu dizine manuel olarak kopyaladım. Glory! X64 yapım mucizevi bir şekilde, bulunan ve dolaylı olarak bağlanan uygun montaj ile başarılı oldu. Bu klasöre x64 derlemesi için bir yapı hedef dizini ayarlamak için çözümümü değiştirmek dakikalar aldı. Bu adımlardan sonra çözüm, MSBuild dosyalarını manuel olarak düzenlemeden hem x86 hem de x64 için otomatik olarak derlenir.

Sonuç olarak:

  1. Tek bir projede x86 ve x64 hedefleri oluşturun
  2. X86 derlemelerine tüm uygun proje referanslarını ekleyin
  3. Tüm x64 derlemeleri için ortak bir yapı hedef dizini ayarlayın
  4. Hazır x64 derlemelerine sahipseniz, bunları bir kez x64 derleme hedef dizininize kopyalayın

Bu adımlar tamamlandıktan sonra, çözümünüz hem x86 hem de x64 yapılandırmaları için uygun şekilde oluşturulacaktır.

Bu benim için Visual Studio 2010 .NET 4.0 C # projesinde çalıştı. Açıktır ki bu, 2012, 2013 ve 2015 sürümlerinde değişikliğe konu olabilecek Visual Studio'nun bir tür belgelenmemiş dahili davranışıdır. Birisi diğer sürümleri deneyecekse, lütfen deneyiminizi paylaşın.


-1

Daha kolay bir çözüm olduğunu düşündüğüm şeyi, yani Micke'nin tersine çevirmeyi kullandım. Proje, x86 ve x64 hedefleri olan bir C # form uygulaması olan Visual Studio 2015'tir. .NET derlemelerinden birine başvurdum, 32 bit olanı kullandım. Referans özelliklerinde "Yerel Kopyala" yı yanlış olarak ayarlıyorum. Sonra her hedef dizine uygun (32 veya 64 bit) .Net derlemesini manuel olarak koydum. Sadece harici arabirimi tanımladığı için aynı yeteneklere sahip olduklarını varsayarak gerçek referans bitliği ilgisizdir. Süslü olmak istiyorsanız, bir post build copy adımı da koyabilirsiniz. Bu projenin de bir COM referansı olduğunu unutmayın, aynı şey çalışır. Referans, nesneleri / arayüzleri tanımlar, böylece referans DLL'nin bitliği ilgisizdir. Hem 32 bit hem de 64 bit COM DLL'ler kayıtlıysa, uygulama kayıt defterinde uygun yere bakacak ve doğru 32 veya 64 bit COM nesnesini oluşturacaktır. Benim için çalışıyor!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.