1#
2# Support Clang static analyzer on SRCS.
3#
4#
5# +++ variables +++
6#
7# CLANG_ANALYZE_CHECKERS	Which checkers to run for all sources.
8#
9# CLANG_ANALYZE_CXX_CHECKERS	Which checkers to run for C++ sources.
10#
11# CLANG_ANALYZE_OUTPUT		Output format for generated files.
12# 				text - don't generate extra files.
13# 				html - generate html in obj.plist/ directories.
14# 				plist - generate xml obj.plist files.
15# 				See also:
16# 				  contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/Analyses.def
17#
18# CLANG_ANALYZE_OUTPUT_DIR	Sets which directory output set by
19# 				CLANG_ANALYZE_OUTPUT is placed into.
20#
21# +++ targets +++
22#
23#	analyze:
24#		Run the Clang static analyzer against all sources and present
25#		output on stdout.
26
27.if !target(__<bsd.clang-analyze.mk>__)
28__<bsd.clang-analyze.mk>__:
29
30.include <bsd.compiler.mk>
31
32.if ${COMPILER_TYPE} != "clang" && (make(analyze) || make(*.clang-analyzer))
33.error Clang static analyzer requires clang but found that compiler '${CC}' is ${COMPILER_TYPE}
34.endif
35
36CLANG_ANALYZE_OUTPUT?=	text
37CLANG_ANALYZE_OUTPUT_DIR?=	clang-analyze
38CLANG_ANALYZE_FLAGS+=	--analyze \
39			-Xanalyzer -analyzer-output=${CLANG_ANALYZE_OUTPUT} \
40			-o ${CLANG_ANALYZE_OUTPUT_DIR}
41
42CLANG_ANALYZE_CHECKERS+=	core deadcode security unix
43CLANG_ANALYZE_CXX_CHECKERS+=	cplusplus
44
45.for checker in ${CLANG_ANALYZE_CHECKERS}
46CLANG_ANALYZE_FLAGS+=	-Xanalyzer -analyzer-checker=${checker}
47.endfor
48CLANG_ANALYZE_CXX_FLAGS+=	${CLANG_ANALYZE_FLAGS}
49.for checker in ${CLANG_ANALYZE_CXX_CHECKERS}
50CLANG_ANALYZE_CXX_FLAGS+=	-Xanalyzer -analyzer-checker=${checker}
51.endfor
52
53.SUFFIXES: .c .cc .cpp .cxx .C .clang-analyzer
54
55CLANG_ANALYZE_CFLAGS=	${CFLAGS:N-Wa,--fatal-warnings}
56CLANG_ANALYZE_CXXFLAGS=	${CXXFLAGS:N-Wa,--fatal-warnings}
57
58.c.clang-analyzer:
59	${CC:N${CCACHE_BIN}} ${CLANG_ANALYZE_FLAGS} \
60	    ${CLANG_ANALYZE_CFLAGS} \
61	    ${.IMPSRC}
62.cc.clang-analyzer .cpp.clang-analyzer .cxx.clang-analyzer .C.clang-analyzer:
63	${CXX:N${CCACHE_BIN}} ${CLANG_ANALYZE_CXX_FLAGS} \
64	    ${CLANG_ANALYZE_CXXFLAGS} \
65	    ${.IMPSRC}
66
67CLANG_ANALYZE_SRCS= \
68	${SRCS:M*.[cC]} ${SRCS:M*.cc} \
69	${SRCS:M*.cpp} ${SRCS:M*.cxx} \
70	${DPSRCS:M*.[cC]} ${DPSRCS:M*.cc} \
71	${DPSRCS:M*.cpp} ${DPSRCS:M*.cxx}
72.if !empty(CLANG_ANALYZE_SRCS)
73CLANG_ANALYZE_OBJS=	${CLANG_ANALYZE_SRCS:O:u:${OBJS_SRCS_FILTER:ts:}:S,$,.clang-analyzer,}
74.NOPATH:	${CLANG_ANALYZE_OBJS}
75.endif
76
77# .depend files aren't relevant here since they reference obj.o rather than
78# obj.clang-analyzer, so add in some guesses in case 'make depend' wasn't ran,
79# for when directly building 'obj.clang-analyzer'.
80.for __obj in ${CLANG_ANALYZE_OBJS}
81${__obj}: ${OBJS_DEPEND_GUESS}
82${__obj}: ${OBJS_DEPEND_GUESS.${__obj}}
83.endfor
84
85beforeanalyze: depend .PHONY
86.if !defined(_RECURSING_PROGS) && !empty(CLANG_ANALYZE_SRCS) && \
87    ${CLANG_ANALYZE_OUTPUT} != "text"
88	mkdir -p ${CLANG_ANALYZE_OUTPUT_DIR}
89.endif
90
91.if !target(analyze)
92analyze: beforeanalyze .WAIT ${CLANG_ANALYZE_OBJS}
93.endif
94
95.if exists(${CLANG_ANALYZE_OUTPUT_DIR})
96CLEANDIRS+=	${CLANG_ANALYZE_OUTPUT_DIR}
97.endif
98
99.endif	# !target(__<bsd.clang-analyze.mk>__)
100