Makefile many similar files - makefile

With many similar files in a directory:
answer1.c
answer2.c
answer3.c
To be able to run:
# make s1
# ./answer1
Currently I have:
s1:
gcc -Wall -ansi answer1.c -o answer1
s2:
gcc -Wall -ansi answer2.c -o answer2
etc.
I know I can put the compiler and the flags in variables, which makes changing things later easier. However, is there a way (some kind of macro expansion) to automate, something like:
#=1 2 3 4 5 6
s#:
gcc -Wall -ansi answer#.c -o answer#
Or even better
#=range(7)
Or would I be better off using a scripting language, perhaps to write the Makefile?

I'd use just 3 lines of makefile:
CFLAGS = -Wall -ansi
all: answer1 answer2 answer3
With that, you can simply run make and it knows what you want it to do: it will create program answer1 from answer1.c, and program answer2 from answer2.c, and program answer3 from answer3.c.
To build any one of the programs, simply say:
make answer2
Etc.

You're looking for pattern rules:
s%: answer%
answer%: answer%.c
gcc -Wall -ansi $< -o $#
Issue make -p | less (at least with GNU make) and you will see that make already has built-in rules very similar to that.

Related

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

Why does Make use ASFLAGS for both gcc and as when their flags aren't compatible?

I want to assemble and link some code for a 32-bit target from a 64-bit host, and I'm trying to use make's implicit rules as much as possible.
If I put -m32 in ASFLAGS it works fine for linking and assembling in one step, as make will use gcc for this. But if one of my executables needs separate linking, everything breaks, because make will then use as for assembling, and as doesn't understand -m32. To solve this I can use --32 instead, but this will of course not work with gcc.
$ cat Makefile
ASFLAGS = -m32
all: prog1 prog2
prog2: prog2.o
$ make
cc -m32 prog1.s -o prog1
as -m32 -o prog2.o prog2.s
as: unrecognized option '-m32'
<builtin>: recipe for target 'prog2.o' failed
make: *** [prog2.o] Error 1
Why does make use ASFLAGS for both gcc and as when their flags aren't compatible? Am I not supposed to specify the architecture this way? Do I really have to hack my way around this (i.e. actually write something in my Makefile), or is there something I've missed?
Since ASFLAGS is used by both LINK.s (gcc) and COMPILE.s (as) as you mentioned, one possible solution is to add following in the Makefile for compiling %.s with $(AS),
EXTRA_ASFLAGS = --32
%.o : %.s
$(AS) $(ASFLAGS) $(EXTRA_ASFLAGS) $(TARGET_MACH) -o $# $<
, or
COMPILE.s += --32
Well, you lied to make and as. If you put in ASFLAGS something that is not an assembler option, you're doing something out of spec.
make cannot know what options the compiler and assembler understand. To deal with this, make provides a way to specify the options for each tool separately: use CFLAGS for the compiler, ASFLAGS for the assembler, LDFLAGS for the link step.
I suggest using make CFLAGS=-m32 ASFLAGS=--32.

Link static library using gcc with gnu make

I'm following Zed Shaw's tutorial "Learn C the Hard Way" and trying to teach myself c programming language.
On my ubuntu desktop, I encountered the linking problem he mentioned in the note of this post.
That is, when linking a static library with gcc, using a command like this:
gcc -Wall -g -DNDEBUG -lmylib ex29.c -o ex29
The linker fails to find the functions in the lib. To link correctly, I have to change the order of source file and lib to this:
gcc -Wall -g -DNDEBUG ex29.c -lmylib -o ex29
And I'm trying to use the makefile offered by Zed to automate unit test. The makefile looks like this:
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/libYOUR_LIBRARY.a
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
The rest part of the makefile that isn't listed here can build the $(TARGET) lib flawlessly.
The problem is Zed append the lib to the $(CFLAGS) and use the implicit rule to compile the test files which leads to a command like this:
gcc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG tests/hashmap_tests.c build/mylib.a -o tests/list_tests
The command fails because of the link problem mentioned before as expected.
The solution I came up with was to write the compilation command explicitly like this so I can change the order:
$(TESTS): $(TARGET)
$(CC) $(CFLAGS) $^ $(TARGET) -o $#
This works fine if there is only one main source file. Unfortunately, I have several out there under the ./tests directory, and a command like this is a total disaster.
My question is, how should I change my makefile to make it work or is there any other way I can do the same work as elegant as expected?
CFLAGS holds compiler flags, like -g -O2. You should not add linker flags to it. CPPFLAGS holds preprocessor flags like -Isrc -DNDEBUG. LDFLAGS holds linker flags, which would include things like -L (capital L) if you need it to find libraries, and -rdynamic. And the LDLIBS variable holds libraries, so you should do this:
CPPFLAGS = -Isrc -DNDEBUG
CFLAGS = -g -O2 -Wall -Wextra
LDFLAGS = -rdynamic
LDLIBS = -lmylib
Now you can use the built-in rules for GNU make to build your program. You can see a list of the build-in rules by running make -p -f/dev/null.
Of course the above are just the default variables make defines and uses with its default rules. You don't have to use them, but in general it's better to follow conventions rather than flaunt them.

Compile program using a Makefile with gcc instead of clang

I am writing a program to spell-check a given text. On my pc I used this Makefile to compile the program:
# compiler to use
CC = clang
# flags to pass compiler
CFLAGS = -ggdb3 -O0 Qunused-arguments -std=c99 -Wall -Werror
# name for executable
EXE = speller
# space-separated list of header files
HDRS = dictionary.h
# space-separated list of source files
SRCS = speller.c dictionary.c
# automatically generated list of object files
OBJS = $(SRCS:.c=.o)
# default target
$(EXE): $(OBJS) $(HDRS) Makefile
$(CC) $(CFLAGS) -o $# $(OBJS) $(LIBS)
# dependencies
$(OBJS): $(HDRS) Makefile
I would like to continue programming on my Raspberry Pi but I only have gcc installed. Is it possible to make this Makefile work for gcc? I tried to change the compiler with:
CC = gcc
but It doesn't work. I get the error message "unrecognised option -Qunused-arguments".
The problem is that the -Q option which Clang accepts isn't an option which GCC recognises.
GCC and Clang are completely separate compilers, and so one shouldn't really expect one of them to understand the other's options. In fact, Clang does make some efforts to be modestly compatible with GCC, in large part to make it possible to use it as a drop-in replacement for GCC. However that compatibility isn't, and probably shouldn't be, complete.
So your solution is simply to change the CFLAGS definition at the same time as you change the CC definition.

Is optimization and generating debug info part of compilation or linkage

I am reading a Makefile from someone else as follows.
LDFLAGS=-lm -ljpeg -lpng
ifeq ($(DEBUG),yes)
OPTIMIZE_FLAG = -ggdb3 -DDEBUG -fno-omit-frame-pointer
else
OPTIMIZE_FLAG = -ggdb3 -O3
endif
CXXFLAGS = -Wall $(OPTIMIZE_FLAG)
all: test
test: test.o source1.o source2.o
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
Makefile.depend: *.h *.cc Makefile
$(CC) -M *.cc > Makefile.depend
clean:
\rm -f test *.o Makefile.depend
-include Makefile.depend
Here are my questions:
Although not explicitly, is $(CXXFLAGS) used by the implicit rule not shown in this Makefile during compilation to generate object files?
I am also wondering why $(CXXFLAGS) appears in the linkage stage? I think it is only for compilation stage? Can I remove $(CXXFLAGS) from "$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)"? If I am wrong, does it mean g++ also generate debugging info and doing optimization at linkage?
why use -ggdb3 -O3 together for nondebugging purpose? What whould its purpose be? If merely considering to improve speed, then isn't using -O3 only better?
for debugging purpose, how using -ggdb3 -fno-omit-frame-pointer together will do better than -ggdb3 alone? I trying to understand the purpose of -fno-omit-frame-pointer by reading gcc document but still confused.
can I move " -include Makefile.depend" to be just under "$(CC) -M *.cc > Makefile.depend" and above "clean"? Does its position in Makefile matter?
CXXFLAGS is used by the implicit rule. Do make -n -p to see the complete list of variables and rules that Make generates from its internal rule sets and the make file.
-g debugging options are only used at the compile stage. -O options are used at the compile and link stages, potentially. You can use both together. From my gcc man page:
GCC allows you to use -g with -O.
The shortcuts taken by optimized code
may occasionally produce surprising
results:
some variables you declared may not exist at all; flow of control
may briefly move where you did not
expect it; some
statements may not be executed because they compute constant
results or their values were already
at hand; some state-
ments may execute in different places because they were
moved out of loops.
Nevertheless it proves possible to debug optimized output.
This makes it reasonable to use the
optimizer for programs that might have bugs.
-fno-omit-frame-pointer actually reduces the optimization. The optimization can interfere with debugging and the person who wrote this makefile clearly intended to run the debugger on optimized code. If it's unclear to you from the gcc manual how it works, you might want to sit down some Saturday with the Intel or AMD architecture reference manual and learn about function calls and argument passing at the instruction level. (Then again, maybe not. :) )
Position matters in Makefiles. I would leave that include file at the end. To do otherwise risks breaking the include file dependency checking.

Resources