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