Making native library builds more consistent with GitHub Actions
When we first started building C# libraries that relied on native libraries to do their function, we tried to make this goal stand still: maintaining cross platform support across all popular architectures, such as AMD64 and ARM64. For consistency, we wanted to bundle the native libraries that we built to a single NuGet package, just like all other NuGet packages that packaged their native libraries.
However, our method of relying on different mechanisms, such as using GitHub Actions for building on one platform and using our virtual machines for building on others was wrong, because we didn’t create isolated build environments to be able to successfully reproduce builds of the native libraries. As a result, we had to often mix and match dependencies to get things to go smoothly, which resulted in more wasted time.
It was at the time that GitHub Actions didn’t support Windows ARM64. However, we’re relieved to see that GitHub have added a new GitHub-hosted runner for Windows 11 ARM64 and Ubuntu 24.04 ARM64, alongside the macOS ARM64 runners!
So, we’ve decided to re-evaluate our approach of building those native libraries so that we’d save time, considering the resource constraints that we currently have, by taking those runners into account. As a result, six workflow files were added to the library repository. Here, we’ll be talking about BassBoom.Basolia and how it managed to use mpg123 v1.33.3.
The following workflow files were added:
- build-mpg123-linux-amd64.yml
- build-mpg123-linux-arm64.yml
- build-mpg123-mac-amd64.yml
- build-mpg123-mac-arm64.yml
- build-mpg123-windows-amd64.yml
- build-mpg123-windows-arm64.yml
We’ve adjusted the workflow files to point to the correct commands to build the native library. For example, on the Ubuntu workflow, we’ve added commands that installed build dependencies of mpg123 according to the Debian package control file.
- name: Setting up environment run: | sudo apt update sudo apt install libasound2-dev libaudio-dev libjack-dev libltdl-dev libopenal-dev libpulse-dev pkgconf portaudio19-devThen, we’ve changed the link to the archive file of the MPG123 source code to point to version v1.33.3 as follows:
- name: Setting up MPG123 library run: | curl -o mpg123.tar.bz2 https://www.mpg123.de/download/mpg123-1.33.3.tar.bz2 tar xvf mpg123.tar.bz2Afterwards, we’ve added the parameters to the ./configure command to disable building the application, while only building the relevant libraries that BassBoom uses, to save time. We’ve also added a new command, make install DESTDIR=$PWD/outlib, to group the artifacts together in one folder that is to be uploaded to the action workflow artifacts.
Once done, the resulting ZIP file is then manually downloaded, and the resulting library files are placed to the appropriate directories. For example, we extract libmpg123.so and libout123.so files from /usr/local/lib in the archive to the public/BassBoom.Native/runtimes/linux-x64/native folder. Afterwards, the out123 modules are then copied from /usr/local/lib/mpg123 to the plugins folder underneath the abovementioned native folder.
We’ve done something almost similar to the macOS workflows, except that the dynamic link libraries are under the .dylib extension instead of the .so extension that FreeBSD uses.
However, in Windows, we had to do something different to build the library. In order to do this, we had leveraged the MinGW development environment with CLANGARM64 for ARM64 builds (in the ARM64 workflow) and MINGW64 for AMD64 builds (in the AMD64 workflow) under the MSYS2 environment. This was done to avoid cross-compiling the ARM64 version in the AMD64 environment, thus reducing the failure rate.
The following was done for AMD64:
- name: Setting up environment uses: msys2/setup-msys2@v2 with: msystem: MINGW64 update: true install: | base-devel mingw-w64-x86_64-gcc mingw-w64-x86_64-make autoconf automake libtool tar bzip2The following was done for ARM64:
- name: Setting up environment uses: msys2/setup-msys2@v2 with: msystem: CLANGARM64 update: true install: | base-devel mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-make autoconf automake libtool tar bzip2Then, after downloading the archive file for the source code of the MPG123 libraries and extracting it under the MSYS2 shell, we’ve run the compilation of the library as follows:
- name: MPG123 compilation shell: msys2 {0} run: | cd mpg123-1.33.3 ; ./configure --prefix=/mingw64 --disable-components --enable-libmpg123 --enable-libout123 --enable-libout123-modules --with-default-audio=win32 CFLAGS="-O2 -D__USE_MINGW_ANSI_STDIO=0" ; make ; make install DESTDIR=$PWD/outlib cp /mingw64/bin/libgcc_s_seh-1.dll outlib/ || true cp /mingw64/bin/libwinpthread-1.dll outlib/ || trueWe’ve selected the win32 audio driver as the default, enabled the optimization level 2 to generate optimized code, and disabled ANSI for stdio, as per the C compiler flags. Afterwards, the two dependencies, libgcc_s_seh-1.dll and libwinpthread-1.dll, have been copied to the artifacts folder, as specified above.
We had to do the same thing for ARM64:
- name: MPG123 compilation shell: msys2 {0} run: | export lt_cv_deplibs_check_method=pass_all cd mpg123-1.33.3 ; ./configure --prefix=/clangarm64 --disable-components --enable-libmpg123 --enable-libout123 --enable-libout123-modules --with-default-audio=win32 CFLAGS="-O2 -D__USE_MINGW_ANSI_STDIO=0" ; make ; make install DESTDIR=$PWD/outlib cp /clangarm64/bin/libunwind.dll outlib/ || true cp /clangarm64/bin/libc++.dll outlib/ || trueThe difference was that we had added an export for the environment variable, called lt_cv_deplibs_check_method, with the value of pass_all, because building MPG123 in a CLANGARM64 environment within the ARM64 runner would yield messages like this:
This environment variable tells libtool to trust all system libraries, such as winmm and ole32, to mitigate this issue and to let the build system generate DLL files for the ARM64 installation. As a result, we now have DLLs in the /clangarm64/bin folder (/mingw64/bin for AMD64), and the out123 modules are located in the /clangarm64/lib/mpg123 folder (/mingw64/lib/mpg123 for AMD64). After that, they’re extracted to their appropriate places in the runtime folder of the managed library, BassBoom.Native.
For Windows, we have to rename the generated library DLL file name to mpg123.dll and out123.dll, as per the initializer source code. Afterwards, BassBoom.Native can load the updated libraries and make use of them in BassBoom.Basolia.
As a result, we have managed to achieve consistency in building the native library for BassBoom, Magico, and SpecProbe, all of which have been updated in order to update those libraries to their latest versions.
Photo by Nicole Wolf on Unsplash
#C #github #GitHubActions #NativeLibraries #NativeLibrary #news #PInvoke #Tech #Technology #update

