首页 > 其他分享 >Makefile - What is a Makefile and how does it work?

Makefile - What is a Makefile and how does it work?

时间:2023-11-19 18:22:58浏览次数:37  
标签:target CC make work Makefile echo how foo hello

If you want to run or update a task when certain files are updated, the make utility can come in handy. The make utility requires a file, Makefile (or makefile), which defines set of tasks to be executed. You may have used make to compile a program from source code. Most open source projects use make to compile a final executable binary, which can then be installed using make install.

In this article, we'll explore make and Makefile using basic and advanced examples. Before you start, ensure that make is installed in your system.

Basic examples

Let's start by printing the classic "Hello World" on the terminal. Create a empty directory myproject containing a file Makefile with this content:

say_hello:
        echo "Hello World"

Now run the file by typing make inside the directory myproject. The output will be:

$ make
echo "Hello World"
Hello World

In the example above, say_hello behaves like a function name, as in any programming language. This is called the target. The prerequisites or dependencies follow the target. For the sake of simplicity, we have not defined any prerequisites in this example. The command echo "Hello World" is called the recipe. The recipe uses prerequisites to make a target. The target, prerequisites, and recipes together make a rule.

To summarize, below is the syntax of a typical rule:

target: prerequisites
<TAB> recipe

As an example, a target might be a binary file that depends on prerequisites (source files). On the other hand, a prerequisite can also be a target that depends on other dependencies:

final_target: sub_target final_target.c
	Recipe_to_create_final_target

sub_target: sub_target.c
	Recipe_to_create_sub_target

It is not necessary for the target to be a file; it could be just a name for the recipe, as in our example. We call these "phony targets."

Going back to the example above, when make was executed, the entire command echo "Hello World" was displayed, followed by actual command output. We often don't want that. To suppress echoing the actual command, we need to start echo with @:

say_hello:
        @echo "Hello World"

Now try to run make again. The output should display only this:

$ make
Hello World

Let's add a few more phony targets: generate and clean to the Makefile:

say_hello:
        @echo "Hello World"

generate:
	@echo "Creating empty text files..."
	touch file-{1..10}.txt

clean:
	@echo "Cleaning up..."
	rm *.txt

If we try to run make after the changes, only the target say_hello will be executed. That's because only the first target in the makefile is the default target. Often called the default goal, this is the reason you will see all as the first target in most projects. It is the responsibility of all to call other targets. We can override this behavior using a special phony target called .DEFAULT_GOAL.

Let's include that at the beginning of our makefile:

.DEFAULT_GOAL := generate

This will run the target generate as the default:

$ make
Creating empty text files...
touch file-{1..10}.txt

As the name suggests, the phony target .DEFAULT_GOAL can run only one target at a time. This is why most makefiles include all as a target that can call as many targets as needed.

Let's include the phony target all and remove .DEFAULT_GOAL:

all: say_hello generate

say_hello:
	@echo "Hello World"

generate:
	@echo "Creating empty text files..."
	touch file-{1..10}.txt

clean:
	@echo "Cleaning up..."
	rm *.txt

Before running make, let's include another special phony target, .PHONY, where we define all the targets that are not files. make will run its recipe regardless of whether a file with that name exists or what its last modification time is. Here is the complete makefile:

.PHONY: all say_hello generate clean

all: say_hello generate

say_hello:
	@echo "Hello World"

generate:
	@echo "Creating empty text files..."
	touch file-{1..10}.txt

clean:
	@echo "Cleaning up..."
	rm *.txt

The make should call say_hello and generate:

$ make
Hello World
Creating empty text files...
touch file-{1..10}.txt

It is a good practice not to call clean in all or put it as the first target. clean should be called manually when cleaning is needed as a first argument to make:

$ make clean
Cleaning up...
rm *.txt

Now that you have an idea of how a basic makefile works and how to write a simple makefile, let's look at some more advanced examples.

 

Advanced examples

Variables

In the above example, most target and prerequisite values are hard-coded, but in real projects, these are replaced with variables and patterns.

The simplest way to define a variable in a makefile is to use the = operator. For example, to assign the command gcc to a variable CC:

CC = gcc

This is also called a recursive expanded variable, and it is used in a rule as shown below:

hello: hello.c
    ${CC} hello.c -o hello

As you may have guessed, the recipe expands as below when it is passed to the terminal:

gcc hello.c -o hello

Both ${CC} and $(CC) are valid references to call gcc. But if one tries to reassign a variable to itself, it will cause an infinite loop. Let's verify this:

CC = gcc
CC = ${CC}

all:
    @echo ${CC}

Running make will result in:

$ make
Makefile:8: *** Recursive variable 'CC' references itself (eventually).  Stop.

To avoid this scenario, we can use the := operator (this is also called the simply expanded variable). We should have no problem running the makefile below:

CC := gcc
CC := ${CC}

all:
    @echo ${CC}

Patterns and functions

The following makefile can compile all C programs by using variables, patterns, and functions. Let's explore it line by line:

# Usage:
# make        # compile all binary
# make clean  # remove ALL binaries and objects

.PHONY = all clean

CC = gcc			# compiler to use

LINKERFLAG = -lm

SRCS := $(wildcard *.c)
BINS := $(SRCS:%.c=%)

all: ${BINS}

%: %.o
	@echo "Checking.."
	${CC} ${LINKERFLAG} $< -o $@

%.o: %.c
	@echo "Creating object.."
	${CC} -c $<

clean:
	@echo "Cleaning up..."
	rm -rvf *.o ${BINS}
  • Lines starting with # are comments.

  • Line .PHONY = all clean defines phony targets all and clean.

  • Variable LINKERFLAG defines flags to be used with gcc in a recipe.

  • SRCS := $(wildcard *.c)$(wildcard pattern) is one of the functions for filenames. In this case, all files with the .c extension will be stored in a variable SRCS.

  • BINS := $(SRCS:%.c=%): This is called as substitution reference. In this case, if SRCS has values 'foo.c bar.c'BINS will have 'foo bar'.

  • Line all: ${BINS}: The phony target all calls values in${BINS} as individual targets.

  • Rule:

    %: %.o
      @echo "Checking.."
      ${CC} ${LINKERFLAG} $&lt; -o $@

    Let's look at an example to understand this rule. Suppose foo is one of the values in ${BINS}. Then % will match foo(% can match any target name). Below is the rule in its expanded form:

    foo: foo.o
      @echo "Checking.."
      gcc -lm foo.o -o foo

    As shown, % is replaced by foo$< is replaced by foo.o$< is patterned to match prerequisites and $@ matches the target. This rule will be called for every value in ${BINS}

  • Rule:

    %.o: %.c
      @echo "Creating object.."
      ${CC} -c $&lt;

    Every prerequisite in the previous rule is considered a target for this rule. Below is the rule in its expanded form:

    foo.o: foo.c
      @echo "Creating object.."
      gcc -c foo.c
  • Finally, we remove all binaries and object files in target clean.

Below is the rewrite of the above makefile, assuming it is placed in the directory having a single file foo.c:

# Usage:
# make        # compile all binary
# make clean  # remove ALL binaries and objects

.PHONY = all clean

CC = gcc			# compiler to use

LINKERFLAG = -lm

SRCS := foo.c
BINS := foo

all: foo

foo: foo.o
	@echo "Checking.."
	gcc -lm foo.o -o foo

foo.o: foo.c
	@echo "Creating object.."
	gcc -c foo.c

clean:
	@echo "Cleaning up..."
	rm -rvf foo.o foo

 

Copied from: https://opensource.com/article/18/8/what-how-makefile

标签:target,CC,make,work,Makefile,echo,how,foo,hello
From: https://www.cnblogs.com/zhangzhihui/p/17842364.html

相关文章

  • visual studio2022中如何添加另外新下载的框架Net.framework4.8.1 ?
    visualstudio2022中如何添加另外新下载的框架Net.framework4.8.1?作者:张晓栋链接:https://www.zhihu.com/question/577090786/answer/2832018198来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。不要自己去下载,需要通过VisualStudioInstaller安......
  • ctf.show 信息泄露部分题解
    源码泄露根据题目可以知道这个是源码泄露,所以是看源代码,查看源代码的三种方式:CTRL+U,F12,右键选择查看源代码,flag就在源代码内前台JS绕过启动靶场后给出的提示是无法查看源代码,右键和F12都无法使用,题目是前台JS绕过,所以我们进入浏览器的设置界面,搜索javascript找到后把他禁用,然后再返......
  • How Attentive are Graph Attention Networks?
    目录概符号说明GATv2代码BrodyS.,AlonU.andYahavE.Howattentivearegraphattentionnetworks?ICLR,2022.概作者发现了GAT的attention并不能够抓住边的重要性,于是提出了GATv2.符号说明\(\mathcal{V}=\{1,\ldots,n\}\),nodeset;\(\mathcal{E}\su......
  • .net 和.net framework相比的优势
    .net是一个平台,不是一门语言。.net包含.netframework、.netcore.一、.netframework缺点(1) 系统级别的安装(.netframework版本、补丁),互相影响;(2) 无法独立部署(3) Asp.net和IIS深度耦合;(4) ASP.net资源消耗大;(5) 非云原生。(6) 历史包袱:拖控件、不能很好支持......
  • Fully-Convolutional Siamese Networks for Object Tracking
    论文代码......
  • Python如何使用Networkx实现复杂的人物关系图?
    (Python如何使用Networkx实现复杂的人物关系图?)1简单引入日常工作、生活中我们经常会遇到一些复杂的事务关系,比如人物关系,那如何才能清楚直观的看清楚这些任务关系呢?比如我们从网上搜索1个人物关系图,大家看看:声明:以下图片来源于网络,如果涉及版权问题,请联系作者删除。本文仅......
  • hudson.plugins.git.GitException: Failed to delete workspace
    持续集成环境(git+gitlab+jenkins+pipeline+maven+harbor+docker+k8s)之前都是ok的,突然就报错了:CloningtheremoteGitrepositoryCloningrepositorygit@192.168.117.180:qzcsbj/gift.gitERROR:Failedtocleantheworkspacejenkins.util.io.CompositeIOExc......
  • 在Rider 中使用Entity Framework Core UI 插件创建EFCore 的 Migration迁移文件时报错
    报错信息EFCoretoolsarerequiredtoexecutethisaction在点击报错信息中的发Fix进行安装时,再次出错这次是提示版本不匹配这里我使用的是EFCore7.0.14版本的报错原因没有安装dotnettool点击Fix进行安装时,是安装的最新版,是要是.net7的安装dotnettool直......
  • Decoupling the Depth and Scope of Graph Neural Networks
    目录概符号说明Shadow-GNN代码ZengH.,ZhangM.,XiaY.,SrivastavaA.,MalevichA.,KannanR.,PrasannaV.,JinL.andChenR.Decouplingthedepthandscopeofgraphneuralnetworks.NIPS,2021.概为每个结点抽取一子图作为结点的代表,然后推理过程仅限定在子......
  • SOLIDWORKS参数化设计之主参数设置
    SOLIDWORKS参数化设计是通过主参数来驱动整个模型的变化,因此确定主参数是很重要的部分。主参数可以是数值,也可以是条件,可以手动输入,也可以做成下拉列表。今天我们就来看看主参数的下拉列表是如何做到的。SolidKits.AutoWorks软件的参数表是外置参数表,使用软件提取所有参数后,可以......