Derleme başvurularında sorun giderme

MSBuild ve .NET derleme işlemindeki en önemli görevlerden biri, görevde gerçekleşen derleme başvurularını çözümlemektir ResolveAssemblyReference . Bu makalede, nasıl ResolveAssemblyReference çalıştığına ilişkin bazı ayrıntılar ve başvuru çözümlenemediğinde ResolveAssemblyReference gerçekleşebilecek derleme hatalarını giderme adımları açıklanmaktadır. Derleme başvurusu hatalarını araştırmak için YAPıLANDıRıLMıŞ Günlük Görüntüleyicisi'ni yükleyip MSBuild günlüklerini görüntülemek isteyebilirsiniz. Bu makaledeki ekran görüntüleri Yapılandırılmış Günlük Görüntüleyicisi'nden alınmıştır.

AmacıResolveAssemblyReference, öğe aracılığıyla <Reference> dosyalarda .csproj (veya başka bir yerde) belirtilen tüm başvuruları almak ve bunları dosya sistemindeki derleme dosyalarına eşlemektir.

Derleyiciler yalnızca dosya sistemindeki bir .dll yolu başvuru olarak kabul edebilir, bu nedenle ResolveAssemblyReference proje dosyalarında görünen gibi mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 dizeleri gibi C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dllyollara dönüştürür ve bu da daha sonra anahtar aracılığıyla /r derleyiciye geçirilir.

ResolveAssemblyReference Ayrıca, tüm .dll ve başvuruların tamamını (aslında grafik teorisi terimlerinde geçişli kapanış) belirler ve .exe her biri için derleme çıkış dizinine kopyalanıp kopyalanmayacağını belirler. Gerçek kopyalamayı yapmaz (daha sonra gerçek derleme adımından sonra işlenir), ancak kopyalanacak dosyaların bir öğe listesini hazırlar.

ResolveAssemblyReference hedeften çağrılır ResolveAssemblyReferences :

Derleme işleminde ResolveAssemblyReferences çağrıldığını gösteren günlük görüntüleyicisinin ekran görüntüsü.

Sıralamayı fark ederseniz, ResolveAssemblyReferences öncesinde Compilegerçekleşir ve elbette CopyFilesToOutputDirectory sonrasında Compilegerçekleşir.

Not

ResolveAssemblyReference görev, MSBuild yükleme klasörlerindeki standart .targets dosyada Microsoft.Common.CurrentVersion.targets çağrılır. .NET SDK MSBuild hedeflerine de adresinden https://github.com/dotnet/msbuild/blob/a936b97e30679dcea4d99c362efa6f732c9d3587/src/Tasks/Microsoft.Common.CurrentVersion.targets#L1991-L2140çevrimiçi olarak göz atabilirsiniz. Bu bağlantı, görevin dosyada ResolveAssemblyReference tam olarak nerede çağrıldığı .targets gösterir.

ResolveAssemblyReference girişleri

ResolveAssemblyReference girişlerini günlüğe kaydetme hakkında kapsamlıdır:

ResolveAssemblyReference görevinin giriş parametrelerini gösteren ekran görüntüsü.

Düğüm Parameters tüm görevler için standarttır, ancak buna ek olarak ResolveAssemblyReference Girişler altında kendi bilgi kümesini günlüğe kaydeder (temelde altında Parametersolduğu gibi ancak farklı yapılandırılmıştır).

En önemli girişler şunlardırAssemblies:AssemblyFiles

    <ResolveAssemblyReference
        Assemblies="@(Reference)"
        AssemblyFiles="@(_ResolvedProjectReferencePaths);@(_ExplicitReference)"

Assemblies, proje için çağrıldığı ResolveAssemblyReference anda MSBuild öğesinin içeriğini Reference kullanır. NuGet başvurularınız da dahil olmak üzere tüm meta veriler ve derleme başvuruları bu öğede yer almalıdır. Her başvuruya eklenmiş zengin bir meta veri kümesi vardır:

Derleme başvurusundaki meta verileri gösteren ekran görüntüsü.

AssemblyFileshedefin adlı _ResolvedProjectReferencePathsçıkış öğesinden ResolveProjectReference gelir. ResolveProjectReference daha önce ResolveAssemblyReference çalıştırılır ve öğeleri disk üzerindeki yerleşik derlemelerin yollarına dönüştürür <ProjectReference> . Bu nedenle, AssemblyFiles geçerli projenin tüm başvurulu projeleri tarafından oluşturulan derlemeleri içerecektir:

AssemblyFiles'ın gösterildiği ekran görüntüsü.

Başka bir yararlı giriş, değerini özelliğinden _FindDependencies alan boole FindDependencies parametresidir:

FindDependencies="$(_FindDependencies)"

Geçişli bağımlılık derlemelerinin analizini kapatmak için derlemenizde bu özelliği false olarak ayarlayabilirsiniz.

ResolveAssemblyReference algoritması

Görevin basitleştirilmiş algoritması ResolveAssemblyReference aşağıdaki gibidir:

  1. Günlük girişleri.
  2. Ortam değişkenini MSBUILDLOGVERBOSERARSEARCHRESULTS denetleyin. Daha ayrıntılı günlükler almak için bu değişkeni herhangi bir değere ayarlayın.
  3. Başvurular nesnesinin tablosunu başlatın.
  4. Önbellek dosyasını (varsa) dizininden obj okuyun.
  5. Bağımlılıkların kapatılmasını hesaplama.
  6. Çıkış tablolarını oluşturun.
  7. Önbellek dosyasını dizine obj yazın.
  8. Sonuçları günlüğe kaydetme.

Algoritma, derlemelerin giriş listesini alır (hem meta verilerden hem de proje başvurularından), işlediği her derleme için başvuru listesini alır (meta verileri okuyarak) ve başvuruda bulunılan tüm derlemelerin eksiksiz bir kümesini (geçişli kapanış) oluşturur ve bunları çeşitli konumlardan (GAC, AssemblyFoldersEx vb.) çözümler.

Başvuruda bulunan derlemeler, yeni başvuru ekleninceye kadar listeye yinelemeli olarak eklenir. Ardından algoritma durdurulur.

Göreve sağladığınız doğrudan başvurular Birincil başvurular olarak adlandırılır. Geçişli başvuru nedeniyle kümeye eklenen dolaylı derlemelere Bağımlılık adı verilir. Her dolaylı derlemenin kaydı, dahil edilmesine ve buna karşılık gelen meta verilerine yol açan tüm birincil ("kök") öğeleri izler.

ResolveAssemblyReference görevinin sonuçları

ResolveAssemblyReference sonuçların ayrıntılı günlüğünü sağlar:

Yapılandırılmış günlük görüntüleyicisinde ResolveAssemblyReference sonuçlarını gösteren ekran görüntüsü.

Çözümlenen derlemeler iki kategoriye ayrılır: Birincil başvurular ve Bağımlılıklar. Birincil başvurular, oluşturulan projenin başvuruları olarak açıkça belirtildi. Bağımlılıklar, başvuru başvurularından geçişli olarak çıkarılmıştır.

Önemli

ResolveAssemblyReference belirli bir derlemenin başvurularını belirlemek için derleme meta verilerini okur. C# derleyicisi bir derleme yaydığında, yalnızca gerçekten gerekli olan derlemelere başvurular ekler. Bu nedenle, belirli bir projeyi derlediğinizde, proje derlemede işlenmeyen gereksiz bir başvuru belirtebilir. Gerekli olmayan projeye başvurular eklemek sorun değil; yoksayılır.

CopyLocal öğesi meta verileri

Başvurular da meta veriye CopyLocal sahip olabilir veya olmayabilir. Başvuruda varsa CopyLocal = true, daha sonra hedef tarafından CopyFilesToOutputDirectory çıkış dizinine kopyalanır. Bu örnekte true DataFlow CopyLocal olarak ayarlanmış, ancak Immutable ayarlanmamaktadır:

Bazı başvurular için CopyLocal ayarlarını gösteren ekran görüntüsü.

CopyLocal Meta veriler tamamen eksikse varsayılan olarak true olduğu varsayılır. Bu nedenle ResolveAssemblyReference , aksi bir neden bulmadığı sürece varsayılan olarak bağımlılıkları çıkışa kopyalamaya çalışır. ResolveAssemblyReference , belirli bir başvuruyu olmak CopyLocal veya seçmemek için nedenlerini kaydeder.

Karar için CopyLocal tüm olası nedenler aşağıdaki tabloda listelenir. Derleme günlüklerinde arama yapabilmek için bu dizeleri bilmek yararlı olur.

CopyLocal durumu Açıklama
Undecided Kopyalama yerel durumu şu anda kararsız.
YesBecauseOfHeuristic Herhangi bir nedenle 'hayır' olmadığından başvuru olmalıdır CopyLocal='true' .
YesBecauseReferenceItemHadMetadata Kaynak öğesi Private='true' olduğundan Başvuru olmalıdır CopyLocal='true'
NoBecauseFrameworkFile Başvurunun olması CopyLocal='false' gerekir çünkü bu bir çerçeve dosyasıdır.
NoBecausePrerequisite Başvurunun önkoşul CopyLocal='false' dosyası olması gerekir.
NoBecauseReferenceItemHadMetadata Özniteliği projede 'false' olarak ayarlandığından Private başvuru CopyLocal='false' olmalıdır.
NoBecauseReferenceResolvedFromGAC Başvuru, GAC'den çözümlendiği için olmalıdır CopyLocal='false' .
NoBecauseReferenceFoundInGAC Derleme GAC'de bulunduğunda (başka bir yerde çözümlendiğinde bile) eski davranış CopyLocal='false' .
NoBecauseConflictVictim Başvurunun, aynı adlı derleme dosyası arasındaki çakışmayı kaybettiğinden olması CopyLocal='false' gerekir.
NoBecauseUnresolved Başvuru çözümlenmedi. Bulunamadığından bin dizinine kopyalanamaz.
NoBecauseEmbedded Başvuru eklenmiştir. Çalışma zamanında yüklenmeyacağından bin dizinine kopyalanmamalıdır.
NoBecauseParentReferencesFoundInGAC özelliği copyLocalDependenciesWhenParentReferenceInGac false olarak ayarlanır ve tüm üst kaynak öğeleri GAC'de bulundu.
NoBecauseBadImage Sağlanan derleme dosyası, hatalı bir görüntü olduğundan, büyük olasılıkla yönetilmediğinden, büyük olasılıkla hiç derleme olmadığından kopyalanmamalıdır.

Özel öğe meta verileri

Belirlemenin CopyLocal önemli bir kısmı, tüm birincil başvurulardaki meta verilerdir Private . Her başvurunun (birincil veya bağımlılık), bu başvurunun kapanışa eklenmesine katkıda bulunan tüm birincil başvuruların (kaynak öğeler) bir listesi vardır.

  • Kaynak öğelerden hiçbiri meta veri belirtmezse Private , CopyLocal olarak ayarlanır True (veya ayarlanmaz; varsayılan olarak True)
  • Kaynak öğelerden herhangi biri öğesini belirtirsePrivate=trueCopyLocal, olarak ayarlanırTrue
  • Kaynak derlemelerden hiçbiri belirtmezse Private=true ve en az biri belirtirse Private=false, CopyLocal olarak ayarlanır False

Hangi başvuru Özel değerini false olarak ayarladı?

Son nokta, false olarak ayarlanması için CopyLocal sık kullanılan bir nedendir: This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true".

MSBuild hangi başvurunun false olarak ayarlandığını Private bize söylemez, ancak yapılandırılmış günlük görüntüleyicisi yukarıda belirtilen öğelere meta veriler ekler Private :

Yapılandırılmış günlük görüntüleyicisinde Özel'in false olarak ayarlandığını gösteren ekran görüntüsü.

Bu, araştırmaları basitleştirir ve söz konusu bağımlılığın ile CopyLocal=falseayarlanmasına tam olarak hangi başvurunun neden olduğunu bildirir.

Genel Derleme Önbelleği

Genel Derleme Önbelleği (GAC), başvuruların çıkışa kopyalanıp kopyalanmayacağını belirlemede önemli bir rol oynar. GaC'nin içeriği makineye özgü olduğundan ve bu durum yeniden üretilebilir derlemelerde sorunlarla sonuçlandığından (davranış, GAC gibi makine durumuna bağlı farklı makinelerde farklılık gösterdiğinde) bu durum talihsiz bir durumdur.

Durumu hafifletmek için ResolveAssemblyReference son düzeltmeler yapıldı. bu iki yeni giriş ResolveAssemblyReferenceile davranışını denetleyebilirsiniz:

    CopyLocalDependenciesWhenParentReferenceInGac="$(CopyLocalDependenciesWhenParentReferenceInGac)"
    DoNotCopyLocalIfInGac="$(DoNotCopyLocalIfInGac)"

AssemblySearchPaths

Bir derlemeyi bulmaya çalışırken yol ResolveAssemblyReference aramalarının listesini özelleştirmenin iki yolu vardır. Listeyi tam olarak özelleştirmek için özelliği AssemblySearchPaths önceden ayarlanabilir. Sipariş önemlidir; bir derleme iki konumdaysa, ResolveAssemblyReference ilk konumda bulduklarında durur.

Varsayılan olarak, on konum araması vardır (.NET SDK kullanıyorsanız dört konum ResolveAssemblyReference ) ve ilgili bayrak false olarak ayarlanarak her birini devre dışı bırakabilirsiniz:

  • Geçerli projeden dosya arama özelliği false olarak ayarlanarak AssemblySearchPath_UseCandidateAssemblyFiles devre dışı bırakılır.
  • Başvuru yolu özelliğinde arama (dosyadan .user ) özelliği false olarak ayarlanarak AssemblySearchPath_UseReferencePath devre dışı bırakılır.
  • Öğeden ipucu yolunun kullanılması özelliği false olarak ayarlanarak AssemblySearchPath_UseHintPathFromItem devre dışı bırakılır.
  • MSBuild'in hedef çalışma zamanı ile dizini kullanmak, özelliği false olarak ayarlanarak AssemblySearchPath_UseTargetFrameworkDirectory devre dışı bırakılır.
  • AssemblyFolders.config dosyasından derleme klasörleri aranırken özelliği false olarak ayarlanarak AssemblySearchPath_UseAssemblyFoldersConfigFileSearchPath devre dışı bırakılır.
  • Özelliği false olarak ayarlanarak AssemblySearchPath_UseRegistry kayıt defterinde arama devre dışı bırakılır.
  • Eski kayıtlı derleme klasörlerinde arama özelliği false olarak ayarlanarak AssemblySearchPath_UseAssemblyFolders devre dışı bırakılır.
  • GAC'ye bakmak özelliği false olarak ayarlanarak AssemblySearchPath_UseGAC devre dışı bırakılır.
  • Özelliği false olarak ayarlanarak AssemblySearchPath_UseRawFileName başvurunun Include değerini gerçek bir dosya adı olarak ele almak devre dışı bırakılır.
  • Özelliği false olarak ayarlanarak AssemblySearchPath_UseOutDir uygulamanın çıkış klasörü denetleniyor.

Bir çakışma oluştu

Sık karşılaşılan bir durum, MSBuild'in farklı başvurular tarafından kullanılan aynı derlemenin farklı sürümleri hakkında bir uyarı vermesidir. Çözüm genellikle app.config dosyasına bağlama yeniden yönlendirmesi eklemeyi içerir.

Bu çakışmaları araştırmanın kullanışlı bir yolu, MSBuild Yapılandırılmış Günlük Görüntüleyicisi'nde "Çakışma oldu" araması yapmaktır. Hangi başvuruların söz konusu derlemenin hangi sürümlerine ihtiyaç duyduğu hakkında ayrıntılı bilgiler gösterir.