120253Sjoerg# SPDX-License-Identifier: BSD-2-Clause
220302Sjoerg#
320302Sjoerg# RCSid:
420253Sjoerg#	$Id: warnings.mk,v 1.18 2024/02/17 17:26:57 sjg Exp $
520253Sjoerg#
620253Sjoerg#	@(#) Copyright (c) 2002-2023, Simon J. Gerraty
720253Sjoerg#
820253Sjoerg#	This file is provided in the hope that it will
920302Sjoerg#	be of use.  There is absolutely NO WARRANTY.
1020253Sjoerg#	Permission to copy, redistribute or otherwise
1120253Sjoerg#	use this file is hereby granted provided that
1220253Sjoerg#	the above copyright notice and this notice are
1320253Sjoerg#	left intact.
1420302Sjoerg#
1520253Sjoerg#	Please send copies of changes and bug-fixes to:
1620253Sjoerg#	sjg@crufty.net
1720302Sjoerg#
1820253Sjoerg
1920253Sjoerg.ifndef _w_cflags
2020253Sjoerg# make sure we get the behavior we expect
2120253Sjoerg.MAKE.SAVE_DOLLARS = no
2220253Sjoerg
2320253Sjoerg# Any number of warnings sets can be added.
2420253Sjoerg.-include <warnings-sets.mk>
2520253Sjoerg# This is more in keeping with our current practice
2620253Sjoerg.-include <local.warnings.mk>
2730259Scharnier
2830259Scharnier# Modest defaults - put more elaborate sets in warnings-sets.mk
2950479Speter# -Wunused  etc are here so you can set
3030259Scharnier# W_unused=-Wno-unused etc.
3130259ScharnierMIN_WARNINGS ?= -Wall \
3220253Sjoerg	-Wformat \
3320253Sjoerg	-Wimplicit \
3420253Sjoerg	-Wunused \
3520253Sjoerg	-Wuninitialized
3620253Sjoerg
3720253SjoergLOW_WARNINGS ?= ${MIN_WARNINGS} -W -Wstrict-prototypes -Wmissing-prototypes
3820253Sjoerg
3920253SjoergMEDIUM_WARNINGS ?= ${LOW_WARNINGS}
4020253Sjoerg
4120253SjoergHIGH_WARNINGS ?= ${MEDIUM_WARNINGS} \
4220253Sjoerg	-Wcast-align \
4320253Sjoerg	-Wcast-qual \
4420253Sjoerg	-Wparentheses \
4520253Sjoerg	-Wpointer-arith \
4620253Sjoerg	-Wmissing-declarations \
4720253Sjoerg	-Wreturn-type \
4820253Sjoerg	-Wswitch \
4920253Sjoerg	-Wwrite-strings
5020253Sjoerg
5120253SjoergEXTRA_WARNINGS ?= ${HIGH_WARNINGS} -Wextra
5220253Sjoerg
53243894Seadler# The two step default makes it easier to test build with different defaults.
5420253SjoergDEFAULT_WARNINGS_SET ?= MIN
5520253SjoergWARNINGS_SET ?= ${DEFAULT_WARNINGS_SET}
5620253Sjoerg
5720253Sjoerg# There is always someone who wants more...
5820253Sjoerg.if !empty(WARNINGS_XTRAS)
5920253Sjoerg${WARNINGS_SET}_WARNINGS += ${WARNINGS_XTRAS}
6020253Sjoerg.endif
6120253Sjoerg
6220253Sjoerg# Keep this list ordered!
6320253SjoergWARNINGS_SET_LIST ?= MIN LOW MEDIUM HIGH EXTRA
6420253Sjoerg
6520253Sjoerg# We assume WARNINGS_SET_LIST is an ordered list.
6620253Sjoerg# if WARNINGS_SET is < WERROR_SET we add WARNINGS_NO_ERROR
6720253Sjoerg# otherwise we add WARNINGS_ERROR
6820253SjoergDEFAULT_WERROR_SET ?= MEDIUM
6920253SjoergWERROR_SET ?= ${DEFAULT_WERROR_SET}
7020253SjoergWARNINGS_ERROR ?= -Werror
7120253SjoergWARNINGS_NO_ERROR ?=
7220253Sjoerg
7320253Sjoerg.if ${MAKE_VERSION} >= 20170130
7420253Sjoerg.for i in ${WARNINGS_SET_LIST:range}
7520253Sjoerg.if ${WARNINGS_SET_LIST:[$i]} == ${WARNINGS_SET}
7620253SjoergWARNINGS_SETx = $i
7720253Sjoerg.endif
7820253Sjoerg.if ${WARNINGS_SET_LIST:[$i]} == ${WERROR_SET}
7920253SjoergWERROR_SETx = $i
8020253Sjoerg.if ${MAKE_VERSION} >= 20220924
8120253Sjoerg.break
8220253Sjoerg.endif
8320253Sjoerg.endif
8420253Sjoerg.endfor
8520253Sjoerg.if ${WARNINGS_SETx:U${WERROR_SETx:U0}} < ${WERROR_SETx:U0}
8620253Sjoerg${WARNINGS_SET}_WARNINGS += ${WARNINGS_NO_ERROR:U}
8720253Sjoerg.else
8820253Sjoerg${WARNINGS_SET}_WARNINGS += ${WARNINGS_ERROR}
8920253Sjoerg.endif
9020253Sjoerg.endif
9120253Sjoerg
9220253Sjoerg.if !empty(WARNINGS_SET)
9320253Sjoerg.for ws in ${WARNINGS_SET}
9420253Sjoerg.if empty(${ws}_WARNINGS)
9520253Sjoerg.if ${MAKE_VERSION:[1]:C/.*-//} >= 20050530
9620253Sjoerg.BEGIN:	_empty_warnings
9720253Sjoerg_empty_warnings: .PHONY
9820253Sjoerg.else
9920253Sjoerg.BEGIN:
10020253Sjoerg.endif
10120253Sjoerg	@echo "ERROR: Invalid: WARNINGS_SET=${ws}"
10220253Sjoerg	@echo "ERROR: Try one of: ${WARNINGS_SET_LIST}"; exit 1
10320253Sjoerg
10420253Sjoerg.endif
10520253Sjoerg.endfor
10620253Sjoerg.endif
10720253Sjoerg
10820253Sjoerg# Without -O or if we've set -O0 somewhere - to make debugging more effective,
10920253Sjoerg# we need to turn off -Wuninitialized as otherwise we get a warning that
11020253Sjoerg# -Werror turns into an error.  To be safe, set W_uninitialized blank.
11120253Sjoerg_w_cflags= ${CFLAGS} ${CFLAGS_LAST} ${CPPFLAGS}
11220253Sjoerg.if ${_w_cflags:M-O*} == "" || ${_w_cflags:M-O0} != ""
11320253SjoergW_uninitialized=
11420253Sjoerg.endif
11520253Sjoerg
11620253Sjoerg
11720253Sjoerg# .for loops have the [dis]advantage of being evaluated when read,
11820253Sjoerg# so adding to WARNINGS_SET[_${MACHINE_ARCH}] after this file is
11920253Sjoerg# read has no effect.
12020253Sjoerg# Replacing the above .for loops with the WARNINGS+= below solves that
12120253Sjoerg# but tiggers a double free bug in bmake-20040118 and earlier.
12220253Sjoerg# Don't try and read this too fast!
12320253Sjoerg#
12420253Sjoerg# The first :@ "loop" handles multiple sets in WARNINGS_SET
12520253Sjoerg#
12620253Sjoerg# In the second :@ "loop", the ::?= noise sets W_foo?=-Wfoo etc
12720253Sjoerg# which makes it easy to turn off override individual flags
12820253Sjoerg# (see W_uninitialized above).
12920253Sjoerg#
13020253Sjoerg# The last bit expands to
13120253Sjoerg# ${W_foo_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}:U${W_foo}}
132# which is the bit we ultimately want.  It allows W_* to be set on a
133# per target basis.
134#
135# NOTE: that we force the target extension to be .o
136# TARGET_PREFIX_FILTER defaults to R
137#
138
139TARGET_PREFIX_FILTER ?= R
140
141# define this once, we use it a couple of times below (hence the doubled $$).
142M_warnings_list = @s@$${$$s_WARNINGS} $${$$s_WARNINGS.${COMPILER_TYPE}:U}@:O:u:@w@$${$${w:C/-(.)/\1_/}::?=$$w} $${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U$${$${w:C/-(.)/\1_/}_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U$${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}:U$${$${w:C/-(.)/\1_/}}}}}@
143
144# first a list of warnings from the chosen set
145_warnings = ${WARNINGS_SET_${MACHINE_ARCH}:U${WARNINGS_SET}:${M_warnings_list}}
146# now a list of all -Wno-* overrides not just those defined by WARNINGS_SET
147# since things like -Wall imply lots of others.
148# this should be a super-set of the -Wno-* in _warnings, but
149# just in case...
150_no_warnings = ${_warnings:M-Wno-*} ${WARNINGS_SET_LIST:${M_warnings_list}:M-Wno-*}
151# -Wno-* must follow any others
152WARNINGS += ${_warnings:N-Wno-*} ${_no_warnings:O:u}
153
154.ifndef NO_CFLAGS_WARNINGS
155# Just ${WARNINGS} should do, but this is more flexible?
156CFLAGS+= ${WARNINGS_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U${WARNINGS}}
157.endif
158
159# it is rather silly that g++ blows up on some warning flags
160NO_CXX_WARNINGS+= \
161	implicit \
162	missing-declarations \
163	missing-prototypes \
164	nested-externs \
165	shadow \
166	strict-prototypes
167
168WARNINGS_CXX_SRCS += ${SRCS:M*.c*:N*.c:N*h}
169.for s in ${WARNINGS_CXX_SRCS:O:u}
170.for w in ${NO_CXX_WARNINGS}
171W_$w_${s:T:${TARGET_PREFIX_FILTER:ts:}}.o=
172.endfor
173.endfor
174
175.endif # _w_cflags
176