I have two targets in my Makefile, namely:
all: $(TARGET)
valgrind: $(TARGET)
...
...
...
The valgrind
target simply runs the executable with the valgrind program. The CFLAGS
for this Makefile includes:
CFLAGS += -fsanitize=address
CFLAGS += -fsanitize=undefined
CFLAGS += -fsanitize=bounds-strict
CFLAGS += -fsanitize=leak
CFLAGS += -fsanitize=null
CFLAGS += -fsanitize=signed-integer-overflow
CFLAGS += -fsanitize=bool
CFLAGS += -fsanitize=pointer-overflow
CFLAGS += -fsanitize-address-use-after-scope
CFLAGS += -fanalyzer
When doing make valgrind
(assuming the target was already built), I have to first run make clean
(this simply removes *.obj/
and $(TARGET)
, and then comment out these flags because Valgrind and sanitizers do not work together. And then uncomment them back for the next build, and so on.
How can I make the valgrind
target unconditionally rebuild the target each time but with the sanitizers disabled?
The whole Makefile (with some fluff removed):
CC = gcc-13
CFLAGS += -DBENCHMARKING
CFLAGS += -O3
CFLAGS += -std=c2x
CFLAGS += -s
CFLAGS += -no-pie
CFLAGS += -fno-builtin
CFLAGS += -fno-common
CFLAGS += -fno-omit-frame-pointer
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Warray-bounds
CFLAGS += -Wconversion
CFLAGS += -Wformat-signedness
CFLAGS += -Wno-parentheses
CFLAGS += -Wpedantic
CFLAGS += -pendatic-errors
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wwrite-strings
CFLAGS += -Wno-missing-braces
CFLAGS += -Wno-missing-field-initializers
CFLAGS += -fsanitize=address
CFLAGS += -fsanitize=undefined
CFLAGS += -fsanitize=bounds-strict
CFLAGS += -fsanitize=leak
CFLAGS += -fsanitize=null
CFLAGS += -fsanitize=signed-integer-overflow
CFLAGS += -fsanitize=bool
CFLAGS += -fsanitize=pointer-overflow
CFLAGS += -fsanitize-address-use-after-scope
CFLAGS += -fanalyzer
SRC_DIR = src
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJ_DIR = obj
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
DEPS = $(OBJS:.o=.d)
TARGET = read_file
all: $(TARGET)
$(TARGET): $(OBJ_DIR) $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
$(OBJ_DIR):
$(MKDIR) $(OBJ_DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -MMD -c -o $@ $<
-include $(DEPS)
valgrind: $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --mmap_memchr $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --getline $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --mmap_getline $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --fread $(TARGET)
One way is to use MAKECMDGOALS
and look for valgrind
and only add the -fsanitize*
options if the goals do not have valgrind
in them.
To test this:
Makefile
to run on my system (e.g. no gcc-13
) and some mispelled options.clean
target and made it a prereq for all
and valgrind
.PHONY: whatever
linessrc/main.c
, src/foo.c
, and src/bar.c
So, build with either:
make
make valgrind
Here is the modified Makefile
:
###CC = gcc-13
CC = gcc
MKDIR = mkdir -p
CFLAGS += -DBENCHMARKING
CFLAGS += -O3
###CFLAGS += -std=c2x
CFLAGS += -std=c1x
CFLAGS += -s
CFLAGS += -no-pie
CFLAGS += -fno-builtin
CFLAGS += -fno-common
CFLAGS += -fno-omit-frame-pointer
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Warray-bounds
CFLAGS += -Wconversion
CFLAGS += -Wformat-signedness
CFLAGS += -Wno-parentheses
CFLAGS += -Wpedantic
CFLAGS += -pedantic-errors
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wwrite-strings
CFLAGS += -Wno-missing-braces
CFLAGS += -Wno-missing-field-initializers
# add sanitize options if _not_ building for valgrind
ifeq ($(findstring valgrind,$(MAKECMDGOALS)),)
CFLAGS += -fsanitize=address
CFLAGS += -fsanitize=undefined
CFLAGS += -fsanitize=bounds-strict
CFLAGS += -fsanitize=leak
CFLAGS += -fsanitize=null
CFLAGS += -fsanitize=signed-integer-overflow
CFLAGS += -fsanitize=bool
CFLAGS += -fsanitize=pointer-overflow
CFLAGS += -fsanitize-address-use-after-scope
###CFLAGS += -fanalyzer
endif
SRC_DIR = src
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJ_DIR = obj
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
DEPS = $(OBJS:.o=.d)
TARGET = read_file
.PHONY: all
all: clean $(TARGET)
$(TARGET): $(OBJ_DIR) $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
$(OBJ_DIR):
$(MKDIR) $(OBJ_DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -MMD -c -o $@ $<
-include $(DEPS)
.PHONY: valgrind
valgrind: clean $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --mmap_memchr $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --getline $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --mmap_getline $(TARGET)
valgrind --tool=memcheck --leak-check=yes ./$(TARGET) --fread $(TARGET)
.PHONY: clean
clean:
rm -fr $(TARGET) $(OBJ_DIR)
Here is the output of make
:
rm -fr read_file obj
mkdir -p obj
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=leak -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bool -fsanitize=pointer-overflow -fsanitize-address-use-after-scope -MMD -c -o obj/foo.o src/foo.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=leak -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bool -fsanitize=pointer-overflow -fsanitize-address-use-after-scope -MMD -c -o obj/main.o src/main.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=leak -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bool -fsanitize=pointer-overflow -fsanitize-address-use-after-scope -MMD -c -o obj/bar.o src/bar.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=leak -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bool -fsanitize=pointer-overflow -fsanitize-address-use-after-scope -o read_file obj/foo.o obj/main.o obj/bar.o
Here is the output of make valgrind
:
rm -fr read_file obj
mkdir -p obj
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -MMD -c -o obj/foo.o src/foo.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -MMD -c -o obj/main.o src/main.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -MMD -c -o obj/bar.o src/bar.c
gcc -DBENCHMARKING -O3 -std=c1x -s -no-pie -fno-builtin -fno-common -fno-omit-frame-pointer -Wall -Wextra -Warray-bounds -Wconversion -Wformat-signedness -Wno-parentheses -Wpedantic -pedantic-errors -Wstrict-prototypes -Wwrite-strings -Wno-missing-braces -Wno-missing-field-initializers -o read_file obj/foo.o obj/main.o obj/bar.o
valgrind --tool=memcheck --leak-check=yes ./read_file --mmap_memchr read_file
==1519900== Memcheck, a memory error detector
==1519900== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1519900== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1519900== Command: ./read_file --mmap_memchr read_file
==1519900==
foo: hello
bar: hello
==1519900==
==1519900== HEAP SUMMARY:
==1519900== in use at exit: 0 bytes in 0 blocks
==1519900== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==1519900==
==1519900== All heap blocks were freed -- no leaks are possible
==1519900==
==1519900== For lists of detected and suppressed errors, rerun with: -s
==1519900== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
valgrind --tool=memcheck --leak-check=yes ./read_file --getline read_file
==1519902== Memcheck, a memory error detector
==1519902== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1519902== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1519902== Command: ./read_file --getline read_file
==1519902==
foo: hello
bar: hello
==1519902==
==1519902== HEAP SUMMARY:
==1519902== in use at exit: 0 bytes in 0 blocks
==1519902== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==1519902==
==1519902== All heap blocks were freed -- no leaks are possible
==1519902==
==1519902== For lists of detected and suppressed errors, rerun with: -s
==1519902== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
valgrind --tool=memcheck --leak-check=yes ./read_file --mmap_getline read_file
==1519903== Memcheck, a memory error detector
==1519903== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1519903== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1519903== Command: ./read_file --mmap_getline read_file
==1519903==
foo: hello
bar: hello
==1519903==
==1519903== HEAP SUMMARY:
==1519903== in use at exit: 0 bytes in 0 blocks
==1519903== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==1519903==
==1519903== All heap blocks were freed -- no leaks are possible
==1519903==
==1519903== For lists of detected and suppressed errors, rerun with: -s
==1519903== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
valgrind --tool=memcheck --leak-check=yes ./read_file --fread read_file
==1519904== Memcheck, a memory error detector
==1519904== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1519904== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1519904== Command: ./read_file --fread read_file
==1519904==
foo: hello
bar: hello
==1519904==
==1519904== HEAP SUMMARY:
==1519904== in use at exit: 0 bytes in 0 blocks
==1519904== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==1519904==
==1519904== All heap blocks were freed -- no leaks are possible
==1519904==
==1519904== For lists of detected and suppressed errors, rerun with: -s
==1519904== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Merely for completeness, here are the dummy source files I created:
==> src/bar.c <==
#include <stdio.h>
void
bar(void)
{
printf("bar: hello\n");
}
==> src/foo.c <==
#include <stdio.h>
void
foo(void)
{
printf("foo: hello\n");
}
==> src/main.c <==
#include <stdio.h>
void foo(void);
void bar(void);
int
main(void)
{
foo();
bar();
return 0;
}