Blog Kokosa

.NET i okolice, wydajność, architektura i wszystko inne

NAVIGATION - SEARCH

.NET Core - kompilacja, uruchomienie, debuggowanie

Dziś chciałbym Was przeprowadzić przez proces skompilowania, uruchomienia i debuggowania .NET Core - czyli wersji open source środowiska .NET. Bez zbędnych wstępów przejdźmy do odpowiedzi na proste pytanie...

Po co?

Żeby bawić się, żeby bawić się, żeby bawić się na całego. Mamy źródła .NETa! Po co nam je kompilować? Żeby grzebać, zmieniać, analizować, psuć - aż w końcu wynajdziemy dla siebie miejsce na Pull Request i zapiszemy się w Hall Of Fame, a nasz kod powędruje na miliony komputerów na całym świecie!

A nawet jeśli nie mamy tak ambitnych planów, czy nie fajnie popatrzeć "do środka", jak działa .NET? Oczywiście CoreCLR to nie jest kod komercyjnego .NETa jeden-do-jednego. Ale zdecydowana większość trzewiów jest taka sama, więc jest się czym bawić. Na stronie .NET foundation mówią wprost:

.NET Core has two major components. It includes a small runtime that is built from the same codebase as the .NET Framework CLR. The .NET Core runtime includes the same GC and JIT (RyuJIT), but doesn’t include features like Application Domains or Code Access Security. (...)

.NET Core also includes the base class libraries. These libraries are largely the same code as the .NET Framework class libraries, but have been factored (removal of dependencies) to enable us to ship a smaller set of libraries.

Jeśli zatem coś nas pociąga w spojrzeniu w kod frameworka, którego używamy od lat, mamy ku temu okazję.

Jak?

Wszystko najlepiej zorganizować w jeden folder, by było obok siebie. Ja go nazwałem C:\Projects\DotNetCore. Następnie musimy skompilować dwa komponenty, będące osobnymi repozytoriami na githubie.

CoreCLR

Pierwszy z nich to sam runtime w swej okazałości. Napisany w zdecydowanej większości w C++, z pewnymi wstawkami assemblera. Krok po kroku:

1. Wykonujemy fork dotnet/coreclr żeby móc w przyszłości wykonać nasz wyśmienity Pull Request, w moim przypadku jest to fork https://github.com/kkokosa/coreclr

2. Standardowa procedura, czyli dodajemy dodatkowe źródło do naszego lokalnego repozytorium wskazujące na główne repozytorium. Dzięki temu będziemy mogli się z nim synchronizować:

$ git clone https://github.com/kkokosa/coreclr.git
$ git remote add upstream https://github.com/dotnet/coreclr.git

3. Od teraz co jakiś czas warto taką synchronizację przeprowadzić za pomocą:

$ git fetch upstream
$ git checkout master
$ git merge upstream/master

4. Skompilowanie - trzeba przejść przez kroki opisane w https://github.com/dotnet/coreclr/blob/master/Documentation/building/windows-instructions.md. W skrócie:

  1. Instalujemy Visual Studio 2015, może być wersja Community, powinna być wersja Update 3 (obecnie w wersji RC) ale mi skompilowało się też w wersji Update 2
  2. Instalujemy CMake - pamiętajmy przy instalacji zaznaczyć, by zostało dodane do zmiennych środowiskowych
  3. Instalujemy Pythona - znów pamiętajmy o opcji dodania do zmiennych środowiskowych
  4. Upewniamy się, że mamy PowerShella, co raczej powinno mieć miejsce

Ja musiałem m.in. zainstalować aktualizację Visual Studio 2015 Update 3, Pythona oraz CMake.

5. Wchodzimy do katalogu coreclr i wykonujemy komendę:

$ build clean

Ewentualnie

$ build clean skiptests

To sporo przyśpieszy cały proces. Powinniśmy w nagrodę, dostać komunikat:

BUILDTEST: Test build successful.
BUILDTEST: Test binaries are available at c:\Projects\DotNetCore\coreclr\tests\..\bin\tests\Windows_NT.x64.Debug
BUILD: Repo successfully built.
BUILD: Product binaries are available at c:\Projects\CoreNet\coreclr\bin\Product\Windows_NT.x64.Debug
BUILD: Test binaries are available at c:\Projects\CoreNet\coreclr\bin\tests\Windows_NT.x64.Debug

Uwaga - na moim, imho niezgorszym kompie, z testami to zajęło jakieś 22 minuty. Zwróćmy też uwagę, że domyślnie kompiluje się wersja 64bit w trybie Debug - w sam raz do debuggowania.

CoreFX

Drugi komponent to zestaw bibliotek standardowych. Wykonujemy dokładnie to samo co powyżej, tylko w folderze corefx

1. Fork https://github.com/dotnet/corefx do naszego konta https://github.com/kkokosa/corefx
2. Gitowe klonowanie i konfiguracja:

$ git clone https://github.com/kkokosa/corefx.git
$ git remote add upstream https://github.com/dotnet/corefx.git

3. Później ew. synchronizacja:

$ git fetch upstream
$ git checkout master
$ git merge upstream/master

Jeśli nanieśliśmy jakieś zmiany to pamiętajmy o git push Smile
4. Startujemy kompilację komendą:

$ build.cmd

Jeśli jakieś testy nie powiodą się, to się nie martwimy, ważne żeby jedyne błędy pochodziły właśnie z niepomyślnych testów.

Uruchamiamy

Gratuluję! Prawdopodobnie mamy już skompilowane oba klocki, musimy je teraz złożyć w całość. Najpierw musimy przekopiować kilka plików w jedno miejsce ze skompilowanych projektów do folderu, gdzie stworzymy pierwszy programik testowy. Będą tam podfoldery ref oraz runtime. Najlepiej zrobić sobie z tego plik batchowy:

copy coreclr\bin\Product\Windows_NT.x64.debug\clrjit.dll coreclr-demo\runtime
copy coreclr\bin\Product\Windows_NT.x64.debug\CoreRun.exe coreclr-demo\runtime
copy coreclr\bin\Product\Windows_NT.x64.debug\coreclr.dll coreclr-demo\runtime
copy coreclr\bin\Product\Windows_NT.x64.debug\mscorlib.dll coreclr-demo\runtime
copy coreclr\bin\Product\Windows_NT.x64.debug\System.Private.CoreLib.dll coreclr-demo\runtime

copy corefx\bin\Windows_NT.AnyCPU.Debug\System.Console\System.Console.dll coreclr-demo\runtime
copy corefx\bin\Windows_NT.AnyCPU.Debug\System.Diagnostics.Debug\System.Diagnostics.Debug.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.IO\System.IO.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.IO.FileSystem.Primitives\System.IO.FileSystem.Primitives.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Runtime\System.Runtime.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Runtime.InteropServices\System.Runtime.InteropServices.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Text.Encoding\System.Text.Encoding.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Text.Encoding.Extensions\System.Text.Encoding.Extensions.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Threading\System.Threading.dll coreclr-demo\runtime
copy corefx\bin\AnyOS.AnyCPU.Debug\System.Threading.Tasks\System.Threading.Tasks.dll coreclr-demo\runtime

copy corefx\bin\ref\System.Runtime\4.0.0.0\System.Runtime.dll coreclr-demo\ref
copy corefx\bin\ref\System.Console\4.0.0.0\System.Console.dll coreclr-demo\ref


W ten sposób do folderu runtime trafia nam pełen komplet środowiska potrzebnego do prostego programu, który możemy sobie przygotować:

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello, Windows");
        Console.WriteLine("Love from CoreCLR.");
    }
}

I odpowiednio skompilować:

$ csc /nostdlib /noconfig /r:ref\System.Runtime.dll /r:ref\System.Console.dll /out:runtime\hello.exe hello.cs

Następnie (już ostatni krok!) przechodząc do c:\Projects\DotNetCore\coreclr-demo\runtime możemy ten program uruchomić:

$ corerun hello.exe
Hello, Windows
Love from CoreCLR.

Gratuluję! Może nie wygląda to jakoś zniewalająco, ale bądźmy świadomi tego, czego właśnie dokonaliśmy! Skompilowaliśmy od zera całe środowisko .NETa i uruchomiliśmy na nim normalny konsolowy program skompilowany za pomocą Visual Studio. A to jeszcze nie koniec.

Debugowanie

Skoro źródła, to możemy zacząc debuggować CLR. Jak tego dokonać? Korzystamy w tym celu z plików projektu, które powstają przy kompilacji CoreCLR i znajdują się w katalogu c:\Projects\DotNetCore\coreclr\bin\obj. Szukamy tam tej, której chcemy akurat użyć, domyślnie będzie to 64 bitowa wersja Debug.

1. Otwieramy w Visual Studio c:\Projects\CoreNet\coreclr\bin\obj\Windows_NT.x64.Debug\CoreCLR.sln 

2. Projekt INSTALL ustawiamy jako StartUp project

3. W ustawieniach Configuration Properties->Debugging projektu INSTALL wpisujemy:

  • Command jako $(SolutionDir)..\..\product\Windows_NT.$(Platform).$(Configuration)\corerun.exe
  • Command Arguments jako hello.exe
  • Working Directory tam gdzie nasze demo (czyli ścieżka do coreclr-demo\runtime)

4. Rozpoczynamy debuggowanie poprzez Step Into (F11) - wtedy zaczniemy od źródeł programu CoreRun.exe:

coreclr2

5. Możemy też ustawić interesujące nas breakpointy w samym CoreCLR i uruchomić debugowanie po prostu poprzez F5. Ja polecam zacząć np. od pliku ceemain.cpp i metody EEStartup, w której dzieje się naprawdę sporo (a właściwie w metodzie pomocniczej EEStartupHelper):

coreclr1

Uwaga: jest wysoce prawdopodobne, że Visual Studio będzie twierdzić, że ma stare buildy pewnych bibliotek i będzie chciał je przekompilować. Szkoda na to czasu, skoro kompilację już wykonaliśmy. Dlatego polecam w menu Tools -> Options w sekcji Projects and Solutions -> Build and Run wybrać dla opcji "On Run, when projects are out of date" wartość "Never build" albo "Prompt to build".

coreclr3

Teraz już możemy bawić się na całego. Ja na przykład z wielkim zainteresowaniem debuguję sobie kod Garbage Collectora, ale Was może zainteresować całkiem innego.


 

blog comments powered by Disqus