1# SPDX-License-Identifier: BSD-2-Clause 2# 3# RCSid: 4# $Id: rust.mk,v 1.37 2025/01/11 03:17:36 sjg Exp $ 5# 6# @(#) Copyright (c) 2024, Simon J. Gerraty 7# 8# This file is provided in the hope that it will 9# be of use. There is absolutely NO WARRANTY. 10# Permission to copy, redistribute or otherwise 11# use this file is hereby granted provided that 12# the above copyright notice and this notice are 13# left intact. 14# 15# Please send copies of changes and bug-fixes to: 16# sjg@crufty.net 17# 18 19## 20# This makefile is used when a build includes one or more Rust projects. 21# 22# We first include local.rust.mk to allow for customization. 23# You can get very fancy - the logic/functionality here is minimal but 24# can be extended via local.rust.mk 25# 26# If RUST_PROJECT_DIR (where we find Cargo.toml) is not set, we will 27# make it ${.CURDIR:C,/src.*,,} actually we use 28# ${SRCTOP}/${RELDIR:C,/src.*,,} to ensure we don't confuse ${SRCTOP} 29# with ${RUST_PROJECT_DIR}/src. 30# 31# If ${.OBJDIR} is not ${.CURDIR} we will default CARGO_TARGET_DIR 32# to ${.OBJDIR}. 33# 34# First, if ${.CURDIR} is a subdir of ${RUST_PROJECT_DIR} (will happen 35# if an Emacs user does 'M-x compile' while visiting a src file) we 36# will need to adjust ${.OBJDIR} (and hence CARGO_TARGET_DIR). 37# 38# We assume that RUST_CARGO will be used to build Rust projects, 39# so we default RUST_CARGO_PROJECT_DIR to ${RUST_PROJECT_DIR} and 40# provide a _CARGO_USE that we automatically associate with 41# targets named 'cargo.*' the default is 'cargo.build'. 42# 43# _CARGO_USE will chdir to ${RUST_CARGO_PROJECT_DIR} and run 44# ${RUST_CARGO} with ENV, FLAGS and ARGS variables derived from 45# ${.TARGET:E:tu} so in the case of 'cargo.build' we get: 46# RUST_CARGO_BUILD_ENV, RUST_CARGO_BUILD_FLAGS and RUST_CARGO_BUILD_ARGS 47# 48# _CARGO_USE will "just work" for additional targets like 49# 'cargo.test', 'cargo.clippy', ... which will run '${RUST_CARGO} test', 50# '${RUST_CARGO} clippy' etc. 51# 52# If MK_META_MODE is "yes" 'cargo.build' will touch ${.TARGET} 53# so the default make rules will not consider it always out-of-date. 54# In META MODE, 'bmake' will know if anything changed that should 55# cause the target to be re-built. 56# 57# If MK_STAGING_RUST is "yes" we will stage the binary we 58# built to a suitable location under ${STAGE_OBJTOP}. 59# 60 61all: 62.MAIN: all 63 64# allow for customization 65.-include <local.rust.mk> 66 67RUST_CARGO ?= cargo 68RUSTC ?= rustc 69.if ${.CURDIR} == ${SRCTOP} 70RELDIR ?= . 71.else 72RELDIR ?= ${.CURDIR:S,${SRCTOP}/,,} 73.endif 74.if empty(RUST_PROJECT_DIR) 75# we want this set correctly from anywhere within 76# using RELDIR avoids confusing ${SRCTOP} with ${RUST_PROJECT_DIR}/src 77RUST_PROJECT_DIR := ${SRCTOP}/${RELDIR:C,/src.*,,} 78.if ${RUST_PROJECT_DIR:T:Nsrc:N.} == "" 79RUST_PROJECT_DIR := ${RUST_PROJECT_DIR:H} 80.endif 81.endif 82 83.if ${.OBJDIR} != ${.CURDIR} 84.if ${.CURDIR:M${RUST_PROJECT_DIR}/*} != "" 85# Our .CURDIR is below RUST_PROJECT_DIR and thus our 86# .OBJDIR is likely not what we want either. 87# This can easily happen if in Emacs we do 'M-x compile' while 88# visiting a src file. 89# It is easily fixed. 90__objdir := ${.OBJDIR:S,${.CURDIR:S,${RUST_PROJECT_DIR},,},,} 91.OBJDIR: ${__objdir} 92.endif 93# tell cargo where to drop build artifacts 94CARGO_TARGET_DIR ?= ${.OBJDIR} 95.if !empty(OBJROOT) && exists(${OBJROOT}) 96CARGO_HOME_RELDIR ?= rust/cargo_home 97CARGO_HOME ?= ${OBJROOT}/common/${RUST_CARGO_HOME_RELDIR} 98.endif 99.elif ${.CURDIR} != ${RUST_PROJECT_DIR} 100.OBJDIR: ${RUST_PROJECT_DIR} 101.endif 102CARGO_TARGET_DIR ?= target 103 104.if ${MK_DIRDEPS_BUILD:Uno} == "no" || ${.MAKE.LEVEL} > 0 105.export CARGO_HOME CARGO_TARGET_DIR RUST_PROJECT_DIR RUSTC 106 107all: cargo.build 108 109.if empty(RUST_PROJECT_FILES) 110RUST_PROJECT_FILES != find ${RUST_PROJECT_DIR} -type f \( \ 111 -name '*.rs' -o \ 112 -name Cargo.lock -o \ 113 -name Cargo.toml \) | sort 114.endif 115RUST_CARGO_BUILD_DEPS += ${RUST_PROJECT_FILES:U} 116.endif 117 118RUST_CARGO_PROJECT_DIR ?= ${RUST_PROJECT_DIR} 119 120.if ${RUSTC:M/*} 121# make sure we find all the other toolchain bits in the same place 122RUST_CARGO_ENV += PATH=${RUSTC:H}:${PATH} 123 124# cargo clippy needs extra help finding the sysroot 125# https://github.com/rust-lang/rust-clippy/issues/3523 126RUST_CARGO_CLIPPY_ENV += RUSTC_SYSROOT=${${RUSTC} --print sysroot:L:sh} 127.endif 128 129.if ${LDFLAGS:U:M-[BL]*} != "" 130# we may need to tell rustc where to find the native libs needed 131# rustc documents a space after -L so put it back 132RUST_LDFLAGS := ${LDFLAGS:C/(-[BL]) /\1/gW:M-[BL]*:S/-L/& /:S/-B/-C link-arg=&/} 133.endif 134.if !empty(RUST_LDFLAGS) 135RUSTFLAGS += ${RUST_LDFLAGS} 136.endif 137.if !empty(RUSTFLAGS) 138RUST_CARGO_BUILD_ENV += RUSTFLAGS="${RUSTFLAGS}" 139.endif 140 141_CARGO_USE: .USEBEFORE 142 @(cd ${RUST_CARGO_PROJECT_DIR} && ${RUST_CARGO_ENV} \ 143 ${RUST_CARGO_${.TARGET:E:tu}_ENV} \ 144 ${RUST_CARGO} ${RUST_CARGO_${.TARGET:E:tu}_FLAGS:U${RUST_CARGO_FLAGS}} \ 145 ${.TARGET:E} ${RUST_CARGO_${.TARGET:E:tu}_ARGS}) 146 147RUST_CARGO_TARGETS += cargo.build 148cargo.build: ${RUST_CARGO_BUILD_DEPS} 149.if ${.OBJDIR} != ${RUST_PROJECT_DIR} 150 test ! -s Cargo.lock || cp -p Cargo.lock ${RUST_CARGO_PROJECT_DIR} 151.endif 152 @${META_COOKIE_TOUCH} 153 154# handle cargo.{run,test,...} 155RUST_CARGO_TARGETS += ${.TARGETS:Mcargo.*} 156${RUST_CARGO_TARGETS:O:u}: _CARGO_USE 157 158.if ${MK_DEBUG_RUST:Uno} == "no" && \ 159 ${DEBUG_RUST_DIRS:Unone:@x@${RELDIR:M$x}@} == "" 160RUST_CARGO_BUILD_ARGS += --release 161.endif 162 163.if ${RUST_CARGO_BUILD_ARGS:U:M--release} != "" 164RUST_CARGO_TARGET = release 165.else 166RUST_CARGO_TARGET = debug 167.endif 168 169# do we want cargo.build to depend on cargo.fmt --check ? 170# if user did make cargo.fmt the target would exist by now 171.if ${MK_RUST_CARGO_FMT_CHECK:Uno} == "yes" && !target(cargo.fmt) 172RUST_CARGO_FMT_CHECK_ARGS ?= --check 173RUST_CARGO_FMT_ARGS += ${RUST_CARGO_FMT_CHECK_ARGS} 174cargo.fmt: _CARGO_USE 175cargo.build: cargo.fmt 176.endif 177 178# useful? defaults 179RUST_CARGO_CLIPPY_ARGS ?= -- -D warnings --no-deps 180 181# do we want cargo.clippy to be run after cargo.build? 182.if ${MK_RUST_CARGO_CLIPPY:Uno} == "yes" && !target(cargo.clippy) 183cargo.clippy: _CARGO_USE 184cargo.clippy: cargo.build 185all: cargo.clippy 186.endif 187 188.if !defined(RUST_LIBS) 189RUST_PROGS ?= ${RUST_PROJECT_DIR:T} 190.endif 191.if !empty(RUST_PROGS) 192BINDIR ?= ${prefix}/bin 193# there could be a target triple involved 194RUST_CARGO_TARGET_DIR ?= ${CARGO_TARGET_DIR} 195RUST_CARGO_OUTPUT_DIR ?= ${RUST_CARGO_TARGET_DIR}/${RUST_CARGO_TARGET} 196 197RUST_CARGO_BUILD_OUTPUT_LIST := ${RUST_PROGS:S,^,${RUST_CARGO_OUTPUT_DIR}/,} 198 199${RUST_CARGO_BUILD_OUTPUT_LIST}: cargo.build 200.endif 201 202# for late customizations 203.-include <local.rust.build.mk> 204