Add libxkbcommon as a submodule

This commit is contained in:
Jakub Hlusička 2026-01-11 22:37:17 +01:00
parent e69a871c2a
commit a07d13f4e8
11 changed files with 117 additions and 50 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "firmware2/libxkbcommon"]
path = firmware2/libxkbcommon
url = https://github.com/xkbcommon/libxkbcommon

View file

@ -12,6 +12,7 @@ rustflags = [
[env]
LIBXKBCOMMON_BUILD_DIR = "libxkbcommon/build"
ESP_LOG = "warn"
# This is overkill, but we can afford it.
SLINT_FONT_SIZES = "8,11,10,12,13,14,15,16,18,20,22,24,32"

1
firmware2/Cargo.lock generated
View file

@ -31,6 +31,7 @@ dependencies = [
"esp-storage",
"gix",
"i-slint-common",
"indoc",
"itertools 0.14.0",
"json",
"lazy_static",

View file

@ -85,6 +85,7 @@ embuild = "0.33"
cc = "1.2.9"
slint-build = "1.14.1"
gix = { version = "0.76.0", default-features = false, features = ["max-performance", "status"] }
indoc = "2.0.7"
[[bin]]
name = "acid-firmware"

View file

@ -4,28 +4,46 @@
### Compiling libxkbcommon
Before compiling the firmware itself, its C dependencies must be compiled separately first.
This needs to be done on Linux or in WSL.
meson.build needs to be changed such that `pkgconfig.generate` is called with the `variables` field embedded directly, for some reason:
```meson
variables: [
f'xkb_root=@XKB_CONFIG_ROOT@',
f'xkb_extra_path=@XKB_CONFIG_EXTRA_PATH@',
],
```
Then, the tests, fuzzes and benches need to be commented out.
Afterwards, the following command should succeed in building the static library in debug mode:
Download and install [`eim`, the ESP-IDF Installation Manager](github.com/espressif/idf-im-ui/releases/latest).
Enable the ESP-IDF using:
```sh
meson setup build-debug -Denable-x11=false -Dxkb-config-root=/usr/share/X11/xkb -Dx-locale-root=/usr/share/X11/locale -Denable-wayland=false --cross-file cross-esp32s3.txt -Denable-xkbregistry=false -Denable-docs=false -Denable-tools=false --wipe --buildtype=debug
meson compile -C build-debug
eim select
```
Afterwards, a static library with redefined externally-linked symbols needs to be generated:
Compile the libxkbcommon library.
```sh
./libxkbcommon-compile.sh build
```
path/to/root/libxkbcommon-redefine-syms.sh build-debug/libxkbcommon{,_redefined_syms}.a
### Compiling the firmware
To compile the firmware, run:
```ps1
cargo build --release
```
If you wish to download the firmware on the keyboard, the following command can be used:
```ps1
cargo run --release -- --port=[PORT]
```
where `[PORT]` shall be replaced by a serial port such as `COM5`.
## Building for development
The following arguments are useful to build the libxkbcommon library for debugging.
```sh
./libxkbcommon-compile.sh build-debug --buildtype=debug -Dc_args="-fdebug-prefix-map=@GLOBAL_SOURCE_ROOT@=[PATH_TO_LIBRARY_ON_WINDOWS]"
```
where `[PATH_TO_LIBRARY_ON_WINDOWS]` is the path to the libxkbcommon submodule on Windows.
This replaces the debugging symbols with paths that will be available when debugging on Windows.
Then compile the firmware with:
```ps1
$env:LIBXKBCOMMON_BUILD_DIR="libxkbcommon/build-debug"; cargo build
```
### Creating keymaps

View file

@ -1,20 +1,17 @@
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use std::path::{Path, PathBuf};
use const_gen::*;
use indoc::formatdoc;
use json::JsonValue;
use slint_build::{CompilerConfiguration, EmbedResourcesKind};
use xz2::read::XzEncoder;
fn main() {
if let Ok(repo) = gix::discover(
env::var_os("CARGO_MANIFEST_DIR")
.unwrap()
.into_string()
.unwrap(),
) {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
if let Ok(repo) = gix::discover(&manifest_dir) {
let commit_hash = repo.head_commit().unwrap().short_id().unwrap();
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", commit_hash);
println!(
@ -36,22 +33,27 @@ fn main() {
// println!("cargo:rustc-link-arg=-Tdefmt.x");
// TODO: Make it a submodule and use relative paths.
//
// 1. Tell cargo where to find the library
// let lib_path = PathBuf::from(manifest_dir).join("libs");
// println!(r#"cargo:rustc-link-search=native={}"#, lib_path.display());
println!(
r#"cargo:rustc-link-search=native=C:\Users\Limeth\workspace\c\libxkbcommon-linux\build-debug-redefined-syms"#
);
// 2. Link the static library (strip the 'lib' prefix and '.a' extension)
// Link libxkbcommon.
let libxkbcommon_build_dir = env::var("LIBXKBCOMMON_BUILD_DIR")
.expect("The build directory of libxkbcommon must be specified using the `LIBXKBCOMMON_BUILD_DIR` environment variable.");
let libxkbcommon_library_path = PathBuf::from(&libxkbcommon_build_dir).join("libxkbcommon.a");
if !libxkbcommon_library_path.is_file() {
panic!(
"{}",
formatdoc! {"
The compiled libxkbcommon library was not found at path {libxkbcommon_library_path:?}.
Most likely, the library was not compiled. See the `README.md` for compilation instructions.
If the `LIBXKBCOMMON_BUILD_DIR` environment variable is not set to the build directory you want to use, change it.
Currently, `LIBXKBCOMMON_BUILD_DIR` is set to: {libxkbcommon_build_dir}
"}
);
}
println!("cargo:rustc-link-search=native={libxkbcommon_build_dir}");
println!("cargo:rustc-link-lib=static=xkbcommon");
// 3. Re-run if build.rs or the library changes
// println!(r#"cargo:rerun-if-changed=C:\Users\Limeth\workspace\c\libxkbcommon-linux\build-debug\libxkbcommon.a"#);
println!(
r#"cargo:rerun-if-changed=C:\Users\Limeth\workspace\c\libxkbcommon-linux\build-debug-redefined-syms\libxkbcommon.a"#
);
println!("cargo:rerun-if-changed={libxkbcommon_build_dir}/libxkbcommon.a");
// Slint config and compilation
{
@ -62,7 +64,8 @@ fn main() {
// .with_scale_factor(2.0)
.with_style("cosmic-dark".to_string())
.embed_resources(EmbedResourcesKind::EmbedForSoftwareRenderer);
slint_build::compile_with_config("ui/main.slint", slint_config).expect("Slint build failed");
slint_build::compile_with_config("ui/main.slint", slint_config)
.expect("Slint build failed");
slint_build::print_rustc_flags().unwrap()
}
}

View file

@ -4,25 +4,24 @@ cpp = 'xtensa-esp32s3-elf-g++'
ar = 'xtensa-esp32s3-elf-ar'
strip = 'xtensa-esp32s3-elf-strip'
[build_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
# It seems like this is not necessary:
#[build_machine]
#system = 'linux'
#cpu_family = 'x86_64'
#cpu = 'x86_64'
#endian = 'little'
[host_machine]
system = 'bare-metal' # Crucial: prevents Meson from assuming a POSIX environment
system = 'none'
cpu_family = 'xtensa'
cpu = 'esp32s3'
endian = 'little'
[built-in options]
c_args = [
'-fdebug-prefix-map=@GLOBAL_SOURCE_ROOT@=C:/Users/Limeth/workspace/c/libxkbcommon-linux',
'-ffreestanding',
'-fno-builtin',
'-mlongcalls',
'-mfix-esp32-psram-cache-issue',
# Manually define the missing inttypes.h macros
'-DPRId64="lld"',
'-DPRIu64="llu"',
@ -35,5 +34,4 @@ c_link_args = [
'-nostdlib',
'-static'
]
# Ensure we only build static libraries for bare-metal
default_library = 'static'

@ -0,0 +1 @@
Subproject commit db1f61ca9a3a3bb05f28550227ca3419e8a22c90

View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <build-directory-name> [args-passed-to-meson-setup]..."
exit 1
fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
LIBXKBCOMMON_DIR="$SCRIPT_DIR/libxkbcommon"
BUILD_DIR_NAME="$LIBXKBCOMMON_DIR/$1"
STATIC_LIB_PATH="$BUILD_DIR_NAME/libxkbcommon.a"
SETUP_ARGS=${@:2}
git submodule update --init --recursive
pushd "$LIBXKBCOMMON_DIR" >/dev/null
meson setup "$BUILD_DIR_NAME" \
--wipe \
--cross-file "$SCRIPT_DIR/cross-esp32s3.txt" \
-Denable-x11=false \
-Denable-wayland=false \
-Denable-xkbregistry=false \
-Denable-docs=false \
-Denable-tools=false \
-Dxkb-config-root=/usr/share/X11/xkb \
-Dx-locale-root=/usr/share/X11/locale \
$SETUP_ARGS
meson compile -C "$BUILD_DIR_NAME"
$SCRIPT_DIR/libxkbcommon-redefine-syms.sh "$STATIC_LIB_PATH" "$STATIC_LIB_PATH"
popd >/dev/null
GREEN='\033[0;32m'
RESET='\033[0m'
echo -e "${GREEN}Successfully compiled libxkbcommon. Path to static library:\n$STATIC_LIB_PATH${RESET}"

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
INPUT_LIB=$1
OUTPUT_LIB=$2
PREFIX="__xkbc_"
@ -11,10 +11,14 @@ fi
echo "Redefining symbols from $INPUT_LIB into $OUTPUT_LIB..."
xtensa-esp-elf-objcopy --redefine-syms=<(
# Perform set subtraction of undefined symbols and defined symbols, to get globally undefined symbols.
comm -23 \
<(xtensa-esp-elf-nm -u "$INPUT_LIB" | awk '{print $NF}' | sort -u) \
<(xtensa-esp-elf-nm --undefined-only "$INPUT_LIB" | awk '{print $NF}' | sort -u) \
<(xtensa-esp-elf-nm --defined-only "$INPUT_LIB" | awk '{print $NF}' | sort -u) | \
# Do not prefix already prefixed symbols (idempotency)
grep -v "^${PREFIX}" | \
# Print each symbol followed by the symbol with the prefix
awk -v p="$PREFIX" '{print $1 " " p $1}'
) "$INPUT_LIB" "$OUTPUT_LIB"
echo "Done! Prefixed all externally linked symbols with $PREFIX."
echo "Prefixed all externally linked symbols in $INPUT_LIB with $PREFIX, and written the result to: $OUTPUT_LIB"

View file

@ -56,6 +56,11 @@ pub unsafe extern "C" fn __xkbc_fread(
todo!()
}
#[unsafe(no_mangle)]
unsafe extern "C" fn __xkbc_fputs(s: *const c_char, stream: *mut FILE) -> c_int {
todo!()
}
// Printing
#[unsafe(no_mangle)]