Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Prilikom razvoja dodataka za CAD aplikacije (u mom slučaju to su AutoCAD, Revit i Renga) s vremenom se javlja jedan problem - izlaze nove verzije programa, mijenja im se API i treba napraviti nove verzije dodataka.

Kada imate samo jedan plugin ili ste još uvijek samouk početnik po ovom pitanju, možete jednostavno napraviti kopiju projekta, promijeniti potrebna mjesta u njemu i sastaviti novu verziju plugina. Sukladno tome, naknadne izmjene kodeksa dovest će do višestrukog povećanja troškova rada.

Kako budete stjecali iskustvo i znanje, pronaći ćete nekoliko načina za automatizaciju ovog procesa. Hodao sam ovim putem i želim vam reći što sam završio i koliko je to zgodno.

Prvo, pogledajmo metodu koja je očita i koju koristim već dugo vremena.

Veze na projektne datoteke

A kako bi sve bilo jednostavno, vizualno i razumljivo, sve ću opisati pomoću apstraktnog primjera razvoja dodataka.

Otvorimo Visual Studio (imam verziju Community 2019. I da - na ruskom) i stvorimo novo rješenje. Nazovimo ga MySuperPluginForRevit

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Napravit ćemo dodatak za Revit za verzije 2015-2020. Stoga, kreirajmo novi projekt u rješenju (Net Framework Class Library) i nazovimo ga MojSuperPluginForRevit_2015

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Moramo dodati veze na Revit API. Naravno, možemo dodati poveznice na lokalne datoteke (morat ćemo instalirati sve potrebne SDK-ove ili sve verzije Revita), ali ćemo odmah krenuti pravim putem i spojiti NuGet paket. Možete pronaći dosta paketa, ali ja ću koristiti svoje.

Nakon povezivanja paketa kliknite desnom tipkom miša na stavku "reference" i odaberite stavku "Premjesti packages.config u PackageReference...»

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Ako iznenada u ovom trenutku počnete paničariti, jer u prozoru svojstava paketa neće biti važne stavke "Kopiraj lokalno", koju svakako moramo postaviti na vrijednost lažan, onda ne paničarite - idite u mapu s projektom, otvorite datoteku s nastavkom .csproj u uređivaču koji vam odgovara (ja koristim Notepad++) i tamo pronađite unos o našem paketu. Ona sada izgleda ovako:

<PackageReference Include="ModPlus.Revit.API.2015">
  <Version>1.0.0</Version>
</PackageReference>

Dodajte mu svojstvo vrijeme izvođenja. Ispast će ovako:

<PackageReference Include="ModPlus.Revit.API.2015">
  <Version>1.0.0</Version>
  <ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>

Sada, prilikom izgradnje projekta, datoteke iz paketa neće biti kopirane u izlaznu mapu.
Idemo dalje – zamislimo odmah da će naš dodatak koristiti nešto iz Revit API-ja, koji se s vremenom promijenio kada su objavljene nove verzije. Pa, ili samo trebamo promijeniti nešto u kodu ovisno o verziji Revita za koju radimo dodatak. Da bismo riješili takve razlike u kodu, koristit ćemo simbole uvjetne kompilacije. Otvorite svojstva projekta, idite na karticu "zbor"i na terenu"Notacija uvjetne kompilacije"idemo pisati R2015.

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Imajte na umu da se simbol mora dodati i za konfiguracije Debug i Release.

Pa, dok smo u prozoru svojstava, odmah idemo na karticu "primjena"i na terenu"Zadani prostor imena» uklonite sufiks _2015tako da je naš imenski prostor univerzalan i neovisan o nazivu sklopa:

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

U mom slučaju, u konačnom proizvodu, dodaci svih verzija se stavljaju u jednu mapu, tako da nazivi mojih sklopova ostaju sa sufiksom obrasca _20hh. Ali također možete ukloniti sufiks iz naziva sklopa ako se datoteke trebaju nalaziti u različitim mapama.

Idemo na kod datoteke Klasa1.cs i tamo simulirajte neki kod, uzimajući u obzir različite verzije Revita:

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;
        }
    }
}

Odmah sam uzeo u obzir sve verzije Revita iznad verzije 2015. (koje su bile dostupne u vrijeme pisanja) i odmah uzeo u obzir prisutnost simbola uvjetne kompilacije koji su stvoreni pomoću istog predloška.

Prijeđimo na glavni naglasak. Izrađujemo novi projekt u našem rješenju, samo za verziju dodatka za Revit 2016. Ponavljamo sve gore opisane korake, odnosno zamjenjujemo broj 2015 brojem 2016. Ali datoteka Klasa1.cs izbrisati iz novog projekta.

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Datoteka sa potrebnim kodom - Klasa1.cs – već ga imamo i samo trebamo ubaciti poveznicu na njega u novi projekt. Postoje dva načina za umetanje veza:

  1. dugo – desnom tipkom miša kliknite projekt i odaberite "Dodati»->«Postojeći element", u prozoru koji se otvori pronađite traženu datoteku i umjesto opcije "Dodati"odaberi opciju"Dodaj kao vezu»

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

  1. kratke – izravno u pregledniku rješenja odaberite željenu datoteku (ili čak datoteke ili čak cijele mape) i povucite je u novi projekt držeći pritisnutu tipku Alt. Dok povlačite, vidjet ćete da će se, kada pritisnete tipku Alt, pokazivač miša promijeniti iz znaka plus u strelicu.
    UPS: Napravio sam malu zabunu u ovom odlomku - za prijenos nekoliko datoteka trebate držati pritisnuto Shift + Alt!

Nakon provedene procedure imat ćemo datoteku u drugom projektu Klasa1.cs s odgovarajućom ikonom (plava strelica):

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Prilikom uređivanja koda u prozoru uređivača, također možete odabrati u kojem kontekstu projekta želite prikazati kod, što će vam omogućiti da vidite kod koji se uređuje pod različitim simbolima uvjetne kompilacije:

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Sve ostale projekte (2017.-2020.) izrađujemo koristeći ovu shemu. Life hack - ako povučete datoteke u Solution Exploreru ne iz osnovnog projekta, već iz projekta gdje su već umetnute kao veza, tada ne morate držati tipku Alt!

Opisana opcija je dosta dobra do trenutka dodavanja nove verzije dodatka ili do trenutka dodavanja novih datoteka u projekt - sve to postaje jako zamorno. I nedavno sam iznenada iznenada shvatio kako to sve riješiti s jednim projektom i prelazimo na drugu metodu

Čarolija konfiguracija

Nakon što završite s čitanjem ovdje, možete uzviknuti: "Zašto ste opisali prvu metodu, ako je članak odmah o drugoj?!" I sve sam opisao kako bi bilo jasnije zašto su nam potrebni simboli uvjetne kompilacije i na kojim se mjestima naši projekti razlikuju. I sada nam postaje jasnije koje točno razlike u projektima trebamo implementirati, ostavljajući samo jedan projekt.

I da sve bude jasnije, nećemo kreirati novi projekt, već ćemo unijeti izmjene u naš trenutni projekt kreiran na prvi način.

Dakle, prvo uklanjamo sve projekte iz rješenja osim glavnog (koji izravno sadrži datoteke). Oni. projekti za verzije 2016-2020. Otvorite mapu s rješenjem i tamo izbrišite mape ovih projekata.

Ostao nam je još jedan projekt u odluci - MojSuperPluginForRevit_2015. Otvorite njegova svojstva i:

  1. Na kartici "primjena"uklonite sufiks iz naziva sklopa _2015 (kasnije će biti jasno zašto)
  2. Na kartici "zbor» uklonite simbol uvjetne kompilacije R2015 iz odgovarajućeg polja

Napomena: najnovija verzija Visual Studio ima grešku - simboli uvjetne kompilacije nisu prikazani u prozoru svojstava projekta, iako su dostupni. Ako imate ovaj problem, trebate ih ručno ukloniti iz .csproj datoteke. Međutim, još uvijek moramo raditi u njemu, pa čitajte dalje.

Preimenujte projekt u prozoru Solution Explorer uklanjanjem sufiksa _2015 a zatim uklonite projekt iz rješenja. Ovo je neophodno za održavanje reda i osjećaja perfekcionista! Otvorimo mapu našeg rješenja, tamo preimenujemo mapu projekta na isti način i učitamo projekt natrag u rješenje.

Otvorite upravitelja konfiguracije. US konfiguracija Pustite u principu neće biti potreban pa ga brišemo. Stvaramo nove konfiguracije s nazivima koji su nam već poznati R2015, R2016, ..., R2020. Imajte na umu da ne morate kopirati postavke iz drugih konfiguracija i ne morate kreirati konfiguracije projekta:

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Idite u mapu s projektom i otvorite datoteku s nastavkom .csproj u uređivaču koji vam odgovara. Usput, možete ga otvoriti i u Visual Studio - morate istovariti projekt i tada će se željena stavka naći u kontekstnom izborniku:

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Uređivanje u Visual Studiju čak je i poželjno, jer uređivač i poravnava i šalje upite.

U datoteci ćemo vidjeti elemente PropertyGroup – na samom vrhu je opći, a onda dolaze uvjeti. Ovi elementi postavljaju svojstva projekta kada je izgrađen. Prvi element, koji je bez uvjeta, postavlja opća svojstva, a elementi s uvjetima, prema tome, mijenjaju neka svojstva ovisno o konfiguracijama.

Idite na zajednički (prvi) element PropertyGroup i pogledajte imanje Ime sklopa – ovo je naziv skupštine i trebali bismo ga imati bez sufiksa _2015. Ako postoji sufiks, uklonite ga.

Pronalaženje elementa s uvjetom

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

Ne treba nam - brišemo ga.

Element s uvjetom

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

bit će potrebni za rad u fazi razvoja koda i otklanjanja pogrešaka. Možete promijeniti njegova svojstva kako bi odgovarala vašim potrebama - postaviti različite izlazne staze, promijeniti simbole uvjetne kompilacije itd.

Kreirajmo sada nove elemente PropertyGroup za naše konfiguracije. U ovim elementima samo trebamo postaviti četiri svojstva:

  • OutputPath - izlazna mapa. Postavio sam zadanu vrijednost binR20xx
  • Definirajte Konstante – simboli uvjetne kompilacije. Treba navesti vrijednost TRAG;R20hh
  • TargetFrameworkVersion – verzija platforme. Različite verzije Revit API-ja zahtijevaju navođenje različitih platformi.
  • Ime sklopa – naziv sklopa (tj. naziv datoteke). Možete napisati točan naziv sklopa, ali zbog svestranosti preporučujem da napišete vrijednost $(AssemblyName)_20hh. Da bismo to učinili, prethodno smo uklonili sufiks iz naziva sklopa

Najvažnija značajka svih ovih elemenata je da se jednostavno mogu kopirati u druge projekte bez ikakve promjene. Kasnije ću u članku priložiti sav sadržaj .csproj datoteke.

U redu, shvatili smo svojstva projekta - nije teško. Ali što učiniti s bibliotekama dodataka (NuGet paketi). Ako pogledamo dalje, vidjet ćemo da su uključene biblioteke navedene u elementima ItemGroup. Ali loša sreća - ovaj element neispravno obrađuje uvjete kao element PropertyGroup. Možda je to čak i greška Visual Studio-a, ali ako navedete nekoliko elemenata ItemGroup s konfiguracijskim uvjetima i umetnite različite veze na NuGet pakete unutra, a zatim kada promijenite konfiguraciju, svi navedeni paketi povezani su s projektom.

Element nam dolazi u pomoć Odaberite, koji radi prema našoj uobičajenoj logici ako-onda-drugo.

Korištenje elementa Odaberite, postavljamo različite NuGet pakete za različite konfiguracije:

Svi sadržaji 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>

Imajte na umu da sam u jednom od uvjeta naveo dvije konfiguracije putem ILI. Na taj će način potrebni paket biti povezan tijekom konfiguracije Otkloniti neispravnost.

A kod nas je gotovo sve savršeno. Učitavamo projekt natrag, omogućujemo konfiguraciju koja nam je potrebna, pozivamo stavku " u kontekstnom izborniku rješenja (ne projekta)Vratite sve NuGet pakete"i vidimo kako se naši paketi mijenjaju.

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

I u ovoj sam fazi došao do slijepe ulice - kako bismo prikupili sve konfiguracije odjednom, mogli bismo koristiti serijsku montažu (izbornik "zbor»->«Skupna izrada"), ali prilikom promjene konfiguracije paketi se ne vraćaju automatski. A prilikom sastavljanja projekta to se također ne događa, iako bi u teoriji trebalo. Nisam našao rješenje za ovaj problem standardnim sredstvima. I najvjerojatnije je ovo također greška Visual Studio.

Stoga je za serijsku montažu odlučeno koristiti poseban automatizirani sustav montaže Nuke. Zapravo to nisam želio jer mislim da je pretjerano u smislu razvoja dodataka, ali trenutno ne vidim drugo rješenje. A na pitanje "Zašto Nuke?" Odgovor je jednostavan – koristimo ga na poslu.

Dakle, idite u mapu našeg rješenja (ne projekta), držite tipku smjena i desnom tipkom miša kliknite prazan prostor u mapi - u kontekstnom izborniku odaberite stavku “Ovdje otvorite PowerShell prozor".

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Ako ga nemate instaliran nuke, zatim prvo napišite naredbu

dotnet tool install Nuke.GlobalTool –global

Sada napišite naredbu nuke i od vas će se tražiti da konfigurirate nuke za trenutni projekt. Ne znam kako ovo ispravnije napisati na ruskom - na engleskom će biti napisano Nije moguće pronaći .nuke datoteku. Želite li postaviti izgradnju? [da/ne]

Pritisnite tipku Y i tada će se prikazati stavke izravnih postavki. Trebamo koristiti najjednostavniju opciju MSBuild, pa odgovaramo kao na snimku zaslona:

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Idemo u Visual Studio, koji će nas potaknuti da ponovno učitamo rješenje, budući da mu je dodan novi projekt. Ponovno učitavamo rješenje i vidimo da imamo projekt graditi u kojoj nas zanima samo jedna datoteka - Build.cs

Izrađujemo jedan plugin projekt s kompilacijom za različite verzije Revit/AutoCAD-a

Otvorite ovu datoteku i napišite skriptu za izgradnju projekta za sve konfiguracije. Pa, ili upotrijebite moju skriptu koju možete urediti prema svojim potrebama:

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"));
            }
        });
}

Vraćamo se u PowerShell prozor i ponovno pišemo naredbu nuke (možete napisati naredbu nuke s naznakom traženog Meta. Ali imamo jednog Meta, koji se pokreće prema zadanim postavkama). Nakon što pritisnemo tipku Enter, osjećat ćemo se kao pravi hakeri, jer će se, kao u filmu, naš projekt automatski sastavljati za različite konfiguracije.

Usput, PowerShell možete koristiti izravno iz Visual Studio (izbornik "Pregledati»->«Ostali prozori»->«Konzola upravitelja paketa"), ali sve će biti crno-bijelo, što nije baš zgodno.

Ovim završavam svoj članak. Siguran sam da možete sami smisliti opciju za AutoCAD. Nadam se da će ovdje prezentirani materijal pronaći svoje „klijente“.

Hvala vam!

Izvor: www.habr.com

Dodajte komentar