C++ Makefile, C code


So far, we have dealt with C++ code exclusively. Today, I was looking at the makefile, and I realized that it would be quite simple to compile C code as well. In addition, we will generalize the code, so that our C++ files can have file extensions other than .cc.

First, we need to define the rules to compile C code into object files. These are nearly identical to the rules to compile C++ code. The only difference is that we use the $(CC) variable for the compiler, and we pass it flags from $(CFLAGS) instead of $(CXXFLAGS).

CC = gcc

build/$(BUILD)/build/%.o: %.c
	@$(call run_and_test,$(CC) -c $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< -o $@,Compiling)

build/$(BUILD)/build/%.os: %.c
	@$(call run_and_test,$(CC) -c $(PIC_FLAG) $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< -o $@,Compiling)

Now, all that is needed is to indicate that those .o files are generated, and are included in the appropriate libraries.

find_in_dir = $(foreach ext,$(2),$(wildcard $(1)/*.$(ext)))
o_file_name = $(foreach file,$(1),build/$(BUILD)/build/$(basename $(file)).o)

EXE_SRC_FILES = $(wildcard *.$(CPP_EXT)) $(wildcard *.$(C_EXT))
SRC_FILES = $(call find_in_dir,src/,$(CPP_EXT) $(C_EXT))
O_FILES = $(call o_file_name,$(SRC_FILES))

library_src_files = $(call find_in_dir,lib$(1)/src/,$(CPP_EXT) $(C_EXT))
library_o_files   = $(call o_file_name,$(call library_src_files,$(1)))

And done.

That was rather short, so let’s extend it a bit more. Instead of hard coding the file extension, let’s allow it to be user-defined. Also, let’s allow there to be more than one. We will define a variable, then use $(eval ...) to transform it into a rule.

C_EXT = c
CPP_EXT = C cc cpp cxx c++ cp

build/$$(BUILD)/build/%.o: %.$(1)
	@$$(call run_and_test,$$(CC) -c $$(ALL_CPPFLAGS) $$(ALL_CFLAGS) $$< -o $$@,Compiling)

build/$$(BUILD)/build/%.os: %.$(1)
	@$$(call run_and_test,$$(CC) -c $$(PIC_FLAG) $$(ALL_CPPFLAGS) $$(ALL_CFLAGS) $$< -o $$@,Compiling)

$(foreach ext,$(C_EXT),$(eval $(call C_BUILD_RULES,$(ext))))

Note that the variables inside the definition have two dollar signs preceding them. This is because they are evaluated twice. Once in the call to $(eval ...), and once when the rule is used.

This isn’t needed much for C files, since most will use the .c extension. For C++, there are quite a few extensions, and so it is useful to be able to compile them all.

The makefile can be found on github.