Aynı çözümde / projede Visual Studio ile hem 32 bit hem de 64 bit hedefleme


111

Çoklu hedefleme için görsel stüdyomu nasıl kuracağım konusunda biraz ikilemim var.

Arka plan: c # .NET v2.0, 3. taraf 32 bit DLL'lere p / çağırma, SQL compact v3.5 SP1, bir Kurulum projesi ile. Şu anda, platform hedefi Windows x64'te çalıştırılabilmesi için x86 olarak ayarlandı.

Üçüncü taraf şirket, DLL'lerinin 64 bit sürümlerini yayınladı ve özel bir 64 bit program oluşturmak istiyorum.

Bu, henüz cevaplarını bulamadığım bazı soruları gündeme getiriyor. Aynı kod tabanına sahip olmak istiyorum. 32bit DLL setine veya 64bit DLL dosyalarına referanslarla oluşturmalıyım. (Hem 3. taraf hem de SQL Server Compact)

Bu 2 yeni konfigürasyon seti ile çözülebilir mi (Debug64 ve Release64)?

2 ayrı kurulum projesi oluşturmalı mıyım (standart görsel stüdyo projeleri, Wix veya başka bir yardımcı program yok), yoksa bu aynı .msi içinde çözülebilir mi?

Herhangi bir fikir ve / veya tavsiye memnuniyetle karşılanacaktır.


@Magnus Johansson: Hedefinizin yarısını gerçekleştirmek için iki konfigürasyon kullanabilirsiniz. MSI biraz daha zor.
user7116

Yanıtlar:


83

Evet, aynı projede aynı kod tabanına sahip hem x86 hem de x64'ü hedefleyebilirsiniz. Genel olarak, VS.NET'te doğru çözüm yapılandırmalarını oluşturursanız işler Sadece Çalışır (ancak tamamen yönetilmeyen DLL'lere P / Invoke büyük olasılıkla bazı koşullu kodlar gerektirecektir): özel dikkat gerektirdiğini bulduğum öğeler şunlardır:

  • Aynı ada ancak kendi özel bitliklerine sahip dış yönetilen derlemelere başvurular (bu, COM birlikte çalışma derlemeleri için de geçerlidir)
  • MSI paketi (daha önce belirtildiği gibi x86 veya x64'ü hedeflemesi gerekecektir)
  • MSI paketinizdeki tüm özel .NET Installer Sınıfı tabanlı eylemler

Derleme başvurusu sorunu tamamen VS.NET içinde çözülemez, çünkü yalnızca bir projeye belirli bir adla bir başvuru eklemenize izin verir. Bu sorunu çözmek için proje dosyanızı manuel olarak düzenleyin (VS'de, Çözüm Gezgini'nde proje dosyanızı sağ tıklayın, Projeyi Kaldır'ı seçin, ardından tekrar sağ tıklayın ve Düzenle'yi seçin). Örneğin bir derlemenin x86 sürümüne bir başvuru ekledikten sonra, proje dosyanız aşağıdaki gibi bir şey içerecektir:

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

Bu Referans etiketini, geçerli olduğu çözüm yapılandırmasını belirten bir ItemGroup etiketi içine sarın, örneğin:

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

Ardından, ItemGroup etiketinin tamamını kopyalayıp yapıştırın ve 64 bit DLL'nizin ayrıntılarını içerecek şekilde düzenleyin, örneğin:

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

Projenizi VS.NET'te yeniden yükledikten sonra, Montaj Referansı iletişim kutusu bu değişikliklerle biraz karışacak ve yanlış hedef işlemciye sahip derlemeler hakkında bazı uyarılarla karşılaşabilirsiniz, ancak tüm yapılarınız iyi çalışacaktır.

Bir sonraki adımda MSI sorununun çözümü var ve maalesef bu , VS.NET dışı bir araç gerektirecek: Bu amaç için Caphyon'un Gelişmiş Yükleyicisini tercih ediyorum , çünkü ilgili temel numarayı (32-bit'in yanı sıra ortak bir MSI oluşturun) ve 64-bit özel MSI'ları ve doğru sürümü ayıklamak ve çalışma zamanında gerekli düzeltmeleri yapmak için bir .exe kurulum başlatıcısı kullanın) çok, çok iyi.

Muhtemelen diğer araçları veya Windows Installer XML (WiX) araç setini kullanarak aynı sonuçları elde edebilirsiniz , ancak Advanced Installer işleri o kadar kolaylaştırıyor (ve bu konuda oldukça uygun), alternatiflere hiç bakmadım.

Eğer bir şey olabilir Gelişmiş Installer kullanırken bile hala da uygun WiX gerektirir NET Yükleyici Sınıf özel eylemler içindir. Yalnızca belirli platformlarda çalışması gereken belirli eylemleri belirlemek önemsiz olsa da (sırasıyla VersionNT64 ve NOT VersionNT64 yürütme koşullarını kullanarak), yerleşik AI özel eylemleri 64 bit makinelerde bile 32 bit Çerçeve kullanılarak yürütülecektir. .

Bu, gelecekteki bir sürümde düzeltilebilir, ancak şimdilik (veya aynı soruna sahip MSI'larınızı oluşturmak için farklı bir araç kullanırken), WiX 3.0'ın yönetilen özel eylem desteğini, uygun bitlik düzeyine sahip eylem DLL'leri oluşturmak için kullanabilirsiniz. ilgili Çerçeve kullanılarak yürütülecektir.


Düzenleme: 8.1.2 sürümünden itibaren, Advanced Installer 64-bit özel eylemleri doğru şekilde destekler. Orijinal cevabımdan bu yana, ne yazık ki fiyatı oldukça arttı, InstallShield ve ilkine kıyasla hala son derece iyi bir değer olsa da ...


Düzenleme: DLL'leriniz GAC'de kayıtlıysa, standart referans etiketlerini bu şekilde de kullanabilirsiniz (örnek olarak 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>

Koşul ayrıca tüm yapı türlerine, sürüm veya hata ayıklamaya indirgenir ve yalnızca işlemci mimarisini belirtir.


Visual Studio 2008'de, <ItemGroup> öğelerinin yuvalanamadığını buldum. Bu çözüm, grubun altındaki yeni <ItemGroup> ’leri <Reference>’ lerin geri kalanını oluşturduğumda iyi çalıştı. Ayrıca x86'yı AnyCPU olarak değiştirmek zorunda kaldım, bu da muhtemelen projemin geçmişiyle ilgili.
Oliver Bock

Bu Gelişmiş Yükleyici oldukça harika görünüyor.
Patenti

Bu aptalca bir soru olabilir, ancak manuel olarak düzenlemek için dosyaya nasıl ulaşırsınız?
hrh

1
VS içindeki dosyayı düzenlemek için, Solution Explorer'da projeye sağ tıklayın ve "Unload Project" i bulun. Proje kaldırıldıktan sonra, üzerine tekrar sağ tıklayın ve "<proje dosyası adını> Düzenle" seçeneğine tıklayın. Proje dosyasını düzenledikten sonra kaydedin ve proje dosyasına tekrar sağ tıklayın ve yükleyin. Yazım hatası veya hata yoksa, yeniden yüklenir. Değilse, VS size dosyadaki sorunun ne olduğunu hemen hemen söyleyecektir. Umarım yardımcı olur!
John Baughman

Mükemmel cevap! Teşekkür ederim!
John Baughman

27

Diyelim ki her iki platform için derlenmiş DLL'leriniz var ve bunlar aşağıdaki konumda:

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

.Csproj dosyanızı buradan düzenlemeniz yeterlidir:

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

Buna:

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

Daha sonra projenizi her iki platformu hedefleyerek oluşturabilmelisiniz ve MSBuild, seçilen platform için doğru dizine bakacaktır.


İşe yararsa harika olurdu, ama olmadı. En azından benim için değil.
John Sheehan

10
Bunun şöyle olması gerekmiyor muydu: <HintPath> C: \ ne olursa olsun \ $ (Platform) \ ne olursa olsun.dll </HintPath>
Andreas

Benim için Visual Studio 2008'de iyi çalıştı, ancak DLL'yi normal bir <Reference> 'in yaptığı gibi otomatik olarak derleme hedef dizinine kopyalamadı. mdb'nin çözümü benim için daha iyi çalıştı.
Oliver Bock

1

Sorunuzun toplam cevabından emin değilim - ancak x64'e baktığınızı gören SQL Compact 3.5 SP1 indirme sayfasının Ek Bilgiler bölümünde bir yoruma işaret edeceğimi düşündüm - umarım yardımcı olur.

SQL Server Compact SP1'deki değişiklikler ve ek 64-bit sürüm desteği nedeniyle, SQL Server Compact 3.5'in 32-bit sürümünün merkezi olarak yüklenmiş ve karma mod ortamları ve SQL Server Compact 3.5 SP1'in 64-bit sürümü, aralıklı görünenleri oluşturabilir sorunları. Çakışma olasılığını en aza indirmek ve yönetilen istemci uygulamalarının platformdan bağımsız dağıtımını sağlamak için, Windows Installer (MSI) dosyası kullanılarak SQL Server Compact 3.5 SP1'in 64 bit sürümünü merkezi olarak yüklemek, SQL Server'ın 32 bit sürümünü yüklemeyi de gerektirir Kompakt 3.5 SP1 MSI dosyası. Yalnızca yerel 64 bit gerektiren uygulamalar için, SQL Server Compact 3.5 SP1'in 64 bit sürümünün özel dağıtımı kullanılabilir.

"32bit SQLCE dosyaları dahil olarak ben bunu okuyun yanı sıra 64bit müşteriler için dağıtmak eğer 64bit dosyalarını".

Sanırım hayatı ilginç kılıyor sanırım .. "Aralıklı sorunlar gibi görünen" satırını sevdiğimi söylemeliyim ... biraz "bir şeyler hayal ediyorsun, ama her ihtimale karşı şunu yap ..." gibi geliyor.


1

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.

Bunun için bir sıhhi tesisat kodu yazmalısınız.

Ç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 betiğini başlangıç ​​projenize ekleyin, tüm x86 / x64 dll'lerinizi derleme bininizin \ x86 \ bin \ x64 \ alt klasörlerine kopyalayacak şekilde bu betiğin yollarını kullanın ve değiştirin.

    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öntem içeren bir 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: - Doğru dll'lerin başlangıçta ikili klasörünüze kopyalandığından emin olursanız AssemblyResolve olay işleyicisine ihtiyacınız yoktur (İş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.


0

Son sorunuzla ilgili olarak. Büyük olasılıkla bunu tek bir MSI içinde çözemezsiniz. Kayıt defteri / sistem klasörleri veya ilgili herhangi bir şey kullanıyorsanız, MSI'nın kendisi bunun farkında olmalı ve 32 bit makineye düzgün bir şekilde kurmak için 64 bit MSI hazırlamanız gerekir.

Ürününüzü bir 32 IT uygulaması olarak yükletme ve yine de 64 bit olarak çalıştırma imkanı var, ancak bunu başarmanın biraz zor olabileceğini düşünüyorum.

Her şey için tek bir kod tabanı tutmanız gerektiğini düşünüyorum. Şu anki iş yerimde bunu başardık. (ama her şeyin birlikte oynaması için biraz hokkabazlık gerekiyordu)

Bu yardımcı olur umarım. 32/64 bit sorunlarıyla ilgili bazı bilgilere bir bağlantı vardır: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


0

MSI yükleyicinizin bir parçası olarak .NET'te yazılmış Özel Eylemler kullanıyorsanız, başka bir sorununuz var demektir.

Bu özel eylemleri çalıştıran 'shim' her zaman 32bittir, ardından özel eyleminiz, belirttiğiniz hedefe rağmen 32bit çalışacaktır.

Daha fazla bilgi ve bazı ninjalar dolaşmak için hareket eder (temelde MSI'yı bu dolgunun 64 bit sürümünü kullanacak şekilde değiştirin)

SharePoint 64 üzerinde çalışmak için Visual Studio 2005 / 2008'de bir MSI oluşturma

Visual Studio ile 64 bit Yönetilen Özel Eylemler


0

Farklı şekilde iki çözüm üretebilir ve daha sonra birleştirebilirsiniz! Bunu VS 2010 için yaptım ve işe yarıyor. CMake tarafından üretilen 2 farklı çözümüm vardı ve bunları birleştirdim


0

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