Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_018Ae69wJS7sueQMUwNxV3nX
266 lines
9.5 KiB
Makefile
266 lines
9.5 KiB
Makefile
# port.mk - Shared rules for MontaukOS ports.
|
|
#
|
|
# There are two kinds of port.
|
|
#
|
|
# NOTE: a port must set its PORT_* variables BEFORE including this file --
|
|
# the install rules are expanded at include time.
|
|
#
|
|
# LIBRARY PORTS set PORT_LIB := 1 and install headers and a static archive
|
|
# into the shared ports sysroot at $(PORT_SYSROOT):
|
|
#
|
|
# sysroot/include/... public headers
|
|
# sysroot/lib/lib<x>.a static archive
|
|
#
|
|
# Dependent ports pick these up automatically: $(PORT_CFLAGS_COMMON) already
|
|
# includes -I $(PORT_SYSROOT_INC), so a port that needs zlib just adds
|
|
# $(PORT_SYSROOT_LIB)/libz.a to its link line. A library port declares its own
|
|
# prerequisites with PORT_DEPENDS (names only, for documentation and for the
|
|
# top-level build order).
|
|
#
|
|
# APPLICATION PORTS produce an app bundle in $(OUTDIR)/apps/<name>/ containing:
|
|
#
|
|
# <name>.elf the binary
|
|
# manifest.toml launcher metadata (name, binary, icon, category)
|
|
# <icon>.svg the launcher icon
|
|
# .port marker so the OS release step can tell ports from
|
|
# in-tree apps (see MontaukOS scripts/install_apps.sh)
|
|
#
|
|
# The desktop readdirs 0:/apps/ at runtime and parses each manifest.toml, so a
|
|
# bundle dropped into the ramdisk needs no changes anywhere in the OS tree.
|
|
#
|
|
# A port Makefile sets PORT_NAME, PORT_ICON and its own sources/flags, then
|
|
# includes this file and uses $(BUNDLE_DIR) as its link target directory.
|
|
|
|
MAKEFLAGS += -rR
|
|
.SUFFIXES:
|
|
|
|
# This file defines rules before the including Makefile does, so pin the
|
|
# default goal rather than letting the first bundle rule claim it.
|
|
.DEFAULT_GOAL := all
|
|
|
|
# ==== Repo root =======================================================
|
|
# Derived from this file's own location so a port builds the same whether it
|
|
# is invoked from the top-level Makefile or directly with `make -C <cat>/<port>`,
|
|
# and regardless of how deeply categories nest it.
|
|
|
|
PORT_MK_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
|
|
MTKPORTS_ROOT := $(abspath $(PORT_MK_DIR)/..)
|
|
|
|
# ==== SDK location ====================================================
|
|
# Ports build against a live MontaukOS checkout rather than a copied
|
|
# sysroot, so libc/header changes are picked up without a sync step.
|
|
|
|
MONTAUKOS ?= $(HOME)/dev/MontaukOS
|
|
|
|
ifeq ($(wildcard $(MONTAUKOS)/programs/link.ld),)
|
|
$(error MontaukOS tree not found at $(MONTAUKOS). Pass MONTAUKOS=/path/to/MontaukOS)
|
|
endif
|
|
|
|
# ==== Toolchain =======================================================
|
|
|
|
TOOLCHAIN_PREFIX := $(MONTAUKOS)/toolchain/local/bin/x86_64-montauk-
|
|
|
|
ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
|
$(error x86_64-montauk toolchain not found. Run $(MONTAUKOS)/toolchain/build-montauk-toolchain.sh first)
|
|
endif
|
|
|
|
CC := $(TOOLCHAIN_PREFIX)gcc
|
|
CXX := $(TOOLCHAIN_PREFIX)g++
|
|
AR := $(TOOLCHAIN_PREFIX)ar
|
|
LD := $(TOOLCHAIN_PREFIX)gcc
|
|
|
|
# ==== SDK paths =======================================================
|
|
|
|
SDK_INC := $(MONTAUKOS)/programs/include
|
|
SDK_LIBC_INC:= $(MONTAUKOS)/programs/include/libc
|
|
SDK_LIB := $(MONTAUKOS)/programs/lib
|
|
SDK_LINK_LD := $(MONTAUKOS)/programs/link.ld
|
|
|
|
LIBC_A := $(SDK_LIB)/libc/liblibc.a
|
|
LIBLOADER_A := $(SDK_LIB)/libloader/liblibloader.a
|
|
LIBTLS_A := $(SDK_LIB)/tls/libtls.a
|
|
LIBBEARSSL_A:= $(SDK_LIB)/bearssl/libbearssl.a
|
|
LIBJPEG_A := $(SDK_LIB)/libjpeg/libjpeg.a
|
|
|
|
# The kernel ABI version this port is being built against. Recorded in the
|
|
# bundle so a stale port can be spotted after a syscall/ABI bump rather than
|
|
# crashing mysteriously at runtime.
|
|
SDK_API_VERSION := $(shell sed -n 's/.*apiVersion = \([0-9]\+\);.*/\1/p' \
|
|
$(MONTAUKOS)/kernel/src/Api/Info.hpp 2>/dev/null | head -1)
|
|
|
|
# ==== Output ==========================================================
|
|
|
|
OUTDIR ?= $(MTKPORTS_ROOT)/out
|
|
OBJDIR ?= obj
|
|
|
|
# Shared sysroot that library ports install into and every port compiles
|
|
# against. Kept separate from the MontaukOS SDK so `make clean` here never
|
|
# touches the OS tree.
|
|
PORT_SYSROOT ?= $(MTKPORTS_ROOT)/sysroot
|
|
PORT_SYSROOT_INC := $(PORT_SYSROOT)/include
|
|
PORT_SYSROOT_LIB := $(PORT_SYSROOT)/lib
|
|
|
|
BUNDLE_DIR := $(OUTDIR)/apps/$(PORT_NAME)
|
|
TARGET := $(BUNDLE_DIR)/$(PORT_NAME).elf
|
|
|
|
# ==== Common flags ====================================================
|
|
# Mirrors the in-tree convention: freestanding, no stdlib, linked with the
|
|
# shared program link script.
|
|
|
|
PORT_CFLAGS_COMMON := \
|
|
-g -O2 -pipe \
|
|
-ffreestanding \
|
|
-fno-stack-protector \
|
|
-fno-stack-check \
|
|
-ffunction-sections \
|
|
-fdata-sections \
|
|
-msse \
|
|
-msse2 \
|
|
-isystem $(SDK_LIBC_INC) \
|
|
-I $(SDK_INC) \
|
|
-I $(PORT_SYSROOT_INC)
|
|
|
|
PORT_LDFLAGS_COMMON := \
|
|
-nostdlib \
|
|
-Wl,--gc-sections \
|
|
-T $(SDK_LINK_LD)
|
|
|
|
# ==== NetSurf library ports ===========================================
|
|
# NetSurf's libraries share one buildsystem (dev-util/netsurf-buildsystem)
|
|
# and all build the same way, so the invocation lives here rather than being
|
|
# copied into each port.
|
|
#
|
|
# It cross-compiles for x86_64-montauk unpatched: HOST is auto-detected from
|
|
# `$(CC) -dumpmachine`, and BUILD != HOST puts it in cross mode. CC/AR must be
|
|
# passed on the command line (their `origin ... default` checks skip them
|
|
# otherwise), while CFLAGS must go through the ENVIRONMENT -- their makefiles
|
|
# do `CFLAGS := -I... $(CFLAGS)`, and a command-line CFLAGS would override
|
|
# that assignment outright and drop their own include paths.
|
|
|
|
NS_BUILDSYSTEM := $(MTKPORTS_ROOT)/dev-util/netsurf-buildsystem/upstream
|
|
NS_BUILDDIR := build-montauk
|
|
|
|
NS_CFLAGS := \
|
|
-ffreestanding \
|
|
-fno-stack-protector \
|
|
-fno-stack-check \
|
|
-msse \
|
|
-msse2 \
|
|
-isystem $(SDK_LIBC_INC) \
|
|
-I $(SDK_INC) \
|
|
-I $(PORT_SYSROOT_INC)
|
|
|
|
NS_MAKE_ARGS := \
|
|
NSSHARED=$(NS_BUILDSYSTEM) \
|
|
CC=$(CC) \
|
|
AR=$(AR) \
|
|
COMPONENT_TYPE=lib-static \
|
|
BUILDDIR=$(NS_BUILDDIR) \
|
|
WANT_TEST=no
|
|
|
|
# MAKEFLAGS must be cleared for the sub-make. This file sets `-rR`, which
|
|
# disables built-in variables, and their buildsystem probes those with
|
|
# `ifeq ($(origin RM),default)` style tests -- under -rR the origin is
|
|
# "undefined" instead, so RM/ARFLAGS silently expand to nothing and the
|
|
# archive rule tries to *execute* the .a file (exit 127).
|
|
NS_MAKE := MAKEFLAGS= $(MAKE)
|
|
|
|
# Their makefiles resolve dependencies through pkg-config, so point it at the
|
|
# ports sysroot (prepended, so host packages still resolve for host tools).
|
|
# PYTHON is forced to python3: libcss's codegen invokes $(PYTHON), and this
|
|
# host has no bare `python`.
|
|
NS_ENV := \
|
|
PKG_CONFIG_PATH="$(PORT_SYSROOT_LIB)/pkgconfig:$$PKG_CONFIG_PATH" \
|
|
PYTHON=python3
|
|
|
|
# Build a NetSurf library in $(1) (its checkout dir) and copy the archive to
|
|
# $(PORT_ARCHIVE). Usage in a recipe: $(call ns_build,upstream,wapcaplet)
|
|
# A port may add its own flags by setting NS_CFLAGS_EXTRA (expanded at call
|
|
# time, so it can be set after this file is included).
|
|
ns_build = \
|
|
CFLAGS="$(NS_CFLAGS) $(NS_CFLAGS_EXTRA)" $(NS_ENV) \
|
|
$(NS_MAKE) -C $(1) $(NS_MAKE_ARGS) $(NS_MAKE_ARGS_EXTRA) && \
|
|
cp $(1)/$(NS_BUILDDIR)/lib$(2).a $(PORT_ARCHIVE)
|
|
|
|
ns_clean = $(NS_ENV) $(NS_MAKE) -C $(1) $(NS_MAKE_ARGS) clean >/dev/null 2>&1 || true
|
|
|
|
ifeq ($(PORT_LIB),1)
|
|
|
|
# ==== Library ports ===================================================
|
|
# The port builds $(PORT_ARCHIVE) and lists its public headers in
|
|
# $(PORT_HEADERS); port.mk installs both into the shared sysroot. Headers
|
|
# keep any subdirectory they are named with (e.g. parserutils/parserutils.h
|
|
# installs to sysroot/include/parserutils/parserutils.h), so set
|
|
# PORT_HEADER_ROOT to the directory those paths are relative to.
|
|
|
|
PORT_HEADER_ROOT ?= include
|
|
|
|
INSTALLED_LIB := $(PORT_SYSROOT_LIB)/$(notdir $(PORT_ARCHIVE))
|
|
INSTALLED_HEADERS := $(patsubst $(PORT_HEADER_ROOT)/%,$(PORT_SYSROOT_INC)/%,$(PORT_HEADERS))
|
|
|
|
$(INSTALLED_LIB): $(PORT_ARCHIVE)
|
|
@mkdir -p $(dir $@)
|
|
cp $< $@
|
|
|
|
$(PORT_SYSROOT_INC)/%: $(PORT_HEADER_ROOT)/%
|
|
@mkdir -p $(dir $@)
|
|
cp $< $@
|
|
|
|
# Optional pkg-config file. NetSurf libraries locate their dependencies with
|
|
# pkg-config (REQUIRED_PKGS), so a library that others depend on must publish
|
|
# one into the sysroot or those builds fail to find it. Their .pc.in files use
|
|
# literal PREFIX/LIBDIR/INCLUDEDIR/VERSION placeholders, substituted here the
|
|
# same way their install step would.
|
|
ifneq ($(PORT_PC_IN),)
|
|
INSTALLED_PC := $(PORT_SYSROOT_LIB)/pkgconfig/$(PORT_NAME).pc
|
|
|
|
$(INSTALLED_PC): $(PORT_PC_IN) Makefile
|
|
@mkdir -p $(dir $@)
|
|
sed -e 's|PREFIX|$(PORT_SYSROOT)|' \
|
|
-e 's|LIBDIR|lib|' \
|
|
-e 's|INCLUDEDIR|include|' \
|
|
-e 's|VERSION|$(PORT_PC_VERSION)|' $< > $@
|
|
endif
|
|
|
|
.PHONY: install-lib
|
|
install-lib: $(INSTALLED_LIB) $(INSTALLED_HEADERS) $(INSTALLED_PC)
|
|
@echo "installed lib: $(PORT_NAME) -> $(PORT_SYSROOT)"
|
|
|
|
.PHONY: clean-lib
|
|
clean-lib:
|
|
rm -rf $(OBJDIR) $(PORT_ARCHIVE) $(INSTALLED_LIB) $(INSTALLED_HEADERS) $(INSTALLED_PC)
|
|
|
|
else
|
|
|
|
# ==== Bundle assembly =================================================
|
|
# Ports depend on $(BUNDLE_FILES) to get manifest + icon + marker staged
|
|
# alongside the ELF their link rule produces.
|
|
|
|
BUNDLE_FILES := $(BUNDLE_DIR)/manifest.toml $(BUNDLE_DIR)/.port
|
|
ifneq ($(PORT_ICON),)
|
|
BUNDLE_FILES += $(BUNDLE_DIR)/$(PORT_ICON)
|
|
endif
|
|
|
|
$(BUNDLE_DIR)/manifest.toml: manifest.toml | $(BUNDLE_DIR)
|
|
cp $< $@
|
|
|
|
$(BUNDLE_DIR)/$(PORT_ICON): $(PORT_ICON) | $(BUNDLE_DIR)
|
|
cp $< $@
|
|
|
|
# Marker file consumed by the MontaukOS release step to prune ports from a
|
|
# base ISO. Carries the ABI version so mismatches are diagnosable.
|
|
$(BUNDLE_DIR)/.port: Makefile | $(BUNDLE_DIR)
|
|
printf 'port = "%s"\napi_version = "%s"\n' '$(PORT_NAME)' '$(SDK_API_VERSION)' > $@
|
|
|
|
$(BUNDLE_DIR):
|
|
mkdir -p $@
|
|
|
|
.PHONY: bundle
|
|
bundle: $(TARGET) $(BUNDLE_FILES)
|
|
|
|
.PHONY: clean-bundle
|
|
clean-bundle:
|
|
rm -rf $(OBJDIR) $(BUNDLE_DIR)
|
|
|
|
endif
|