aboutsummaryrefslogtreecommitdiff
path: root/2026-coc/pres.typ
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2026-10-12 22:31:15 +0200
committerKarel Kočí <cynerd@email.cz>2026-10-12 22:31:15 +0200
commit1fc48dd785c6a6f2659ac4cd3c98030d1247eff6 (patch)
treea41398a3d5aa261c575cb2f88394b9ab17ffff48 /2026-coc/pres.typ
parent66741d321c38328bb4ae01baa716841afb78fc9e (diff)
downloadpresentations-master.tar.gz
presentations-master.tar.bz2
presentations-master.zip
Add presentation: 2026 Community Over Code GlasgowHEADmaster
Diffstat (limited to '2026-coc/pres.typ')
-rw-r--r--2026-coc/pres.typ485
1 files changed, 485 insertions, 0 deletions
diff --git a/2026-coc/pres.typ b/2026-coc/pres.typ
new file mode 100644
index 0000000..fbbf097
--- /dev/null
+++ b/2026-coc/pres.typ
@@ -0,0 +1,485 @@
+#import "@preview/polylux:0.4.0": *
+#import "@preview/metropolis-polylux:0.1.0" as metropolis
+
+#show: metropolis.setup
+#show: metropolis.setup.with(footer: [Firmware project with Meson build system])
+#show raw: set text(ligatures: false, features: (calt: 0))
+
+#slide[
+ #set page(header: none, footer: none, margin: 3em)
+
+ #text(size: 1.3em)[*Firmware project with Meson build system*]
+
+ Community Over Code Glasgow 2026
+
+ #metropolis.divider
+
+ #set text(size: .8em, weight: "light")
+ Karel Kočí
+
+ 13.10.2026
+]
+
+#slide[
+ = The Point
+
+ #set text(size: 0.95em)
+ POSIX gives ability to run same programs on NuttX and Linux.
+
+ Advantages:
+ - Options when selecting libraries
+ - Easier and faster testing (including CI/CD)
+ - Possibility to test with tools such as Valgrind
+
+ Workflow:
+ - Develop on PC including libraries
+ - Unit testing on PC
+ - Sw/sw integration on PC
+ - Sw/hw integration on real hardware
+
+ We need a good way to build project for both targets (for NuttX flat build).
+]
+
+#metropolis.new-section[NuttX external]
+
+#slide[
+ = Standard NuttX
+ ```
+ .
+ ├── nuttx
+ │   └── ...
+ └── apps
+ └── ...
+ ```
+ \
+ ```bash
+ cd nuttx
+ ./tools/configure.sh rv-virt:nsh
+ make
+ ```
+]
+
+#slide[
+ = External Applications and Libraries
+ ```
+ ├── nuttx
+ │   ├── external -> ../project-libs
+ │   └── ...
+ ├── apps
+ │   ├── external -> ../project-apps
+ │   └── ...
+ ├── project-libs
+ │   └── ...
+ └── project-apps
+ └── ...
+ ```
+ #text(weight: "bold")[`configure-nuttx.sh`]
+ ```bash
+ ln -sf ../project-libs nuttx/external
+ ln -sf ../project-apps apps/external
+ ```
+]
+
+#slide[
+ = Apps Directory
+
+ #text(weight: "bold")[`project-apps/Make.defs`]
+ ```make
+ include $(wildcard $(APPDIR)/external/*/Make.defs)
+ ```
+
+ #text(weight: "bold")[`project-apps/Makefile`]
+ ```make
+ MENUDESC = "Project Applications"
+ include $(APPDIR)/Directory.mk
+ ```
+]
+
+#slide[
+ = A Project App
+
+ #text(weight: "bold")[`project-apps/project_hello/Make.defs`]
+ ```make
+ CONFIGURED_APPS += $(APPDIR)/external/project_hello
+ ```
+
+ #text(weight: "bold")[`project-apps/project_hello/Makefile`]
+ ```make
+ include $(APPDIR)/Make.defs
+ PROGNAME = $(CONFIG_NUTTX_USBNSH_PROGNAME)
+ PRIORITY = $(CONFIG_NUTTX_USBNSH_PRIORITY)
+ STACKSIZE = $(CONFIG_NUTTX_USBNSH_STACKSIZE)
+ MODULE = $(CONFIG_NUTTX_USBNSH)
+ MAINSRC = project_hello_main.c
+ include $(APPDIR)/Application.mk
+ ```
+
+ #text(weight: "bold")[`project-apps/project_hello/Kconfig`] ...
+]
+
+#slide[
+ = A Project App: In More Depth
+ #text(size: 0.9em)[
+ ```make
+ all:: .built
+ context::
+ register::
+ $(call REGISTER,$(PROGNAME_$@),$(PRIORITY_$@),$(STACKSIZE_$@),$@_main)
+
+ .built: $(AROBJS)
+ $(call ARLOCK, $(call CONVERT_PATH,$(BIN)), $^)
+
+ CFLAGS += ${DEFINE_PREFIX}main=$(addsuffix _main,$(PROGSYM_$@))
+ ```
+ ]
+]
+
+#slide[
+ = External Board
+
+ ```bash
+ mkdir board
+ cp -r nuttx/boards/risc-v/qemu-rv/rv-virt/{src,include,scripts} board/
+ ```
+
+ #text(weight: "bold")[`board/defconfig`] (replace `CONFIG_ARCH_BOARD*`)
+ ```Kconfig
+ ...
+ CONFIG_ARCH_BOARD_CUSTOM=y
+ CONFIG_ARCH_BOARD_CUSTOM_DIR="../board"
+ CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y
+ CONFIG_ARCH_BOARD_CUSTOM_NAME="TEMPLATE"
+ ```
+
+ #text(weight: "bold")[`configure-nuttx.sh`]
+ ```bash
+ ...
+ cp -f board/defconfig nuttx/.config
+ make -C nuttx olddefconfig
+ ```
+]
+
+#slide[
+ = Bonus Round: Config verification
+ ```bash
+ while read -r line; do
+ [[ "$cnf" == CONFIG_* ]] || continue
+ if [[ "${line#*=}" == "n" ]]; then
+ if grep -q "^${line%=*}=(y|m)$" nuttx/.config; then
+ echo "Not correctly set: $line" >&2; exit 1
+ fi
+ else
+ if ! grep -qF "$line" nuttx/.config; then
+ echo "Not correctly set: $line" >&2; exit 1
+ fi
+ fi
+ done <"board/defconfig"
+ done
+ ```
+]
+
+#metropolis.new-section[Meson]
+
+#slide[
+ = Requirements for Build System
+ - Build libraries and applications
+ - No special rules in build system for NuttX
+ - Support for external projects with minimal NuttX boilerplate
+]
+
+#slide[
+ = Quick Overview
+
+ Leading build system for building libraries and executables for Linux.
+
+ \
+
+ #text(weight: "bold")[`meson.build`]
+ ```python
+ project('tutorial', 'c')
+ libfoo = library('foo', files('foo.c'),
+ include_directories=include_directories('.'))
+ executable('demo', files('main.c'), dependencies: [libfoo],
+ install: true)
+ ```
+ \
+
+ Outputs ninja or other build systems.
+]
+
+#slide[
+ = Compare with make and cmake
+ #text(size: 0.9em)[
+ #toolbox.side-by-side[
+ #text(weight: "bold")[Make]
+ - 🙂 Generic build system (language)
+ - 😕 Can be tweaked to build almost anything
+ - 😢 Good build systems are complex
+ - 😢 Build targets standardization old and obsolete
+ - 🫣 No standard way to set toolchain
+ - 😕 No standard way to manage build time dependencies
+ ][
+ #text(weight: "bold")[CMake]
+ - 🙂 Generic build system (language)
+ - 😕 Can be tweaked to build almost anything
+ - 😊 Has build target standardization
+ - 😢 Build target standardization is optional
+ - 😊 Toolchain.cmake
+ - 😢 Alternative ways to manage toolchain
+ - 😊 FetchContent
+ ]
+ ]
+]
+#slide[
+ = While Meson...
+ - 😊 Can build only predefined types
+ - 😊 Can't be tweaked that much
+ - 🙃 Not a complete language
+ - 😊 crossfile.ini
+ - 😍 makes it hard to not use standard way
+ - 😊 subprojects with even cmake support
+]
+
+#metropolis.new-section[Meson Integration]
+
+#slide[
+ = Two Ways
+ #toolbox.side-by-side[
+ #text(weight: "bold")[NuttX as project's library]
+
+ Use exported libraries and linker script from NuttX in any other build
+ system.
+
+ ```bash
+ make -C nuttx export
+ ```
+ ][
+ #text(weight: "bold")[Project as app in NuttX]
+
+ NuttX build system deals with Firmware build.
+
+ App integration uses our project's build system and adds results to NuttX
+ linkage.
+ ]
+]
+
+#slide[
+ = Phase 1: crossfile
+ #text(size: 0.8em)[
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ crossfile.ini: .FORCE
+ ./crossfile.sh '$(CC)' '$(AR)' '$(CFLAGS)'
+ ```
+ #text(weight: "bold")[`project-apps/meson-apps/crossfile.sh`]
+ ```bash
+ march="${3/*-march=/}"; march="${march/ */}"
+ flags_sanit() { sed -E "s#-Wshadow##;s#\"##g; s#-I #-I#g" <<<"$1" }
+ cat >crossfile.ini <<-EOF
+ [binaries]
+ c = '$1'
+ ar = '$2'
+ [built-in options]
+ c_args = [$(flags_sanit "$cflags" | sed -E "s#([^ ]+)#'\1'#g; s# +#, #g")]
+ c_link_args = ['-nostdlib', '-static', '-r']
+ [host_machine]
+ system = 'nuttx'
+ cpu_family = '${1%%-*}'
+ cpu = '${march}'
+ EOF
+ ```
+ ]
+]
+#slide[
+ = Phase 1.1: Toolchain.cmake
+ #text(weight: "bold")[`project-apps/meson-apps/crossfile.sh`]
+ ```bash
+ cat >>crossfile.ini <<-EOF
+ [properties]
+ cmake_toolchain_file = '$(pwd)/Toolchain.cmake'
+ EOF
+ cat >Toolchain.cmake <<-EOF
+ add_compile_options($(flags_sanit "$cflags"))
+ add_link_options(-nostdlib -static -r)
+ EOF
+ ```
+]
+
+#slide[
+ = Phase 2: context
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ context:: build/build.ninja
+ build/build.ninja: crossfile.ini meson-setup.sh
+ ./meson-setup.sh
+ ```
+ #text(weight: "bold")[`project-apps/meson-apps/meson-setup.sh`]
+ ```bash
+ meson setup --default-library static -Db_staticpic=false \
+ --backend ninja --cross-file crossfile.ini build ../..
+ ```
+]
+
+#slide[
+ = Phase 3: build / build.ninja.mk
+ #text(size: 0.8em)[
+ #text(weight: "bold")[`project-apps/meson-apps/meson-setup.sh`]
+ ```make
+ {
+ meson introspect --targets "build" |
+ jq -r '.[]
+ | select((.type == "static library" or .type == "executable") and .installed)
+ | .name, .filename[0], .type' |
+ while read -r name && read -r file && read -r type; do
+ target="${file#"$sdir/build/"}"
+ if [[ "$type" == "executable" ]]; then
+ echo "\$(eval \$(call EXECUTABLE,$target,$name,${name//-/_}_main))"
+ else
+ echo "\$(eval \$(call STATIC_LIBRARY,$target))"
+ fi
+ done
+ meson introspect --buildsystem-files build | jq -r '.[]' |
+ sed 's#^#build/build.ninja: #'
+ } >"build.ninja.mk"
+ ```
+ ]
+]
+
+#slide[
+ = Phase 3.1: built
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ all:: .built
+ @
+
+ .built: build.ninja.mk $(BUILDS)
+ touch $@
+ ```
+]
+
+#slide[
+ = Phase 3.2: build NINJA_TARGET
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ define NINJA_TARGET
+
+ .NOTPARALLEL: build/$(1)
+ build/$(1): build/build.ninja .FORCE
+ flock build ninja $$(if $$(V),,--quiet) -C build $(1)
+
+ endef
+ ```
+]
+
+#slide[
+ = Phase 3.3: build STATIC_LIBRARY
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ define STATIC_LIBRARY
+ BUILDS += build/$(1).built
+ LIBRARIES += build/$(1)
+ $(call NINJA_TARGET,$(1))
+ build/$(1).built: build/$(1)
+ mkdir -p build/$(1).a
+ $$(UNAR) --output build/$(1).a build/$(1)
+ cd build/$(1).a && for f in *.o; do mv "$$$$f" "$(subst $(DELIM),.,$(1))_$$f"; done
+ $$(call ARLOCK, $$(call CONVERT_PATH,$$(BIN)), build/$(1).a/*)
+ $$(call DELDIR, build/$(1).a)
+ touch $$@
+ endef
+ ```
+]
+
+#slide[
+ = Phase 3.4: libsyms
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ libsyms: $(LIBRARIES)
+ $(NM) --quiet --just-symbols --defined-only $^ | sort -u > $@
+ ```
+]
+
+#slide[
+ = Phase 3.5: register EXECUTABLE
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ define EXECUTABLE
+
+ register:: $$(BUILTIN_REGISTRY)$$(DELIM)$(2).bdat
+
+ $$(BUILTIN_REGISTRY)$$(DELIM)$(2).bdat: build/build.ninja
+ $$(call REGISTER,$(2),$$(PRIORITY),$$(STACKSIZE),$(3))
+
+ endef
+ ```
+]
+
+#slide[
+ = Phase 3.5: build EXECUTABLE
+ #text(weight: "bold")[`project-apps/meson-apps/Makefile`]
+ ```make
+ define EXECUTABLE
+ BUILDS += build/$(1).built
+ $(call NINJA_TARGET,$(1))
+ build/$(1).built: build/$(1) libsyms
+ $$(NM) --quiet --just-symbols --defined-only build/$(1) \
+ | sort -u | comm -2 - libsyms >build/$(1).syms
+ $$(OBJCOPY) --redefine-sym main=$(3) \
+ --localize-symbols=build/$(1).syms \
+ --weaken-symbols=libsyms \
+ build/$(1) build/$(1).o
+ $$(call ARLOCK, $$(call CONVERT_PATH,$$(BIN)), build/$(1).o)
+ touch $$@
+
+ ```
+]
+
+#slide[
+ #show: metropolis.focus
+
+ Demonstration
+]
+
+#slide[
+ = LTO
+ With LTO we can't modify symbols.
+
+ Workaround: add `-flinker-output=nolto-rel` to `c_link_args`
+
+ That removes LTO from linked objects objects (executables).
+
+ LTO not applied to calls from executables to libraries and nuttx.\
+ LTO is still applied to calls between libraries and from libraries to NuttX
+
+]
+
+#slide[
+ = Conclusion
+ Demonstrated possibilities:
+ - How to have project specific applications
+ - How to use off-tree board
+ - How to convince meson to build for NuttX
+ - How to merge meson built files to NuttX
+
+ All this without forking NuttX or Meson.
+
+ Actual implementation provides resiliency against parameters change compared
+ to the examples.
+]
+
+#slide[
+ #show: metropolis.focus
+ Thank you
+
+ Karel Kočí
+
+ #metropolis.divider
+
+ #text(size: 0.6em)[
+ https://gitlab.com/Cynerd/nuttx-meson-template/-/tree/master
+
+ https://gitlab.com/Cynerd/nixos-personal
+
+ https://git.cynerd.cz/presentations/tree/2026-communitycvercode
+ ]
+]