software-development
March 21, 2023

Разработка на .NET под FreeBSD

Вы хотели это увидеть? Получите, распишитесь. «Зеленый слоник» от разработки, грайндхаус в коде и ночной кошмар быдлокодеров. Курлык епта.

Музыка для статьи:

Это все несерьезно

Не надо пытаться заниматься такой разработкой на серьезных щщах, по моему описанию ниже. Это просто тест для оценки текущего состояния дел с дотнетом и его реальной а не декларируемой кроссплатформенностью

spoiler: все сильно лучше чем я полагал

Есть куда расти и что чинить, но прогресс за 4 года чудовищный.

Если вы ходите заниматься разработкой на дотнете то вам нужен линукс, а лучше — венды, но точно не BSD.

Я предупредил.

Текущее состояние дел

Текущее состояние дел с дотнетом под FreeBSD выкладывают тут.

.NET был официально открыт Microsoft и выложен в Github в декабре 2018го года, совсем недавно по меркам индустрии — той же Java.

С тех пор выпускается каждый год новая версия:

Вот так выглядел этот исторический момент выкладывания .NET в опенсорс:

Microsoft's press release highlights that the cross-platform commitment now allows for a fully open-source, modern server-side .NET stack. Microsoft released the source code for WPF, Windows Forms and WinUI on December 4, 2018.[16]

Гуй и десктоп

Нативно не поддерживаются конечно, если вы вдруг успели раскатать губу, но процесс пинания вендора ногами идет.

Пока есть запуск через Wine, стабильный:

На текущий момент даже нет поддержки сборки WPF-приложений на линуксе, настолько все плохо.

Есть альтернативные решения, например Avalonia, но на FreeBSD оно не собирается.

Вот тут лежит огромная обзорная статья про всю историю кроссплатформенной разработки с UI на дотнете. Наслаждайтесь, крайне занимательное чтиво.

Вообщем FreeBSD официально не поддерживается нигде, но на удивление работа по поддержке активно идет.

Как пропатчить .NET под FreeBSD

Cуществует и активно развивается вот такой набор скриптов, по сборке из исходников .NET последних версий 6 и 7.

Уже даже над 8й версией идет работа.

Тут же выкладываются бинарные сборки .NET под FreeBSD, поэтому если у вас вдруг почему-то не возникнет желания собирать дотнет из исходников — просто скачайте сборку.

Но это не тру, само собой.

Для запуска дотнета, как самосборного так и бинарника, нужно поставить:

pkg install libunwind icu libinotify

Погружение в тему

Ниже я расскажу как собрать .NET из исходников, если вы недостаточно круты — прокрутите ниже до следующего раздела.

Нужно будет ~40Гб свободного места на диске и минимум 8Гб памяти на машине:

Если памяти меньше — могут быть падения при сборке, поскольку дотнет собирается другим дотнетом, линуксовым.

Ради него и ставился слой совместимости с линуксом.

Оригинальная инстукция описана в README.MD в ветке репозитория для конкретной версии, я использовал 7ю, как последнюю стабильную.

Имейте ввиду что инструкция частично устарела:

1. Run as root install_tools.sh - make sure to mount all needed things (add them to /etc/fstab, then mount -a)

Речь тут про Java, которая при первой установке на FreeBSD действительно просит себе procfs, если у вас она уже стояла и работала то ничего монтировать не надо.

Нужно поставить вот такие пакеты:

pkg install autoconf libtool automake cmake llvm10 krb5 terminfo-db libunwind icu libinotify python3 pkgconf binutils npm-node14 node14 openjdk11 bash git wget protobuf linux_base-c7 grpc

И запустить слой эмуляции линукса :

service linux onestart

Который скорее всего у вас и так есть и запущен.

Вообщем fstab должен в итоге выглядеть как-то так:

Запускаем инициализацию сборки

2. ./init.sh

Скрипт выше выкачивает рекурсивно репозитории с исходниками дотнета и бинарные сборки, необходимые для запуска.

Бинарные сборки уже для FreeBSD, собранные на линуксе через crossbuild:

Working SDK for FreeBSD - at the moment it's using binaries from https://github.com/Thefrank/dotnet-freebsd-crossbuild created during crosscompile under Linux

Дальше запускаем сборку рантайма .NET:

3. ./build_runtime.sh

Начнется скачивание большого количества библиотек, которое будет регулярно прерываться.

В оригинале предлагается добавить ключ в случае ошибок:

add -v d inside if it will fail with SEHExceptions...

К сожалению этого не хватит и придется выкачивать все эти библиотеки вручную через wget или curl и перезапускать скрипт.

Много раз перезапускать.

Дальше мы по шагам собираем части дотнета и по-сути вкладываем результаты одной сборки в другую.

То что в оригинале написано «try to skip» означает что можно взять готовую сборку и подложить ее для следующего шага.

Первый шаг это сборка ASP.NET Core:

4. (try to skip this and goto build_aspnetcore.sh) build_installer_without_aspnet.sh

Дальше происходит как раз подкладывание бинарной сборки (обратите внимание что тут подкладывается 6й дотнет, хотя сборка идет 7го:

5. (try to skip this and goto build_aspnetcore.sh) run tar zxfv ../../installer/artifacts/packages/Release/Shipping/dotnet-sdk-6.0.101-freebsd-x64.tar.gz inside aspnetcore/.dotnet to extract newly created SDK

Следующий шаг — сборка ASP.NET Core на 7м дотнете:

6. ./build_aspnetcore.sh - as for now, this one need v7 SDK - grab one and do

Дальше запускаем «Fake .NET Core Installer for FreeBsd»:

7. ./bsd_dotnet_install.sh sdk7.tgz aspnetcore/

Вот весь код:

#!/bin/sh
# Fake .NET Core Installer for FreeBsd ;)
# $1 - SDK BIN for FreeBSD
# $2 - dest dir
echo Extracting .NET Core SDK into $2...
mkdir -p $2/.dotnet
tar zxf $1 --directory $2/.dotnet
echo 'exit 0' > $2/.dotnet/dotnet-install.sh

Идея думаю понятна — банальная распаковка сборки из предыдущего шага в нужное место.

Дальше запускается сборка дистрибьютива .NET SDK:

8. ./build_installer.sh - this one also need v7 SDK - do the same as above. Add -v d inside build script if it will fail, check the logs (maybe download some zips by hand, as this is common fail)

Код вот такой:

#!/bin/csh
if (`uname -m` == "arm64") then
setenv ARCH arm64
else
setenv ARCH x64
endif
mkdir -p installer/artifacts/obj/redist/Release/downloads/
cp runtime/artifacts/packages/Release/Shipping/dotnet-runtime-*-freebsd-$ARCH.tar.gz installer/artifacts/obj/redist/Release/downloads/
cp aspnetcore/artifacts/installers/Release/aspnetcore-runtime-* installer/artifacts/obj/redist/Release/downloads/
cp sdk/artifacts/packages/Release/NonShipping/dotnet-toolset-internal-*.zip installer/artifacts/obj/redist/Release/downloads/
setenv TAG `cat installer.tag`
installer/build.sh -c Release -ci -pack --runtime-id freebsd-$ARCH /p:OSName=freebsd /p:OfficialBuildId=`./common.sh $TAG` /p:IncludeAspNetCoreRuntime=true

Тут происходит точно такое же подкладывание готовых артефактов и запуск сборки уже дистрибьютива.

Наконец, в случае успеха вот тут будет финальная сборка:

9. Get and use installer/artifacts/packages/Release/Shipping/dotnet-sdk-*-freebsd-x64.tar.gz

Можно сравнить с тем что выкладывается в раздел релизов:

https://github.com/sec/dotnet-core-freebsd-source-build/releases

Дополнительные шаги

Очистка сборки для освобождения места:

1. clean.sh if you want to save disk space after use

Упаковать все результаты сборки в один архив:

2. gather_output.sh to tar artifacts into one big file, for future use (doesn't make sense to compress this, as it contains compressed files already)

Также можно использовать собранный SDK в качестве начального рантайма:

you can use output SDK as seed (instead of the one that was crosscompiled), move it here and rename to sdk.tgz

Будет максимально нативная версия .NET SDK для FreeBSD.

Отладка

Официальный WSL работает только под VSCode и только линуксовым. Альтернативный отладчик от Samsung я пока собрать под FreeBSD не смог, увы.

Но варианты все равно есть:

Unfortunately, this is going to be a very painful experience. There's no real command line debugger available for .NET Core.

However, CoreCLR developers use a plugin for lldb (on *nix) that teaches lldb about a number of commands that it can use to help debug .NET code.

Essentially:

lldb /path/to/dotnet/dotnet
plugin load /path/to/dotnet/shared/Microsoft.NETCore.App/*/libsosplugin.so
b SystemNative_ReceiveMessage
r run
clrstack

Вот тут и тут лежат подробные инструкции, если кому действительно надо расставлять брейкпойнты в managed языке.

Но я например все же как-то справляюсь одним выводом в консоль — старая школа.

Среда разработки

Конечно же это VSCode, который достаточно давно есть в портах и успешно работает.

Если не интересно собирать из портов — можно поставить пакет:

pkg install vscode

Вот так выглядит проект на дотнете из среды разработки под FreeBSD:

Тестовый проект

Я взял для примера знаменитый шаблон AspBoilerplate и сгенерировал на нем тестовый проект.

Вот с такими настройками:

Если кто вдруг не сталкивался — это большая такая болванка типичного корпоративного проекта, с EF и миграцией данных, с интерфейсом, с авторизацией и так далее.

Новая разработка корпоративного софта с нуля начинается с таких вот шаблонов, которые затем наполняются нужной вам логикой.

Дальше этот шаблон пришлось переделывать на компиляцию 7м дотнетом, использование Postgres вместо Microsoft SQL Server и еще по мелочи.

Полный исходный код выложил вот сюда.

Для работы вам нужен собранный либо скачанный .NET SDK 7 , распакованный и добавленный в переменную окружения PATH.

Еще будет нужно поставить свежую Node.js и yarn.

Нода есть в портах, yarn ставится как обычно:

npm i -g yarn

Сборка

Все достаточно просто и банально.

Скачиваем библиотеки, в дотнете это называется restore dependencies:

dotnet restore

Дальше запускаем сборку

dotnet build

В результате должны появиться папки bin и obj в подпапках модулей

Запуск

В готовом виде (production build) это будет один бинарник, со всеми ресурсами и настройками.

Для разработки бекэнд и фронтэнд запускаются отдельно, на фронте включен hotswap — автоматическая пересборка и обновление SPA в браузере при правках исходного кода.

Запуск бекэнда

Бекэнд запускается из проекта TestApp.Web.Host:

dotnet run

Если запуск будет успешен - сервер поднимется на порту 44311

Запуск фронтэнда

Фронт также в проекте TestApp.Web.Host, запускается через yarn:

yarn start

Вот так это выглядит:

Работа с базой данных

Я использую DB Visualizer, который даже есть в портах.

К сожалению, даже из портов ставится «бинарная» (на Java) версия, поскольку исходники не открыты. Не то чтобы это была какой-то проблемой, но тем не менее.

Еще можно использовать Aqua Data Studio , он отлично работает на любых BSD и легко находится на торрентах.

Настройка подключения к базе данных находится в appsettings.json:

"ConnectionStrings": {
"Default": "User ID=postgres;Password=qwerty;Host=127.0.0.1;Port=5432;Database=test2;Pooling=true;"
},

Таких файла два — один будет в проект TestApp.Web.Host, другой в TestApp.Migrator. Настроить подключение нужно будет в обоих.

Перед первым запуском необходимо запустить миграцию, для того чтобы автоматически создались таблицы в базе и наполнились тестовыми данными.

Заходим в каталог с проектом TestApp.Migrator и запускаем:

dotnet run update-database

Результат

После успешного запуска, открываете в браузере http://localhost:4200

Страница авторизации

Учетка по-умолчанию:

admin / 123qwe

Новых пользователей можно задать в самой системе:

Управление пользователями

Дашборд на самом деле практически пустой, данные тестовые:

Главный экран.

Этот тестовый проект сразу идет как multi-tenant, те с поддержкой разделения между пользовательскими данными.

Управление этими самыми тенантами выглядит вот так:

Выводы

Все это было написано лишь для исследования текущего состояния дел с дотнетом вне экосистемы Windows, которое мне показалось очень даже неплохим.

Напомню что прошло лишь 4 года с момента выкладывания исходников .NET в публичный доступ, что для такого проекта очень небольшой срок.

Если у вас есть legacy-проект на дотнете и вы хотите отказаться от Windows-платформы, думаю стоит задуматься.

Могу помочь с оценкой и возможными сроками такого переезда — пишите.