Why does this make file only call one target? - makefile

I am new to make and I am trying to make a super simple build script. This is what I have:
.PHONY: all main
all:
mkdir -p build && cd build
main: main.o install
g++ -o main main.o
main.o: ../src/main.cpp
g++ -c ../src/main.cpp
.PHONY: install
install:
mkdir -p build
mv main.o build
.PHONY: clean
clean:
rm -r build/
I would expect it to call all followed by main. In actuality, here's what happens:
$ make
mkdir -p build && cd build
Only all is called and main is not ran. Why? I have main as a prerequisite after all in the .PHONY line. And help?

.PHONY is not a real target (it is a special make construct), and does not cause its prerequisites to be run. Instead, the first real target mentioned is all, and if you just type make, it will invoke the all as the default target. Because all is not dependent on anything, it is the only target that is run.
You can add a line at the very top:
default: all main
which will cause both all and main to run (don't forget to add default to .PHONY. Notice though that you are not guaranteed that all will run before main. If you want to guarantee this, you would also have to add
main: all
which would force all to be run before main

Related

Makefile loses configuration

I'm pretty much a makefile novice so I don't even know the terminology I'm looking for. I'm trying to build the latest valgrind release alongside other 3rdparty tools my company uses. I basically have
../3rdparty/
/Makefile <- What gets called to recursively build everything
/valgrind/Makefile <- What I'm pasting below
/valgrind/valgrind-3.16.1/Makefile <- what gets configure'd
So I can go into ../3rdparty/valgrind/valgrind-3.16.0/ and call...
./configure --host=arm-linux-gnueabihf
make
...and have it succeed without issue. However, when I try to build it from the Makefile in ../3rdparty/valgrind I get errors due to configuration generated variables being lost. I can see it clean up everything, I can see configuration succeed, but when the make process starts I get warnings that aren't seen using the process above.
cc1: warning: switch -mcpu=cortex-a8 conflicts with -march=armv7ve switch
Which eventually leads to an error
<command-line>:0:5: error: expected identifier or ‘(’ before numeric constant pub_core_basics.h:78:12: note: in expansion of macro ‘ARM’
I basically copy pasted what is used for other 3rd party libs in our codebase and made changes where applicable....
include ../common.mak
VERSION=valgrind-3.16.1
all: configure build #install
configure: configure_$(TARGET)
configure_$(TARGET):
$(MAKE) distclean
#echo -e "\nConfiguring $(VERSION) for $(TARGET)...\n"
pushd $(VERSION)/ \
&& bash configure --host=${TARGET} \
&& popd
touch $#
#echo -e "\nConfiguration $(VERSION) complete for $(TARGET)...\n"
build: configure
$(MAKE) "-SC" $(VERSION)
install: build
$(MAKE) -SC $(VERSION) $#
# call folder's makefile targets verbatim
clean distclean:
test -f $(VERSION)/Makefile && $(MAKE) -SC $(VERSION) $# || :
rm -f configure_*
uninstall:
$(MAKE) -SC $(VERSION) $#
I'm guessing it's a one line thing, but I'd also be interested in any docs or websites that would be
useful. A lot of makefile tutorials go over the same super basic stuff.

About execution order in makefile

in this Makefile:
ifeq ($(shell uname),Darwin)
LDFLAGS := -Wl,-dead_strip
else
LDFLAGS := -Wl,--gc-sections -lpthread -ldl
endif
all: target/double
target/double
target:
mkdir -p $#
target/double: target/main.o target/debug/libdouble_input.a
$(CC) -o $# $^ $(LDFLAGS)
target/debug/libdouble_input.a: src/lib.rs Cargo.toml
cargo build
target/main.o: src/main.c | target
$(CC) -o $# -c $<
clean:
rm -rf target
when i excute make all, get this output:
hello_c_use_rust [master] ⚡ make all
mkdir -p target
cc -o target/main.o -c src/main.c
cargo build
Compiling hello_c_use_rust v0.1.0 (/Users/jelly/code/own/hello_rust/hello_c_use_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
cc -o target/double target/main.o target/debug/libdouble_input.a -Wl,-dead_strip
target/double
4 * 2 = 8
Please tell me why this is the execution order ? txs ^_^.
What puzzled me was why the first step was mkdir -p target;
Your goal is all. all depends on target/double that must thus be done first. In turn target/double depends on target/main.o and target/debug/libdouble_input.a. So target/main.o and target/debug/libdouble_input.a must be done first. Here, you are lucky (we'll see why later): make tries to build target/main.o first. As target/main.o has target as a prerequisite, target must be done first and it is. Qed.
Note: target is an order-only prerequisite of target/main.o, not a regular prerequisite (the | sign starts the list of order-only prerequisites). It means that make pays only attention to its existence. It ignores its last modification time, which is good as last modification times of directories are usually not relevant in a build process.
Why is target a prerequisite of target/main.o? Because you cannot build target/main.o if the target directory does not exist yet. The build would simply fail. So the order-only prerequisite tells make that the directory must exist first.
Why are you lucky? Because if make had tried to build target/debug/libdouble_input.a first and if cargo build does not create the destination directory, it would have failed. Even if you know that target/main.o is built first because it is the first prerequisite of target/double, you should not count on this. One day or another somebody could try to use parallel make (make -j) and things could go wrong. Moreover target could exist but not target/debug...
Note: even if you know that cargo build takes care of creating the destination directory it is probably wise to add one more order-only prerquisite to your Makefile. Just in case something changes one day or another. And also to show readers of your Makefile that you know what you are doing here:
target target/debug:
mkdir -p $#
target/debug/libdouble_input.a: src/lib.rs Cargo.toml | target/debug
cargo build
It is not a big deal and could save you some errors.

Make rebuilds everytime

I have a Makefile as :
BUILD_DIR= $(BASE_DIR)/build
_OBJ := a.o b.o
CLEAN_OBJECTS := $(_OBJ)
.PHONY: clean
create_code:
python ../script/my_script.py
all: create_code $(_OBJ)
$(_OBJ): %.o: %.c
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $(INCLUDE_PATH) -c $< -o $#
cp *.o $(BUILD_DIR)
clean:
rm -f $(CLEAN_OBJECTS)
The target create_code executes the python script and generates a set of .c/.h files.
The target _obj compiles them.
Every time I run make all , create_code target is run even though there is no change to .c/.h generated earlier .
Any suggestions on why this is happening and how to make this create_code target run only if make clean was done earlier .
The underlying problem is that you have one or more generated files that depend on something other than the underlying file system -- namely the contents of your database.
One possibility would be to take advantage of the fact that make, having invoked a rule to rebuild a target will, nonetheless, always check the update time of that target when it is specified as a prerequisite in any other rule.
So, given the rule (untested)...
.PHONY: FORCE
%.c: FORCE
command-to-generate-source $#.tmp
diff -q $#.tmp $# || cp $#.tmp $#
Invoking make foo.c from the command line. make will run the commands...
command-to-generate-source foo.c.tmp
diff -q foo.c.tmp foo.c || cp foo.c.tmp foo.c
where command-to-generate-source foo.c.tmp is expected to leave its output in foo.c.tmp. If the newly generated output file is different than the existing file the cp operation will be run and, hence, the target timestamp will be updated and anything dependent on the target will be updated accordingly.
If, however, the newly generated output file is the same as the existing one then no cp will be run, the target file will be left untouched and make will not consider it to be changed when it appears as a prerequisite in other rules.
This is just one possibility but it's the obvious one given that you already have most (if not all) of the required logic in the command python ../script/my_script.py.

makefile parallel clean+compile issue

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

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