Is there a more general makefile?
Write before:
This general mkaefile document comes from one of the documents mentioned in the positive atom learning board. Of course, this does not mean that it is the most appropriate. It is just the most powerful document I have encountered in the learning process.
The focus is still on learning. Learn how to write general makefiles and the basic knowledge of makefiles.
Code: (pick up the bsp tweet I wrote)
Project source: https://gitee.com/iron2222/linux-driver-development.git
You can download 5 of them directly_ ledc_ BSP, it's all sorted out.
CROSS_COMPILE ?= arm-linux-gnueabihf-#This line can be changed for different compilers TARGET ?= bsp#The name of the target should also be changed for different processes CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy OBJDUMP := $(CROSS_COMPILE)objdump #The variable INCDIRS contains the. h header file directory of the whole project. All header file directories in the file should be added to the variable INCDIRS INCDIRS := imx6ul \ bsp/clk \ bsp/led \ bsp/delay #SRCDIRS contains all. c and. S file directories of the whole project SRCDIRS := project \ := bsp/clk \ := bsp/led \ := bsp/delay #The variable INCLUDE uses the function patsubst. Add a "- I" to the variable incdir through the function patsubst, because the Makefile syntax requires that "- I" be added when indicating the header file directory INCLUDE := $(patsubst %, -I %, $(INCDIRS)) #The variable SFILES saves all. S assembly files (including absolute paths) in the project. The variable SRCDIRS has stored all. c and. S files in the project, so we only need to pick out all. S assembly files from it SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S)) #The variable CFILES is the same as the variable SFILES, except that CFILES saves all. c files (including absolute paths) in the project CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) #Use the function notdir to remove the paths in SFILES and CFILES SFILENDIR := $(notdir $(SFILES)) CFILENDIR := $(notdir $(CFILES)) #By default, all compiled. o files and source files are in the same directory SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o)) COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o)) #The variable OBJS is a collection of variables SOBJS and COBJS OBJS := $(SOBJS) $(COBJS) #VPATH specifies the search directory. The search element directory specified here is the directory saved by the variable SRCDIRS, so that the required. S and. c files will be found in the directory specified in SRCDIRS when compiling VPATH := $(SRCDIRS) .PHONY: clean $(TARGET).bin : $(OBJS) $(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(OBJCOPY) -O binary -S $(TARGET).elf $@ $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis $(SOBJS) : obj/%.o : %.S $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< $(COBJS) : obj/%.o : %.c $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< clean: rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
No matter what you do, the most important thing is the framework and logic. What is your goal?
Just like listening to the senior brothers' topic yesterday, the first senior brother on the stage was asked a question by the Dean: do you know the meaning of the topic?
The elder martial brother said: find problems and solve them.
Yes, it is to find problems, determine goals, select methods, practice, achieve goals and solve problems. (in fact, sometimes they create their own problems to solve)
What is the purpose of writing a makefile document?
Simplify our operation steps and compile more efficiently to obtain the target file.
What problems do you face when writing makefile documents?
This is much more. The directory structure is different for different project frameworks. Here is only for this project:
- Different support files are placed in different folders
- The generated files should be placed in the specified folder
These are two difficult points. Let's go step by step until we achieve the above goal!!
Start writing
1) Compilation preparation
CROSS_COMPILE ?= arm-linux-gnueabihf-#This line can be changed for different compilers TARGET ?= bsp#The name of the target should also be changed for different processes CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy OBJDUMP := $(CROSS_COMPILE)objdump
First of all, of course, determine the cross compilation tool chain. This should be written according to your actual situation, and don't forget the target file.
gcc, ld, objcopy and objdump are one-stop services.
- gcc compilation
- ld connection
- objcopy converts. elf files into. bin files( The difference between the two can be seen in this connection)
- objdump disassembly generates. dis file
2) Then the file path
The file path here includes the path where the header file is located and. c and. s files are in the path, which is used for subsequent search.
#The variable INCDIRS contains the. h header file directory of the whole project. All header file directories in the file should be added to the variable INCDIRS INCDIRS := imx6ul \ bsp/clk \ bsp/led \ bsp/delay #SRCDIRS contains all. c and. S file directories of the whole project SRCDIRS := project \ := bsp/clk \ := bsp/led \ := bsp/delay
3) The path is processed and placed in different variables
#The variable INCLUDE uses the function patsubst. Add a "- I" to the variable incdir through the function patsubst, because the Makefile syntax requires that "- I" be added when indicating the header file directory INCLUDE := $(patsubst %, -I %, $(INCDIRS))
A function patsubat is mentioned here to replace wildcards.
That is, replace all items in $(INCDIRS) that meet% with - I%, that is, add - I in front of all header files.
#The variable SFILES saves all. S assembly files (including absolute paths) in the project. The variable SRCDIRS has stored all. c and. S files in the project, so we only need to pick out all. S assembly files from it SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S)) #The variable CFILES is the same as the variable SFILES, except that CFILES saves all. c files (including absolute paths) in the project CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
First, foreach is like a for loop. The specific usage is as follows:
$(foreach ,,)
What this function means is, put the parameters; Take out the words in one by one and put them into the parameters; In the specified variable, and then execute < text >; The contained expression. every time; A string will be returned. During the loop,; Each string returned by will be separated by a space. Finally, when the whole loop ends,; The entire string (separated by spaces) of each returned string will be the return value of the foreach function.
In addition, the wildcard function is simpler, which is to expand the wildcard, find and splice the absolute path of the target file.
#Use the function notdir to remove the paths in SFILES and CFILES SFILENDIR := $(notdir $(SFILES)) CFILENDIR := $(notdir $(CFILES))
The notdir function removes the path and all. s and. c files.
After the above operation, let's see what variables we have now:
- CFILENDIR and SFILENDIR in. c and. s files (no path)
- INCLUDE of header file. h
- Of course, there are various tool variables for cross compilation
4) Determine sub target document
Previously, we have the overall goal after connection. Now we want to define each sub goal.
#By default, all compiled. o files and source files are in the same directory SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o)) COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
Here is a new usage:
For A defined variable, you can use replace reference to replace the suffix character (string) in its value with the specified character (string). The format is "$(VAR:A=B)" (or "${VAR:A=B}"), which means that all words ending with "A" in the replacement variable "VAR" are words ending with "B". "End" means before A space (space is used to separate multiple words of variable value). The "A" character in other parts of the variable is not replaced.
In this way, we get the target file format of C file and S file.
Finally, gather:
#The variable OBJS is a collection of variables SOBJS and COBJS OBJS := $(SOBJS) $(COBJS)
5) Start compiling, connecting, decompiling
$(TARGET).bin : $(OBJS) $(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(OBJCOPY) -O binary -S $(TARGET).elf $@ $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis $(SOBJS) : obj/%.o : %.S $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< $(COBJS) : obj/%.o : %.c $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< clean: rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
These are basic operations.
END!!!
Write at the end:
If I encounter a better makefile in the process of learning, I will continue to update it. If you have problems, you can also communicate with me privately. After all, I have just started learning, and there will be a lot of mistakes.
Good morning, good afternoon, good night!