Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Implicit rules of make (11)

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/03 Report--

What happens if we split commands for the same goal and write them in different places? Let's take a look at the code below

.PHONY : allall : @echo "command-1"VAR := test all : @echo "all : $(VAR)"

Let's analyze it. There are two targets all in this code, so when we execute make. Which one does it execute? One might be to execute both, and the other might be to execute the first, because the default is to execute the first goal. Come down and let's see what happens.

We see that it says all repeatedly, so we ignore the previous all command. The last command is the last all command. Therefore, when a target with the same name appears in the makefile, all dependencies are merged together to become the final dependency of the target; when multiple commands with the same target appear, make issues a warning that all previously defined commands are replaced by the last defined command. Note: When using the include keyword to include other files, you need to ensure that the target of the same name in the included file is only dependent and there is no command; otherwise, the command of the target of the same name will be overwritten! Let's see if we can create a new makefile.1

makefile.1 source code

all : @echo "this is command from makefile.1"

makefile source code

.PHONY : allVAR := testall : @echo "all : $(VAR)"include makefile.1

Let's look at the compilation result and see if it prints all : test.

We see that the output is "this is command from makefile.1," not all : test as we expected. In fact, it is not difficult to understand, because we include makefile.1 also contains the all command, so the above all is replaced. In other words, this phenomenon may have unexpected consequences for us. Then this is also an implicit rule in makefile. What is an implicit rule? In make, it provides some common, routine rule implementations; make tries to use implicit rules when rules for the target are not provided. So let's see if this makefile can compile successfully.

.PHONY : allSRCS := $(wildcard *.c)OBJS := $(SRCS:.c=.o)app.out : $(OBJS) $(CC) -o $@ $^ $(RM) $^ @echo "Target ==> $@"

Let's see if the compilation results will report errors.

We see that it has compiled correctly, and the result is correct. So we didn't define the corresponding rules in it, so why did it compile correctly? Let's write a rule according to its format and try changing cc to gcc to see if the result will be the same.

.PHONY : allCC := gccSRCS := $(wildcard *.c)OBJS := $(SRCS:.c=.o)app.out : $(OBJS) $(CC) -o $@ $^ $(RM) $^ @echo "Target ==> $@"%.o : %.c @echo "my rule" $(CC) -c -o $@ $^

The compilation results are as follows

The result is the same as before, except that we output our custom statement, replacing cc with gcc. So what is cc? Why compile source files? cc The first c is C, and the second is compiler. So where did this cc compiler come from? In the original Unix system there is cc compiler, because it is a commercial version, need to charge, so in Linux system is also to support cc, but this cc is not that cc, let's see what the final prototype of cc is

We see that cc ends up pointing to gcc, so compiling with cc is actually the same as compiling with gcc. So who implements the pattern rules above? This is an implicit rule in makefile. Make provides implicit rules for generating target files. Implicit rules use predefined variables to complete compilation; changing predefined variables partially changes the behavior of implicit rules, and implicit rules are no longer used when custom rules exist. When make finds that the target dependency does not exist, it tries to find the implicit rule one by one by the dependency name, and deduces the source file that may be needed by the dependency name, as follows

Since implicit compilation is so powerful, shouldn't we write our own rules? Actually, it wasn't, based on the experience of the seniors. In real projects, it is still necessary to prohibit implicit rules in makefiles because implicit rules have side effects. The specific performance is: a> compilation behavior is difficult to control, and a large number of implicit rules may produce unexpected compilation behavior;b> compilation efficiency is low, and make selects the final rule from implicit rules and custom rules.

So let's look at implicit rule chains. When the dependent target does not exist, make tries to combine various implicit rules to create the target, resulting in unexpected compilation behavior! For example, a target named N.o is required: N.y --> N. c--> N.o. Let's take code as an example to analyze and explain

main.c source code

#include extern void greeting();int main(){ greeting(); return 0;}

func.p source code (this is just a test code, using Pascal language)

unit Func;interfaceprocedure Greeting(); attribute (name = 'greeting');implementationprocedure Greeting();begin WriteLn('Hello, Pascal! ');end;end.

makefile source code

app.out : main.o func.o $(CC) -lstdc++ -o $@ $^

So we want to use func.c to implement a certain function, but now there is no func.c, so there must be an error at compile time

We saw func.o being generated using func.p, but eventually it went wrong. Do we wonder why such mistakes occur? There is clearly no corresponding source file, but it is reported that there is no pc command. This is the implicit rule in makefile, so how many implicit rules does make provide? How do I view implicit rules? The way to see implicit rules is: see all is make -p; see specific rules is make -p| grep "XXX"。Let's look at the implicit rules in make.

Because there are so many rules, we've only clipped a few of them. Let's look at the rules corresponding to %.o.

We see that it supports many formats by default, including.c and.p files, so it compiles our previous test code as source files. So how do we avoid its implicit rules? For partial disable, customize rules directly in makefile or define patterns in makefile (e.g.%.o : %.p); for global disable, use make -r. Next, let's first use the local disable method, directly define the pattern in the makefile, but do not do specific processing.

It simply reported incorrectly that there was no corresponding source text. Let's take a look at ways to use global disable

We see that even the main.o file cannot be generated after using the global disable method. Let's talk about suffix rules, which are old-fashioned "pattern rules" that can be customized in the way suffixes are described. format is as follows

Suffix rules are divided into double suffix rules and single suffix rules. Double suffix rules refer to defining a pair of file suffixes (dependent file suffix and target file suffix), such as: .cpp.o %.o : %.cpp; single suffix rules refer to defining a single file suffix (source file suffix), such as: .c % : %.c. Suffix rules have several precautions: 1. No dependency is allowed in suffix rules;2. Suffix rules must have commands, otherwise they are meaningless;3. Suffix rules will be gradually replaced by pattern rules.

Next, we still take the code as an example to analyze and explain, we create a new func.c file to explain the problem

func.c source code

#include void greeting(){ printf("void greeting : %s\n", "hello makefile! ");}

makefile source code

app.out : main.o func.o $(CC) -lstdc++ -o $@ $^.c.o : @echo "my suffix rule" $(CC) -o $@ -c $^.c : @echo "my suffix rule" $(CC) -o $@ -c $^

Let's look at the compilation results

We see that it has been done correctly. However, in current engineering projects, we generally abandon the suffix rule and adopt the pattern rule. Through the study of implicit rules in makefile, the following conclusions can be summarized: 1. When commands with the same target appear in multiple places, only the last defined command is valid;2. Make provides a series of implicit rules that can be used. When no relevant rules are defined in makefile, implicit rules will be tried;3. Predefined variables in make may be used in implicit rules, and changing predefined variables can partially change the behavior of predefined rules; Implicit rules may cause unexpected compilation behavior, so try not to use implicit rules in practical engineering projects;5. Suffix rules are an old pattern rule, which is gradually being replaced by pattern rules.

Welcome everyone to learn makefile, you can add me QQ: 243343083.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report