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.
Related
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: ...
I have a Makefile containing rules for building a small project and cleaning it. For example:
CC:=gcc
LD:=gcc
SOURCES:=$(wildcard src/*.c)
OBJS:=$(SOURCES:src/%.c=build/%.o)
TARGET:=bin/program
all: $(TARGET)
$(TARGET): $(OBJS)
#mkdir -p bin
$(LD) $+ -o $#
build/%.o: src/%.c
#mkdir -p build
$(CC) $+ -c -o $#
clean:
rm -rf $(OBJS)
rm -rf $(TARGET)
rmdir bin
rmdir build
.PHONY: clean all
I am now interested in creating a rule rebuild which would perform clean and all in that order. I do not see how properly achieve the correct ordering.
The solutions I have seen are wrong to my knowledge.
rebuild: clean all
.PHONY: rebuild
Is naturally wrong, because there is no guarantee that dependencies are actually performed in the order of their appearance. all may execute before clean.
I have seen answers suggesting order-only dependencies, e.g.
rebuild: | clean all
.PHONY: rebuild
To my knowledge, this does not solve the problem. If you say a: | b c it means that a depends on b and c, but if b or c is taken, it does not force executing the a rule. It has nothing to do with ordering the dependencies.
The only option I see right now is launching a new instance of make, by having
rebuild : clean
make build
I would really like to avoid launching a new make instance for doing something simple like that!
I did some reasearch on SO. I have seen similar questions but no correct answer. To my knolwedge, making a target .PHONY or using order-only dependencies is not a solution.
First, it's not true that in a rule:
rebuild: clean all
that all could be built before clean when running serially (that is, without parallelism -j enabled). Make does always build prerequisites in the order they are listed in the makefile (there is a special case for the rule containing the recipe but that's not relevant here). When parallel builds are used then make still walks the dependency tree in the same order but because rules are built in parallel they may not be started in the same order.
However, you're right that this rule is not a great idea for other reasons (directory caching, etc.)
I recommend you use recursive make invocations to do this:
.PHONY: rebuild
rebuild:
$(MAKE) clean
$(MAKE) all
There is a way to do it without recursion; the price is a small amount of redundancy:
.PHONY: rebuild
$(TARGET) rebuild: $(OBJS)
#mkdir -p bin
$(LD) $+ -o $(TARGET) # note that I have replaced $# with $(TARGET)
rebuild: | clean
You can use MAKECMDGOALS to conditionally add a dependency between clean and all when the goal is rebuild. Something like this:
ifeq (rebuild,$(findstring rebuild,${MAKECMDGOALS}))
all: clean
rebuild: all
endif
Now, I don't really see the benefit of doing this in the makefile when there are other trivial and safe ways to do it (just "make clean && make all" might be a better option)
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.
I have a complex makefile with a lot of recipes. I would like run them with no parallel execution except for the generation of my objects files. I noticed that the .NOTPARALLEL target cannot take any prerequisites otherwise it would have been much easier to solve my issue.
My first guess was to use a nonexistent target named ".PARALLEL" with which I would have mentioned the objects files as dependancies like this:
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
.PARALLEL: $(OBJ)
%.o: %.c
gcc –c –o$# $< -M
a.out: $(OBJ)
gcc –o$# $^
A more functional solution I have found is to use an intermediate target. However, since MyObjects has no dependancies, make will always call MyObjects and recreate a.out.
%.o: %.c
$(CC) –c –o$# $< -M
MyObjects:
$(MAKE) -j $(OBJ)
a.out: MyObjects
$(CC) –o$# $(OBJ)
To avoid this I've found nothing better than using dummy files. I wrote this example to illustrate it:
NAMES = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
SRC = $(addsuffix .c, $(NAMES))
OBJ = $(patsubst %.c,%.o,$(SRC))
DUM = $(addsuffix .dummy,$(OBJ))
all: a.out
$(SRC):%.c:
touch $#
$(OBJ):%.o: %.c
cp $< $#
touch $(addsuffix .dummy, $#)
$(DUM):
$(MAKE) -j8 $(OBJ)
a.out: $(DUM) $(OBJ)
zip $# $(OBJ)
clean:
-rm *.o
-rm *.out
-rm *.c
-rm *.dummy
I'm sure this is not the best solution I can get. I would be glad to get some help.
P.S. MadScientist, thank you for your advices.
This is really not right:
MyObjects: $(OBJ)
$(MAKE) -j $(OBJ)
This means that before make tries to build the MyObjects target, it will first try to update all the $(OBJ) files. Once that's all done, then it will try to build the MyObjects target by recursively invoking make to rebuild them again. Obviously that's not what you want. Plus you're using -j which is basically "infinitely parallel" and is likely (if you have enough object files) to bring your system to its knees.
You want something like this:
MyObjects:
$(MAKE) -j5 $(OBJ)
As for your second question about trying to rebuild targets, there's no way we can help without some kind of specific example. Typically this happens because your rules are written incorrectly, and they don't actually update the target you told make they would. So for example, you have a target recipe_a but the rule for recipe_a updates some other target, not recipe_a.
I'll add a few notes based on your second question. Probably if you don't get it after this you should take this off of StackOverflow and ask on the help-make#gnu.org mailing list, or else consider breaking this up and asking several specific StackOverflow questions.
First, why you see make[1]: '15.o' is up to date. for every file in your recursive make: because make always prints that message for every target on the command line, so if you run make 1.o 2.o 3.o ... (doesn't matter whether you use -j or not or what value of -j you use) you'll get that message for every target which doesn't need to be rebuilt. Just as if you ran that same make command from the command line yourself.
Second, why you don't get a.out is up to date, because a.out is NOT up to date. It depends on the build target, and the file build doesn't exist, and thus it's out of date, and so it must be rebuilt every time. And that means anything that depends on the build target, like a.out, must be rebuilt every time. Which explains why it always re-runs the zip command.
Third, the behavior with all.c is because if you create a pattern rule like %.c: with no prerequisites, that tells make that it can create ANY file with a .c extension by running that command. Well, one of the targets you asked make to build is the all target. Since you didn't declare that as a .PHONY target, make tries to build it. Normally that attempt fails because make can't find any rules that know how to build all so nothing happens, but after you tell make how to build a .c file out of nothing (no prerequisites), then when make wants to build all it looks in its internal database of predefined rules and sees a pattern rule % : %.c, which tells make how to build an executable from a source file with the same name (on UNIX systems executables don't have any suffix like .exe: they're just make or cc etc.) So, make tries to run those rules and they fail.
For any target which you don't expect to actually be created, like all, clean, etc. you should declare them to be .PHONY so make won't try to build them.
As for your problem. I think the simplest thing to do is push the entire build of the zip file down into the recursive make, rather than trying to build the objects only in the recursive make. Something like this:
NAMES = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
SRC = $(addsuffix .c,$(NAMES))
OBJ = $(patsubst %.c,%.o,$(SRC))
all: recurse
recurse: non-parallel-targets
$(MAKE) -j8 a.out PARALLEL=true
ifneq($(PARALLEL),true)
.NOTPARALLEL:
endif
%.o: %.c
cp $< $#
a.out: $(OBJ)
zip $# $(OBJ)
init: $(SRC)
clean:
-rm *.o
-rm *.out
.PHONY: all clean init
I have a simple makefile with 3 build rules:
clean (that cleans the .o)
debug (compiles my code with debgging stuff)
release (compiles my code with optimization stuff)
sometimes I want to switch between debug mode and release so I would issue this
make clean debug -j8
or
make clean release -j8
that has a drawback because while it's doing the clean stuff, the -j8 allows make to jump some command since the .o are still there Then those .o are removed by the clean rule and the compiler complains because it can't find those .o
I could do something like
make clean; make debug -j8
but since I use an odd makefile in another dir, the command becomes
make -C ../src -f nMakefile clean ; make -C ../src -f nMakefile -j8 release
that is more annoying. I was wondering if there was an hiddedn-guru-mode-rule that allows me to do it in one line
Hope it's clear enough...
I needed to solve this very same problem, and the solution I came up was to parse the MAKECMDGOALS for clean, and dispatch a shell command to do the actual cleaning work; RATHER than clean the build as a target. This way, any MAKECMDGOALS that include "clean" will clean the build as part of that build, first, sequentially, rather than clean running asynchronously as its own target.
-include $(deps)
bin/%.o : %.cpp
#mkdir -p $#D
g++ $(flags) $(includes) -MMD -c $< -o $#
.PHONY : clean
clean:
#echo rm -rf bin/
ifneq ($(filter clean,$(MAKECMDGOALS)),)
$(shell rm -rf bin/)
endif
As I stated above, the normal practice is to have different sub directories for the object files. As you are running in parallel I would think you need to enforce serial execution so that clean is completed before release. One way of doing it could be:
clean_release: clean
+#$(MAKE) -s --no-print-directory release
or if you prefer
clean_release:
+#$(MAKE) -s --no-print-directory clean && $(MAKE) -s --no-print-directory release