Multifile Makefile

In the process of work, I usually don't pay much attention to the writing rules of Makefile. I can understand the basic rules of Makefile for the compilation errors encountered. But if you want to write Makefile file is still quite difficult, not to mention the process of including multiple directories and files. So after debugging for an afternoon, I finally realized a basic Makefile containing multiple directories, and hereby record it. In fact, the purpose of writing this Makefile is simple: it is convenient for centralized classification and management of usual small programs . (The article is not used to describe Makefile rules)

1. Makefile multiple directory structure

On Windows, you can use the tree command to view the tree-like information of the directory (the following picture is viewed under the tree / f directory under Windows ). A
Insert picture description here
simple description:
the project currently contains four source code directories and a compilation directory target . Write this The purpose of the function is to facilitate the management and testing of the usually written small programs.

Directory name Explanation
main Store the C file of the main function to test and run other interface programs
process Process and thread related
scheduler Task scheduling code implementation
sleep Delay function implementation: select, pselect, etc.
target Store the .o file generated during the compilation process, so makefile is not included

2. Multi-directory Makefile writing ideas

  • First compile the files in each subdirectory to generate a series of object files (.o files)
  • Then link the object files generated by the compilation of each subdirectory into the final executable file

3. General Makefile in the root directory of the project

#Makefile
#author : sunzd
#date  :  2020-02-23
#location: Beijing

CC = gcc
MAKE = make
CFLAGS = -g -W -O2
LFLAGS = 

#directory
TOP_DIR := $(PWD)

OBJ_DIR := $(TOP_DIR)/target

BIN_DIR := $(TOP_DIR)

SRC_SCHEDULE_DIR := $(TOP_DIR)/scheduler
SRC_SLEEP_DIR    := $(TOP_DIR)/sleep
SRC_PROCESS_DIR  := $(TOP_DIR)/process
SRC_MAIN_DIR     := $(TOP_DIR)/main
#这里指定要编译的子目录信息
SUB_DIR := $(SRC_SCHEDULE_DIR) $(SRC_SCHEDULE_DIR) $(SRC_SLEEP_DIR) $(SRC_MAIN_DIR)
 
TARGET := demo.out

#方法一:手动指定所有的目标文件 
#OBJS ?= $(OBJ_DIR)/scheduler.o 
#OBJS +=	$(OBJ_DIR)/scheduler_demo.o 
#OBJS +=	$(OBJ_DIR)/mySleep.o 
#OBJS +=	$(OBJ_DIR)/main.o

#方法二:自动获取指定目录下的目标文件 
#OBJS  = $(shell ls $(OBJ_DIR)/*.o)  works
#OBJS := $(shell ls $(OBJ_DIR)/*.o)  can't work
#OBJS ?= $(OBJ_DIR)/$(wildcard *.o)  can't work
OBJS  ?= $(shell ls $(OBJ_DIR)/*.o)

#将重要的变量export,供子目录中的Makefile使用
export CC CFLAGS TOP_DIR OBJ_DIR BIN_DIR SRC_PROCESS_DIR SRC_SCHEDULE_DIR SRC_SLEEP_DIR OBJS \
		SRC_MAIN_DIR
 
all : $(SUB_DIR) $(TARGET)

#依次进入各个子目录进行编译
$(SUB_DIR):ECHO
	$(MAKE) -C $@

ECHO:
	@echo sub directorys: $(SUB_DIR) 
	@echo begin compile::::

#最终要生成的目标文件规则	
$(TARGET):$(OBJS)	
	#@echo ======== OBJS: $(OBJS) =======
	$(CC) $(LFLAGS) $(CFLAGS) $(OBJS) -o $@

.PHNOY: clean
clean:
	rm  -rf $(OBJ_DIR)/*.o  $(TARGET)

Description :

Variable definition Explanation
= Delay variable
?= Delay variable
:= Immediate variable
Delay variable Do not calculate the value of the variable when it is defined, and then calculate the value of the variable when it is used
Immediate variable Calculate the value of the variable when it is defined

Because I do n’t want to manually specify all .o files here, and these files will be generated only after the subdirectory is completely compiled successfully, so the immediate variable cannot be used in the definition, and the delay variable must be used. Calculate and obtain all .o files in the target directory. Mainly to facilitate subsequent expansion.

4. Makefiles in subdirectories

The Makefile files in the four subdirectories of the project are the same (it is really convenient). If you need to create new directories in advance with new functions, if there are no special requirements, you can directly use the Makefile.

#获取当前目录下所有的.c文件
src := $(shell ls *.c)

#获取要编译的目标文件(.o文件): 使用patsubst函数做后缀替换实现
objs := $(patsubst %.c,%.o,$(src))

#OBJS += $(OBJ_DIR)/$(objs)

#目标: 1)编译.o文件  2)将.o文件移动到指定目录
all : $(objs) MOVE
 
#1)编译.o文件
%.o:%.c
	$(CC) -c $^ -o $@
	
#2)将.o文件移动到指定目录
MOVE:
	mv *.o $(OBJ_DIR)
 

4. Doubts

At the end of the Makefile rule, the target file in each directory is generally linked to generate the final executable file. There are three ways you can think of:

  • Manually specify all .o files in the central control Makefile (there may also be link libraries, header files, etc.). This way is inconvenient to expand, every time you add or delete files, you need to modify the Makefile of the master control
  • Put all the target files in a specific directory, and finally read the corresponding directory file to complete the final link operation. The shortcomings are obvious: there is no way to implement programs that need to link special libraries and search for specified paths, and they need to be specified manually.
  • Variables are pre-defined in the Makefile of the master control. The variables of each subdirectory add their own target files, link files, and search paths to specific global variables. The Makefile of the master control finally references the corresponding when generating the final executable file. Global variables are sufficient.

When trying to use the third method, although the subdirectory successfully modified the global variable OBJS, it was still empty in the Makefile of the master control, and it was not clear which reason. Keep follow-up

81 original articles published · Liked 69 · Visitors 50,000+

Guess you like

Origin blog.csdn.net/s2603898260/article/details/104463399