Tuesday, August 11, 2015

Yet Another Make Tutorial - III

In the first Yet Another Make Tutorial a simple make file, makefile10a, was created to handle the organization of a parent directory, a source directory and an include directory. Yet Another Make Tutorial - II updated makefile10a to include sub-directories in the source directory, makefile13, and makefile14.

All files are found in a BitBucket archive here.

Both make files 13 and 14 dealt with only one source file extension *.c and only one compiler gcc.

Here we are going to expand to add C++ source files and clang.

clang is the up and coming compiler that is replacing gcc, part of the LLVM project. clang.llvm.org.

Pre-built images are available for Windows and Linux.

In makefile13, the source files were selected by the statement


SRC_LIST := $(shell find $(SRC_DIR) -name "*.c" -type f)

If we want to use this make file for both C and C++ files changes need to be made.

Typically the compiler options used for building C files are not the same as those used for C++ files, in fact gcc is used for C files and linkage, where g++ is used for C++ files.

We will need a second set of variables to handle C++ files.

We will also create a set of mixed source files, main.cpp, suba.cpp, subc.c, and subd.c.

These new files are found in the folder Make15 of the BitBucket repository.

Something that has been missing from the tutorials is the standard variable names used for the compiler, CC and CXX.

Let's add the CC variable, used to define the C compiler and CXX to define the C++ compiler. The default for make is cc for the C compiler and g++ for the C++ compiler. We will define both just to be clear.

CC = gcc
CXX = g++

Now add the new set of variables for the C++ source files and objects. The C and C++ source files will be mixed together in the same source tree.

SRC_LIST_CXX := $(shell find $(SRC_DIR) -name "*.cpp" -type f)
SRC_DIR_LIST_CXX := $(patsubst %/,%,$(sort $(dir $(SRC_LIST_CXX))))
OBJS_CXX := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(notdir $(SRC_LIST_CXX)))
DEPS_CXX := $(OBJS_CXX:.o=.d)

Remember to tell make where to find the *.cpp files via vpath.

vpath %.cpp $(SRC_DIR_LIST_CPP)


These updates result in makefile15.

#makefile15
SRC_DIR := src
OBJ_DIR := obj
INC_DIR := inc
SRC_LIST_C := $(shell find $(SRC_DIR) -name "*.c" -type f)
SRC_DIR_LIST_C := $(patsubst %/,%,$(sort $(dir $(SRC_LIST_C))))
OBJS_C := $(patsubst %.c,$(OBJ_DIR)/%.o,$(notdir $(SRC_LIST_C)))
DEPS_C := $(OBJS_C:.o=.d)
SRC_LIST_CXX := $(shell find $(SRC_DIR) -name "*.cpp" -type f)
SRC_DIR_LIST_CXX := $(patsubst %/,%,$(sort $(dir $(SRC_LIST_CXX))))
OBJS_CXX := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(notdir $(SRC_LIST_CXX)))
DEPS_CXX := $(OBJS_CXX:.o=.d)
TARGET_DIR := target
TARGET := $(TARGET_DIR)/aprogram
vpath %.c $(SRC_DIR_LIST_C)
vpath %.cpp $(SRC_DIR_LIST_CXX)
.PHONY: all clean

CC = gcc
CXX = g++

all: $(TARGET)

clean:
@rm -f $(OBJ_DIR)/*.o $(OBJ_DIR)/*.d
@rm -f $(TARGET)
@rmdir $(OBJ_DIR)
@rmdir $(TARGET_DIR)

$(TARGET): $(OBJS_C) $(OBJS_CXX)
gcc -lstdc++ $^ -o $@

$(OBJ_DIR)/%.o: %.c
$(CC) -c -MMD -I $(INC_DIR) $< -o $@

$(OBJ_DIR)/%.o: %.cpp
$(CXX) -c -MMD -I $(INC_DIR) $< -o $@

REQUIRED_DIRS := $(OBJ_DIR) $(TARGET_DIR)
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
 do              \
 mkdir -p $$d;   \
 done)

-include $(DEPS_C)
-include $(DEPS_CXX)

Let's review each of the updates.

The new C++ variables have been discussed above.

The new vpath statement has been discussed above.

The new CC and CXX variables have been discussed above.

$(TARGET): $(OBJS_C) $(OBJS_CXX)
gcc $^ -o $@

The linkage statement adds $(OBJS_CXX). This makes $(TARGET) dependent on the C++ object files as well as the C object files.

$(OBJ_DIR)/%.o: %.cpp
$(CXX) -c -MMD -I $(INC_DIR) $< -o $@

The new dependent statement builds the C++ object files from the C++ sources, specifically *.cpp extensions.

-include $(DEPS_CXX)

Finally, the second -include statement to add the *.d dependencies for C++ files.

[Note: To update to use *.cc or *.cxx extensions one can changes the 'find' statement for  SRC_LIST_CXX and the OBJ_DIR dependency.]

If more than one extension is used, two sets of code mixed together, one can add an additional -name argument using the -o, the or operator.

SRC_LIST_CXX := $(shell find $(SRC_DIR)-type f -name "*.cpp" -o -name "*.cc" )

However, just adding -o -name "*.cc" is not all that is required to handle multiple extensions. Another post will go into the details. Note that a new pattern, another vpath, and the OBJS need updating.

Now lets change to use clang. Simple. Update CC and CXX.


CC = clang

CXX = clang++

Both C and C++ files are handled by clang.

Another step forward to more make know how.

Next blog on make performance, IV.

No comments:

Post a Comment