DEV Community

Cover image for How to distribute a .NET Core app in Arch Linux
Axel Navarro for Cloud(x);

Posted on • Updated on

How to distribute a .NET Core app in Arch Linux

In this post we'll build a netcore CLI app called taskcore and learn about the interaction between makepkg and a self-contained .NET app. We start from a PKGBUILD file and examine what it does with this self-contained app.

What is a self-contained app?

In the .NET world this means that the published artifacts of the app will include everything to run without requiring .NET installed in the user's system.

Building the app

This is the PKGBUILD for build the taskcore app in Arch Linux using the publish command:

pkgname=taskcore
pkgver=1.0.0beta3
_pkgver=1.0.0-beta.3
pkgrel=1
arch=('x86_64')
url='https://github.com/tarikguney/taskcore'
license=("APACHE")
depends=("icu")
makedepends=("dotnet-sdk")
options=("staticlibs")
source=("$url/archive/v$_pkgver.tar.gz")
sha256sums=('8472c31bb7cff8b6f543a46288753747d9c47fee8f32b3e198f8da5bcea3fca6')

build() {
  cd "$pkgname-$_pkgver/TaskCore.App"
  MSBUILDDISABLENODEREUSE=1 dotnet publish \
    --configuration Release \
    --self-contained true \
    --runtime linux-x64 \
    -p:PublishTrimmed=true \
    --output ../$pkgname \
    ./TaskCore.App.csproj
}

package() {
  cd "$pkgname-$_pkgver"

  install -d $pkgdir/usr/{bin,lib}
  cp -r $pkgname "$pkgdir/usr/lib/"
  ln -s "/usr/lib/$pkgname/$pkgname" "$pkgdir/usr/bin/$pkgname"
}

The dependencies

The installation of .NET Core in Arch Linux is so easy:

depends=("icu")
makedepends=("dotnet-sdk")

We need the icu package (International Components for Unicode library) to run this app, otherwise we'll get this error:

Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

The makepkg options

We should use the staticlibs option in the PKGBUILD to tell Arch to leave static library files in the package, otherwise the makepkg will assume the libraries will be installed as a dependency package to avoid duplicated files in the OS.

The publish arguments

The -p:PublishTrimmed=true will remove unused libraries in the build output if they aren't statically linked to our executable file.

The --self-contained true produces a platform-specific executable, so we should include the target platform with --runtime linux-x64, other options are linux-arm64, or linux-musl-x64 for lightweight distributions using musl like Alpine Linux.

We can publish the libraries inside the executable with -p:PublishSingleFile=true, but makepkg will strip all the libraries from the executable file. This optimization is useful to remove symbols (commonly used for debug) and get a lighter package, but for .NET we should use:

options=("!strip")

What about the MSBUILDDISABLENODEREUSE=1? I found this error when I run the build several times:

MSBUILD : error MSB4166: Child node "2" exited prematurely. Shutting down...

Looks like the failed builds leave MSBuild processes lying around.

How to package the app

We should move all the build output to the /usr/lib/taskcore:

cp -r $pkgname "$pkgdir/usr/lib/"

Then, we should make the taskcore command accessible by locally logged in users with a symlink:

ln -s "/usr/lib/$pkgname/$pkgname" "$pkgdir/usr/bin/$pkgname"
# /usr/bin/taskcore -> /usr/lib/taskcore/taskcore

And, it's done! We've our first .NET self-contained app for Linux. Just build it:

makepkg -s

More about .NET

If you want to start with .NET you could see this awesome video from Scott Hanselman

Top comments (1)

Collapse
 
dement6d profile image
dement6d • Edited

package() fails at cp -r $pkgname "$pkgdir/usr/lib/":

cp: cannot create directory '/home/demented/Documents/pkgs/pkg/snipesharp/usr/lib/': No such file or directory
Enter fullscreen mode Exit fullscreen mode

if i remove $pkgdir from the output path i get Permission denied for trying to move to /usr/lib

also getting

ln: failed to create symbolic link '/usr/bin/snipesharp': Permission denied
Enter fullscreen mode Exit fullscreen mode

from doing ln -s bin/Release/net6.0/linux-arm64/publish/app /usr/bin/
but even if i do sudo ln -s.. when the link is created in /usr/bin/ i still cant execute app, the link appears red when i do ls /usr/bin/app