missing operand after `homework1' - Makefile - makefile

I keep getting an error message that says "diff: missing operand after `homework1'", but I have included a bash file. Can someone take a look at my makefile and give me a hint on how to fix it? Thanks!
#
# $RCSfile$
# $Revision$
# $Author$
# $Date$
# $Log$
#
CC=gcc
DEBUG=-g
CFLAGS=#(DEBUG) -Wall -Wshadow -Wunreachable-code -Wredundant-decls -Wmissing-declarations -Wold-style-definition -Wmissing-prototypes -Wdeclaration-after-statement
PROGS=homework1
all: $(PROGS) test
homework1: homework1.o
$(CC) $(CFLAGS) -o homework1 homework1.o
homework1.o: homework1.c
$(CC) $(CFLAGS) -c homework1.c
test: *
diff $(PROGS) $(example.bash) || exit 0
clean:
rm -f $(PROGS) *.o *~

You've referenced a make variable $(example.bash) but there is no variable example.bash set in your makefile. Did you mean the file example.bash? You shouldn't use make variable syntax, if that's true:
test: *
diff $(PROGS) example.bash || exit 0
(why do you have * as a prerequisite here? That doesn't seem useful)

To compare the output of two commands using diff, you need the output of at least one of those two commands redirected to a file while the output of another command is piped to the input stream of diff. Here is an example that replaces $(PROGS) with its output file:
./$(PROGS) > progs_output
bash example.bash | diff progs_output - || exit 0
It executes the value of $(PROGS), sending its output to a file called progs_output. Then the bash script is executed, with its output piped to the standard input stream of the diff utility, which compares progs_output with the stuff coming from its standard input stream. Everything else is your doing. Why would you use exit 0 though? If the test fails, wouldn't you want make to tell you?
Also, what's with the asterisk (*) as a prerequisite for the test target?

Related

How to compile a test snippet nicely with gnu make?

I don't have a configure stage in my baseline (for various reasons), but I need to check whether my C compiler can support the -mavx2 flag or not.
If I have an empty file, call it test.cc then I can do something like:
$(CC) -mavx2 -c test.cc -o test.o
And check the return status code. Obviously I don't want to leave those test.* files lying around though, but can't think of a good way to generate/test/delete them outside of a recipe. Does anyone know of a good pattern to do this?
Or, you could just take input from stdin, and output to /dev/null:
SUPPORTS_MAVX2:=$(shell echo 'void main(){}' | \
gcc -x c -maxv3 -o /dev/null - 2>/dev/null; \
echo $$?)
Then there are no artifact files to be deleted. The -x c is necessary to tell gcc what language it is (as it can't determine that from the filename in this case), and you need the trailing - as well.
Turns out you can use "eval" to remove the temporary file and return the status code, so this works:
AVX2 = $(shell touch test.cc; $(CC) -mavx2 -c test.cc -o /dev/null >& /dev/null; eval "rm -f test.cc; echo $$?")
Edit and without the temporary file (assuming a sane system):
AVX2 = $(shell $(CC) -mavx2 -c /usr/include/stdlib.h -o /dev/null >& /dev/null; echo $?)

Reduce recipe echoing in make

I know the silent flag (-s) for make will hide the recipe echoing completely, however this makes it hard to see progress.
For example currently I have hundreds of lines such as (I've broken up the line to fit SO):
g++ -I. -std=c++11 -Wall -Wno-unused-local-typedefs -Wno-literal-suffix
-Wno-unused-but-set-variable `wx-config --cxxflags --unicode=no`
-MT dialog_export.o -MD -MP -MF .deps/dialog_export.Tpo
-c -o dialog_export.o dialog_export.cpp
It would be great if it could just print part of the line, say without the flags, something like:
g++ dialog_export.o dialog_export.cpp
Or just some way of seeing progress, but without spamming the console with a tonne of messages.
A number of build systems from the autotools to the kernel build system to CMake, etc. do this sort of thing.
The trick is to dynamically control whether the silencing # is present on the recipe lines or not and if it is to replace it with a manual echo of some friendlier message.
To get a message like what you want you would use something like this:
E_g++ := #echo 'g++ $(filter %.o,$^) $#'
%.o: %.cpp
$(E_g++)g++ ... -o $# $^
To make this sort of thing easier for myself in projects that don't use the autotools or anything like that I wrote Silent Make Rules.
Which you would use like this:
include silent_rules.mk
$(eval $(call vrule,G++,g++ $$(filter %.o,$$^) $$#))
%.o: %.cpp:
$(SR_V_G++)g++ ... -o $# $^
This would also (like the autotools and kernel make versions) allow you to specify V=1 on the make command line to go back to the normal make output and use V=-1 to silence the output entirely.
I like rules like this:
dialog_export.o: dialog_export.cpp
#echo $#...
#g++ -I. -std=c++11 -Wall -Wno-unused-local-typedefs -Wno-literal-suffix -Wno-unused-but-set-variable `wx-config --cxxflags --unicode=no` -MT dialog_export.o -MD -MP -MF .deps/dialog_export.Tpo -c -o $# $<
The leading '#' symbols suppress command echoing, and the first command echoes the name of the target:
dialog_export.o...
If you have a makefile with hundreds of rules, you can convert them all to that form in minutes with a good editor. Or faster with a macro or sed, if you're bold.
(If you have hundreds of lines like that, your makefile can probably be simplified quite a lot, but that's for another day.)
I always use $(Q):
ifeq ("$(V)","1")
Q :=
vecho = #echo
else
Q := #
vecho = #true
endif
somerule:
$(vecho) building $# verbosely
$(Q)do command
You can then modify your pattern rules to only output the text you care about. If you need more verbose, then you just build with make V=1. I don't think there's any shortcut in make to doing this automatically save piping your output through sed (which I wouldn't recommend).

How to hide print information of Makefile?

when Makefile execute some tasks, il will print many information in console, can we choose to hide them? when I have many .o to generate, these information will be too many to see and they are just meaningless if we don't read them.
The following code
$(obj)environment.o: $(src)environment.c
$(CC) $(AFLAGS) -Wa, --no-warn \
-DENV_CRC=$(shell $(obj)../tools/envcrc) \
-c -o $# $(src)environment.c
will print heavy information like
arm-linux-gcc -g -Os -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float
-D__KERNEL__ -DTEXT_BASE=0x01000000
-I/home/mingzhao/Documents/bootloader/u-boot-1.2.0/include
-fno-builtin -ffreestanding -nostdinc -isystem
/home/mingzhao/Documents/bootloader/arm/4.3.2/bin/../lib/
gcc/arm-none-linux-gnueabi/4.3.2/include -pipe -DCONFIG_ARM
-D__ARM__ -march=armv4 -mabi=apcs-gnu -Wall -Wstrict-prototypes
-c -o environment.o environment.c
The "right" way to handle this (IMO) is to add this to your makefile:
$(VERBOSE).SILENT:
Then in your rules where you don't ever want the command printed (for example, an echo statement as in Beta's answer below) you prefix it with #. For all other commands, you don't prefix it with #.
What this does is enable "silent" mode by default (because the variable VERBOSE is not set and so this resolves to the .SILENT pseudo-target).
Then if you want to see everything, you add a VERBOSE=1 (actually you can set it to any non-empty value, so VERBOSE=true if you prefer). When you do that it turns off "silent" mode because the above line expands to 1.SILENT: (or true.SILENT: or whatever) which is meaningless to make.
You can use the option make --silent which will suppress output for all targets. If you want to suppress output for some commands, you can prefix them by #
I like something like this:
$(obj)environment.o: $(src)environment.c
#echo building $#
#$(CC) $(AFLAGS) -Wa, --no-warn \
-DENV_CRC=$(shell $(obj)../tools/envcrc) \
-c -o $# $(src)environment.c
The #echo ... gives a minimal status message, the '#' in front of the $(CC) suppresses standard output (but still allows error messages).
You can use this syntax : #$(CC) $(AFLAGS) -Wa, --no-warn \...

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.)

Compilation errors with Make File creation

While running my make file which is as follows,
../bin/output : ../lib/libfun.a ../obj/main.o
gcc ../main.o -L ../lib/ -lfun -o $#
../lib/libfun.a : ../obj/file_write.o ../obj/error.o
ar -rc $# $^
../obj/main.o : ../src/main.c
gcc -c $^ -o $# -I ../include
../obj/file_write.o : ../src/file_write.c
gcc -c $^ -o $# -I ../include
../obj/error.o : ../src/error.c
gcc -c $^ -o $# -I ../include
I am getting error like
make: Warning: File `makefile' has modification time 2.2e+03 s in the future
ar -rc ../lib/libfun.a ../obj/file_write.o ../obj/error.o
ar: ../lib/libfun.a: No such file or directory
make: *** [../lib/libfun.a] Error 1
and sometimes
"* missing separator (did you mean TAB instead of 8 spaces?). Stop"
Why is this happening? I gave correct Target,Pre-Requests and Command values whichever needed. Whats wrong in this?
For the first error, make sure the ../lib directory exists before trying to create a library in it. ar will return that error if the path doesn't exist.
For the second make syntax is strict: the commands after a target must be indented with a tab, not spaces.
target: deps
command
# ^ this here needs to be a tab character, not spaces

Resources