Makefile skips dependency - makefile

I've created a makefile for my little project
.SUFFIXES:
%.cpp:
$(COMP) -c -o $(subst .cpp,.o,$#) $(SRCDIR)$# $(CFLAGS)
platformL: COMP:=gcc
platformL: $(FILES)
$(COMP) -o $(NAME) $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
platformW: COMP:=wine gcc
platformW: $(FILES)
$(COMP) -o $(NAME).exe $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
default: platformL platformW
echo Done!
Everything worked fine until I branched to 2 different platforms, 'make' command executes only my platformL branch. After spending some time with it I discovered that adding '.PHONY' won't fix the problem. Also, it appears that only the first branch from the top gets executed (I have put the lines of platformW before platformL and only Windows compilation was performed).
How can I make it execute both branches?

Make always builds the first explicit target (and all prerequisites of the first explicit target) in the makefile, by default. That's all it will build by default.
You can either specify multiple things to build on the command line, like make platformL platformW, or you can add a new first target that depends on all the other targets you want built. By tradition that target is named all but you can call it whatever you want:
all: platformL platformW
.PHONY: all
...
platformL: ...
...
platformW: ...

Related

How to avoid this recursive Makefile to relink?

today I'm requesting your help about a Makefile that's driving me crazy. There it is:
# Executable name
NAME = libft.a
# Compiler and archive linker settings
CC = gcc
AR = ar
CFLAGS = -Wall -Wextra -Werror -O3 -g3
ARFLAGS = -rsc
IFLAGS = -I./includes/
# Project layout
SRC_DIR = ./src/
INC_DIR = ./inc/
OBJ_DIR = ./obj/
OBJ = $(shell grep -r .o ./obj | awk '{print $$3}' | tr '\n' ' ')
.PHONY: all clean fclean re
#------------------------------------------------------------------------------#
all: $(OBJ_DIR) $(NAME)
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
$(NAME): compile $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $(NAME) $(OBJ)
#echo " ✧ $(AR) $(ARFLAGS) $(NAME) object files: OK! √\n"
compile:
make -C src/io
make -C src/lists
make -C src/memory
make -C src/strings
make -C src/tests
I've tried multiple combination of dependencies, rules, etc but I just don't get it. Sometimes I got it to stop relinking but in thoses cases it wouldn't re-compile object files because $(OBJ) was empty and wasn't updated after I ran compile.
This version is close to be good, but everytime I run make it executes the recipe $(NAME) and does the ar -rsc %(OBJ) .. How can I put them in dependencies to $(NAME) ?
Well, basically your entire approach here cannot succeed. Just for one example: you are trying to find the object files using grep (honestly I don't understand that shell command at all; what does printing the $3 word from the output of grep -r do??? Don't you just mean find $(OBJ_DIR) -name \*.o here?) This will expand to all the object files found in your subdirectories. But, that shell command runs when your top-level makefile is parsed, and that parsing happens before make runs any rules... so, no object files have been built yet! So, this target doesn't depend on anything. Even after some object files have been built, it only depends on object files that already exist, not on object files that are created during the build.
Really if I were you I'd do this completely differently. However, the simplest way to make your makefile work properly as written is to build $(NAME) using a recursive make as well; change your makefile like this:
all: compile
$(NAME): $(OBJ) $(INC_DIR)libft.h
#echo "Linking library $(NAME).\n"
#$(AR) $(ARFLAGS) $# $^
#echo " ✧ $(AR) $(ARFLAGS) $# object files: OK! √\n"
compile:
mkdir -p $(OBJ_DIR)
$(MAKE) -C src/io
$(MAKE) -C src/lists
$(MAKE) -C src/memory
$(MAKE) -C src/strings
$(MAKE) -C src/tests
$(MAKE) $(NAME)
Here all doesn't depend on $(NAME); instead, the compile step first builds everything then at the end it recursively invokes itself to build $(NAME); at this point we know everything is up to date and we can depend on the object files existing.
Other things: note I used the automatic variable $^ here not $(OBJ); that variable is a simple variable that runs a shell script: it's expensive! Every time you expand the $(OBJ) variable you pay that cost, so you only ever want to do it one time. Alternatively, you can use := to set OBJS instead so it's only invoked once per make instance. That's still one more time than you need but avoiding this will be painful.
I also moved the mkdir into the compile rule. It's cleaner there than as a prerequisite of all.
Finally, you should never invoke sub-makes using the make command directly. Always use the $(MAKE) variable, or various things will not work correctly.
The question was obvioulsy solved by the previous post.
You need to use the $(MAKE) variable to call recursively your make file with the $(NAME) rule instead of putting $(NAME) as a all dependency, after subsequent calls to your underlying Makefiles using the $(MAKE) variable again.

Makefile automatic variable changed by prerequisite

first time here. I am relatively new to makefiles. Here is my current makefile:
# Closure compiler php script path
closure = ../../cli/scripts/Compilers/closure.php
# Destination directory
dest = ../../static/js/
# Build directory
build = build/
# Tell "make" to search build and destination dirs
vpath %.o $(build)
vpath %.js $(dest)
all: main.js
#echo "Done.";
main.js: \
date.o \
jquery.autocomplete.o \
jquery.bullseye.o \
jquery.clickopen.o \
jquery.fbmodal.o \
jquery.helpers.o \
jquery.pulljson.o \
jquery.thumbrotate.o \
jquery.timefmt.o \
jquery.tools.o \
layout.main.o
cat $^ > $(dest)$#
%.o: %.js
php $(closure) $*.js $(build)$#
clean:
rm -rf $(build)*.o
rm -rf $(dest)*.js
The problem is with the following line:
cat $^ > $(dest)$#.
It is supposed to cat all the prerequisite objects (minified javascript) into one final js library. According to makefile docs, $^ is an automatic variable which contains a list of prerequisites with directories they are in. From my experience, it behaves differently depending on wether prerequisite needs to be compiled or not.
If prerequisite is up-to-date, this code works perfectly and $^ contains a list like:
build/date.o build/jquery.autocomplete.o build/jquery.bullseye.o....
However if prerequisite needs a fresh compile, then $^ gets directory part stripped and looks like:
date.o jquery.autocomplete.o jquery.bullseye.o
Only the file which needs a fresh compile gets directory part stripped.
I have managed to work around this issue by replacing
cat $^ > $(dest)$#
with
cat $(addprefix $(build), $(^F) ) > $(dest)$#.
I don't like it because:
It's a hack
$(^F) is semi-deprecated
I want to understand why make behaves like this.
thanks
Look here:
# Tell "make" to search build and destination dirs
vpath %.o $(build)
If Make is looking for foo.o, it will look in the local directory first. If it finds no foo.o there, it will look in $(build) (i.e. build/, and you might reconsider your variable names).
And how would Make build foo.o, if it couldn't find it anywhere? With this rule:
%.o: %.js
php $(closure) $*.js $(build)$#
This rule violates an important guideline of makefiles, in that the target (foo.o) is not the name of the thing actually built (build/foo.o).
Now consider what happens when Make tries to execute this rule:
main.js: date.o ...
cat $^ > $(dest)$#
So if date.o is up to date, it's in build/. Make finds it there, and the automatic variable $^ expands to build/date.o ...
But if date.o must be rebuilt, then Make looks to the %.o rule, which promises to build date.o (not build/date.o), so Make takes that rule at its word and $^ expands to date.o ...
There are several ways to solve this problem. I'd do something like this:
OBJS := date.o jquery.autocomplete.o jquery.bullseye.o ...
OBJS := $(addprefix $(build),$(OBJS))
$(dest)main.js: $(OBJS)
cat $^ > $#
# you might have to tinker with this rule a little
$(build)%.o: %.js
php $(closure) $< $#

Simple pattern rule in make

I've written a simple make to test with pattern rule. Here it is:
default:
echo This is default target
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
I have a three *.c files in pwd. After make command I have:
echo This is default target
This is default target
but I expected that any *.c file in pwd will be compiled.
The first target in the makefile is the one that is built when you do not specify a specific target name.
In your makefile, default is first, so it is created.
Often, you'll create a target all as the first target, and list the programs that should be built by some more or less devious means.
.PHONY: default all clean
default:
#echo "You must specify which program you want built (or specify all)"
SRCS = $(wildcard *.c)
PROGS = ${SRCS:.c=}
all: ${PROGS}
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
The .PHONY target specifies that default, all and clean are not real files but phony targets.
I have a directory with many source files in it, and I have a default rule similar to the above as the first target, but I also have an all target so that make all works sensibly.
I prefer to use the ${...} notation around make variables, which make has always accepted; many people use $(...) notation the whole time.
I think default is your program target, but it did not link any objects? see my makefile:
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
default:
#echo This is default target
Program: $(OBJS)
gcc $^ -o $#
$(OBJS): $(SRCS)
gcc -c $^
clean:
rm -f $(OBJS) $(Program)
if you type make, it just echo This is default target, if you want to make real target, you can type make Program

Adding dependencies changes the target to the first C file

Consider the following makefile:
.SUFFIXES:
SRC:=../Src
OBJ:=../Obj
# Sources
SOURCES := $(SRC)/App/a.c $(SRC)/App/b.c $(SRC)/App/c.c
HEADERS := $(wildcard $(SRC)/App/*.h)
# Directories
INC_DIRS := $(SRC)/App
OBJ_INC_DIRS := $(INC_DIRS:$(SRC)/%=$(OBJ)/%)
# Objects
OBJECTS := $(SOURCES:$(SRC)%=$(OBJ)%.obj)
# Dependencies
DEPS := $(SOURCES:$(SRC)%.c=$(OBJ)%.d)
-include $(DEPS)
GCC_INCLUDES := $(foreach directory, $(INC_DIRS), -I$(directory))
all: target
target: $(OBJECTS)
touch target
#Objects
$(OBJ)%.c.obj: $(SRC)%.c
#echo Compiling $#
#touch $#
# Dependencies
$(OBJ)%.d: $(SRC)%.c
#echo Checking dependencies for $<
#gcc -MM $< $(GCC_INCLUDES) -MT '$(patsubst %.d,%.c.obj,$#)' -MT '$#' -MF '$#'
#[ ! -s $# ] && rm -f $#
# Creating directory tree before checking dependencies
$(DEPS):|$(OBJ_INC_DIRS)
$(OBJ_INC_DIRS):
#mkdir $#
clean:
echo clean
#rm $(OBJ_INC_DIRS)
When running the first time, I get:
Checking dependencies for ../Src/App/a.c
Checking dependencies for ../Src/App/b.c
Checking dependencies for ../Src/App/c.c
clean
Compiling ../Obj/App/a.c.obj
Compiling ../Obj/App/b.c.obj
Compiling ../Obj/App/c.c.obj
touch target
It's ok, but now, make again (without modifying any file):
make: `../Obj/App/a.c.obj' is up to date.
Now if I modify the file a.c
Checking dependencies for ../Src/App/a.c
Compiling ../Obj/App/a.c.obj
target isn't remade !
It's like my file a.c is the target but it isn't... Can someone explain me what's wrong here?
If I remove the include to the DEPS, I observe the expected behavior...
Thanks
EDIT
By putting the include at the end as mentioned by #Beta works but now I added the target clean and show the result...
I'll have to do some experiments to be sure, but I think the problem is:
-include $(DEPS)
...
all: target
You include $(DEPS) before the first target. So if you modify a.c, Make sees that it must rebuild a.d, then since it includes that file it must start over, and now a.c.obj is an earlier target than all.
Try moving -include $(DEPS) to the end of the makefile.
EDIT:
(Two small points: your clean rule is incorrect, since it tries to rm a directory, and I would do make clean; make all rather than make all, since I am not certain that Make promises to build targets in the given order in all cases.)
Yes, this makefile will rebuild the DEPS even when running clean. The makefile includes those files and has a rule for them, so if they are missing or out of date it must rebuild them and restart, no matter what the target is. The best way to deal with this is by Advanced Auto-Dependency Generation; basically, the commands that build dependency files go in the %.obj rule, so that a.d is a side effect of building a.c.obj. It's a sophisticated technique, not obvious, but it works beautifully. (Let us know if you try this and have trouble setting it up.)

Pre-build step in makefile

How can I run a script, which must execute before all other makefile commands? And it will be nice (but not mandatory) to the script is not executed if there is nothing to build.
I've searched SO and Google, but can't find anything.
I have this workaround:
# myscript.bat output is empty
CHEAT_ARGUMENT = (shell myscript.bat)
CFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)
AFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)
But it's very ugly. Is there other way to run "pre-build step" in makefile?
I propose two solutions. The first mimics what NetBeans IDE generates:
CC=gcc
.PHONY: all clean
all: post-build
pre-build:
#echo PRE
post-build: main-build
#echo POST
main-build: pre-build
#$(MAKE) --no-print-directory target
target: $(OBJS)
$(CC) -o $# $(OBJS)
clean:
rm -f $(OBJS) target
The second one is inpired by what Eclipse IDE generates:
CC=gcc
.PHONY: all clean
.SECONDARY: main-build
all: pre-build main-build
pre-build:
#echo PRE
post-build:
#echo POST
main-build: target
target: $(OBJS)
$(CC) -o $# $(OBJS)
#$(MAKE) --no-print-directory post-build
clean:
rm -f $(OBJS) target
Note that in the first one, pre and post builds are always called regardless of whether the main build is determined to be up to date or not.
In the second one, the post-build step is not executed if the state of the main build is up to date. While the pre-build step is always executed in both.
Depending on your make version, something like the following should at least avoid running dozens of times if CFLAGS and AFLAGS are evaluated dozens of times:
CHEAT_ARG := $(shell myscript)
Note the colon.
This runs exactly once. Never more than once, but also never less than once. Choose your own tradeoffs.
You could add a special target to your Makefile and have all your build rules depend on that:
run-script:
myscript
.o.c: run-script
$(CC) $(CFLAGS) -o $# $<
.o.S: run-script
$(AS) $(AFLAGS) -o $# $<
Depending on what your script actually does, putting it to run once in a stage before the Makefile (configure stage in autoconf terms) could make even more sense (and be less work).
What you are proposing seems a bit "un-make-like". Why not just run the command in whatever makefile target you need it to go before?
Example, if you need it to run before linking foo:
foo: ${OBJS}
my-command-goes-here
${CC} -o $# ${OBJS} ${LIBS}
Thank you for answers. ndim helped me much, asveikau. The final file is one binary executable, so I can use now something like this:
run-script:
myscript
$(AXF_FILE): run-script $(OBJ_DIRS) $(OBJ_FILES)
$(LINK) #......
It will run myscript once. {AXF_FILE} value depends on myscript and I must run it before. And in this case myscript runs always, not only when rebuild is needed.
After, The Simplest Answer came to my mind:
all: run-script $(AXF_FILE)
That's all ;) (Of course, any target can be used instead of "all")
Edit: this method execute script after $(AXF_FILE) is calculated too. So it's possible to get wrong value of AXF_FILE.
Now only the first answer by ndim works as I need.

Resources