Linux c编程之Makefile

一、说明

  使用linux gcc编译程序时,需要输入很多命令及参数,很复杂,容易出错,并且会浪费很多时间。Makefile应运而生,使用Makefile来管理整个软件工程的编译流程,在实际软件工程中,通过make一条指令就可以完成整个软件工程的编译。
作用:

  1. 大量代码的关系维护
  2. 减少重复编译时间

二、Makefile构成

Makefile三要素:
目标
依赖
执行命令,命令要以table开头
多条命令,每条占一行

执行方式:
make
make -f my-makefile

三、常见命令

  1. make
  2. 查看版本
    $ make -v
    GNU Make 3.81
    Copyright © 2006 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.

This program built for x86_64-pc-linux-gnu

  1. 打印命令,但不执行
    用于调试
    $ make -n
    echo “compile start…”
    gcc main.c

四、符号说明

< :第一个依赖文件
@ :目标文件的名称
^ :依赖文件(不重复)

  • :目标文件的名称,不包含文件的扩展名
    ? :修改过的依赖文件
  • :所有的依赖文件(包含重复)

五、 Makefile中的函数

调用方法:
$(,)
${,}
• function是函数名,arguments是函数的参数。 参数之间要用逗号分开。
• 可以使用小括弧,或者花括弧,一般选择小括弧。

  1. 获取匹配模式文件名:wildcard函数
    wildcard – 查找指定目录下的指定类型的文件
    src = $(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src

  2. 模式字符串替换:patsubst函数
    obj = $(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o

  3. 字符串替换:subst函数

  4. notdir 函数

  5. Suffix

  6. 过滤函数:filter

makefile中也提供了一些变量(变量名大写)供用户直接使用。
CC = gcc #arm-linux-gcc

CPPFLAGS : C预处理的选项 如:-I

CFLAGS: C编译器的选项 -Wall -g -c

LDFLAGS : 链接器选项 -L -l

  1. 宏定义使用
    A:宏定义
    -D DEBUG
    -D DEBUG=[value]

  2. ifeq的使用
    ifeq ( ( T A R G E T A R C H ) , a r m ) L O C A L S R C F I L E S : = . . . e l s e i f e q ( (TARGET_ARCH), arm) LOCAL_SRC_FILES := ... else ifeq ( (TARGETARCH),arm)LOCALSRCFILES:=...elseifeq((TARGET_ARCH), x86)
    LOCAL_SRC_FILES := …
    else ifeq ($(TARGET_ARCH), mips)
    LOCAL_SRC_FILES := …
    else
    LOCAL_SRC_FILES := …
    endif

  3. 注释方法
    使用#作为注释方法

  4. 忽略错误
    Makefile:

all:
	gcc main.c

.PHONY:
clean:
	-rm a.out
$ make clean
rm a.out
rm: cannot remove ‘a.out’: No such file or directory
make: [clean] Error 1 (ignored)

$ make clean
rm a.out
rm: cannot remove ‘a.out’: No such file or directory
make: [clean] Error 1 (ignored)
  1. 不打印命令
$ make
gcc main.c

Makefile:
all:
	@gcc main.c

.PHONY:
clean:
	-@rm a.out

$ make
$ make clean

  1. 日志打印
    Makefile:
all:
	@echo "compile start..."
	@gcc main.c

.PHONY:
clean:
	-@rm a.out

$ make
compile start...

六、 实例说明

1.条件编译的使用
2.1 使用静态库
LIB_A_SUPPORT=y
#LIB_SO_SUPPORT=y

编译:

$ make
echo ./lib/src/math_method.c   math_method.o
./lib/src/math_method.c math_method.o
gcc -fPIC -c ./lib/src/math_method.c
ar cr libmath_method.a math_method.o
ranlib libmath_method.a
gcc -o a.out main.c -L. -Wl,-dn -lmath_method -Wl,-dy -lgcc_s -I./lib/include

测试:

$ ./a.out 
hello world
1 + 9 = 10

2.2 使用动态库
LIB_SO_SUPPORT=y
#LIB_A_SUPPORT=y

编译:

$ make
echo ./lib/src/math_method.c   math_method.o
./lib/src/math_method.c math_method.o
gcc -fPIC -c ./lib/src/math_method.c
gcc -shared -o libmath_method.so math_method.o
gcc -o a.out main.c -L. -Wl,-dy -lmath_method -Wl,-dy -lgcc_s -I./lib/include 

测试:

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/001-program
$ ./a.out 
hello world
1 + 9 = 10

源码:

$ tree .
.
├── lib
│   ├── include
│   │   └── math_method.h
│   └── src
│       └── math_method.c
├── main.c
└── Makefile

main.c:

#include <stdio.h>

#include "math_method.h"

int main(int arc, char *argv[])
{
    printf("hello world\n");

    printf("%d + %d = %d\n", 1, 9, math_add(1, 9));

    return 0;
}

math_method.c:

#include <stdio.h>

int math_add(int a, int b)
{
        return a + b;
}

int math_sub(int a, int b)
{
        return a - b;
}

math_method.h:

#ifndef __MATH_METHOD_H__
#define __MATH_METHOD_H__

int math_add(int a, int b);

int math_sub(int a, int b);

#endif

Makefile:

LIB_A_SUPPORT=y
LIB_SO_SUPPORT=y

CC=gcc

ifeq ($(LIB_A_SUPPORT), y)
	LIBRARY=-L. -Wl,-dn -lmath_method -Wl,-dy -lgcc_s
endif

ifeq ($(LIB_SO_SUPPORT), y)
	LIBRARY=-L. -Wl,-dy -lmath_method -Wl,-dy -lgcc_s
endif

INCLUDE=-I./lib/include

CFLAGS=

TARGET=a.out

ifeq ($(LIB_SO_SUPPORT), y)
DEPEND_TARGET += libmath_method.so

endif

ifeq ($(LIB_A_SUPPORT), y)

DEPEND_TARGET += libmath_method.a

endif

LIB_SRCS=$(wildcard ./lib/src/*.c)
LIB_NDIR_SRCS=$(notdir $(LIB_SRCS))
LIB_OBJ=$(patsubst %.c, %.o, $(LIB_NDIR_SRCS))

$(TARGET): $(DEPEND_TARGET)
	gcc -o $@ main.c $(LIBRARY) $(INCLUDE) $(CFLAGS)

$(LIB_OBJ): $(LIB_SRCS)
	echo $(LIB_SRCS)  $(LIB_OBJ)
	$(CC) -fPIC -c $(LIB_SRCS)

ifeq ($(LIB_A_SUPPORT), y)
libmath_method.a: $(LIB_OBJ)
	ar cr $@ $^
	ranlib $@

endif

ifeq ($(LIB_SO_SUPPORT), y)
libmath_method.so: $(LIB_OBJ)
	$(CC) -shared -o $@ $^

endif

.PHONY:
clean:
	-@rm -rf *.o *.a *.so
	-@rm $(TARGET)

伪目标的使用

Makefile
a.out: hello_world_main.c
	gcc -o a.out hello_world_main.c
clean:
	-rm a.out

在上面的Makefile中,a.out是默认目标,clean也是一个目标。
执行make

$ make
gcc -o a.out hello_world_main.c

执行make clean

$ make clean
rm a.out

如果Makefile所在目录下有目标clean同名的文件时,执行make clean会一直提示”make: `clean’ is up to date.”

$ make clean
make: `clean' is up to date.

因为clean目标只是为了执行一些清理命令,而不是真正的目标。为了解决上述问题,可以将clean定义为伪目标,如下所示:
Makefile:

a.out: hello_world_main.c
	gcc -o a.out hello_world_main.c

.PHONY:clean
clean:
	-rm a.out

再执行make clean时,不会提示”`clean’ is up to date.”,如下:

$ make clean
rm a.out
rm: cannot remove ‘a.out’: No such file or directory
make: [clean] Error 1 (ignored)

二、内置函数的使用

  1. wildcard
$ tree .
.
├── log.h
├── log_int.c
├── log_str.c
├── main.c
└── Makefile

log_int.c:

#include <stdio.h>

int show_int(int value)
{
    printf("value: %d\n", value);return 0;
}

log_str.c:

#include <stdio.h>

int show_log(char *str)
{
    printf("str: %s\n", str);

    return 0;
}

log.h:

#ifndef __LOG_H__
#define __LOG_H__

int show_log(char *str);
int show_int(int value);

#endif

main.c:

#include <stdio.h>
#include "log.h"

int main(int arc, char *argv[])
{
    show_log("hello world");
    show_int(5);

    return 0;
}

Makefile:

SRC=$(wildcard *.c)

a.out: $(SRC)
	gcc -o a.out $(SRC)

.PHONY:clean
clean:
	-rm a.out

编译:

$ make
gcc -o a.out log_int.c log_str.c main.c

Makefile:

file_name=$(notdir /tmp/a.c,/tmp/b.c)
filter_list=$(filter %.c %.h, a.c b.c m.h m.o)
suffix_name=$(suffix test.c)
new_obj = $(patsubst %.c, %.o, a.c b.c)
obj=$(subst .c,.o,"a.c b.c")

all:
	@echo "file_name: "$(file_name)
	@echo "filter_list: "$(filter_list)
	@echo "suffix_name: "$(suffix_name)
	@echo "new_obj: "$(new_obj)
	@echo "obj: "$(obj)

测试:

$ make
file_name: b.c
filter_list: a.c b.c m.h
suffix_name: .c
new_obj:  a.o b.o
obj: a.o b.o

七、基础实例

源码工程
目录结构:

.
├── hello_world_main.c
└── Makefile

hello_world_main.c:

#include <stdio.h>

int main(int arc, char *argv[])
{
    printf("hello world\n");

    return 0;
}
a.out: hello_world_main.c
	@gcc hello_world_main.c
.PHONY:
clean:
	-@rm a.out

a. out和clean表示目标, hello_world_main.c是a.out依赖的文件
目标下面的内容是执行的指令,如 “gcc -o a.out hello_world_main.c”和“-@rm a.out”,指令以table头,可以有多行
#开头的行是注释
第一个目标是默认目标,如a.out
默认目标直接使用make即可完成编译,其它目标需要显示指明,比如clean目标,需要使用make clean
Makefile文件名不区分大小写,一般使用首字母大写的形式
Makefile可以管理复杂的编译过程,如多种条件、多个目录及文件等

clean用途: 清除编译生成的中间.o文件和最终目标文件
make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令,解决方案:

伪目标声明: .PHONY:clean
编译及运行
编译:

$ make
gcc -o a.out hello_world_main.c

运行:

$ ./a.out 
hello world

删除编译文件:

$ make clean

依赖文件没有更新时,重复执行make不会重新编译

$ make
make: `a.out' is up to date.

修改依赖文件hello_world_main.c

hello_world_main.c 
#include <stdio.h>

int main(int arc, char *argv[])
{
    printf("hello world\n");
    printf("how are you\n");

    return 0;
}

$ make
$ ./a.out 
hello world
how are you
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪游东戴河

你就是这个世界的唯一

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值