Makefile编写

本文详细介绍了Makefile的编写规则,包括文件命名、编译动态库和静态库的步骤,以及如何处理多文件目录下的Makefile。重点讲解了动态库与静态库的区别,并给出了在有多个源文件时的简化编译规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

Linux下的gcc编译器不会给你自动链接自定义的文件,它只能链接一些库里面的文件,因此少量自定义头文件可以自己用gcc命令把它们链接起来
但是当一个工程中定义了大量的函数和变量时我们不可能还像前面一样继续搬砖,这时就不得不用Makefile来实现整个工程的自定义编译了,虽然说很久以前就学习过Makefile的命令了,但是还是俗话说得好,三天不看,不知道啥样!所以还是记录一下以便参考和查询

Makefile文件命名规则

首先编写一个makefile文件文件名是固定的只有三种命名,如果你非要给自己的文件取其他的名字,那么对不起你在执行make命令的时候它就不跟你玩了,其他的名字它根本就不认识,三种名字分别是:

  • Makefile
  • makefile
  • GNUmakefile

文件编写规则

  1. 命令之前绝对不能是空格而是tab键(这里的Table键占8个空格如果你在vim下修改了table键的大小,记得改回来)
    这是当初年轻不懂事瞎改vim最后写makefile时抛的错,现在也放出来看一看
    在这里插入图片描述

  2. 文件编译:
    可执行文件名称 冒号 生成可执行文件的依赖文件(.o文件),文件名间用空格隔开
    在这里插入图片描述
    然后将第一行中冒号后面所有列举的文件每个以单独的模块按下面的规则一一列举
    目标文件名(随便命)冒号 依赖文件名 换行
    table键(8个空格) Linux命令

    在这里插入图片描述
    当然看了上面的最简单的例子有没有一个疑问,就是如果我想编译的一个文件依赖大量的c文件(8-9个或者10多个甚至更多,如果是移植操作系统,那会编译上万个文件,那都像上面那样不是要哭着回家找妈了吗?),
    那么下面这种借助简化符号提高效率的方式就可以解决你的烦恼

    简化符号含义:

    %.o:	表示当前目录下所有的.o文件
    %.c:	表示当前目录下所有的.c文件
    $^:		表示目标文件,:左边的文件
    $@:		表示所有的依赖文件,:右边的所有文件
    

    那么上面的内容就可以改写成这样

    ab:a.o b.o
    %.o:%.c
    	gcc -c $^ -o $@
    .PHONY:clean
    clean:
      	rm -rf *.o
    
  3. 删除:

    .PHONY意思表示clean是一个“伪目标”。也即是无论clean是否最新,一定执行它

    clean:回车
    table(8空格) -rm -rf +文件名

    注意:执行make命令并不会删除*.o文件make clean才会执行makefile中的rm -rf *.o命令,同理,若有其他的 伪目标则要想执行伪目标下的命令应输入make +(“.PHONY:”后面的名称)
    rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但并不理睬。
    在这里插入图片描述
    其实仔细一看makefile 和shell脚本还是比较像的就是把一些在终端上运行的Linux命令封装在文件里面来执行罢了

  4. 使用变量:
    如果文件数目较多就可用个变量来装载我们要操作的文件,最后用命令操作变量,你设想如果还是按照最前面的方法写,那如果我要新添加5个文件进来,我就得在相应的生成和依赖位置添加新的文件名,那我最后的工作量就是新添加至少10文件名,是不是感觉工作量有点线性增加,所以变量使用就是这个好处,可以偷懒,那我这里顺便说明一下下面的 ${VAR} 什么意思, ${变量名} 表示取变量的值

    VAR=a.c b.c
    	gcc ${VAR} -o ab
    clean:
      	rm -rf *.o
    
    
  5. 文件注释和编译内容屏蔽

  • 突然发现Makefile和shell的单行注释是一样的都是借助 # 来注释一行代码,注意最好是在单独一行用 # 来注释,不要在一些命令的后面用 # 来注释,有时候可能注释不成功
  • 如果在每条编译命令的最前面加 @ 符号就会在执行make命令的时候make编译的内容不会打印到屏幕上
VAR=a.c b.c
	@gcc ${
   VAR} -o ab
clean:
  	@rm -rf *.o

编译动态库和静态库

其实有时候我们并不总是想生成可执行程序,有时候不希望自己写的源码被别人看见,而是仅仅被别人使用就可以,或者只是为了给别人提供一个调用的接口,这时就需要学会生成库函数了

动态库
  1. 动态库命名规则
    必须以lib开头,.so结尾,形如下面这种格式,一般的话只要遵循前面用lib开头后面用.so结尾就可以了,后面的各种.x.y.z与动态库的升级有关,这里就不展开了,命名一定要按照这两条规则,不然自己虽然已经编译出.so文件了但是在链接的时候不管你用什么方法都不能让你的程序跑起来,这就是游戏规则,你不遵循自然它也不和你玩咯!
    在这里插入图片描述

  2. 动态库生成和使用
    2.1 用makefile生成动态库命令

    VARABLE = a.c b.c c.c
    # $(变量名) 表示的是此变量的值 
    
    lib.so:$(VARABLE) 
            gcc $(VARABLE) -fPIC -shared -o lib.so
    
    .PHONY:clean
    clean:
            rm -rf *.o a.out lib.so
    

    执行make命令之后就可以看到生成的lib.so文件了
    在这里插入图片描述

    2.2 链接动态库生成可执行文件
    上面已经用makefile把三个文件中的函数都编译进动态库了,下面就是直接调用动态库来使用其中的函数

    gcc test.c -L .-l lib.so
    注意.-l之间没有空格
    

    好家伙在运行的时候遇到了下面的问题
    在这里插入图片描述
    ./a.out: error while loading shared libraries: lib.so: cannot open shared object file: No such file or directory
    解决:
    把动态库文件复制到/usr/local/lib/路径下或者/usr/lib/路径下或者使用export命令指定环境变量

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/google/workspace/test/lib_test_so(动态库文件所在路径)
    

    因为Linux下在运行程序时,会默认到 /lib、/lib64、/usr/lib以及LD_LIBRARY_PATH环境变量指定的路径下查找所需的动态库下查找所需的动态库文件,如果没有则抛错
    再啰嗦一下就是在将动态库文件拷贝到相应的路径下的时候如果拷贝过去还不生效可以运行 ldconfig是一个动态链接库管理命令,其目的为了让动态链接库为系统所共享。

    google@ubuntu1404:~/workspace/test/lib_test_so$ ./a.out 
    ./a.out: error while loading shared libraries: lib.so: cannot open shared object file: No such file or directory
    google@ubuntu1404:~/workspace/test/lib_test_so$ cp -r lib.so /usr/local/lib/
    cp: 无法创建普通文件"/usr/local/lib/lib.so": 权限不够
    google@ubuntu1404:~/workspace/test/lib_test_so$ sudo cp -r lib.so /usr/local/lib/
    google@ubuntu1404:~/workspace/test/lib_test_so$ ./a.out 
    I am the so_a function!
    I am the so_b function
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值