Alternativet på lösningsnivå --output
är inte längre giltigt för build-relaterade kommandon
I SDK:n 7.0.200 skedde en ändring för att inte längre acceptera --output
/-o
alternativet när du använder en lösningsfil med följande kommandon:
build
clean
pack
publish
store
test
vstest
Det beror på att semantiken för OutputPath
egenskapen, som styrs av --output
/-o
alternativet, inte är väldefinierade för lösningar. Projekt som skapats på det här sättet får sina utdata placerade i samma katalog, vilket är inkonsekvent och har lett till ett antal användarrapporterade problem.
Den här ändringen minskades till en varningsnivå av allvarlighetsgrad i SDK:n 7.0.201 och pack
togs bort från listan över kommandon som påverkas.
Version introducerad
.NET 7.0.200 SDK, reducerat till en varning endast i SDK:n 7.0.201.
Tidigare beteende
Om du angav --output
/-o
när du använde en lösningsfil tidigare skulle utdata för alla byggda projekt placeras i den angivna katalogen i en odefinierad och inkonsekvent ordning.
Nytt beteende
dotnet
CLI fel om alternativet --output
/-o
används med en lösningsfil. Från och med 7.0.201 SDK genereras en varning i stället, och om det dotnet pack
inte uppstår någon varning eller ett fel genereras.
Typ av icke-bakåtkompatibel ändring
Den här icke-bakåtkompatibla ändringen kan kräva ändringar för att skapa skript och pipelines för kontinuerlig integrering. Det påverkar därför både binär- och källkompatibilitet.
Orsak till ändringen
Den här ändringen gjordes eftersom semantiken för OutputPath
egenskapen, som styrs av --output
/-o
alternativet, inte är väldefinierade för lösningar. Projekt som skapats på det här sättet får sina utdata placerade i samma katalog, vilket är inkonsekvent och har lett till ett antal användarrapporterade problem.
När en lösning skapas med --output
alternativet OutputPath
anges egenskapen till samma värde för alla projekt, vilket innebär att alla projekt får sina utdata placerade i samma katalog. Beroende på komplexiteten i projekten i lösningen kan olika och inkonsekventa resultat uppstå. Låt oss ta en titt på några exempel på olika lösningsformer och hur de påverkas av en delad OutputPath
.
Enskilt projekt, enstaka TargetFramework
Föreställ dig en lösning som innehåller ett enda projekt som är inriktat på en enda TargetFramework
, net7.0
. I det här fallet motsvarar alternativet --output
att ange OutputPath
egenskapen i projektfilen. Under en version (eller andra kommandon, men låt oss begränsa diskussionen att skapa för tillfället), placeras alla utdata för projektet i den angivna katalogen.
Enskilt projekt, flera TargetFrameworks
Föreställ dig nu en lösning som innehåller ett enda projekt med flera TargetFrameworks
, net6.0
och net7.0
. På grund av flera mål skapas projektet två gånger, en gång för varje TargetFramework
. För var och en av dessa "inre" byggen OutputPath
kommer att anges till samma värde, så utdata för var och en av de inre versionerna placeras i samma katalog. Det innebär att oavsett vilken version som slutförs senast skrivs utdata från den andra versionen över, och i ett parallellbyggessystem som MSBuild körs i som standard är "last" obestämd.
Library => Console => Test, single TargetFramework
Föreställ dig nu en lösning som innehåller ett biblioteksprojekt, ett konsolprojekt som refererar till biblioteksprojektet och ett testprojekt som refererar till konsolprojektet. Alla dessa projekt är inriktade på en enda TargetFramework
, net7.0
. I det här fallet byggs biblioteksprojektet först och sedan skapas konsolprojektet. Testprojektet skapas senast och refererar till konsolprojektet. För varje byggt projekt kopieras utdata från varje bygge till katalogen som anges av OutputPath
, och därför kommer den slutliga katalogen att innehålla tillgångar från alla tre projekten. Detta fungerar för testning, men för publicering kan det leda till att testtillgångar skickas till produktion.
Bibliotek => Konsol => Test, flera TargetFrameworks
Ta nu samma projektkedja och lägg till en net6.0
TargetFramework
version till dem utöver bygget net7.0
. Samma problem som den enskilda projektversionen med flera mål uppstår – inkonsekvent kopiering av TFM-specifika tillgångar till den angivna katalogen.
Flera appar
Hittills har vi tittat på scenarier med ett linjärt beroendediagram – men många lösningar kan innehålla flera relaterade program. Det innebär att flera appar kan skapas samtidigt till samma utdatamapp. Om apparna innehåller en beroendefil med samma namn kan bygget ibland misslyckas när flera projekt försöker skriva till filen i utdatasökvägen samtidigt.
Om flera appar är beroende av olika versioner av en fil kan även om versionen lyckas, vilken version av filen som kopieras till utdatasökvägen vara icke-deterministisk. Detta kan inträffa när projekten är beroende (eventuellt transitivt) av olika versioner av ett NuGet-paket. I ett enda projekt ser NuGet till att dess beroenden (inklusive eventuella transitiva beroenden via NuGet-paket och/eller projektreferenser) är enhetliga till samma version. Eftersom enandet görs inom ramen för ett enskilt projekt och dess beroende projekt innebär det att det är möjligt att lösa olika versioner av ett paket när två separata toppnivåprojekt skapas. Om projektet som är beroende av den högre versionen kopierar beroendet sist, körs ofta apparna korrekt. Men om den lägre versionen kopieras sist kommer appen som kompilerades mot den högre versionen inte att läsa in sammansättningen vid körning. Eftersom den version som kopieras kan vara icke-deterministisk kan detta leda till sporadiska, otillförlitliga versioner där det är mycket svårt att diagnostisera problemet.
Andra exempel
Fler exempel på hur det här underliggande felet visas i praktiken finns i diskussionen om dotnet/sdk#15607.
Rekommenderad åtgärd
Den allmänna rekommendationen är att utföra den åtgärd som du tidigare vidtog utan --output
/-o
alternativet och sedan flytta utdata till önskad plats när kommandot har slutförts. Det är också möjligt att utföra åtgärden i ett visst projekt och ändå tillämpa --output
/-o
alternativet, eftersom det har mer väldefinierade semantik.
Om du vill behålla det befintliga beteendet exakt kan du använda --property
flaggan för att ange en MSBuild-egenskap till önskad katalog. Vilken egenskap som ska användas varierar beroende på kommandot:
Command | Property | Exempel |
---|---|---|
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 |
Obs! För bästa resultat bör DESIRED_PATH vara en absolut sökväg. Relativa sökvägar kommer att vara "förankrade" (dvs. absoluta) på sätt som du kanske inte förväntar dig och kanske inte fungerar på samma sätt med alla kommandon.