I have this command from my bash script
find . -type f -name "*.c" -execdir bash -c "f={}; kos-cc $KOS_CFLAGS -c {} -o $PWD/\${f%.c}.o" \;
Its job it to recursively search the current directory ($PWD) for .c files, compile them with my "kos-cc" compiler then output all the .o files into the current working directory.
I want to move parts of my bash script into a makefile and this line is the last one that stumps me. I know how to make rules that compiles c files from directory A and outputs the .o files into directory B, but here directory A isn't always the same (Since I need to handle sub directories too). How do I do the equivalent task in a Makefile either with a rule or a command?
It is not trivial because you have your sources in different directories and simple make pattern rules cannot easily handle this. But using slightly more advanced make features can make it:
SRC := $(shell find . -type f -name "*.c")
OBJ := $(patsubst %.c,%.o,$(notdir $(SRC)))
.PHONY: all
all: $(OBJ)
define COMPILE_rule
$$(patsubst %.c,%.o,$$(notdir $(1))): $(1)
kos-cc $$(KOS_CFLAGS) -c -o $$@ $$<
endef
$(foreach s,$(SRC),$(eval $(call COMPILE_rule,$(s))))
.PHONY: clean
clean:
rm -f $(OBJ)
Beware: you could have several source files with the same base name in different directories. And if this happens, you will end up with a fatal conflict of object file names...
EDIT (add conflicts detection):
The following detects conflicts situations and issues an error (replace error
by warning
or info
depending on the severity level you assign to these conflicts):
SRC := $(shell find . -type f -name "*.c")
OBJ := $(patsubst %.c,%.o,$(notdir $(SRC)))
ifneq ($(words $(OBJ)),$(words $(sort $(OBJ))))
$(error object file name conflicts detected)
endif
(sort
sorts and also removes duplicates and words
returns the number of space-separated words in its string parameter).