Skiasharp: Linux support

Created on 16 Jun 2016  路  70Comments  路  Source: mono/SkiaSharp

Does SkiaSharp work on Linux?

area-libHarfBuzzSharp.native area-libSkiaSharp.native os-Linux

Most helpful comment

Added a wiki to help when building on Linux:
https://github.com/mono/SkiaSharp/wiki/Building-on-Linux

All 70 comments

SkiaSharp should, but the native supporting code needs to be compiled individually on each Linux distribution.

Sadly, NuGet was not designed to cope with this scenario, so there is not much that we can do to ship precompiled binaries.

What we should do is at least provide a simple Makefile to create the native library support, so third parties can build/install it easily.

@migueldeicaza compilations could be provided for several linux flavors using the runtimes/RID feature: https://dotnet.github.io/docs/core-concepts/rid-catalog.html

@tmds An ARM Linux was actually work with this guy: #18
@migueldeicaza not too sure of all the limitations, but as the native dll is the only thing that needs switching... is it possible to do something like this for a few supported (popular) versions of Linux: https://github.com/mono/SkiaSharp/blob/master/binding/SkiaSharp.Desktop/SkiaSharp.dll.config

The issue is not identifying the library, the issue is that creating a package with the binaries is incredibly cumbersome (you need to create a package with all available systems upfront, build the native bits, and then package all the bits together).

What should ideally happen is that these native binaries should be "addons" to the core package, and could be published independently of the core package.

@migueldeicaza Any idea when makefiles for popular distros will be available? Is it going to happen this year or are we looking more at 2017? With .Net Core in the wild, lack of server side graphics library in Linux environment all of the sudden seems like a pressing matter.

That being said, you are doing wonderful things with SkiaSharp and in Windows as GDI+ replacement it is just amazing.

@migueldeicaza I think if you compile skia using sufficiently old distro (e. g. CentOS 6, Debian 5) it will just work everywhere. In the worst case you can just bundle dependencies (skia don't really need much: libfontconfig, libfreetype, libz, libpng12) and rely only on libc which is guaranteed to be present by LSB.

I'm looking into the build.cake file and trying to work out how to convert it to build for linux.
Are there any attempts of pointers for me to start updating the build system.

@jameswalmsley I would say you probably need to just get the externals building. These are grouped using the Task ("externals-<platform>") steps. For the case of Linux, I would suggest following the Android style: Task ("externals-android") https://github.com/mono/SkiaSharp/blob/v1.53.0/build.cake#L674-L724

It pretty much follows the official docs by google: https://skia.org/user/quick/linux

It follows the pattern of:

  1. set global env vars
  2. set gyp defines for platform
  3. build *.a (using ninja) for platform
  4. link all *.a together into a dynamic library of some sort
  5. repeat 2-4 for each platform

In the case of Android, I did step 4 using ndk-build, but you could use whatever it is that is used on Linux. @galvesribeiro did it without much trouble, after he built his compilers first ;)

Basically, build all the *.a files and then dynamically link them together. Let me know how this goes as we do want to have support for as many platforms as possible.

The rest of the stuff is pure C#/.NET P/Invoke

Yes. Build for Android linux is already there on the Gyp files however, if you plan to build it to any other linux, you will either have to hack the .gyp files to point to your dependencies (specially if you are cross compiling to another arch) and the output will be a bunch of .a. After that all compiled, you need to link it to the skiasharp. I had everything statically linked since the ld and glibc on the targed device was too old (pre-C++11).

Basically this is the buld script:

export PATH=/home/guto/x-tools/arm-unknown-linux-gnueabi.485/bin:/home/guto/x-tools/crosstool-ng/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/guto/dev/chromium/depot_tools
export TARGETMACH=arm-arm1176jzs-linux-gnueabi
export BUILDMACH=i686-pc-linux-gnu
export CROSS=arm-arm1176jzs-linux-gnueabi
export CC=${CROSS}-gcc
export LD=${CROSS}-ld
export CXX=${CROSS}-g++
export STRIP=${CROSS}-strip
export LINK=${CROSS}-g++
export AS=${CROSS}-as
export AR=${CROSS}-ar
export RANLIB=${CROSS}-ranlib
export NM=${CROSS}-nm
export CROSS_COMPILE="arm-arm1176jzs-linux-gnueabi"
export PKG_CONFIG_PATH=/home/guto/dev/libs/lib/pkgconfig
export INSTALLPATH=/home/guto/dev/libs/

GYP_DEFINES='skia_gpu=0 skia_pdf= skia_os=linux skia_arch_type=arm' SK_SUPPORT_PDF=0  CC='arm-unknown-linux-gnueabi-gcc' CXX='arm-unknown-linux-gnueabi-g++' PKG_CONFIG_PATH=/home/guto/dev/libs/lib/pkgconfig LDFLAGS=-L/home/guto/dev/libs/lib  python bin/sync-and-gyp

ninja -C out/Release skia_lib

//Compiling source to object files
$CXX -MMD /home/guto/dev/SkiaSharp/native-builds/src/SkiaKeeper.c /home/guto/dev/SkiaSharp/native-builds/src/SkManagedStream.cpp /home/guto/dev/SkiaSharp/native-builds/src/sk_managedstream.cpp /home/guto/dev/SkiaSharp/native-builds/src/sk_xamarin.cpp -g -fPIC -O3 -DSKIA_DLL -DSKIA_IMPLEMENTATION=1 -DSK_INTERNAL -DSK_BUILD_FOR_UNIX -I/home/guto/dev/SkiaSharp/skia/include -I/home/guto/dev/SkiaSharp/skia/include/c -I/home/guto/dev/SkiaSharp/skia/include/config -I/home/guto/dev/SkiaSharp/skia/include/core -I/home/guto/dev/SkiaSharp/skia/include/pathops -I/home/guto/dev/SkiaSharp/skia/include/pipe -I/home/guto/dev/SkiaSharp/skia/include/ports -I/home/guto/dev/SkiaSharp/skia/include/private -I/home/guto/dev/SkiaSharp/skia/include/utils -I/home/guto/dev/SkiaSharp/skia/include/images -I/home/guto/dev/SkiaSharp/skia/src/c -I/home/guto/dev/SkiaSharp/skia/src/core -I/home/guto/dev/SkiaSharp/skia/src/sfnt -I/home/guto/dev/SkiaSharp/skia/src/image -I/home/guto/dev/SkiaSharp/skia/src/opts -I/home/guto/dev/SkiaSharp/skia/src/utils -I/home/guto/dev/SkiaSharp/skia/include/gpu -I/home/guto/dev/SkiaSharp/skia/src/gpu -I/home/guto/SSBuild/SkiaSharp/SkiaSharp/obj/Debug/prec/Debug -L/home/guto/dev/libs/lib -lfontconfig -c -std=c++11

//Generating shared object "libSkiaSharp.so" from object files
$CXX -shared -o Release/libSkiaSharp.so SkiaKeeper.o sk_managedstream.o SkManagedStream.o sk_xamarin.o -L/home/guto/dev/SkiaSharp/skia/out/Release/lib -Wl,--start-group /home/guto/dev/SkiaSharp/skia/out/Release/libskia_core.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_ports.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_images.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_sfnt.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_opts.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_codec.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_effects.a /home/guto/dev/SkiaSharp/skia/out/Release/libskia_utils.a -Wl,--end-group /home/guto/dev/SkiaSharp/skia/out/Release/libpng_static.a /home/guto/dev/libs/lib/libfreetype.a /home/guto/dev/libs/lib/libfontconfig.so /home/guto/dev/libs/lib/libz.a /home/guto/dev/libs/lib/libturbojpeg.a /home/guto/dev/libs/lib/libjpeg.a /home/guto/dev/libs/lib/libexpat.a /home/guto/dev/libs/lib/libwebp.a /home/guto/dev/libs/lib/libwebpdecoder.a /home/guto/dev/libs/lib/libwebpdemux.a /home/guto/dev/libs/lib/libwebpextras.a /home/guto/dev/libs/lib/libwebpmux.a  /home/guto/x-tools/arm-unknown-linux-gnueabi.485/arm-unknown-linux-gnueabi/lib/libstdc++.a -L/home/guto/dev/libs/lib -lfontconfig

One can create a makefile and make things easier but this native linux "macumba" is not something we are good here. So thanks to @mattleibow we got it to work.

The C# side of SkiaSharp is just PInvokes with a .Net like APIs, so just point it to the right lib name and you are set.

I hope it help.

Thanks for this @galvesribeiro!

Hello guys, I have some tips for you here. When I was messing with skia on linux half a year ago, I've run into an issue with really huge library file (50MB+). I've managed to strip it down to 2MB.

  • Linker has a wonderful flag --gc-sections which allows it to remove parts that aren't needed by the final so binary. The issue is it doesn't work properly for shared libs unless you specify -ffunction-sections -fdata-sections compiler flags for each source file
  • Disabling RTTI also saves a great deal of space

You can find a patch to skia.gyp here: https://github.com/AvaloniaUI/libperspesk/blob/master/linux/skia.patch

Another issue with linking it was the fact that for some reason linker doesn't work properly with static library dependencies when you compile your shared library. --whole-archive just bloats your binary size and even then doesn't always work. So the trick is to unpack object files from static libs using ar utility and then combine them into one. The script for that is here: https://github.com/AvaloniaUI/libperspesk/blob/master/linux/mergelibs.sh

I also recommend you to specify --no-undefined linker flag so you won't run into weird undefined symbol errors at runtime, and could figure out dependencies properly.

My old makefile is here:

https://github.com/AvaloniaUI/libperspesk/blob/master/linux/Makefile#L32

Oh, forgot to add the script that downloads and actually builds skia itself: https://github.com/AvaloniaUI/libperspesk/blob/master/linux/getskia.sh

I wish I had that! Hehehe btw, after strip, my release build was 3mb with everything statically linked.

@mattleibow Did you see this? https://github.com/phusion/holy-build-box

If anyone is interested, I've managed to run Cake in that docker container.

First, you need to acquire mono-opt package for CentOS 5. For some reason I wasn't able to use the repo, so I've downloaded it manually from https://copr-be.cloud.fedoraproject.org/results/tpokorra/mono-opt/epel-5-x86_64/00496651-mono-opt/mono-opt-4.6.2-1.x86_64.rpm . In case it gets deleted, here is mega link: https://mega.nz/#!cswD2Jza!EqE-Q_rwmTK0vwYeNDaWSGm0aHK6y5roF1BHZdPGtz8

You need to install this package with --no-gpg-check option. You also need to install curl and unzip packages. Synchronizing certs is also mandatory.

yum install -y --nogpgcheck ./mono-opt-4.6.2-1.x86_64.rpm
yum install -y curl unzip
source /opt/mono/env.sh

After that you should be able to run bootstrapper.sh. Of course it would need more steps to produce an actual build.

BTW, last time when I was messing with Skia, my library was depending on:

        linux-vdso.so.1 =>  (0x00007ffd7adf3000)
        libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f1cabc08000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1cab9ee000)
        libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f1cab7af000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1cab591000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1cab20f000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1caaf06000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1caab3c000)
        libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f1caa916000)
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f1caa6ec000)
        /lib64/ld-linux-x86-64.so.2 (0x000055b85c884000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1caa4d5000)

So it probably should be possible to provide a build of Skia that works everywhere

Hello Guys,

I was able to get the whole thing working on .net core on linux. I will share that when I have some time. If someone is interested and can't wait let me know and I'll share my new gn target. (Not using gyp)

@Kuqd I'm interested in learning that, I've been working on a way to make a Wayland Program under Linux. (Would love to avoid using OpenGL.)

@Kuqd I am busy looking to get Linux support in, especially for .NET Core. I have been using gyp because that was there, but if it is possible to share what you have done I would like to try using gn. Also, what OS specs are you running?

Not using gyp is actually a good idea, since there is a lot of stuff hardcoded there. With custom scripts it should be much easier to build in unusual environments like ARM platforms with custom toolchains, HBB, etc.

Just referencing this as it is relevant: https://github.com/NuGet/Home/issues/3114

I have created a partially complete script and makefile.
I have been using Ubuntu 14.04 and right now it can fully build, package and run fine, but many things are hardcoded and may not work on other versions or flavors. I am still working on this, and this was more for testing purposes. But, the output is fully functional and all the bits are there.

Build Script: https://github.com/mono/SkiaSharp/blob/21306d6267aeadcba31255d823e89edd54055440/cake/BuildExternals.cake#L420-L463
Makefile: https://github.com/mono/SkiaSharp/blob/21306d6267aeadcba31255d823e89edd54055440/native-builds/libSkiaSharp_linux/Makefile

The basic steps are to gyp (create the internal makefiles), ninja (build the skia static libraries), and make (create the dynamic, linked libSkiaSharp). The Makefile is also pretty straight forward, take the skia outputs, and the xamarin classes and link together. I don't actually do anything specific for linux.

I am still using gyp right now, but I will be looking to switch to gn sometime in the near future.

Sorry I was away, here is the target to add to the build.gn:

component("libSkiaSharp") {
    sources = [
        "../../native-builds/src/sk_managedstream.cpp",
        "../../native-builds/src/sk_xamarin.cpp",
        "../../native-builds/src/SkiaKeeper.c",
        "../../native-builds/src/SkManagedStream.cpp",
     ]
    include_dirs = [
        "include/c",
        "include/config",
        "include/core",
        "include/effects",
        "include/pathops",
        "include/codec",
        "include/pathops",
        "include/pipe",
        "include/ports",
        "include/private",
        "include/utils",
        "include/images",
        "src/c",
        "src/core",
        "src/sfnt",
        "src/image",
        "src/opts",
        "src/utils",
        "include/gpu",
        "src/gpu"
    ]
    public_deps = [":skia"]
    configs += [":skia_library",":skia_public"]
    visibility = [ ":*" ]  # Prevent accidental dependencies.
  }

then run this :

gn gen ../../native-builds/lib/linux/x64/ --args="is_component_build=true is_debug=false"
ninja -C ../../native-builds/lib/linux/x64/ libSkiaSharp

This is going to build 2 so :

libSkiasharp.so and libskia.so, libSkiasharp.so depend on libskia.so, so make sure you update your LD_LIBRARY_PATH correclty on linux.

I also have the .netstandard (1.6) project, with build task to create the correct nugetpackage that you can use on linux and .net core.If I have time I can create a pull request later @mattleibow , next month.

The project I have is using the new visual studio 2017 RC3 (so you need the last toolchain) csproj, I've added my .net standard binding to SkiaSharp\binding\SkiaSharp.NETStandard\SkiaSharp.NETStandard.csproj :

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
  <PropertyGroup>
    <Description>SkiaSharp for .net standard</Description>
    <TargetFramework>netstandard1.6</TargetFramework>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>portable</DebugType>
    <AssemblyName>SkiaSharp.NetStandard</AssemblyName>
    <OutputType>library</OutputType>
    <RuntimeIdentifiers>win7-x64;win7-x86;linux-x64</RuntimeIdentifiers>
    <PackageOutputPath>..\..\..\..\built_packages\</PackageOutputPath>
    <IncludeSymbols>true</IncludeSymbols>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Release' ">
    <Optimize>True</Optimize>
    <DefineConstants>
    </DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Debug' ">
    <Optimize>False</Optimize>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="..\Binding\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**;Properties\**" />
    <Compile Remove=".vscode\**" />
    <Compile Remove=".vs\**" />
    <EmbeddedResource Remove=".vscode\**" />
    <EmbeddedResource Remove=".vs\**" />
    <None Remove=".vscode\**" />
    <None Remove=".vs\**" />
    <Content Include="..\..\native-builds\lib\windows\x64\libSkiaSharp.dll">
      <PackagePath>runtimes\win7-x64\native</PackagePath>
      <Pack>true</Pack>
    </Content>
    <Content Include="..\..\native-builds\lib\windows\x86\libSkiaSharp.dll">
      <PackagePath>runtimes\win7-x86\native</PackagePath>
      <Pack>true</Pack>
    </Content>
    <Content Include="..\..\native-builds\lib\linux\x64\libSkiaSharp.so">
      <PackagePath>runtimes\linux-x64\native\libSkiaSharp.so</PackagePath>
      <Pack>true</Pack>
    </Content>
    <Content Include="..\..\native-builds\lib\linux\x64\libskia.so">
      <PackagePath>runtimes\linux-x64\native\libskia.so</PackagePath>
      <Pack>true</Pack>
    </Content>
  </ItemGroup>
  <ItemGroup>
    <None Include="README.md" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
  </ItemGroup>
</Project>

Once you have the package built all you need is to add a root nuget.config to fetch from the local folder like such:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="http_proxy" value="http://proxy-mtl.ubisoft.org:3128/" />
  </config>
   <packageSources>
      <!--To inherit the global NuGet package sources remove the <clear/> line below -->
      <clear />
      <add key="local" value="built_packages" />
      <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
   </packageSources>
</configuration>

then you can reference it like that in your project :

 <PackageReference Include="SkiaSharp.NETStandard">
      <Version>1.0.0</Version>
      <PrivateAssets>All</PrivateAssets>
    </PackageReference>

I can provide built package if you want, but you will need to make sure that you fullfil all shared libraries dependencies use:

ldd libskia.so`` and ``ldd libSkiasharp.so to see what's missing.

We're are in a middle of a big launch so can't really do more.

I'm having very good performance by the way on ubuntu ! :) Hope it helps

Cyril

238 Docker image and changes needed to produce a portable library that should work on most modern Linux distributions.

I am looking at what is pulled in when adding the GPU bits. It is quite a bit and maybe the experts can tell me how much of this really portable. My local build and that of the holy build box is very similar:

Holy Build Box:

linux-vdso.so.1 =>  (0x00007ffe04f5d000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f696e40f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f696e20b000)
libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f696dfce000)
libGL.so.1 => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1 (0x00007f696dd66000)
libGLU.so.1 => /usr/lib/x86_64-linux-gnu/libGLU.so.1 (0x00007f696daf8000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f696d7c2000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f696d4be000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f696d1b8000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f696cfa1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f696cbdc000)
/lib64/ld-linux-x86-64.so.2 (0x000056496cd15000)
libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f696c939000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f696c70e000)
libxcb-dri3.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri3.so.0 (0x00007f696c50b000)
libxcb-present.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-present.so.0 (0x00007f696c308000)
libxcb-sync.so.1 => /usr/lib/x86_64-linux-gnu/libxcb-sync.so.1 (0x00007f696c101000)
libxshmfence.so.1 => /usr/lib/x86_64-linux-gnu/libxshmfence.so.1 (0x00007f696beff000)
libglapi.so.0 => /usr/lib/x86_64-linux-gnu/libglapi.so.0 (0x00007f696bcd1000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f696babe000)
libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f696b8bb000)
libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f696b6b5000)
libX11-xcb.so.1 => /usr/lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007f696b4b2000)
libxcb-glx.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-glx.so.0 (0x00007f696b29b000)
libxcb-dri2.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri2.so.0 (0x00007f696b096000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f696ae76000)
libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f696ac70000)
libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0x00007f696aa62000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f696a848000)
libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f696a622000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f696a41d000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f696a217000)

Full -v: https://gist.github.com/mattleibow/f98bdd8b5a1bfc824f175a905bc48a9c

My Local Build:

linux-vdso.so.1 =>  (0x00007ffddb1c9000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0543d08000)
libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f0543acc000)
libGL.so.1 => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1 (0x00007f0543863000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f054355f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0543259000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f0543042000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0542c7d000)
/lib64/ld-linux-x86-64.so.2 (0x0000556078b83000)
libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f05429da000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f05427af000)
libxcb-dri3.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri3.so.0 (0x00007f05425ac000)
libxcb-present.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-present.so.0 (0x00007f05423a9000)
libxcb-sync.so.1 => /usr/lib/x86_64-linux-gnu/libxcb-sync.so.1 (0x00007f05421a2000)
libxshmfence.so.1 => /usr/lib/x86_64-linux-gnu/libxshmfence.so.1 (0x00007f0541fa0000)
libglapi.so.0 => /usr/lib/x86_64-linux-gnu/libglapi.so.0 (0x00007f0541d72000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f0541b5f000)
libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f054195c000)
libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f0541756000)
libX11-xcb.so.1 => /usr/lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007f0541553000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f054121e000)
libxcb-glx.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-glx.so.0 (0x00007f0541007000)
libxcb-dri2.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri2.so.0 (0x00007f0540e01000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f0540be2000)
libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f05409dc000)
libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0x00007f05407cd000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f05405c9000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f05403af000)
libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f0540189000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f053ff84000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f053fd7e000)

Full -v: https://gist.github.com/mattleibow/636ffaf7e9edf081bb08b094cdce3bea

libGL.so.1 => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1 (0x00007f696dd66000)
libGLU.so.1 => /usr/lib/x86_64-linux-gnu/libGLU.so.1 (0x00007f696daf8000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f696d7c2000)

Would be nice if X11, GL and HW acceleration would be optional/configurable while building... That would make low-powered/non-X11 targets to use it as well...

Also, about x86/32-bit builds. Is there a way to do this on a 64-bit OS? And should I even try?

The same build config and I get these errors:

/usr/bin/ld: cannot find -lfontconfig
/usr/bin/ld: cannot find -lGL
/usr/bin/ld: cannot find -lGLU
/usr/bin/ld: cannot find -lX11

It appears those packages only come with either x86 or x64 libraries, not both. Should I just use an x86 environment, or is there a clean way to do this properly?

@galvesribeiro Let me see if I can make that a nice flag that can be set...

@mattleibow just noticed one thing... HBB is x86/x64 only :(

I wonder if someone with experience in that could create the same environment using https://buildroot.org/ since it support more targets including ARM.

When building without the GPU, the requirements are far less:

linux-vdso.so.1 =>  (0x00007ffd37b96000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f459642a000)
libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f45961ee000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4595ee9000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4595be3000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f45959cd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4595607000)
/lib64/ld-linux-x86-64.so.2 (0x00005600634a7000)
libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f4595364000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f459513a000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f4594f20000)
libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f4594cfa000)

Full -v: https://gist.github.com/mattleibow/315f4150746a2163bb8fc3c883850578

Yeah... Looks a lot with the old manual build that I had the first time you were helping me build to ARM. In fact, most of those were statically linked.

If the GPU dependencies are not portable, then we can always create a totally generic build without GPU for any linux. And then for each specific distro, we could enable it. This way everyone gets skia, and some get it with GPU, and the rest can just do a local build?

@mattleibow I agree. As long as the build process is somehow simplified you just need to publish few generic releases.

Guys, you are doing it wrong. ldd will print you all dependencies, even ones that are used by libs that you depend on. Use objdump -p {lib}|grep NEEDED or lddtree.

The actual list of portable version dependencies is:

  NEEDED               libpthread.so.0
  NEEDED               libdl.so.2
  NEEDED               libfontconfig.so.1
  NEEDED               libGL.so.1
  NEEDED               libGLU.so.1
  NEEDED               libX11.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6
  NEEDED               ld-linux-x86-64.so.2

Having GPU dependencies compiled out will be nice as long as you just remove GrGLCreateNativeInterface and deps on libGL/libGLU/libX11 and keep GrContext-related stuff with GrGLAssembleGLInterface to allow user to pass the address of glGetProcAddress. That will still allow to use GPU acceleration if needed, but remove dependency on unnecessary libs.

BTW, Access to GrGLAssembleGLInterface and GrGLAssembleGLESInterface would be quite nice in general, since we need them to access EGL on Linux, see my old code: https://github.com/AvaloniaUI/libperspesk/blob/master/src/gl.cpp#L201

Nvm, solved "excessive dependencies" issue by using dlsym: https://github.com/mono/skia/pull/50/files

@kekekeks @galvesribeiro I did some more work (https://github.com/mono/skia/pull/49) to get a GL-free build of libSkiaSharp. The GLX bits are loaded at runtime, and so the only dependency is fontconfig.

The managed part, with test, is here: https://github.com/mono/SkiaSharp/pull/241

The new dependency chain:

libSkiaSharp.so.56.1.0 => native-builds/libSkiaSharp_linux/bin/x64/libSkiaSharp.so.56.1.0
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0
        ld-linux-x86-64.so.2 => /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
    libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1
        libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6
            libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1
            libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6

Looks good what's the matter with gpu ?

@Kuqd Nothing particularly. We were just trying to find a way so that we didn't link directly to the GL libraries on linux. This might reduce potential portability of the library. I am really trying to get the ultimate portable linux binary 馃槂 (I am a .NET dev at 鉂わ笍 - everything needs to be AnyCPU)

I just merged the GPU bits into master, so that should produce a nice portable binary. With GPU, but not linked to GL. At runtime it will look for libGL.so.1 and load symbols for that. If that is not available, you can do so manually using the GRGlInterface.AssembleGlInterface method -- you may get a linux build that uses DirectX 馃槣

Added a wiki to help when building on Linux:
https://github.com/mono/SkiaSharp/wiki/Building-on-Linux

@mattleibow
Are you going to use my Docker image for builds shipped with nuget package? You need to use build using distro with old glibc, you will be getting errors like /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.14' not found otherwise. So you can't use library built on Ubuntu 16.04 for Ubuntu 14.04 or another distro with older glibc. My image is based on HBB, which is based on CentOS 5 which is sufficiently old.

@kekekeks I am not sure at the moment. I need to discuss the release bits with our release engineering team. But, until we get a release out, I want to make it as easy and quick as possible to get a Linux build.

@mattleibow
CC=gcc-4.8 CXX=g++-4.8 AR=gcc-ar-4.8 NM=gcc-nm-4.8 ./bootstrapper.sh -t everything

That is great! I can use my own custom compiler for ARM. Thanks! What about the dependencies? Are all they compiled within the bootstrapper process or are they linked with the versions installed on the build machine? Also, you mentioned a flag to remove GL and HW accell, where did it goes?

Great work! :)

@galvesribeiro Everything is compiled and statically linked from the skia source. The only external dependency is fontconfig, dl and pthread. Also, currently the only project that is generated is x64. To disable ALL HW, you can change set the SUPPORT_GPU variable.

GL is already "optional" as the skia Gr* is compiled in, but not actually linked. If you try and use the GRGlInterface, it will try and find the libGL.so.1 library and use that.

I am not sure exactly what you need to change to get your ARM going, so just change what you need and let me know / send a PR and I will add those flags/toggles/options so that you can just build.

@mattleibow I guess if everything is compiled from skia source except that external dependencies, I would suggest add a parameter that we can pass a path pointing the directory of those dependencies so it would be something like this:

CC=gcc-4.8 CXX=g++-4.8 AR=gcc-ar-4.8 NM=gcc-nm-4.8 LD=ld FONTCONFIG_DIR=/my_fc_path PTHREAD_DIR=/my_pthread_path ./bootstrapper.sh -t everything

I can look at it but I'm pretty sure you are more familiar with those build systems and I would have to ask you about that anyway.

i.e. ld is usually placed along with gcc, ar, nm, so just adding a new variable like that would work and the dependencies are just a matter of point to the pre-compiled dependency.

Also, I remember that when you was helping me manually build it, there was a flag that doesn't exist on the original skia code which make it run yasm assembler for x86 that we have to remove. That would be good to add a IGNORE_YASM or something...

You can control the native build using these variables: CC, CXX, LD, LDXX, AR, NM and READELF. So you can specify the tools. Then you can control the build with CFLAGS, CXXFLAGS, LDFLAGS and LDXXFLAGS.

Ok right, then LD problem is OK. What about the external dependencies and the yasm?

For the linker, you can just use LDFLAGS. For example, they default to LDFLAGS='-lpthread -ldl -lfontconfig', but in your case you can just specify your paths & libraries. It will override the defaults. If they aren't correct, you'll just get a linker error.

The YASM, I am trying to remember what we did...

OH! So they do respect the includes and lib from the variable. Great!

For the Yasm, I remember there was an IF which was only checking the OS and not the architecture on some of the gyp files... You gave me the proper condition and I changed it... Just don't remember where it goes 馃槩

@mattleibow LDFLAGS, CFLAGS and CXXFLAGS from environment shouldn't completely override values from your Makefile, you just append your defaults to them.

Hi,

how is it going with the Linux integration? I would like to integrate Skiasharp to an application that is deployed via docker containers. Unfortunately I am not a Linux expert. Installing some dependencies to my docker container would be perfectly fine for me too.

I am a little bit lost at the moment.

@SebastianStehle you can grab Avalonia.Skia.Linux.Natives nuget package with prebuilt libSkiaSharp.so that should work for most libc based distros (Debian/Ubuntu/RHEL/CentOS)

Is there something else I have to do? I always get "Unable to load DLL 'libSkiaSharp': The specified module could not be found."

I also tried to add add the *.so file as runtimeTarget to SkiaSharp:

 "runtimes/linux-x64/native/libSkiaSharp.so": {
    "rid": "linux-x64",
    "assetType": "native"
  }

I also tested other rid, e.g. just linux But it does not work so far

1) Check that libSkiaSharp.so is deployed with your app when you run dotnet publish
2) I think, this particular version of the library needs the following:

  NEEDED               libpthread.so.0
  NEEDED               libdl.so.2
  NEEDED               libfontconfig.so.1
  NEEDED               libGL.so.1
  NEEDED               libGLU.so.1
  NEEDED               libX11.so.6
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6

Yes, it is deloyed to the following folder: "runtimes/linux-x64/native/libSkiaSharp.so", I also tested it to move the file to another folder, e.g. the root, but it does not help so far. Do you have a small example

I will check that the other libraries are there as well. I guess I would get another error, e.g. cannot open shared object file 'libGL.so.1" or so.

Check the library with ldd command it should give you the list of missing dependencies.

I guess, I need to update the package so it won't require libGL.

Hi,
I tested it with an updated docker file:

FROM microsoft/aspnetcore:1.1.1

WORKDIR /app

COPY . .

RUN apt-get update \
 && apt-get install -y --no-install-recommends libfontconfig libgl1-mesa-dev \
 && apt-get clean \

ENTRYPOINT ["dotnet", "ConsoleApp2.dll"]

Now I have all the dependencies (checked with ldd)

Before the following dependencies were missing:

libfontconfig.so.1
libGL.so.1
libGLU.so.1
libX11.so.6

I still get the same error, when I run the container (on a linux host):

System.DllNotFoundException: Unable to load DLL 'libSkiaSharp': The specified module could not be found.

I've updated the package (1.56.1.3) so it only requires libfontconfig.so.1 and you don't need x11/gl deps anymore.

Also make sure that libSkiaSharp.so has executable flag set.

Thanks for your work on this @kekekeks. I am still waiting on our release engineering team to get a nice build of SkiaSharp out. I hope building linux using the new scripts is easer than it was. As you noticed, the last version (1.56.2) had no hard dependencies on anything except fontconfig.

Right now I am in the process of updating to the m57 release of skia. This also comes with the new build system GN. A fair bit has changed with the build system, and I think for the better.

I'm using your latest scripts with slightly modified holy-build-box-based docker image from before (I had to remove built-in LDFLAGS since they override ones from your Makefile).

Unfortunately I'm can't provide a proper dockerfile, since environment setup process involves some issues with installing Mono and I was unable to get it automated.

I recommend to use the same approach, since it produces a portable binary that can run on almost all distros that matter.

I have moved forward a small step. Now I get:

    Error: assembly specified in the dependencies manifest was not found -- package: 'skiasharp', version: '1.56.2', path: 'lib/netstandard1.3/SkiaSharp.dll'

My dockerfile

    FROM microsoft/aspnetcore:1.1.1

RUN apt-get update \
 && apt-get install -y --no-install-recommends libfontconfig \
 && apt-get clean \

WORKDIR /app

COPY . .

RUN ldd runtimes/linux-x64/native/libSkiaSharp.so
RUN chmod -x runtimes/linux-x64/native/libSkiaSharp.so

ENTRYPOINT ["dotnet", "ConsoleApp2.dll"]

If I don't install libfontconfig I get the old error. Chaning the paths in deps.json does not make a difference.

I also noticed that there is a mismatch here in Skiasharp.dll:

[assembly: AssemblyVersion("1.56.0.0")]
[assembly: AssemblyFileVersion("1.56.1.0")]

Don't know if this is an issue but I also noticed some minor differences on .NET Core in Linux vs Win (often related to network stack btw.).

Error: assembly specified in the dependencies manifest was not found -- package: 'skiasharp', version: '1.56.2', path: 'lib/netstandard1.3/SkiaSharp.dll'

It seems that you are doing something wrong with publishing. Make sure, that your project has proper runtime identifier included and that you have restored deps using said identifier before running dotnet publish.

I'd also recommend to create a self-contained bundle and run it on generic debian image.

I cleaned everything, called "dotnet restore", "dotnet publish" and thats it. My csproj ist very simple as well:

  <Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Avalonia.Skia.Linux.Natives" Version="1.56.1.3" />
    <PackageReference Include="SkiaSharp" Version="1.56.1" />
  </ItemGroup>

</Project>

The published version works correctly on Windows, also on another machine.

Btw: I also tested version 1.56.1 of Skiasharp, therefore the different version numbers, but it does not change anything.

You need dotnet publish to get a somewhat portable bundle. You won't get your dependencies to the target machine otherwise.

Sorry, I was already very tired when I wrote it. I made a dotnet publish.

I suggest to either create a self-contained bundle or simply run from source. Always work for me that way.

I'm trying to figure out why cake is being used for native linux builds at all? Correct me if I'm wrong but to built a native linux library the only thing required is to build libskia and than run make within the "native-builds/libSkiaSharp_linux/" . Using dotnetcore and cake just seems over and above as to what is really needed to compile the native linux library.

@hurricanehrndz The reason for that is basically 2 reasons: I am not that clued up on make (or what the linux guys are using these days), and there are a few extra steps:

https://github.com/mono/SkiaSharp/blob/master/cake/BuildExternals.cake#L102-L105
https://github.com/mono/SkiaSharp/blob/master/cake/BuildExternals.cake#L711-L781

After working on this project, my skills have moved up a tiny bit, but I haven't had time to update the scripts. The best thing would be to actually mix all of this into the Makefile and just call make from cake. Thus, no need for any dependencies if you are just building native.

And, I will mention that the build process has improved recently - the first few versions did not use the nice gn tool, and was a bit harder to do with my very limited knowledge.

If you can go make and have the time, you can move this logic into the Makefile and send a PR. Everyone in the linux side of SkiaSharp will love you. 鉂わ笍 馃惂

Let me close this issue and open new issues with more specific tasks. As of now, linux support is available and working, just a bit rough to do.

The issue to move the build into make: https://github.com/mono/SkiaSharp/issues/311
The issue to distribute linux binaries: https://github.com/mono/SkiaSharp/issues/312

I am closing this issue as it is quite big and is really too broad an issue. If any further questions, comments or issues are for linux support, either use the above issues or just create a new issue with your comment. This way the tasks are smaller and actionable, as well as easier to consume.

Was this page helpful?
0 / 5 - 0 ratings