Here is my Makefile:
NAME := libftprintf.a
LIB := ar rcs
CC := gcc
CFLAGS := -Wall -Wextra -Werror
SRCS_DIR := ./sources/
HDRS_DIR := ./headers/
OBJS_DIR := ./objectives/
SRCS_FILES := ft_conv.c \
ft_eval_hex.c \
ft_eval_number.c \
ft_eval_string.c \
ft_parsers.c \
ft_strs_join.c \
ft_eval_char.c \
ft_eval_int.c \
ft_eval_percent.c \
ft_handler.c \
ft_printf.c
HDRS_FILES := ft_conv.h \
ft_eval_hex.h \
ft_eval_number.h \
ft_eval_string.h \
ft_parsers.h \
ft_strs_join.h \
ft_eval_char.h \
ft_eval_int.h \
ft_eval_percent.h \
ft_handler.h \
ft_printf.h
OBJS_FILES := $(SRCS_FILES:.c=.o)
SRCS := $(addprefix $(SRCS_DIR),$(SRCS_FILES))
HDRS := $(addprefix $(HDRS_DIR),$(HDRS_FILES))
OBJS := $(addprefix $(OBJS_DIR),$(OBJS_FILES))
LIBFT_DIR := ./libft/
LIBFT_NAME := libft.a
LIBFT := $(addprefix $(LIBFT_DIR),$(LIBFT_NAME))
RM := rm -rf
all: $(NAME)
bonus: all
bonus_one: all
bonus_two: all
$(NAME): $(OBJS)
$(LIB) $(NAME) $(OBJS) $(LIBFT)
$(OBJS_DIR)%.o: $(SRCS_DIR)%.c $(HDRS) Makefile | $(OBJS_DIR) subsystem
$(CC) $(CFLAGS) -c $< -o $# -I $(HDRS_DIR) -I $(LIBFT_DIR)
subsystem:
#$(MAKE) -C $(LIBFT_DIR)
$(OBJS_DIR):
mkdir $(OBJS_DIR)
clean:
#$(MAKE) -C $(LIBFT_DIR) clean
$(RM) $(OBJS_DIR)
fclean: clean
#$(MAKE) -C $(LIBFT_DIR) fclean
$(RM) $(NAME)
re: fclean all
.PHONY: all subsystem bonus bonus_one bonus_two clean fclean re
The problem is so: if I do make all, then touch libftprintf.a I would expect that make all will rebuild libftprintf.a since it was changed and target all depends on that file. However, make does nothing and I can't understand this behavior.
Also, there is one more minor issue: during make all I create a directory objectives where I store all .o files. Calling make fclean and make all entirely rebuilds the target, however calling make re results in an error:
rm -rf ./objectives/
rm -rf *libft objectives here*
rm -rf libft.a
rm -rf libftprintf.a
make: *** No rule to make target `objectives', needed by `objectives/ft_conv.o'. Stop.
If I call make re right after this error, the target builds as always. Also, if I change re target to this, I do not receive any errors:
re:
#$(MAKE) fclean
#$(MAKE) all
Could not find solutions to my problems anywhere on the Internet.
Touching libprintf.a won't cause anything to rebuild. Make rebuilds targets that are out of date. Out of date means that either the target doesn't exist, or some prerequisite of the target is newer than the target.
After you run make then libprintf.a is up to date, which means it's newer than all its prerequisites. Running touch libprintf.a just makes it even newer than its prerequisites than it was before, so make still considers it up to date.
If you want to rebuild libprintf.a you need to touch (or delete) one of its prerequisites, not the target itself.
The reason for your second issue seems to be related to the makefile in the libft subdirectory. It seems like you're using the --no-print-directories option here: you should avoid using that, at least as long as you're debugging, so that you can see where make is going and which makefile it's running.
Related
I'm want to have .h files to be included as my dependencies for a given .o file. I followed these instructions and adapted them to my Makefile. However when I do touch myhfile.h a corresponding .o file is not rebuilt. It seems to me dependencies are correct and are included into the Makefile. Just can't figure out why it is not working. Any help is appreciated. Makefile is included below
ROOT=.
BUILDDIR=$(ROOT)/build
LIBDIR=$(BUILDDIR)/lib
OBJDIR=$(BUILDDIR)/obj
INCLUDEDIR=$(BUILDDIR)/include
DEPDIR=$(BUILDDIR)/dep
LIB=mylib
XCOMPILE=arm-linux-gnueabihf-
CC=$(XCOMPILE)gcc
AR=$(XCOMPILE)ar
DEPFLAGS+=\
-MT $# \
-MMD \
-MP \
-MF \
$(DEPDIR)/$*.Td
CFLAGS+=\
-Wall \
-Wextra \
-Werror \
-pedantic \
-std=gnu11 \
-fPIC
CPPFLAGS+=\
$(INCLUDE)
SRCDIRS+=\
$(ROOT)/../3rdparty/log/src \
$(ROOT)/LTC2947/src \
$(ROOT)/i2c/src \
$(ROOT)/spi/src \
$(ROOT)/sensors/src \
$(ROOT)/telegraf/src \
$(ROOT)/uart-packet/src \
$(ROOT)/STCN75/src \
$(ROOT)/utils/src
DEPDIRS+=\
$(SRCDIRS) \
$(ROOT)/addresses-ports/src
VPATH+=\
$(SRCDIRS)
SRC+=$(shell find $(SRCDIRS) -type f -name "*\.c")
DEP+=$(shell find $(DEPDIRS) -type f -name "*\.h")
OBJ=$(patsubst %.c, $(OBJDIR)/%.o, $(notdir $(SRC)))
INCLUDE=$(addprefix -I,$(sort $(dir $(DEP))))
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
release: CFLAGS+=-O3
release: all
debug: CFLAGS+=-ggdb
debug: CPPFLAGS+=-DDEBUG
debug: all
all: lib include
lib: $(LIBDIR)/$(LIB).a $(LIBDIR)/$(LIB).so
include: $(INCLUDEDIR)
$(LIBDIR)/$(LIB).a: $(OBJ) | $(LIBDIR)
$(AR) rcs $# $^
$(LIBDIR)/$(LIB).so: $(OBJ) | $(LIBDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -shared $(LDFLAGS) -lc $^ -o $#
$(INCLUDEDIR): $(DEP)
if [[ ! -d $# ]]; then mkdir -p $#; fi
cp $^ $#
touch $#
%.o: %.c
$(OBJDIR)/%.o: %.c $(DEPDIR)/%.d | $(DEPDIR) $(OBJDIR)
$(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c $< -o $#
$(POSTCOMPILE)
$(DEPDIR):
mkdir -p $#
$(LIBDIR):
mkdir -p $#
$(OBJDIR):
mkdir -p $#
.PHONY: clean
clean:
rm -rf $(BUILDDIR)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))
EDIT
$(info $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))) produced an empty string. $(info $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC)))) produced a right list of dependencies
./build/dep/./../3rdparty/log/src/log.d ./build/dep/./uart-packet/src/uart_packet.d ./build/dep/./utils/src/utils.d ./build/dep/./telegraf/src/telegraf.d ./build/dep/./i2c/src/myproject_i2c.d ./build/dep/./spi/src/myproject_spi.d ./build/dep/./LTC2947/src/LTC2947.d ./build/dep/./sensors/src/sensors.d ./build/dep/./STCN75/src/STCN75.d
So I removed $(wildcard ...) function
However that didn't solve the problem.
To test the it I decided to run:
1. make clean
2. make
3. touch telegraf/src/telegraf.h
4. make build/obj/telegraf.d
5. make build/obj/telegraf.Td
6. make build/obj/telegraf.o
Steps 1-3 worked fine. However steps 4-6 didn't work.
Step 4 produced a following result:
make: *** No rule to make target 'buid/dep/telegraf.d'. Stop.
Step 5 produced a following result:
make: *** No rule to make target 'buid/dep/telegraf.Td'. Stop.
Step 6 simply didn't rebuild the target.
I took a look at build/dep/telegraf.d after step 2 and here is what I have there:
$ cat build/dep/telegraf.d
build/obj/telegraf.o: telegraf/src/telegraf.c ../3rdparty/log/src/log.h \
telegraf/src/telegraf.h utils/src/utils.h
../3rdparty/log/src/log.h:
telegraf/src/telegraf.h:
utils/src/utils.h:
It seems to me dependencies are generated correctly.
I also tried running make -d build/obj/telegraf.o. Unfortunately I can't post a whole output for it (stackoverflow won't allow it, message becomes to large). But here is the end of the output. (For those who are interested, full output can be seen here)
No need to remake target 'telegraf.c'; using VPATH name './telegraf/src/telegraf.c'.
Considering target file 'build/dep/telegraf.d'.
Looking for an implicit rule for 'build/dep/telegraf.d'.
Trying pattern rule with stem 'telegraf'.
Found an implicit rule for 'build/dep/telegraf.d'.
Finished prerequisites of target file 'build/dep/telegraf.d'.
No need to remake target 'build/dep/telegraf.d'.
Considering target file 'build/dep'.
Finished prerequisites of target file 'build/dep'.
No need to remake target 'build/dep'.
Considering target file 'build/obj'.
Finished prerequisites of target file 'build/obj'.
No need to remake target 'build/obj'.
Finished prerequisites of target file 'build/obj/telegraf.o'.
Prerequisite './telegraf/src/telegraf.c' is older than target 'build/obj/telegraf.o'.
Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.
Prerequisite 'build/dep' is order-only for target 'build/obj/telegraf.o'.
Prerequisite 'build/obj' is order-only for target 'build/obj/telegraf.o'.
No need to remake target 'build/obj/telegraf.o'.
make: 'build/obj/telegraf.o' is up to date.
It looks to that this line is the issue, Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.. Somehow I need to make it younger but I'm not sure how.
Any help is appreciated.
Unfortunately you've gone running off in the wrong direction here :).
You should not have removed the $(wildcard ...); that is needed/wanted.
The fact that it returned the empty string is THE problem you're having and rather than just remove it you needed to figure out why and fix it. The fact that your .d files look like ./build/dep/./../3rdparty/log/src/log.d is the problem... that is NOT the path to the .d files you are creating. You are creating files like ./build/dep/log.d
The problem is this: you are creating .d files in the recipe using this rule:
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
Here, $* is the stem of the file so for ./build/obj/log.o the value of $* will be log. So you are creating ./build/dep/log.d.
But when you convert your SRC variable to .d files in the include line, you use the basename function. This merely strips off the suffix of the path, it doesn't remove the directory. So if your source file is ./../3rdparty/log/src/log.c then basename yields ./../3rdparty/log/src/log and your wildcard matches the wrong thing.
You need to compute your wildcard for your include line like this:
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(notdir $(basename $(SRC)))))
Adding the notdir to strip out the paths, as well, will give you the dependency file you want: ./build/dep/log.d etc.
I am trying to build pjsip project..
This is my pjsip projects make file..
include ../../../build.mak
include ../../../build/common.mak
export LIBDIR := ../../lib
RULES_MAK := $(PJDIR)/build/rules.mak
#export MYCOMPRESS_LIB := ../../lib/lmycompresslib-$(TARGET_NAME)$(LIBEXT)
export MYCOMPRESS_LIB := lmycompresslib-$(TARGET_NAME)$(LIBEXT)
ifeq ($(PJ_SHARED_LIBRARIES),)
else
export MYCOMPRESS_SONAME := lmycompresslib.$(SHLIB_SUFFIX)
export MYCOMPRESS_SHLIB := $(MYCOMPRESS_SONAME).$(PJ_VERSION_MAJOR)
endif
###############################################################################
# Gather all flags.
#
export _CFLAGS := $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \
$(CFLAGS) $(CC_INC). $(CC_INC)../../mycompresslib/include \
$(CC_INC)../../../pjlib/include
export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \
$(HOST_CXXFLAGS) $(CXXFLAGS)
export _LDFLAGS := $(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \
$(LDFLAGS)
export MYCOMPRESS_SRCDIR = ../../mycompresslib/src
export MYCOMPRESS_OBJS = mycompress.o
export MYCOMPRESS_CFLAGS = $(_CFLAGS)
export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
###############################################################################
# Main entry
#
# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory.
#
#TARGETS := lmycompresslib
TARGETS := $(MYCOMPRESS_LIB) $(MYCOMPRESS_SONAME)
all: $(TARGETS)
doc:
cd .. && doxygen docs/doxygen.cfg
dep: depend
distclean: realclean
#.PHONY: dep depend lmycompresslib clean realclean distclean
.PHONY: all dep depend clean realclean distclean
.PHONY: $(TARGETS)
.PHONY: $(MYCOMPRESS_LIB) $(MYCOMPRESS_SONAME)
#lmycompresslib:
# $(MAKE) -f $(RULES_MAK) APP=MYCOMPRESS app=lmycompresslib $(MYCOMPRESS_LIB)
lmycompresslib: $(MYCOMPRESS_LIB)
$(MYCOMPRESS_SONAME): $(MYCOMPRESS_LIB)
$(MYCOMPRESS_LIB) $(MYCOMPRESS_SONAME):
$(MAKE) -f $(RULES_MAK) APP=MYCOMPRESS app=lmycompresslib $(subst /,$(HOST_PSEP),$(LIBDIR)/$#)
clean print_lib:
$(MAKE) -f $(RULES_MAK) APP=MYCOMPRESS app=lmycompresslib $#
realclean:
$(subst ##,$(subst /,$(HOST_PSEP),.lmycompresslib-$(TARGET_NAME).depend),$(HOST_RMR))
$(MAKE) -f $(RULES_MAK) APP=MYCOMPRESS app=lmycompresslib $#
depend:
$(MAKE) -f $(RULES_MAK) APP=MYCOMPRESS app=lmycompresslib $#
this is the error i get..
.depend:1: *** missing separator. Stop.
I used this command to verify if there are only tabs in my makefile using this command
cat -e -t -v makefile
But still i get the above error when i am trying to build this project.
Found the solution.This happens because of corrupt dependency file, probably because make dep stopped or was stopped abruptly.It was given actually in website itself.All i need to do was issue this command.
make distclean
this too resulted in errors.As mentioned on site, it instructed me to delete all corrupted dependency files.Following another pjsip mail link
$ find . -name "*.depend" -print | xargs rm -f
After issuing this command,it deleted all corrupted dependancy i was then able to compile and build my project successfully.
When I call the clean rule with make clean all objects are correctly deleted. However if just after I call the all rule with make it recompiles all the objects again, even if the target is already there.
As far as I know, it should not recompile the objects beacuse the $(NAME) dependecy in the all rule is already satisfied. Indeed make clean erase just the object and not the program target too.
Somebody can explain me how to avoid recompiling after a make clean call? Thank you.
Here is the makefile:
NAME = myprogram
CC = clang++
CFLAGS = -Werror -Wextra -Wall -O3 -std=c++11
DIR_SRCS = srcs/
DIR_OBJS = objs/
DIR_INCS = incs/
FILES = main.cpp \
file1.cpp \
files2.cpp \
file3.cpp \
OBJS = $(addprefix $(DIR_OBJS), $(notdir $(addprefix $(DIR_SRCS), $(FILES:.cpp=.o))))
all: $(NAME)
$(NAME): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) -I$(DIR_INCS) -o $(NAME)
$(DIR_OBJS)%.o: $(DIR_SRCS)%.cpp
mkdir -p $(DIR_OBJS)
$(CC) $(CFLAGS) -I$(DIR_INCS) -c $< -o $#
clean:
rm -rf $(DIR_OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re
The $(NAME) dependecy in the all rule is NOT satisfied, because $(NAME) depends on $(OBJS) - and $(OBJS) does not exist (after make clean). This is how make works. If any dependencies don't exists or are newer than the target - the dependecies need to be regenerated (and in turn - the target).
For example: program --> program.o --> (program.c, program.h)
If program.c or program.h is newer than program.o : program.o needs to be regenerated (updated). This causes program.o to be newer than program - program needs to be relinked (using program.o).
This is in reference to the second response here:
How to generate a Makefile with source in sub-directories using just one makefile
The solution works great for me except for when the make rules are called. They never seem to make any once make-goal is called since the files don't exist in the build directory yet. I tested this by creating empty files in the build directory (just anyting.o) and the make rule is then found
my conclusion is that the % wildcard character is only looking for what is in the directory, and can't find the file so it doesnt make a build rule for it, and thus fails to continue. There are two possible solutions:
1) Find a way to make dummy object files that are overwritten when the compiler actually starts
2) Make make "realize" that the wild card is for anything put into the make-goal function, not what is already in the directory
any pointers?
As far as I know, I am the first one to have this issue
\
MODULES := calibration calibration/settings camera/nikon camera ommon
SRC_DIR := $(addprefix src/, $(MODULES)) src
SDK_INCLUDES := include $(addprefix include/, $(MODULES))
BUILD_DIR := build $(addprefix build/, $(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp))
OBJ := $(patsubst src/%.cpp,build/%.o, $(SRC))
# OpenCV directories, change according to your own installation
CV_INCLUDE_DIR = C:\Users\a0225122\Downloads\opencv\build\include
CV_LIB_DIR = C:\Users\a0225122\Downloads\opencv\bin\lib
CV_LIBS = -llibopencv_core249 \
-llibopencv_highgui249 \
-llibopencv_imgproc249 \
-llibopencv_features2d249 \
-llibopencv_calib3d249
CV_FLAGS = -I$(CV_INCLUDE_DIR) -L$(CV_LIB_DIR) $(CV_LIBS)
HID_API_INCLUDE_DIR := 3rd_party/hidapi-master/hidapi/hid.h
# Compiler instructions
CXXFLAGS = -std=c++11 -Wall -I $(SDK_INCLUDE_DIR) -I $(CV_INCLUDE_DIR) -I $(HID_API_INCLUDE_DIR) -L $(CV_LIB_DIR) $(CV_LIBS) -L $(FLYCAP_LIB_DIR) $(FLYCAP_LIBS)
# Clean up instructions
ifdef SystemRoot #This is windows
CXX = mingw32-g++
RM = del /Q
FixPath = $(subst /,\,$1)
BUILD_DIR := $(call FixPath, $(BUILD_DIR))
SRC_DIR := $(call FixPath, $(SRC_DIR))
SDK_INCLUDES := $(call FixPath, $(SDK_INCLUDES))
SRC := $(call FixPath, $(SRC))
OBJ := $(call FixPath, $(OBJ))
CXXFLAGS := $(call FixPath, $(CV_FLAGS))
define make-goal
$1\%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
else #more ifeqs can be added for more OS's but this should be fine
CXX = g++
RM = rm -f
define make-goal
$(1)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
endif
vpath %.cpp $(SRC_DIR)
SDK_LIBS = lib_core.a
default: SDK.exe
.PHONY: clean
clean:
$(RM) build *.a
#executable generation
SDK.exe: $(SDK_LIBS)
$(CXX) $(CXXFLAGS) $^ -o $#
lib_core.a: checkdirs $(OBJ)
ar rcs lib_core.a $(OBJ)
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
mkdir $#
#$(OBJ): $(SRC)
# $(CXX) $(CXXFLAGS) -c $^ -o $#
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
Your first problem is that you cannot use backslashes in GNU make rules, except in recipes (make just sends the recipe to the shell, it doesn't interpret the recipe except for $). All GNU make targets, prerequisites, etc. must use forward slashes, all the time, even on Windows.
Almost all Windows applications will accept forward-slashes as directory separators properly. For the few that don't, you can use your function FixPath, but you must use it inside the recipe, not in the target or prerequisite lists.
Once you've resolved that issue if you still have problems, post what you have and we'll look.
In a project that uses make and bison, I'm having difficulty specifying that the compiled grammar grammar.tab.c depends on the grammar input grammar.y, that each object file depends on a corresponding source file (including grammar.tab.o), and that the executable depends on all object files.
The problem is that running make when grammar.tab.c does not yet exist means that there is no attempt to build it, and when the executable is built the yyparse function is missing.
My Makefile is:
CFLAGS = -g -Wall
YACC = bison -d -r all
OBJ=$(patsubst %.c, %.o, $(wildcard *.c))
HEADERS=grammar.tab.h hex.h compiler.h types.h
all: grammar.tab.h c
clean:
rm -f $(OBJ) *.tab.c *.tab.h c c.exe *.output
c: $(OBJ)
$(CC) -o $# $(OBJ) $(CFLAGS)
grammar.tab.c: grammar.y
$(YACC) grammar.y
grammar.tab.h: grammar.y
$(YACC) grammar.y
%.o: %.c $(HEADERS)
$(CC) -c $< $(CFLAGS)
If I change it with:
OBJ=$(patsubst %.c, %.o, $(wildcard *.c)) grammar.tab.o
Then it will build the compiled grammar if it doesn't already exist. But if it does already exist, then
when building the executable, there will be an error about yyparse being provided twice (presumably because $OBJ contains grammar.tab.o twice).
What I'm aiming for is a Makefile that:
Will correctly build the executable on a make command, rebuilding intermediate files as necessary.
Will pick up all *.c files in the directory (i.e. doesn't need to be changed when new source files are added).
Is easy to read and understand. I don't mind learning new make features as long as it's only one or two at a time.
How do others' grammar-building Makefiles work?
Edit Ok, those are great answers. I went with the filter-out one, since it was the smallest change. I'm really glad that everyone seemed to know exactly what I'm talking about -- I was apprehensive about being told to use something byzantine like automake ;-).
Thanks everyone.
For the general 'run yacc' rule you want something like
%.tab.c: %.y
$(YACC) $<
%.tab.h: %.tab.c
#touch $#
To get all the sources you want
OBJ=$(sort $(patsubst %.c, %.o, $(wildcard *.c)) $(patsubst %.y, %.tab.o, $(wildcard *.y)))
You need the 'sort' mostly for its automatic removal of duplicates
# you can consolidate both rules into one:
grammar.tab.c grammar.tab.h: grammar.y
$(YACC) grammar.y
# but I find ``make'' more workable without many-to-one target-to-prerequisites
grammar.tab.c: grammar.tab.h
touch $#
grammar.tab.h: grammar.y
$(YACC) $<
# your problem, though, does seem to be with linking ``grammar.tab.o''
# you can exclude grammar.tab.o
OBJ =: $(filter-out grammar.tab.o,$(patsubst %.c,%.o,$(wildcard *.c))) grammar.tab.o
# you can remove duplicates from $(OBJ)
OBJ =: $(sort $(patsubst %.c,%.o,$(wildcard *.c)) grammar.tab.o)
# you can remove duplicates when linking
c: $(OBJ)
$(CC) $(LDFLAGS) -o $# $(sort $^) $(LDLIBS)
# but personally, I prefer not to use $(wildcard) at all,
# explicitly updating the makefile as needed
If you're using GNU make, you can use the filter-out predicate to manually exclude a particular file from the dependencies of a target. Like so: OBJ=$(filter-out $(grammar.tab.o), $(patsubst %.c, %.o, ...)) grammar.tab.o.
You first exclude grammar.tab.o from the existing object files (it might not be there), then add it back in all cases. Admittedly a bit roundabout, but it works. That's what we use at work.
Something like this... you'll have to play around with it. This is kind-sort-a how
I did this in the 90's... it's unconventional but served its purpose
SRCS = foo.c bar.c lex.c yacc.c
OBJS = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.o)
OBJS.d = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.d)
CC_RULE = $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
YACC_RULE = cd $(#D); $(YACC) $(YFLAGS) -o $(#F) $<
LEX_RULE = cd $(#D); $(LEX) $(LEXFLAGS) -o$(#F) $<
CC_DEP_RULE = #echo -n "$(#D)/" > $#;
CC_DEP_RULE += gcc -M $(DEFINES) $(INCLUDES) $< |
CC_DEP_RULE += sed -e 's#:#: $(MAKEFILE_DEPS) #' >> $#;
$(OBJ_DEST_DIR)/%.o: $(OBJ_DEST_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.l
$(LEX_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.y
$(YACC_RULE)
$(OBJ_DEST_DIR)/%.o: $(SRC_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.d: $(OBJ_DEST_DIR)/%.c
$(CC_DEP_RULE)
$(OBJ_DEST_DIR)/%.d: $(SRC_DIR)/%.c
$(CC_DEP_RULE)
-include $(OBJS.d)
This is what one of the .d files will look like
/tmp/builds/objs/opt/libiberty/static/alloca.o: /tmp/src/binutils-2.20/libiberty/alloca.c \
/tmp/src/binutils-2.20/libiberty/config.h \
/tmp/src/binutils-2.20/include/libiberty.h \
/tmp/src/binutils-2.20/include/ansidecl.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stddef.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stdarg.h \
/usr/include/stdio.h /usr/include/_types.h /usr/include/sys/_types.h \
/usr/include/sys/cdefs.h /usr/include/machine/_types.h \
/usr/include/i386/_types.h /usr/include/secure/_stdio.h \
/usr/include/secure/_common.h /usr/include/string.h \
/usr/include/secure/_string.h /usr/include/stdlib.h \
/usr/include/Availability.h /usr/include/AvailabilityInternal.h \
/usr/include/sys/wait.h /usr/include/sys/signal.h \
/usr/include/sys/appleapiopts.h /usr/include/machine/signal.h \
/usr/include/i386/signal.h /usr/include/i386/_structs.h \
/usr/include/sys/_structs.h /usr/include/machine/_structs.h \
/usr/include/mach/i386/_structs.h /usr/include/sys/resource.h \
/usr/include/machine/endian.h /usr/include/i386/endian.h \
/usr/include/sys/_endian.h /usr/include/libkern/_OSByteOrder.h \
/usr/include/libkern/i386/_OSByteOrder.h /usr/include/alloca.h \
/usr/include/machine/types.h /usr/include/i386/types.h \
You can play around with the MAKEFILE_DEPS variable to insert other dependencies too