一起笨笨的学C——15makeMake

目录

前言

正文

初级用法:

高级用法:

  拉伸区磨灭大法:

Makefile定义:

高级用法注释:

关键词解释:

CFLAGS:

OPTFLAGS与OPTLIBS:

PREFIX:

.PHONY:

DESTDIR:

wildcard:

patsubst:

install:

后语


前言

        内容是有的,但是你可能感觉我是在吐槽!

        也许不该吐,因为我是站在菜鸟的立场的,而原作是站在培养大神的立场的。


正文

        能看这篇文章的都应该或多或少的知道make吧!

初级用法:

        在代码共同的文件夹下面新建一个Makefile文件,然后输入CFLAGS=-Wall -g,保存。编译ex22.c,就make ex22吧!然后就能发现一个文件大部分bug。

#Makefile

CFLAGS=—Wall -g

高级用法:

CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local

SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))

TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))

PROGRAMS_SRC=$(wildcard bin/*.c)
PROGRAMS=$(patsubst %.c,%,$(PROGRAMS_SRC))

TARGET=build/libex29.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))

#The Target Build
all: $(TARGET) $(SO_TARGET) tests $(PROGRAMS)

dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all

$(TESTS): $(TARGET) $(SO_TARGET)

$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
	ar rcs $@ $(OBJECTS)
	ranlib $@
$(SO_TARGET): $(TARGET) $(OBJECTS)
	$(CC) -shared -o $@ $(OBJECTS)

build:
	@mkdir -p build
	@mkdir -p bin

#THE UNIT TESTS
.PHONY:  tests
tests:	CFLAGS += $(TARGET)
tests:	$(TESTS)
	@sh ./tests/runtests.sh

print:
	@echo($(CFLAGS))
#The Cleaner

clean:
	rm -rf build $(OBJECTS) $(TESTS)
	rm -f tests/tests.log |rm -f tests/tests.out
	find . -name "*.gc*" -exec rm {} \;
	rm -rf 'find . -name "*.dSYM" -print'

#the install
install: all
	install -d $(DESTDIR)/$(PREFIX)/lib/
	install $(TARGET) $(SESTDIR)/$(PREFIX)/lib/

#the checke
check:
	@echo Files with potentially dangerous functions.
	@egrep '[^_.>a-zA-Z0-9] (str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true

如何?感觉到从普通难度升级为深渊了吗?第一次面对时总感觉有一句 “马买皮”一直憋在心口。

如果你也觉得如看天书,那就试试下面的绝招吧!

  拉伸区磨灭大法:

让困难处在“跳一跳就能够的着”,稍微努努力就能解决的地步,这样就能让我们坚持前进的脚步!

Makefile定义:

首先让我们了解下makefile是什么有什么用吧?

Makefile是一个文本文件,它包含了用于构建软件项目的规则和命令。Makefile通常用于C/C++项目,但也可以用于其他编程语言。

Makefile的主要目的是定义项目的编译规则和依赖关系,使得当源代码发生变化时,只需要重新编译发生变化的文件,而不需要重新编译整个项目。这样可以提高构建的效率。

Makefile通常包含以下内容:

  1. 变量定义:用于存储编译器参数、库文件路径、安装目录等常用值,以方便在后续的规则中使用。

  2. 目标定义:每个目标对应一个构建任务,可以是编译源文件、链接可执行文件、生成静态库或共享库等。

  3. 依赖关系定义:定义每个目标的依赖关系,即该目标所依赖的其他目标或文件。当某个依赖发生变化时,该目标会重新构建。

  4. 规则定义:每个目标都有对应的构建规则,规定了如何通过命令行来构建目标。

通过运行make命令,Makefile会按照定义的规则和依赖关系来构建项目。Make工具会自动分析文件的依赖关系,根据文件的修改时间来决定是否需要重新构建。在构建过程中,Make工具会执行指定的命令,如编译源文件、链接可执行文件、生成静态库或共享库等。

Makefile的优点是可以自动化构建过程,减少手动操作的繁琐程度,并提高构建的效率。同时,Makefile也具有可移植性,可以在不同的平台上使用相同的Makefile来构建项目。

所以说它是一个自动化构建项目工具,平台适应性强!

高级用法注释:
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
#编译器参数,通常包括调试选项、优化选项、警告选项等。
LIBS=-ldl $(OPTLIBS) #链接时需要的库文件
PREFIX?=/usr/local #是安装目录的前缀,默认为/usr/local

SOURCES=$(wildcard src/**/*.c src/*.c)#匹配所有的源文件
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))#将源文件的扩展名.c替换为.o,批量获得编译后的目标文件名称

TEST_SRC=$(wildcard tests/*_tests.c)#匹配所有的测试源文件
TESTS=$(patsubst %.c,%,$(TEST_SRC))#通过替换c为空,获得测试的可执行文件名称

PROGRAMS_SRC=$(wildcard bin/*.c)
PROGRAMS=$(patsubst %.c,%,$(PROGRAMS_SRC))

TARGET=build/libex29.a#静态库的名称就是为了方便修改目标,增加效率
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))#动态库的名称


#The Target Build下面是目标与依赖关系,正常人们互相之间的关系也不过如此吧!社畜表示很恐!
all: $(TARGET) $(SO_TARGET) tests $(PROGRAMS) 
#目标all及依赖。所谓依赖不是命令,感觉就像抬轿子一样,四个人抬着all,all依赖四个人,四个人还要依赖他们的胳膊。如果只是其中一个人左胳膊酸了,他换右胳膊就行,别人不动。

dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all
#dev将环境变量改为调试模式重新构建all,同时说明依赖未必是在下面。

$(TESTS): $(TARGET) $(SO_TARGET)

$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
	ar rcs $@ $(OBJECTS) #ar创建一个静态库
	ranlib $@ #创建静态库的索引也就是一种指针,让系统能通过这个导入到程序中
$(SO_TARGET): $(TARGET) $(OBJECTS)
	$(CC) -shared -o $@ $(OBJECTS)
#开始晕了,它为什么要依赖后面的两个呢?
#哦,它首先要有一个合适的环境间,其次需要那么多的中间文件,才能开始构建动态库
build:
	@mkdir -p build
	@mkdir -p bin

#THE UNIT TESTS
.PHONY:  tests
tests:	CFLAGS += $(TARGET)
tests:	$(TESTS)
	@sh ./tests/runtests.sh

print:
	@echo($(CFLAGS))
#The Cleaner

clean:
	rm -rf build $(OBJECTS) $(TESTS)
	rm -f tests/tests.log |rm -f tests/tests.out
	find . -name "*.gc*" -exec rm {} \;
	rm -rf 'find . -name "*.dSYM" -print'

#the install
install: all
	install -d $(DESTDIR)/$(PREFIX)/lib/
	install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/

#the checke
check:
	@echo Files with potentially dangerous functions.
	@egrep '[^_.>a-zA-Z0-9] (str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true

总结一下,以后要写依赖最好备注一下用途,不然最后很容易晕,就像踢皮球一样,踢到最后,究竟皮球最终在哪里了。哦,进了! 进了就好啊,进了就好,庆祝吧,欢呼吧,球进了!    

关键词解释:
CFLAGS:

CFLAGS是一个变量,用于指定编译器的编译选项。在Makefile中,CFLAGS通常被用于设置一些通用的编译选项,如调试选项、优化级别、警告级别等

  • -g:生成包含调试符号的可执行文件,方便调试。
  • -O2:进行优化,提高程序的执行效率。
  • -Wall:打开警告信息,会显示一些潜在的问题或不规范的代码。
  • -Wextra:打开额外的警告信息,可以检测更多的问题。
  • -Isrc:指定头文件搜索的路径,将src目录添加到头文件搜索路径中。
  • -rdynamic:将所有符号(包括未使用的)添加到动态符号表中,方便后续动态链接。
  • -DNDEBUG:定义一个宏NDEBUG,用于屏蔽一些调试相关的代码。如assert与dbg这些代码的输出
  • -fpic:

    用于生成与位置无关的代码(Position Independent Code,PIC)。PIC是一种可以在内存中加载并重定位的代码,它可以在不同的进程之间共享,并且可以在内存地址改变时仍然可以正常工作。在动态链接库和共享对象中使用PIC是很常见的。

    通过在编译目标文件时使用-fPIC选项,生成的目标文件可以用于构建动态链接库(.so文件)。这样,通过链接这些目标文件,我们可以生成可在不同进程中加载和共享的共享对象。

OPTFLAGS与OPTLIBS:

OPTLIBSOPTFLAGS是变量,用于指定编译或链接时的额外选项。OPTLIBS通常用于指定需要链接的额外库文件,OPTFLAGS通常用于指定编译器的额外选项。通过在命令行中设置这些变量,可以为编译或链接过程提供额外的选项。

PREFIX:

DESTDIR是一个变量,用于指定安装目标文件的根目录。在执行make install命令时,可以通过设置DESTDIR变量来改变安装路径

.PHONY:

.PHONY是一个特殊的目标标记。它告诉Make工具,目标不是一个真正的文件,而是一个虚拟的目标。在Makefile中,.PHONY通常被用于定义一些不产生文件输出的目标,如cleaninstalltest等。指定目标为.PHONY可以避免与同名文件产生冲突,并确保目标被正确执行。

我倔脾气犯了,如果不用此标记会怎么样?

如果不用.PHONY特殊标记,Make工具会默认将目标视为一个待生成的文件。这意味着如果存在一个与目标同名的实际文件,并且该文件的创建时间比目标要晚,Make工具将不会执行该目标对应的命令。

这可能会导致一些问题,特别是对于一些常用的目标,如clean。如果没有使用.PHONY标记定义clean目标,当存在一个名为clean的实际文件时,make clean命令将不会执行清理操作,而是认为目标已经是最新的。

因此,使用.PHONY标记可以确保目标被正确执行,而不依赖于同名文件的存在与否。它告诉Make工具这个目标不是一个实际的文件,需要始终执行对应的命令。这样可以避免一些潜在的问题,确保Makefile的正确性和可靠性。

前面的点号不可省略。

DESTDIR:

DESTDIR是一个变量,用于指定安装目标文件的根目录。在执行make install命令时,可以通过设置DESTDIR变量来改变安装路径

wildcard:

wildcard是Makefile中的一个函数,用于搜索指定模式的文件或目录。它的语法是$(wildcard pattern),其中pattern是要搜索的文件或目录的模式。

在Makefile中,wildcard通常用于获取文件列表,以方便后续的构建规则或操作。它可以帮助自动识别符合指定模式的文件,并将它们作为一个列表返回。

patsubst:

patsubst也是Makefile中的一个函数,用于对字符串进行模式替换。它的语法是$(patsubst pattern,replacement,text),其中pattern指定要被替换的模式,replacement指定替换后的字符串,text是要进行替换操作的字符串。

在Makefile中,patsubst通常用于对文件名进行模式匹配和替换,以方便后续的构建规则或操作。它可以帮助自动化文件名的生成或转换。

install:

它不是预定义变量也不是预定义的函数,为啥还要单独介绍呢?因为未知,所以对于它的使用很好奇,了解下吧!

在给定的Makefile中,install是一个目标,用于安装生成的目标文件。以下是install目标的内容:

install: all
	install -d $(DESTDIR)/$(PREFIX)/lib/
	install $(TARGET) $(SESTDIR)/$(PREFIX)/lib/

install目标的执行过程如下:

  1. 首先,install目标依赖于all目标。这意味着在执行install目标之前,需要先执行all目标,以生成目标文件。
  2. install目标使用install命令来安装生成的目标文件。具体地,它使用-d选项创建目标目录的父目录,并使用$(DESTDIR)$(PREFIX)变量指定目标目录的位置。然后,使用install命令将生成的目标文件安装到目标目录中。

通过运行make install命令,Make工具将自动执行install目标,并将生成的目标文件安装到指定的目录中。

我现在一般生成可执行文件,只要输入“./ex15”就能执行程序了,所以不存在安装软件的感觉,所以为什么要安装,什么时候用到,安装的好处有哪些呢?

在这个Makefile中,install目标的目的是将生成的目标文件安装到指定的目录中。安装的目的是为了将软件或程序的可执行文件、库文件或其他相关文件复制到系统的标准位置,以便可以方便地访问和使用这些文件。

安装软件的好处包括:

  1. 方便使用:安装软件后,可以通过系统的命令行或其他方式轻松地启动和运行软件。
  2. 标准化:将软件安装到系统的标准位置,符合系统管理的最佳实践和约定,使软件在不同系统上的安装和升级更加统一和可靠。
  3. 系统集成:通过将软件的库文件安装到系统的标准库目录中,其他程序可以使用和链接到这些库,实现更好的系统集成和共享资源的效果。
  4. 依赖管理:在安装过程中,可以检查和解决软件所依赖的其他库和组件,确保软件能够在目标系统上正常运行。

总之,安装软件可以使软件在系统中更加方便地使用和管理,提高软件的可用性和可靠性。

所以说,把install放到最后也表示这是一场大戏吧,压轴的。下面就是刷副本了吧?依靠make与shell探索数据结构和算法,进而可以搞项目解决问题!好期待啊! 


后语

也许这是最后一篇此系列的学习笔记了,因为我深度学习的目的达到了。看到此篇文章的你们如果在自学C的路上,浮躁总想不求甚解。可以试试边学便写笔记的方法。

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值