run a program several times with a makefile - makefile

I'm really a beginner and I want to build a makefile so I can later run a program several times.
e.g. Terminal Input: make loop 6
loop: $(BIN)
terminalinput= $1 #e.g. the value 6
count=0
while [ $count -lt $terminalinput ]; do
./$(BIN) \
count=$((count+1))
done
I don't know how to get the terminal input and build it in the while loop. I use Ubuntu and I hope somebode can help me.
thank you in advance

You can pass make variables via command line, e.g. make loop LOOPS=10.
You can use ifdef in the Makefile to determine whether a variable has been defined, e.g.
ifdef LOOPS
loop: prog
for ((i=1; i <= ${LOOPS}; ++i)) do ./prog; done
.PHONY: loop
endif
prog:
# Commands for making prog
Together, this might come close enough to what you want.
The above should abort with an error message
(about not knowing how to make loop)
if you forget to define LOOPS in the command line.
If instead you want to have a default value for LOOPS,
simply define it in the Makefile. Then there is no need for ifdef:
LOOPS = 10
loop: prog
for ((i=1; i <= ${LOOPS}; ++i)) do ./prog; done
.PHONY: loop
prog:
# Commands for making prog
Now, make loop runs prog 10 times, but you can still override that
using e.g. make loop LOOPS=3.

I use gmake and must only change a little bit the answer of ccorn(thanks to you again). Because I had to write SHELL := /bin/bash in the first line of my makefile.
Now when I write make loop l=5 in my terminal the programm runs 5 times. When I only write make loop the program runs 10 times (the default value).
This is my little test-makefile:
SHELL := /bin/bash
BIN = stack
SRC = \
stacktest.c \
stack.c \
CC = gcc
CFLAGS = -g -Wall -Wextra -O3 -std=c99 -lm
OBJS = $(SRC:%.c=%.c)
all: $(BIN)
$(BIN): $(OBJS)
val: $(BIN)
valgrind ./$(BIN)
run: $(BIN)
./$(BIN)
l = 10
loop: $(BIN)
for ((i=1; i <= ${l}; ++i)) do ./$(BIN); done
I don't have include phony because I must first read up about that.
Thanks at all for the help! :)

Related

How to enable a makefile to escape wildcard braces

Consider following makefile snippet:
CXX := g++
test := sort{1..4} # i.e. sort1 sort2 sort3 sort4
#all: $(test)
$(test): %: %.cpp
$(CXX) -std=c++17 -Wall -O3 -o $# $<
clean:
rm -f $(test)
where sort1, sort2, sort3, and sort4 are expected to be the output (executable) files. However, when executing in shell:make $test or make clean, the wildcard { } seem NOT to expand, and the command can't remove those four files. How can I expand wildcard { } in a makefile?
Additionally, I've noticed a interesting phenomena: first let's use the non-expanded version (before I figure out above problem), with test := sort1 sort2 sort3 sort4 instead of line 3. When there is no target using the variable test (i.e. comment line 5), then if we try: make $test we will memerly compile sort1. However, when we try to use a target with prerequisites on this variable, for example, uncomment line 5, then make $test is equivalent to make all, thus generating four output files. How to explain this?
Thanks in advance for taking time for this trivial question, but it would mean a lot to me ;)
Although make does not expand sequence expressions internally, a shell that does expand them could be run from make; try the examples below.
Running make $test from a shell likely finds the shell variable $test not set and shell variable substitution yields nothing, so the command-line is reduced to only make, which goes about building the first target. When the #all: line is commented-out, make finds sort1 as the first target (provided test is set as expected); after removing the comment from #all, the first target will be all, so then make would handle the provided prerequisites.
CXX := g++
# straight assignment
test := sort1 sort2 sort3 sort4
$(info plain: "$(test)")
# foreach built-in
nset := 1 2 3 4
test := $(foreach n,$(nset),sort$(n))
$(info foreach: "$(test)")
# run a shell for sequence expression
test := $(shell echo sort{1..4})
$(info shell: "$(test)")
.PHONY: all
all: $(test)
$(test): %: %.cpp
$(CXX) -std=c++17 -Wall -O3 -o $# $<
clean:
rm -f $(test)

GNU make - how to serialize calls to foreach $(MAKE)

I have
$(foreach ___project___, $(UNIT_TEST_STUBS),$(MAKE) -C ../../$(___project___) $(UT_CMD) || exit 1;)
I want make to be parallel INSIDE each submake but I don't want the submakes to be executed in parallel.
How do I do this?
As #Michael Livshin points out, you already seem to have answered your own question.
Might be neater to rely on make rather than shell syntax to tie a load of commands together though.
Basically you want make to see something like this:
.PHONY: all
all:
${MAKE} -C ../../foo/ -j9 ut-cmd
${MAKE} -C ../../bar/ -j9 ut-cmd
${MAKE} -C ../../bum/ -j9 ut-cmd
Auto generation from a list is fairly straight-forward.
submakes := foo bar bum
define generate-submake
${MAKE} -C ../../$1/ ut-cmd
endef
.PHONY: all
all: ; $(foreach _,${submakes},$(call generate-submake,$1))
Note the blank line in the definition of generate-submake. It's important.
Run this with make -j9.
If you really want everything in this makefile to run serially (but the sub-makes to be parallel), then just introduce a .NOTPARALLEL target.
.NOTPARALLEL:

Gnu make: read recipe output into make variable

Is it possible to take a part of the output of a recipe line and use to to set a make variable? For example:
%.o: %.cc
$(eval __time_$* := $(shell date "+%s.%N"))
$(COMPILE.cc) -o $# $<
#echo `date +%s.%N` - $(__time_$*) | bc | xargs printf "%s compile time %6.3f sec\n" $#
Instead of echo'ing the time I want to capture it in a make variable. However, when I use eval and shell instead of the 3rd line above, similar to the 1st line, make appears to read all lines at once, and then schedule the actual recipe shell calls for later. So the result is that the recipe lines are all evaluated at once, so there is little time difference.
The only way I can see to do what you want is to run the compiler inside a $(shell). One problem with doing this is that Make doesn't seem to see the errors, when the command in $(shell) fails. Other than that, here's what I think you wanted:
%.o: %.cc
$(eval __start_$* := $(shell date "+%s.%N"))
#echo $(shell $(COMPILE.cc) -o $# $<)
$(eval __dur_$* := $(shell echo `date +%s.%N` - $(__time_$*) | bc | xargs printf "%s compile time %6.3f sec\n" $#))
Due to the caveat mentioned above, I recommend using the 'time' command to collect these stats, as #wojtow said. If you have different requirements, consider wrapping compilation with a script that collects your timing data and logs it to a file. Then, process the contents of the file as a post-processing step.
The only way I can see to do what you want is to run the compiler
inside a $(shell). One problem with doing this is that Make doesn't
seem to see the errors, when the command in $(shell) fails.
Droid Coder presented a clever approach. A way to solve the problem of make not seeing errors (thereby not aborting on error) is to pass the exit status via the output of the command, while the original compiler output (if any) is redirected to the standard error stream. The rule then is e. g.:
%.o: %.cc
$(eval __start_$* := $(shell date "+%s.%N"))
exit $(shell $(COMPILE.cc) -o $# $< >&2; echo $$?)
$(eval __dur_$* := $(shell echo `date +%s.%N` - $(__time_$*) | bc …))

Make in parallel

In this project, a top level rule looks like this:
all:
for l in $(LIBDIRS); do $(MAKE) -C $$l all; done
If I run make -jx, the files in each directory are compiled in parallel, but because of this bash loop, make doesn't move onto files in the next library until everything is done in the current one. What's the best way to change the loop so that it call truly be done in parallel? I only use gnumake, so gnu extensions are fine.
* Edit * as an aside, I was trying something like this
ALL_DEPENDENCY = $(foreach l, $(LIBDIRS), $(l).PHONY_LIB_RULE)
.PHONY: $(ALL_DEPENDENCY)
%.PHONY_LIB_RULE:
$(MAKE) --no-print-directory -C $(patsubst %.PHONY_LIB_RULE,%,$#) all
all: $(ALL_DEPENDENCY)
but these rules aren't tripped.
You can check this answer for an example of how to do this more correctly: makefile: foreach "make -C" call

Makefile is skipping certain dependencies

So I am writing a makefile that will take some files (*.in) as input to my C++ program and compare their output (results.out) to given correct output (*.out).
Specifically I have files t01.in, t02.in, t03.in, t04.in, and t05.in.
I have verified that $TESTIN = t01.in t02.in t03.in t04.in t05.in.
The problem is that it seems to run the %.in: %.out block only for three of these files, 1,3, and 4. Why is it doing this?
OUTPUT = chart
COMPILER = g++
SOURCES = chart.cpp
HEADERS =
OBJS = $(SOURCES:.cpp=.o)
TESTIN = tests/*.in
all: $(OUTPUT)
$(OUTPUT): $(OBJS)
$(COMPILER) *.o -o $(OUTPUT)
%.o: %.cpp
clear
$(COMPILER) -c $< -o $#
test: $(TESTIN)
%.in: %.out
./$(OUTPUT) < $# > tests/results.out
printf "\n"
ifeq ($(diff $< tests/results.out), )
printf "\tTest of "$#" succeeded for stdout.\n"
else
printf "\tTest of "$#" FAILED for stdout!\n"
endif
Additionally, if there is a better way of accomplishing what I am trying to do, or any other improvements I could make to this makefile (as I am rather new at this), suggestions would be greatly appreciated.
EDIT: If I add a second dependency to the block (%.in: %.out %.err), it runs the block for all five files. Still no idea why it works this way but not the way before.
First, I don't see how TESTIN can be correct. This line:
TESTIN = tests/*.in
is not a valid wildcard statement in Make; it should give the variable TESTIN the value tests/*.in. But let's suppose it has the value t01.in t02.in t03.in t04.in t05.in or tests/t01.in tests/t02.in tests/t03.in tests/t04.in tests/t05.in, or wherever these files actually are.
Second, as #OliCharlesworth points out, this rule:
%.in: %.out
...
is a rule for building *.in files, which is not what you intend. As for why it runs some tests and not others, here is my theory:
The timestamp of t01.out is later than that of t01.in, so Make decides that it must "rebuild" t01.in; likewise t03.in and t04.in. But the timestamp of t02.out is earlier than that of t02.in, so Make does not attempt to "rebuild" t02.in; likewise t05.in. The timestamps of t02.err and t05.err are later than those of t02.in and t05.in, respectively, so when you add the %.err prerequisite, Make runs all tests. You can test this theory by checking the timestamps and experimenting with touch.
Anyway, let's rewrite it. We need a new target for a new rule:
TESTS := $(patsubst %.in,test_%,$(TESTIN)) # test_t01 test_t02 ...
.PHONY: $(TESTS) # because there will be no files called test_t01, test_t02,...
$(TESTS): test_%: %.in %.out
./$(OUTPUT) < $< > tests/results.out
Now for the conditional. Your attempted conditional is in Make syntax; Make will evaluate it before executing any rule, so tests/result.out will not yet exist, and variables like $< will not yet be defined. We must put the conditional inside the command, in shell syntax:
$(TESTS): test_%: %.in %.out
./$(OUTPUT) < $< > tests/results.out
if diff $*.out tests/results.out >/dev/null; then \
echo Test of $* succeeded for stdout.; \
else echo Test of $* FAILED for stdout!; \
fi
(Note that only the first line of the conditional must begin with a TAB.)

Resources