Files

438 lines
8.5 KiB
Markdown

# racket-audio-native-libs
Native library distribution repository for `racket-audio`.
This repository contains the platform-specific native libraries used by
`racket-audio`. It uses one Git branch per published Racket package.
The `main` branch contains the build and maintenance files. The other branches
contain the actual Racket packages that are registered in the Racket Package
Index.
## Branch structure
The repository uses the following branches:
```text
main
native-libs
x86_64-win32
x86_64-linux
aarch64-linux
aarch64-macosx
```
Their purpose is:
```text
main
Build scripts, documentation and maintenance files.
native-libs
Meta-package: racket-audio-native-libs.
Selects the correct platform package.
x86_64-win32
Native libraries for 64-bit Windows.
x86_64-linux
Native libraries for 64-bit Intel/AMD Linux.
aarch64-linux
Native libraries for 64-bit ARM Linux, for example a 64-bit Raspberry Pi.
aarch64-macosx
Native libraries for Apple Silicon macOS, for example an M1 Mac.
```
Each platform branch is a separate Racket package.
## Package names
The intended Racket package names are:
```text
racket-audio-native-libs
racket-audio-x86_64-win32
racket-audio-x86_64-linux
racket-audio-aarch64-linux
racket-audio-aarch64-macosx
```
`racket-audio` itself should depend on:
```text
racket-audio-native-libs
```
The `racket-audio-native-libs` package then selects the correct platform
package.
This keeps the Racket code in `racket-audio` independent of the operating
system and architecture.
## Native package layout
A platform branch contains the native libraries directly in the root of the
branch, together with `info.rkt`.
For example, the `x86_64-win32` branch may look like:
```text
info.rkt
portaudio.dll
libsndfile-1.dll
libmpg123-0.dll
...
```
The exact DLL names depend on the libraries used by `racket-audio`.
The corresponding `info.rkt` uses `copy-foreign-libs`:
```racket
#lang info
(define collection 'multi)
(define version "0.1.0")
(define pkg-desc
"native libraries for \"racket-audio\" on \"x86_64-win32\"")
(define pkg-authors
'(hans))
(define install-platform
"win32\\x86_64")
(define copy-foreign-libs
'("portaudio.dll"
"libsndfile-1.dll"))
(define deps
'("base"))
```
Every native library that must be installed with the package must be listed in
`copy-foreign-libs`.
This also includes DLLs, shared objects or dylibs that are runtime dependencies
of the primary audio libraries.
During package setup, Racket copies these files to a location that can be found
by `ffi-lib`.
## Meta-package
The `native-libs` branch contains the package:
```text
racket-audio-native-libs
```
It contains no native libraries itself.
Its `info.rkt` selects the correct package based on the current Racket
platform.
Conceptually:
```text
racket-audio
|
+-- racket-audio-native-libs
|
+-- racket-audio-x86_64-win32
+-- racket-audio-x86_64-linux
+-- racket-audio-aarch64-linux
+-- racket-audio-aarch64-macosx
```
Only the package matching the current platform is installed.
## Use from racket-audio
The `racket-audio` package should declare `racket-audio-native-libs` as a
dependency in its `info.rkt`.
For example:
```racket
(define deps
'("base"
"racket-audio-native-libs"))
```
The FFI code should preferably load libraries by their logical name instead of
using machine-specific absolute paths.
For example:
```racket
(ffi-lib "portaudio")
```
rather than:
```racket
(ffi-lib "C:\\some\\local\\directory\\portaudio.dll")
```
The native package is responsible for installing the actual library for the
current platform.
## Development workflow
Development and package preparation take place on `main`.
The platform branches should contain only the files required for the published
Racket package.
A typical Windows workflow is:
```text
main
|
| prepare/test Windows DLL package
v
x86_64-win32
|
| commit + push
v
Racket Package Index
```
The same approach can later be used for Linux, Raspberry Pi and macOS.
## Adding or updating a Windows package
Start on `main`:
```bash
git switch main
git pull
```
Prepare or collect the required 64-bit Windows DLL files.
Before publishing, verify that all runtime dependencies are included.
Then switch to the platform branch:
```bash
git switch x86_64-win32
```
Update:
```text
info.rkt
*.dll
```
Make sure `copy-foreign-libs` contains every DLL that belongs to the package.
Commit and push:
```bash
git add info.rkt *.dll
git commit -m "Update Windows native libraries"
git push
```
## Adding or updating Linux x86_64
Use:
```bash
git switch x86_64-linux
```
The branch will normally contain:
```text
info.rkt
*.so
*.so.*
```
Include all shared libraries required at runtime.
After testing:
```bash
git add .
git commit -m "Update Linux x86_64 native libraries"
git push
```
## Adding or updating Raspberry Pi / Linux ARM64
For a Raspberry Pi running a 64-bit operating system and 64-bit Racket, use:
```bash
git switch aarch64-linux
```
This package is intended for:
```text
aarch64-linux
```
Build the libraries natively on the Raspberry Pi where practical.
After testing:
```bash
git add .
git commit -m "Update Linux ARM64 native libraries"
git push
```
## Adding or updating Apple Silicon macOS
For an Apple Silicon Mac, such as an M1 Mac, use:
```bash
git switch aarch64-macosx
```
The branch normally contains:
```text
info.rkt
*.dylib
```
Build and test the libraries on the Apple Silicon target machine.
After testing:
```bash
git add .
git commit -m "Update Apple Silicon native libraries"
git push
```
## Testing a platform package locally
Before registering or updating a package in the Racket Package Index, install
the platform branch locally and verify that `racket-audio` can load and use the
libraries.
For example, from a checkout of the platform branch:
```bash
raco pkg install --auto .
```
After changing an already installed package, use the normal Racket package
update/reinstall workflow as appropriate.
The important test is that the existing FFI code can load the libraries without
using local absolute paths.
## Racket Package Index
Each published branch is registered as a separate Racket package.
The source URL can point directly to the corresponding Git branch.
Conceptually:
```text
racket-audio-native-libs
<repository-url>#native-libs
racket-audio-x86_64-win32
<repository-url>#x86_64-win32
racket-audio-x86_64-linux
<repository-url>#x86_64-linux
racket-audio-aarch64-linux
<repository-url>#aarch64-linux
racket-audio-aarch64-macosx
<repository-url>#aarch64-macosx
```
The Racket Package Index therefore does not need a separate manually uploaded
ZIP file. The Git branch itself is the package source.
## Initial branch publication
If the branches exist locally but not yet on `origin`, publish them with:
```bash
git push -u origin native-libs
git push -u origin x86_64-win32
git push -u origin x86_64-linux
git push -u origin aarch64-linux
git push -u origin aarch64-macosx
```
After that, a normal:
```bash
git push
```
is sufficient when working on a branch that has its upstream configured.
## Build automation
The first goal is to make the packaging work reliably using already available
native libraries.
After that, `main` can grow into a build orchestrator using Racket itself.
The intended direction is:
```text
Windows machine
-> build x86_64-win32
Linux x86_64 machine
-> build x86_64-linux
Raspberry Pi 64-bit
-> build aarch64-linux
Apple Silicon Mac
-> build aarch64-macosx
```
The build orchestration can use `racket-makefile`, the Racket `git` module and,
for remote targets, SSH or another small remote-execution layer.
The native libraries should preferably be built on the target architecture
instead of cross-compiled, unless there is a good reason to do otherwise.
## Versioning
The version in each platform package should correspond to the native library
set delivered by that branch.
When changing the packaged native libraries, update the package version where
appropriate and keep the meta-package dependency versions compatible.
## Licenses
Native libraries may have licenses that differ from the license of the Racket
wrapper.
Before publishing a new library or version, verify:
```text
- the upstream license;
- whether binary redistribution is permitted;
- whether license or copyright files must be included;
- whether additional runtime libraries have separate license requirements.
```
Do not assume that the license of `racket-audio` automatically covers the
native binaries.