1# SPDX-License-Identifier: BSD-2-Clause
2#
3# RCSid:
4#	$Id: warnings.mk,v 1.18 2024/02/17 17:26:57 sjg Exp $
5#
6#	@(#) Copyright (c) 2002-2023, 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.ifndef _w_cflags
20# make sure we get the behavior we expect
21.MAKE.SAVE_DOLLARS = no
22
23# Any number of warnings sets can be added.
24.-include <warnings-sets.mk>
25# This is more in keeping with our current practice
26.-include <local.warnings.mk>
27
28# Modest defaults - put more elaborate sets in warnings-sets.mk
29# -Wunused  etc are here so you can set
30# W_unused=-Wno-unused etc.
31MIN_WARNINGS ?= -Wall \
32	-Wformat \
33	-Wimplicit \
34	-Wunused \
35	-Wuninitialized
36
37LOW_WARNINGS ?= ${MIN_WARNINGS} -W -Wstrict-prototypes -Wmissing-prototypes
38
39MEDIUM_WARNINGS ?= ${LOW_WARNINGS}
40
41HIGH_WARNINGS ?= ${MEDIUM_WARNINGS} \
42	-Wcast-align \
43	-Wcast-qual \
44	-Wparentheses \
45	-Wpointer-arith \
46	-Wmissing-declarations \
47	-Wreturn-type \
48	-Wswitch \
49	-Wwrite-strings
50
51EXTRA_WARNINGS ?= ${HIGH_WARNINGS} -Wextra
52
53# The two step default makes it easier to test build with different defaults.
54DEFAULT_WARNINGS_SET ?= MIN
55WARNINGS_SET ?= ${DEFAULT_WARNINGS_SET}
56
57# There is always someone who wants more...
58.if !empty(WARNINGS_XTRAS)
59${WARNINGS_SET}_WARNINGS += ${WARNINGS_XTRAS}
60.endif
61
62# Keep this list ordered!
63WARNINGS_SET_LIST ?= MIN LOW MEDIUM HIGH EXTRA
64
65# We assume WARNINGS_SET_LIST is an ordered list.
66# if WARNINGS_SET is < WERROR_SET we add WARNINGS_NO_ERROR
67# otherwise we add WARNINGS_ERROR
68DEFAULT_WERROR_SET ?= MEDIUM
69WERROR_SET ?= ${DEFAULT_WERROR_SET}
70WARNINGS_ERROR ?= -Werror
71WARNINGS_NO_ERROR ?=
72
73.if ${MAKE_VERSION} >= 20170130
74.for i in ${WARNINGS_SET_LIST:range}
75.if ${WARNINGS_SET_LIST:[$i]} == ${WARNINGS_SET}
76WARNINGS_SETx = $i
77.endif
78.if ${WARNINGS_SET_LIST:[$i]} == ${WERROR_SET}
79WERROR_SETx = $i
80.if ${MAKE_VERSION} >= 20220924
81.break
82.endif
83.endif
84.endfor
85.if ${WARNINGS_SETx:U${WERROR_SETx:U0}} < ${WERROR_SETx:U0}
86${WARNINGS_SET}_WARNINGS += ${WARNINGS_NO_ERROR:U}
87.else
88${WARNINGS_SET}_WARNINGS += ${WARNINGS_ERROR}
89.endif
90.endif
91
92.if !empty(WARNINGS_SET)
93.for ws in ${WARNINGS_SET}
94.if empty(${ws}_WARNINGS)
95.if ${MAKE_VERSION:[1]:C/.*-//} >= 20050530
96.BEGIN:	_empty_warnings
97_empty_warnings: .PHONY
98.else
99.BEGIN:
100.endif
101	@echo "ERROR: Invalid: WARNINGS_SET=${ws}"
102	@echo "ERROR: Try one of: ${WARNINGS_SET_LIST}"; exit 1
103
104.endif
105.endfor
106.endif
107
108# Without -O or if we've set -O0 somewhere - to make debugging more effective,
109# we need to turn off -Wuninitialized as otherwise we get a warning that
110# -Werror turns into an error.  To be safe, set W_uninitialized blank.
111_w_cflags= ${CFLAGS} ${CFLAGS_LAST} ${CPPFLAGS}
112.if ${_w_cflags:M-O*} == "" || ${_w_cflags:M-O0} != ""
113W_uninitialized=
114.endif
115
116
117# .for loops have the [dis]advantage of being evaluated when read,
118# so adding to WARNINGS_SET[_${MACHINE_ARCH}] after this file is
119# read has no effect.
120# Replacing the above .for loops with the WARNINGS+= below solves that
121# but tiggers a double free bug in bmake-20040118 and earlier.
122# Don't try and read this too fast!
123#
124# The first :@ "loop" handles multiple sets in WARNINGS_SET
125#
126# In the second :@ "loop", the ::?= noise sets W_foo?=-Wfoo etc
127# which makes it easy to turn off override individual flags
128# (see W_uninitialized above).
129#
130# The last bit expands to
131# ${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