How to compile all .c files in a directory and dump every binary without .c extension
I have a directory with several c source files (each file is a small program in itself) that I would like to compile right away and output the binary for each in the bin / subdirectory. The binary file name must be one of the original c file, but no .c extension. How can I accomplish something like this in the Makefile?
Example:
-src
ll.c
lo.c
-bin
ll
lo
The first thing I came up with was this:
CFLAGS=-Wall -g
SRC=$(wildcard *.c)
all: $(SRC)
gcc $(CFLAGS) $(SRC) -o bin/$(SRC)
But it doesn't work as I thought it would.
The line all: $(SRC)
tells make that the target all
contains all source files as prerequisites.
The recipe for this purpose ( gcc $(CFLAGS) $(SRC) -o bin/$(SRC)
) then tries to run gcc on all source files and says that it generates as output bin/<first word in
$ (SRC) with the rest of the words from
$ (SRC) `other, optional, gcc arguments.
You need something more:
SRCS := $(wildcard *.c)
# This is a substitution reference. http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
BINS := $(SRCS:%.c=bin/%)
CFLAGS=-Wall -g
# Tell make that the all target has every binary as a prequisite and tell make that it will not create an `all` file (see http://www.gnu.org/software/make/manual/make.html#Phony-Targets).
.PHONY: all
all: $(BINS)
bin:
mkdir $@
# Tell make that the binaries in the current directory are intermediate files so it doesn't need to care about them directly (and can delete them). http://www.gnu.org/software/make/manual/make.html#index-_002eINTERMEDIATE
# This keeps make from building the binary in the current directory a second time if you run `make; make`.
.INTERMEDIATE: $(notdir $(BINS))
# Tell make that it should delete targets if their recipes error. http://www.gnu.org/software/make/manual/make.html#index-_002eDELETE_005fON_005fERROR
.DELETE_ON_ERROR:
# This is a static pattern rule to tell make how to handle all the `$(BINS)` files. http://www.gnu.org/software/make/manual/make.html#Static-Pattern
$(BINS) : bin/% : % | bin
mv $^ $@
[I forgot where you said you wanted to do this in the Makefile. My solution here is a forward shell.]
I would use something like
CFLAGS=-Wall -g
for cfile in *.c
do
cc $CFLAGS -o bin/`basename $cfile .c` $cfile
done
Make is smart enough to do it with implicit rules. Make sure the makefile doesn't exist and doesn't run:
for f in *.c; do make CFLAGS='-Wall -g' ${f%.c} && mv ${f%.c} bin; done