Ved udvikling af plugins til CAD-applikationer (
Når du kun har ét plugin, eller du stadig er en selvlært begynder i denne sag, kan du blot lave en kopi af projektet, ændre de nødvendige pladser i det og samle en ny version af plugin. Følgelig vil efterfølgende ændringer af kodeksen medføre en multipel stigning i lønomkostningerne.
Efterhånden som du får erfaring og viden, vil du finde flere måder at automatisere denne proces på. Jeg gik denne vej, og jeg vil gerne fortælle dig, hvad jeg endte med, og hvor praktisk det er.
Lad os først se på en metode, der er indlysende, og som jeg har brugt længe.
Links til projektfiler
Og for at gøre alt simpelt, visuelt og forståeligt, vil jeg beskrive alt ved hjælp af et abstrakt eksempel på plugin-udvikling.
Lad os åbne Visual Studio (jeg har Community 2019-versionen. Og ja - på russisk) og skabe en ny løsning. Lad os ringe til ham MySuperPluginForRevit
Vi laver et plugin til Revit til version 2015-2020. Lad os derfor oprette et nyt projekt i løsningen (Net Framework Class Library) og kalde det MySuperPluginForRevit_2015
Vi skal tilføje links til Revit API. Vi kan selvfølgelig tilføje links til lokale filer (vi skal installere alle de nødvendige SDK'er eller alle versioner af Revit), men vi følger straks den rigtige vej og forbinder NuGet-pakken. Du kan finde en del pakker, men jeg vil bruge mine egne.
Efter tilslutning af pakken skal du højreklikke på emnet "RЎSЃS <P "RєRё" og vælg emnet "Flyt packages.config til PackageReference...»
Hvis du pludselig på dette tidspunkt begynder at gå i panik, fordi der i vinduet med pakkens egenskaber ikke er noget vigtigt element "Kopier lokalt", som vi bestemt skal sætte til værdien falsk, så gå ikke i panik - gå til mappen med projektet, åbn filen med filtypen .csproj i en editor, der er praktisk for dig (jeg bruger Notesblok++), og find en post om vores pakke der. Hun ser sådan ud nu:
<PackageReference Include="ModPlus.Revit.API.2015">
<Version>1.0.0</Version>
</PackageReference>
Tilføj en ejendom til den køretid. Det bliver sådan her:
<PackageReference Include="ModPlus.Revit.API.2015">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
Nu, når du bygger et projekt, vil filer fra pakken ikke blive kopieret til output-mappen.
Lad os gå videre – lad os umiddelbart forestille os, at vores plugin vil bruge noget fra Revit API, som har ændret sig over tid, når nye versioner er blevet frigivet. Nå, eller vi skal bare ændre noget i koden afhængigt af den version af Revit, som vi laver pluginnet til. For at løse sådanne forskelle i kode, vil vi bruge betingede kompileringssymboler. Åbn projektegenskaberne, gå til fanen "samling"og i marken"Betinget kompileringsnotation"lad os skrive R2015.
Bemærk, at symbolet skal tilføjes for både Fejlfindings- og Release-konfigurationerne.
Nå, mens vi er i egenskabsvinduet, går vi straks til fanen "App"og i marken"Standard navneområde» fjern suffikset _2015så vores navneområde er universelt og uafhængigt af samlingsnavnet:
I mit tilfælde, i det endelige produkt, er plugins af alle versioner lagt i én mappe, så mine samlingsnavne forbliver med suffikset af formularen _20хх. Men du kan også fjerne suffikset fra samlingsnavnet, hvis filerne skal være placeret i forskellige mapper.
Lad os gå til filkoden Klasse1.cs og simuler noget kode der, under hensyntagen til forskellige versioner af Revit:
namespace MySuperPluginForRevit
{
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
[Regeneration(RegenerationOption.Manual)]
[Transaction(TransactionMode.Manual)]
public class Class1 : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
#if R2015
TaskDialog.Show("ModPlus", "Hello Revit 2015");
#elif R2016
TaskDialog.Show("ModPlus", "Hello Revit 2016");
#elif R2017
TaskDialog.Show("ModPlus", "Hello Revit 2017");
#elif R2018
TaskDialog.Show("ModPlus", "Hello Revit 2018");
#elif R2019
TaskDialog.Show("ModPlus", "Hello Revit 2019");
#elif R2020
TaskDialog.Show("ModPlus", "Hello Revit 2020");
#endif
return Result.Succeeded;
}
}
}
Jeg tog straks højde for alle versioner af Revit ovenfor version 2015 (som var tilgængelige i skrivende stund) og tog straks højde for tilstedeværelsen af betingede kompileringssymboler, som er oprettet ved hjælp af den samme skabelon.
Lad os gå videre til hovedhøjdepunktet. Vi opretter et nyt projekt i vores løsning, kun for versionen af plugin til Revit 2016. Vi gentager alle trinene beskrevet ovenfor, henholdsvis erstatter nummeret 2015 med nummeret 2016. Men filen Klasse1.cs slette fra det nye projekt.
Fil med den nødvendige kode - Klasse1.cs – vi har det allerede, og vi skal bare indsætte et link til det i et nyt projekt. Der er to måder at indsætte links på:
- Lang – højreklik på projektet og vælg “Tilføj»->«Eksisterende element", i vinduet, der åbnes, find den ønskede fil og i stedet for indstillingen "Tilføj"vælg muligheden"Tilføj som forbindelse»
- kort – direkte i løsningsstifinderen, vælg den ønskede fil (eller endda filer eller endda hele mapper) og træk den ind i et nyt projekt, mens du holder Alt-tasten nede. Mens du trækker, vil du se, at når du trykker på Alt-tasten, vil musemarkøren skifte fra et plustegn til en pil.
UPS: Jeg lavede lidt forvirring i dette afsnit - for at overføre flere filer skal du holde nede Skift + Alt!
Efter at have udført proceduren, vil vi have en fil i det andet projekt Klasse1.cs med det tilsvarende ikon (blå pil):
Når du redigerer kode i redigeringsvinduet, kan du også vælge, hvilken projektkontekst koden skal vises i, hvilket giver dig mulighed for at se koden redigeres under forskellige betingede kompileringssymboler:
Vi opretter alle andre projekter (2017-2020) ved hjælp af denne ordning. Life hack - hvis du trækker filer i Solution Explorer ikke fra basisprojektet, men fra projektet, hvor de allerede er indsat som et link, så behøver du ikke holde Alt-tasten nede!
Den beskrevne mulighed er ret god, indtil det øjeblik, hvor du tilføjer en ny version af plugin, eller indtil det øjeblik, hvor du tilføjer nye filer til projektet - alt dette bliver meget kedeligt. Og for nylig indså jeg pludselig, hvordan man ordner det hele med et projekt, og vi går videre til den anden metode
Magien ved konfigurationer
Når du har læst her, kan du udbryde: "Hvorfor beskrev du den første metode, hvis artiklen umiddelbart handler om den anden?!" Og jeg beskrev alt for at gøre det tydeligere, hvorfor vi har brug for betingede kompileringssymboler, og på hvilke steder vores projekter adskiller sig. Og nu bliver det tydeligere for os, præcis hvilke forskelle i projekter, vi skal gennemføre, så der kun er ét projekt tilbage.
Og for at gøre alt mere indlysende, vil vi ikke oprette et nyt projekt, men vil foretage ændringer i vores nuværende projekt, der er oprettet på den første måde.
Så først og fremmest fjerner vi alle projekter fra løsningen undtagen det vigtigste (der direkte indeholder filerne). De der. projekter til versioner 2016-2020. Åbn mappen med løsningen og slet mapperne for disse projekter der.
Vi har et projekt tilbage i vores beslutning - MySuperPluginForRevit_2015. Åbn dens egenskaber og:
- På fanen "App"fjern suffikset fra samlingsnavnet _2015 (det bliver klart hvorfor senere)
- På fanen "samling» fjern det betingede kompileringssymbol R2015 fra det tilsvarende felt
Bemærk: den seneste version af Visual Studio har en fejl - betingede kompileringssymboler vises ikke i vinduet med projektegenskaber, selvom de er tilgængelige. Hvis du oplever denne fejl, skal du fjerne dem manuelt fra .csproj-filen. Vi skal dog stadig arbejde i det, så læs videre.
Omdøb projektet i vinduet Solution Explorer ved at fjerne suffikset _2015 og fjern derefter projektet fra løsningen. Dette er nødvendigt for at opretholde orden og følelser hos perfektionister! Vi åbner mappen med vores løsning, omdøber projektmappen der på samme måde og indlæser projektet tilbage i løsningen.
Åbn konfigurationsmanageren. amerikansk konfiguration Slip i princippet bliver det ikke nødvendigt, så vi sletter det. Vi opretter nye konfigurationer med navne, der allerede er kendte for os R2015, R2016, ..., R2020. Bemærk, at du ikke behøver at kopiere indstillinger fra andre konfigurationer, og du behøver ikke at oprette projektkonfigurationer:
Gå til mappen med projektet, og åbn filen med filtypenavnet .csproj i en editor, der er praktisk for dig. Forresten kan du også åbne det i Visual Studio - du skal fjerne projektet, og så vil det ønskede element være i kontekstmenuen:
Redigering i Visual Studio er endda at foretrække, da editoren både justerer og spørger.
I filen vil vi se elementerne
Gå til det fælles (første) element Ejendomsgruppe og se på ejendommen Forsamlingsnavn – dette er navnet på forsamlingen, og vi skal have det uden suffiks _2015. Hvis der er et suffiks, så fjern det.
At finde et element med en betingelse
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
Vi har ikke brug for det – vi sletter det.
Element med stand
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
vil være nødvendige for at arbejde på stadiet med kodeudvikling og fejlfinding. Du kan ændre dens egenskaber, så den passer til dine behov - indstille forskellige outputstier, ændre betingede kompileringssymboler osv.
Lad os nu skabe nye elementer Ejendomsgruppe til vores konfigurationer. I disse elementer skal vi blot indstille fire egenskaber:
- OutputPath – outputmappe. Jeg indstillede standardværdien binR20xx
- Definer konstanter – betingede kompileringssymboler. Værdien skal angives TRACE;R20хх
- TargetFrameworkVersion – platform version. Forskellige versioner af Revit API kræver, at forskellige platforme angives.
- Forsamlingsnavn – samlingsnavn (dvs. filnavn). Du kan skrive det nøjagtige navn på samlingen, men for alsidighed anbefaler jeg at skrive værdien $(AssemblyName)_20хх. For at gøre dette har vi tidligere fjernet suffikset fra samlingsnavnet
Det vigtigste ved alle disse elementer er, at de ganske enkelt kan kopieres til andre projekter uden at ændre dem overhovedet. Senere i artiklen vil jeg vedhæfte alt indholdet af .csproj-filen.
Okay, vi har fundet ud af projektets egenskaber - det er ikke svært. Men hvad skal man gøre med plug-in-biblioteker (NuGet-pakker). Hvis vi kigger videre, vil vi se, at de inkluderede biblioteker er specificeret i elementerne
Elementet kommer os til hjælp
Brug af element Vælg, indstiller vi forskellige NuGet-pakker til forskellige konfigurationer:
Alt indhold csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5AD738D6-4122-4E76-B865-BE7CE0F6B3EB}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MySuperPluginForRevit</RootNamespace>
<AssemblyName>MySuperPluginForRevit</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>binDebug</OutputPath>
<DefineConstants>DEBUG;R2015</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2015|AnyCPU' ">
<OutputPath>binR2015</OutputPath>
<DefineConstants>TRACE;R2015</DefineConstants>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2015</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2016|AnyCPU' ">
<OutputPath>binR2016</OutputPath>
<DefineConstants>TRACE;R2016</DefineConstants>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2016</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2017|AnyCPU' ">
<OutputPath>binR2017</OutputPath>
<DefineConstants>TRACE;R2017</DefineConstants>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2017</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2018|AnyCPU' ">
<OutputPath>binR2018</OutputPath>
<DefineConstants>TRACE;R2018</DefineConstants>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2018</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2019|AnyCPU' ">
<OutputPath>binR2019</OutputPath>
<DefineConstants>TRACE;R2019</DefineConstants>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2019</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2020|AnyCPU' ">
<OutputPath>binR2020</OutputPath>
<DefineConstants>TRACE;R2020</DefineConstants>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<AssemblyName>$(AssemblyName)_2020</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="PropertiesAssemblyInfo.cs" />
</ItemGroup>
<Choose>
<When Condition=" '$(Configuration)'=='R2015' ">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2015">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
<When Condition=" '$(Configuration)'=='R2016' ">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2016">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
<When Condition=" '$(Configuration)'=='R2017' ">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2017">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
<When Condition=" '$(Configuration)'=='R2018' ">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2018">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
<When Condition=" '$(Configuration)'=='R2019' ">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2019">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
<When Condition=" '$(Configuration)'=='R2020' or '$(Configuration)'=='Debug'">
<ItemGroup>
<PackageReference Include="ModPlus.Revit.API.2020">
<Version>1.0.0</Version>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" />
</Project>
Bemærk venligst, at jeg i en af betingelserne specificerede to konfigurationer via ELLER. På denne måde vil den nødvendige pakke blive forbundet under konfigurationen Debug.
Og her har vi næsten alt perfekt. Vi indlæser projektet tilbage, aktiverer den konfiguration, vi har brug for, kalder elementet " i kontekstmenuen for løsningen (ikke projektet)Gendan alle NuGet-pakker"og vi ser, hvordan vores pakker ændrer sig.
Og på dette stadium kom jeg til en blindgyde - for at samle alle konfigurationer på én gang kunne vi bruge batchsamling (menu "samling»->«Batch build"), men når der skiftes konfigurationer, gendannes pakker ikke automatisk. Og når man samler projektet, sker dette heller ikke, selvom det i teorien burde. Jeg har ikke fundet en løsning på dette problem ved hjælp af standardmidler. Og højst sandsynligt er dette også en Visual Studio-fejl.
Derfor blev det besluttet at bruge et specielt automatiseret montagesystem til batchmontage
Så gå til mappen med vores løsning (ikke projektet), hold tasten nede Flytte og højreklik på et tomt rum i mappen - i kontekstmenuen vælg punktet "Åbn PowerShell-vinduet her'.
Hvis du ikke har det installeret nuke, så skriv først kommandoen
dotnet tool install Nuke.GlobalTool –global
Skriv nu kommandoen nuke og du vil blive bedt om at konfigurere nuke for det aktuelle projekt. Jeg ved ikke, hvordan jeg skriver dette mere korrekt på russisk - på engelsk vil det blive skrevet. Kunne ikke finde .nuke-filen. Vil du opsætte en build? [y/n]
Tryk på Y-tasten, og så vil der være direkte indstillingspunkter. Vi har brug for den enkleste mulighed ved at bruge MSBuild, så vi svarer som på skærmbilledet:
Lad os gå til Visual Studio, som vil bede os om at genindlæse løsningen, da der er tilføjet et nyt projekt til den. Vi genindlæser løsningen og ser, at vi har et projekt bygge hvor vi kun er interesseret i én fil - Byg.cs
Åbn denne fil og skriv et script til at bygge projektet til alle konfigurationer. Nå, eller brug mit script, som du kan redigere, så det passer til dine behov:
using System.IO;
using Nuke.Common;
using Nuke.Common.Execution;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tools.MSBuild;
using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
[CheckBuildProjectConfigurations]
[UnsetVisualStudioEnvironmentVariables]
class Build : NukeBuild
{
public static int Main () => Execute<Build>(x => x.Compile);
[Solution] readonly Solution Solution;
// If the solution name and the project (plugin) name are different, then indicate the project (plugin) name here
string PluginName => Solution.Name;
Target Compile => _ => _
.Executes(() =>
{
var project = Solution.GetProject(PluginName);
if (project == null)
throw new FileNotFoundException("Not found!");
var build = new List<string>();
foreach (var (_, c) in project.Configurations)
{
var configuration = c.Split("|")[0];
if (configuration == "Debug" || build.Contains(configuration))
continue;
Logger.Normal($"Configuration: {configuration}");
build.Add(configuration);
MSBuild(_ => _
.SetProjectFile(project.Path)
.SetConfiguration(configuration)
.SetTargets("Restore"));
MSBuild(_ => _
.SetProjectFile(project.Path)
.SetConfiguration(configuration)
.SetTargets("Rebuild"));
}
});
}
Vi vender tilbage til PowerShell-vinduet og skriver kommandoen igen nuke (du kan skrive kommandoen nuke angiver det nødvendige mål. Men vi har en mål, som kører som standard). Efter at have trykket på Enter-tasten vil vi føle os som rigtige hackere, fordi vores projekt, ligesom i en film, automatisk bliver samlet til forskellige konfigurationer.
I øvrigt kan du bruge PowerShell direkte fra Visual Studio (menu "Vis»->«Andre vinduer»->«Pakkehåndteringskonsol"), men alt vil være i sort og hvid, hvilket ikke er særlig praktisk.
Dette afslutter min artikel. Jeg er sikker på, at du selv kan finde ud af muligheden for AutoCAD. Jeg håber, at det her præsenterede materiale vil finde sine "kunder".
Tak for din opmærksomhed!
Kilde: www.habr.com