[C++ Advanced] Makefile Basics (2)

1. Variables

1.1 Automatic variables

Automatic variables are special variables in Makefiles that are set automatically when the command line in the rule is executed. The following are some commonly used automatic variables:

  • $@: Represents a target in a rule. When we have multiple targets in a rule, it refers to any of the targets that caused the command to be run
  • $^: Represents all dependent files, separated by spaces, does not contain duplicate dependent files
  • $<: represents the first dependent file
  • $?: Represents all dependent files newer than the target, separated by spaces
  • $*: Represents the part of the target file name that removes the suffix

For example:

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

In this example, $<it represents the first dependent file of the current rule (corresponding to a certain .cfile), and $@represents the target of the current rule (corresponding to a certain .ofile).

1.2 Special variables

Special variables are predefined variables in the Makefile that have specific meanings and functions.

  • MAKE: Indicates what the make command name is. This variable needs to be used when we need to call another Makefile in the Makefile. This method is conducive to writing an easy-to-port Makefile
  • MAKEFILE_LIST: List of Makefiles already included
  • MAKECMDGOALS: Refers to the target entered by the user. When we only run the make command, although according to the syntax of the Makefile, the first target will become the default target, that is, the all target, but MAKECMDGOALS is still empty instead of all. This requires Notice

1.3 Types of variables

In Makefile, variables can be divided into two categories: simple variables and recursive variables.

  • Simple variables: Simple variables use := for assignment. They are expanded upon assignment
  • Recursive variables: Recursive variables use = for assignment. They are only expanded when they are used

For example:

VAR1 = $(VAR2)
VAR2 := hello world

In this example, VAR1 is a recursive variable and VAR2 is a simple variable.

1.4 Sources of variable values

The value of a variable can come from the following ways:

  • Assign directly in the Makefile
  • command line parameter passing
  • environment variable

1.5 Reference function of advanced variables

In Makefile, we can use advanced variable references to handle variables more flexibly. For example:

  • $(VAR:str1=str2): In the value of the variable VAR, replace all occurrences of str1 with str2.

1.6 override directive

In the Makefile, we can use overridedirectives to force the value of a variable in the Makefile even if the variable has been defined on the command line. For example:

CFLAGS = -Wall
override CFLAGS += -g

In this example, we use overridedirectives to ensure that CFLAGSvariables defined in the Makefile are preserved and not overwritten by definitions on the command line. CFLAGSOptions in the Makefile CFLAGSare appended even if they are redefined on the command line -g.

1.7 Summary

We use an example Makefile to demonstrate the various variable types and functions discussed above:

CC = gcc
CFLAGS = -Wall
override CFLAGS += -g
SRC = main.c foo.c bar.c

OBJS = $(SRC:.c=.o)

.PHONY: all clean

all: my_program

my_program: $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f $(OBJS) my_program

In this Makefile:

  • We define simple variables CC, CFLAGSandSRC
  • Use overridedirectives to ensure that CFLAGSdefinitions in the Makefile are not overridden by command-line arguments
  • $(SRC:.c=.o)Convert all .cfiles to .oa list of files using advanced variable references
  • On the target my_program's command line, use automatic variables $@for the current target (my_program) and for $^all dependent files ($(OBJS)).

2. Mode

Patterns in Makefiles are a simplified way of writing Makefiles, allowing you to define common rules for multiple similar targets. Pattern rules have one or more patterns, expressed by using wildcard characters (%). Wildcards can match any string. This allows us to use the same rule for multiple targets without having to write a separate rule for each target.

Here are some examples of common Makefile patterns:

  1. Compile C files as object files (.o):

    %.o: %.c
        gcc -c $< -o $@
    

    This pattern means that any .ofile ending with _ (target file) depends on a corresponding .cfile ending with _(source file). The command lines in the rules tell the compiler how to generate object files from source files. $<and $@are automatic variables, representing dependent files and target files, respectively.

  2. Compile C++ files as object files (.o):

    %.o: %.cpp
        g++ -c $< -o $@
    

    This pattern is similar to the example above, except that it applies to C++ source files.

  3. Link multiple object files into one executable:

    my_program: main.o helper.o
        gcc $^ -o $@
    
    main.o: main.c
        gcc -c $< -o $@
    
    helper.o: helper.c
        gcc -c $< -o $@
    

    In this example we didn't use patterns, but we can simplify it with pattern rules:

    my_program: main.o helper.o
    	gcc $^ -o $@
    
    %.o: %.c
        gcc -c $< -o $@
    

    This simplified Makefile applies to all C files, not just main.c and helper.c.

  4. Generate PDF files in a directory:

    %.pdf: %.tex
        pdflatex $<
    

    This pattern means: any .pdffile ending in .depends on a corresponding .texfile ending in . The command lines in the rules tell pdflatex how to generate PDF files from LaTeX source files.

3. Functions

Functions in Makefiles provide some useful text manipulation functions that allow you to deal with filenames and paths more easily.

3.1 addprefix

Function: Add the specified prefix to each word in the list

grammar:$(addprefix <prefix>, <list>)

Example:

files = file1.txt file2.txt file3.txt
prefixed_files = $(addprefix backup/, $(files))

# 结果:prefixed_files = backup/file1.txt backup/file2.txt backup/file3.txt

3.2 filter

Function: Filter out words that match the pattern from the list

grammar:$(filter <pattern>, <list>)

Example:

files = file1.txt file2.cpp file3.h file4.c
c_files = $(filter %.c, $(files))

# 结果:c_files = file4.c

3.3 filter-out

Function: Remove words that match the pattern from the list

grammar:$(filter-out <pattern>, <list>)

Example:

files = file1.txt file2.cpp file3.h file4.c
non_c_files = $(filter-out %.c, $(files))

# 结果:non_c_files = file1.txt file2.cpp file3.h

3.4 patsubst

Function: replace the words in the list according to the specified pattern

grammar:$(patsubst <pattern>, <replacement>, <list>)

Example:

files = file1.txt file2.txt file3.txt
csv_files = $(patsubst %.txt, %.csv, $(files))

# 结果:csv_files = file1.csv file2.csv file3.csv

3.5 strip

Function: Remove the leading and trailing whitespace characters of the words in the list

grammar:$(strip <string>)

Example:

text =      foo    bar   baz
stripped_text = $(strip $(text))

# 结果:stripped_text = foo bar baz

3.6 wildcard

Function: Returns a list of files matching the specified pattern

grammar:$(wildcard <pattern>)

Example:

src_files = $(wildcard *.c)
# 结果:src_files = file1.c file2.c file3.c(假设目录中存在这些文件)

Guess you like

Origin blog.csdn.net/weixin_52665939/article/details/130163495