Share via


Optie op oplossingsniveau --output is niet meer geldig voor build-gerelateerde opdrachten

In de SDK 7.0.200 was er een wijziging om de --output/-o optie niet meer te accepteren bij het gebruik van een oplossingsbestand met de volgende opdrachten:

  • build
  • clean
  • pack
  • publish
  • store
  • test
  • vstest

Dit komt doordat de semantiek van de OutputPath eigenschap, die wordt beheerd door de --output/-o optie, niet goed is gedefinieerd voor oplossingen. Projecten die op deze manier zijn gebouwd, hebben hun uitvoer in dezelfde map geplaatst, wat inconsistent is en heeft geleid tot een aantal door de gebruiker gerapporteerde problemen.

Deze wijziging is gereduceerd tot een waarschuwingsniveau van ernst in de SDK 7.0.201 en pack is verwijderd uit de lijst met opdrachten die worden beïnvloed.

Versie geïntroduceerd

.NET 7.0.200 SDK, beperkt tot een waarschuwing alleen in de SDK 7.0.201.

Vorig gedrag

Als u eerder hebt opgegeven --output/-o bij het gebruik van een oplossingsbestand, wordt de uitvoer voor alle gemaakte projecten in de opgegeven map geplaatst in een niet-gedefinieerde en inconsistente volgorde.

Nieuw gedrag

De dotnet CLI krijgt een foutmelding als de --output/-o optie wordt gebruikt met een oplossingsbestand. Vanaf de SDK 7.0.201 wordt in plaats daarvan een waarschuwing verzonden en wordt er dotnet pack geen waarschuwing of fout gegenereerd.

Type wijziging die fouten veroorzaken

Deze belangrijke wijziging kan wijzigingen vereisen voor het bouwen van scripts en pijplijnen voor continue integratie. Als gevolg hiervan is dit van invloed op zowel binaire als broncompatibiliteit.

Reden voor wijziging

Deze wijziging is aangebracht omdat de semantiek van de OutputPath eigenschap, die wordt beheerd door de --output/-o optie, niet goed zijn gedefinieerd voor oplossingen. Projecten die op deze manier zijn gebouwd, hebben hun uitvoer in dezelfde map geplaatst, wat inconsistent is en heeft geleid tot een aantal door de gebruiker gerapporteerde problemen.

Wanneer een oplossing is gebouwd met de --output optie, wordt de OutputPath eigenschap ingesteld op dezelfde waarde voor alle projecten, wat betekent dat alle projecten hun uitvoer in dezelfde map hebben geplaatst. Afhankelijk van de complexiteit van de projecten in de oplossing kunnen er verschillende en inconsistente resultaten optreden. Laten we eens kijken naar enkele voorbeelden van verschillende oplossingsshapes en hoe deze worden beïnvloed door een gedeelde OutputPathoplossing.

Eén project, één TargetFramework

Stel u een oplossing voor die één project bevat dat gericht is op één TargetFramework, net7.0. In dit geval is het instellen van de eigenschap in het projectbestand gelijk aan het --output instellen van de OutputPath eigenschap. Tijdens een build (of andere opdrachten, maar laten we de discussie nu bepalen om te bouwen), worden alle uitvoer voor het project in de opgegeven map geplaatst.

Eén project, meerdere TargetFrameworks

Stel u nu een oplossing voor die één project bevat met meerdere TargetFrameworks, net6.0 en net7.0. Vanwege meerdere targeting wordt het project twee keer gebouwd, één keer voor elk TargetFramework. Voor elk van deze 'inner'-builds wordt de OutputPath waarde ingesteld op dezelfde waarde, zodat de uitvoer voor elk van de binnenste builds in dezelfde map wordt geplaatst. Dit betekent dat elke voltooide build de uitvoer van de andere build overschrijft en dat in een parallel-buildsysteem zoals MSBuild standaard 'last' is ingesteld.

Library = Console =>> Test, single TargetFramework

Stel nu een oplossing voor die een bibliotheekproject bevat, een consoleproject dat verwijst naar het bibliotheekproject en een testproject dat verwijst naar het consoleproject. Al deze projecten zijn gericht op één TargetFramework, net7.0. In dit geval wordt het bibliotheekproject eerst gebouwd en vervolgens wordt het consoleproject gebouwd. Het testproject wordt als laatste gebouwd en verwijst naar het consoleproject. Voor elk gebouwd project worden de uitvoer van elke build gekopieerd naar de map die door de OutputPathmap is opgegeven en bevat de uiteindelijke map dus assets van alle drie de projecten. Dit werkt voor het testen, maar voor publicatie kan het leiden tot testassets die naar productie worden verzonden.

Library = Console =>> Test, meerdere TargetFrameworks

Neem nu dezelfde keten van projecten en voeg er naast de net7.0 build een net6.0 TargetFramework build aan toe. Hetzelfde probleem als de single-project, multi-targeted build treedt op: inconsistent kopiëren van TFM-specifieke assets naar de opgegeven map.

Meerdere apps

Tot nu toe hebben we gekeken naar scenario's met een lineaire afhankelijkheidsgrafiek, maar veel oplossingen kunnen meerdere gerelateerde toepassingen bevatten. Dit betekent dat meerdere apps gelijktijdig kunnen worden gebouwd in dezelfde uitvoermap. Als de apps een afhankelijkheidsbestand met dezelfde naam bevatten, kan de build af en toe mislukken wanneer meerdere projecten gelijktijdig proberen naar dat bestand te schrijven in het uitvoerpad.

Als meerdere apps afhankelijk zijn van verschillende versies van een bestand, kan zelfs als de build slaagt, welke versie van het bestand wordt gekopieerd naar het uitvoerpad mogelijk niet deterministisch zijn. Dit kan gebeuren wanneer de projecten afhankelijk zijn (mogelijk transitief) van verschillende versies van een NuGet-pakket. Binnen één project zorgt NuGet ervoor dat de afhankelijkheden (inclusief eventuele transitieve afhankelijkheden via NuGet-pakketten en/of projectverwijzingen) zijn geïntegreerd in dezelfde versie. Omdat de eenwording wordt uitgevoerd binnen de context van één project en de afhankelijke projecten, betekent dit dat het mogelijk is om verschillende versies van een pakket op te lossen wanneer twee afzonderlijke projecten op het hoogste niveau worden gebouwd. Als het project dat afhankelijk is van de hogere versie de afhankelijkheid voor het laatst kopieert, worden de apps vaak uitgevoerd. Als de lagere versie echter voor het laatst wordt gekopieerd, kan de assembly tijdens runtime niet worden geladen door de app die is gecompileerd op basis van de hogere versie. Omdat de gekopieerde versie niet-deterministisch kan zijn, kan dit leiden tot sporadische, onbetrouwbare builds waar het erg moeilijk is om het probleem te diagnosticeren.

Andere voorbeelden

Zie de discussie over dotnet/sdk#15607 voor meer voorbeelden van hoe deze onderliggende fout in de praktijk wordt weergegeven.

De algemene aanbeveling is om de actie uit te voeren die u eerder hebt uitgevoerd zonder de --output/-o optie en de uitvoer vervolgens naar de gewenste locatie te verplaatsen nadat de opdracht is voltooid. Het is ook mogelijk om de actie op een specifiek project uit te voeren en nog steeds de --output/-o optie toe te passen, omdat deze meer goed gedefinieerde semantiek heeft.

Als u het bestaande gedrag exact wilt behouden, kunt u de --property vlag gebruiken om een MSBuild-eigenschap in te stellen op de gewenste map. De te gebruiken eigenschap varieert op basis van de opdracht:

Opdracht Eigenschappen Opmerking
build OutputPath dotnet build --property:OutputPath=DESIRED_PATH
clean OutputPath dotnet clean --property:OutputPath=DESIRED_PATH
pack PackageOutputPath dotnet pack --property:PackageOutputPath=DESIRED_PATH
publish PublishDir dotnet publish --property:PublishDir=DESIRED_PATH
store OutputPath dotnet store --property:OutputPath=DESIRED_PATH
test TestResultsDirectory dotnet test --property:OutputPath=DESIRED_PATH

OPMERKING Voor de beste resultaten moet de DESIRED_PATH een absoluut pad zijn. Relatieve paden worden 'verankerd' (d.w. absoluut gemaakt) op manieren die u mogelijk niet verwacht en werken mogelijk niet hetzelfde met alle opdrachten.