xref: /freebsd/contrib/bmake/mk/rust.mk (revision 6a7405f5a6b639682cacf01e35d561411ff556aa)
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