diff options
Diffstat (limited to 'contrib/bmake/mk/rust.mk')
-rw-r--r-- | contrib/bmake/mk/rust.mk | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/contrib/bmake/mk/rust.mk b/contrib/bmake/mk/rust.mk new file mode 100644 index 000000000000..5fc340239c30 --- /dev/null +++ b/contrib/bmake/mk/rust.mk @@ -0,0 +1,203 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# RCSid: +# $Id: rust.mk,v 1.37 2025/01/11 03:17:36 sjg Exp $ +# +# @(#) Copyright (c) 2024, Simon J. Gerraty +# +# This file is provided in the hope that it will +# be of use. There is absolutely NO WARRANTY. +# Permission to copy, redistribute or otherwise +# use this file is hereby granted provided that +# the above copyright notice and this notice are +# left intact. +# +# Please send copies of changes and bug-fixes to: +# sjg@crufty.net +# + +## +# This makefile is used when a build includes one or more Rust projects. +# +# We first include local.rust.mk to allow for customization. +# You can get very fancy - the logic/functionality here is minimal but +# can be extended via local.rust.mk +# +# If RUST_PROJECT_DIR (where we find Cargo.toml) is not set, we will +# make it ${.CURDIR:C,/src.*,,} actually we use +# ${SRCTOP}/${RELDIR:C,/src.*,,} to ensure we don't confuse ${SRCTOP} +# with ${RUST_PROJECT_DIR}/src. +# +# If ${.OBJDIR} is not ${.CURDIR} we will default CARGO_TARGET_DIR +# to ${.OBJDIR}. +# +# First, if ${.CURDIR} is a subdir of ${RUST_PROJECT_DIR} (will happen +# if an Emacs user does 'M-x compile' while visiting a src file) we +# will need to adjust ${.OBJDIR} (and hence CARGO_TARGET_DIR). +# +# We assume that RUST_CARGO will be used to build Rust projects, +# so we default RUST_CARGO_PROJECT_DIR to ${RUST_PROJECT_DIR} and +# provide a _CARGO_USE that we automatically associate with +# targets named 'cargo.*' the default is 'cargo.build'. +# +# _CARGO_USE will chdir to ${RUST_CARGO_PROJECT_DIR} and run +# ${RUST_CARGO} with ENV, FLAGS and ARGS variables derived from +# ${.TARGET:E:tu} so in the case of 'cargo.build' we get: +# RUST_CARGO_BUILD_ENV, RUST_CARGO_BUILD_FLAGS and RUST_CARGO_BUILD_ARGS +# +# _CARGO_USE will "just work" for additional targets like +# 'cargo.test', 'cargo.clippy', ... which will run '${RUST_CARGO} test', +# '${RUST_CARGO} clippy' etc. +# +# If MK_META_MODE is "yes" 'cargo.build' will touch ${.TARGET} +# so the default make rules will not consider it always out-of-date. +# In META MODE, 'bmake' will know if anything changed that should +# cause the target to be re-built. +# +# If MK_STAGING_RUST is "yes" we will stage the binary we +# built to a suitable location under ${STAGE_OBJTOP}. +# + +all: +.MAIN: all + +# allow for customization +.-include <local.rust.mk> + +RUST_CARGO ?= cargo +RUSTC ?= rustc +.if ${.CURDIR} == ${SRCTOP} +RELDIR ?= . +.else +RELDIR ?= ${.CURDIR:S,${SRCTOP}/,,} +.endif +.if empty(RUST_PROJECT_DIR) +# we want this set correctly from anywhere within +# using RELDIR avoids confusing ${SRCTOP} with ${RUST_PROJECT_DIR}/src +RUST_PROJECT_DIR := ${SRCTOP}/${RELDIR:C,/src.*,,} +.if ${RUST_PROJECT_DIR:T:Nsrc:N.} == "" +RUST_PROJECT_DIR := ${RUST_PROJECT_DIR:H} +.endif +.endif + +.if ${.OBJDIR} != ${.CURDIR} +.if ${.CURDIR:M${RUST_PROJECT_DIR}/*} != "" +# Our .CURDIR is below RUST_PROJECT_DIR and thus our +# .OBJDIR is likely not what we want either. +# This can easily happen if in Emacs we do 'M-x compile' while +# visiting a src file. +# It is easily fixed. +__objdir := ${.OBJDIR:S,${.CURDIR:S,${RUST_PROJECT_DIR},,},,} +.OBJDIR: ${__objdir} +.endif +# tell cargo where to drop build artifacts +CARGO_TARGET_DIR ?= ${.OBJDIR} +.if !empty(OBJROOT) && exists(${OBJROOT}) +CARGO_HOME_RELDIR ?= rust/cargo_home +CARGO_HOME ?= ${OBJROOT}/common/${RUST_CARGO_HOME_RELDIR} +.endif +.elif ${.CURDIR} != ${RUST_PROJECT_DIR} +.OBJDIR: ${RUST_PROJECT_DIR} +.endif +CARGO_TARGET_DIR ?= target + +.if ${MK_DIRDEPS_BUILD:Uno} == "no" || ${.MAKE.LEVEL} > 0 +.export CARGO_HOME CARGO_TARGET_DIR RUST_PROJECT_DIR RUSTC + +all: cargo.build + +.if empty(RUST_PROJECT_FILES) +RUST_PROJECT_FILES != find ${RUST_PROJECT_DIR} -type f \( \ + -name '*.rs' -o \ + -name Cargo.lock -o \ + -name Cargo.toml \) | sort +.endif +RUST_CARGO_BUILD_DEPS += ${RUST_PROJECT_FILES:U} +.endif + +RUST_CARGO_PROJECT_DIR ?= ${RUST_PROJECT_DIR} + +.if ${RUSTC:M/*} +# make sure we find all the other toolchain bits in the same place +RUST_CARGO_ENV += PATH=${RUSTC:H}:${PATH} + +# cargo clippy needs extra help finding the sysroot +# https://github.com/rust-lang/rust-clippy/issues/3523 +RUST_CARGO_CLIPPY_ENV += RUSTC_SYSROOT=${${RUSTC} --print sysroot:L:sh} +.endif + +.if ${LDFLAGS:U:M-[BL]*} != "" +# we may need to tell rustc where to find the native libs needed +# rustc documents a space after -L so put it back +RUST_LDFLAGS := ${LDFLAGS:C/(-[BL]) /\1/gW:M-[BL]*:S/-L/& /:S/-B/-C link-arg=&/} +.endif +.if !empty(RUST_LDFLAGS) +RUSTFLAGS += ${RUST_LDFLAGS} +.endif +.if !empty(RUSTFLAGS) +RUST_CARGO_BUILD_ENV += RUSTFLAGS="${RUSTFLAGS}" +.endif + +_CARGO_USE: .USEBEFORE + @(cd ${RUST_CARGO_PROJECT_DIR} && ${RUST_CARGO_ENV} \ + ${RUST_CARGO_${.TARGET:E:tu}_ENV} \ + ${RUST_CARGO} ${RUST_CARGO_${.TARGET:E:tu}_FLAGS:U${RUST_CARGO_FLAGS}} \ + ${.TARGET:E} ${RUST_CARGO_${.TARGET:E:tu}_ARGS}) + +RUST_CARGO_TARGETS += cargo.build +cargo.build: ${RUST_CARGO_BUILD_DEPS} +.if ${.OBJDIR} != ${RUST_PROJECT_DIR} + test ! -s Cargo.lock || cp -p Cargo.lock ${RUST_CARGO_PROJECT_DIR} +.endif + @${META_COOKIE_TOUCH} + +# handle cargo.{run,test,...} +RUST_CARGO_TARGETS += ${.TARGETS:Mcargo.*} +${RUST_CARGO_TARGETS:O:u}: _CARGO_USE + +.if ${MK_DEBUG_RUST:Uno} == "no" && \ + ${DEBUG_RUST_DIRS:Unone:@x@${RELDIR:M$x}@} == "" +RUST_CARGO_BUILD_ARGS += --release +.endif + +.if ${RUST_CARGO_BUILD_ARGS:U:M--release} != "" +RUST_CARGO_TARGET = release +.else +RUST_CARGO_TARGET = debug +.endif + +# do we want cargo.build to depend on cargo.fmt --check ? +# if user did make cargo.fmt the target would exist by now +.if ${MK_RUST_CARGO_FMT_CHECK:Uno} == "yes" && !target(cargo.fmt) +RUST_CARGO_FMT_CHECK_ARGS ?= --check +RUST_CARGO_FMT_ARGS += ${RUST_CARGO_FMT_CHECK_ARGS} +cargo.fmt: _CARGO_USE +cargo.build: cargo.fmt +.endif + +# useful? defaults +RUST_CARGO_CLIPPY_ARGS ?= -- -D warnings --no-deps + +# do we want cargo.clippy to be run after cargo.build? +.if ${MK_RUST_CARGO_CLIPPY:Uno} == "yes" && !target(cargo.clippy) +cargo.clippy: _CARGO_USE +cargo.clippy: cargo.build +all: cargo.clippy +.endif + +.if !defined(RUST_LIBS) +RUST_PROGS ?= ${RUST_PROJECT_DIR:T} +.endif +.if !empty(RUST_PROGS) +BINDIR ?= ${prefix}/bin +# there could be a target triple involved +RUST_CARGO_TARGET_DIR ?= ${CARGO_TARGET_DIR} +RUST_CARGO_OUTPUT_DIR ?= ${RUST_CARGO_TARGET_DIR}/${RUST_CARGO_TARGET} + +RUST_CARGO_BUILD_OUTPUT_LIST := ${RUST_PROGS:S,^,${RUST_CARGO_OUTPUT_DIR}/,} + +${RUST_CARGO_BUILD_OUTPUT_LIST}: cargo.build +.endif + +# for late customizations +.-include <local.rust.build.mk> |