linux Makefile 第二部分

1、Makefile中通用部分做公共头文件

Makefile中,都是先展开所有变量,再调用指令

  • =            赋值,但是用终值,就是不管变量调用写在赋值前还是赋值后,调用时都是取终值。
  • :=           也是赋值,但是只受当前行及之前的代码影响,不受后面的赋值影响。      

例:产生一个以下目录结构:

[blctrl@main-machine p1]$ ls -R
.:
d1  d2  Makefile

./d1:
a.cpp  b.cpp  c.cpp  Makefile

./d2:
Makefile  s1.c  s2.c  s3.c

当前目录下有目录d1,d2以及一个Makefile文件,此Makefile文件内容如下:

SOURCE:=$(wildcard ./*.cpp ./*.c)
OBJS:=$(patsubst %.cpp, %.o, $(SOURCE))
OBJS:=$(patsubst %.c, %.o, $(OBJS))

$(TARGET):$(OBJS)
        $(CXX) $^ -o $(TARGET)


#%.o:%.c
#       $(CXX) $^ -o $@

clean:
        $(RM) *.o $(TARGET)

show:
        echo $(SOURCE)
        echo $(OBJS)

.PHONY:clean show

d1目录下,有三个C++源文件,以及一个Makefile,内容如下:

/* a.cpp */
#include <stdio.h>

void function1()
{
    printf("d1-a-function1\n");
}//

/* b.cpp */
#include <stdio.h>

void function2()
{
    printf("d1-b-function2\n");
}//


/* c.cpp */
#include <stdio.h>
extern void function1();
extern void function2();

int main(int argc, char * argv[])
{
    function1();
    function2();

    return 0;
}

 makefile:用include包含了上级目录中的Makefile文件

TARGET:=c

ifndef TARGET
        TARGET:=test
endif

include ../Makefile

d2目录下,有三个C源文件,以及一个Makefile,内容如下: 

/* s1.c源文件 */
#include <stdio.h>

void function1()
{
    printf("d2-a-function1\n");
}//

/* s2.c源文件 */
#include <stdio.h>

void function2()
{
    printf("d2-b-function2\n");
}//

/* s3.c源文件*/
#include <stdio.h>

extern void function1();
extern void function2();

int main(int argc, char * argv[])
{
    function1();
    function2();

    return 0;
}

 makefile:用include包含了上级目录中的Makefile文件

TARGET:=s3

ifndef TARGET
        TARGET:=test
endif

include ../Makefile

 子目录d1和d2中的Makefile共用了上级目录中的Makefile来编译自己目录中的源文件,并且生成了可执行文件。

执行结果,编译都成功了:

[blctrl@main-machine d1]$ make
g++    -c -o b.o b.cpp
g++    -c -o a.o a.cpp
g++    -c -o c.o c.cpp
g++ b.o a.o c.o -o c
[blctrl@main-machine d1]$ ./c
d1-a-function1
d1-b-function2
[blctrl@main-machine d1]$ cd ../d2
[blctrl@main-machine d2]$ make
cc    -c -o s3.o s3.c
cc    -c -o s2.o s2.c
cc    -c -o s1.o s1.c
g++ s3.o s2.o s1.o -o s3
[blctrl@main-machine d2]$ ./s3
d2-a-function1
d2-b-function2

2、Makefile中调用shell命令

例:在一个目录下新建一个Makefile文件,其内容如下:

FILE:=rec

A:=$(shell ls ../)
B:=$(shell pwd)
C:=$(shell if [ ! -f $(FILE) ];then touch $(FILE);fi)

a:
        echo $(A)
        echo $(B)
        echo $(C)

clean:
        $(RM) $(FILE)

在这个Makefile中定义了变量FILE,A,B,C,A中存储shell命令ls ../的结果,即是当前目录的上一级目录中包含的文件,B中存储pwd的结果,即当前路径,C中执行一条if语句,如果FILE变量中指定名称rec的文件不存在,则创建一个此名称的文件。执行结果如下:

[blctrl@main-machine d3]$ ls
Makefile
[blctrl@main-machine d3]$ make
echo d1 d2 d3 Makefile
d1 d2 d3 Makefile
echo /home/blctrl/CLionProjects/Firtst/practice/d3
/home/blctrl/CLionProjects/Firtst/practice/d3
echo

[blctrl@main-machine d3]$ ls
Makefile  rec

3、Makefile的嵌套调用

创建一个以下目录结构:

[blctrl@main-machine call]$ ls -R
.:
d4  d5  Makefile  Makefile-head

./d4:
a.cpp  b.cpp  c.cpp  Makefile

./d5:
Makefile  s1.c  s2.c  s3.c

d4和到d5中的源文件和头文件分别来自第一部分(Makefile中通用部分做公共头文件)中的d1和d2,但Makefile中做了略微修改,把include语句修改为

include ../Makefile-head

顶层目录Makefile名称也修改为Makefile-head,然后新建一个Makefile,内容如下:

all:
        make -C ./d4
        make -C ./d5


clean:
        make -C ./d4 clean
        make -C ./d5 clean

执行make进行编译,结果如下:

make的-C参数为make制定了工作目录。

[blctrl@main-machine call]$ make
make -C ./d4
make[1]: Entering directory '/home/blctrl/CLionProjects/Firtst/practice/call/d4'
g++    -c -o b.o b.cpp
g++    -c -o a.o a.cpp
g++    -c -o c.o c.cpp
g++ b.o a.o c.o -o c
make[1]: Leaving directory '/home/blctrl/CLionProjects/Firtst/practice/call/d4'
make -C ./d5
make[1]: Entering directory '/home/blctrl/CLionProjects/Firtst/practice/call/d5'
cc    -c -o s3.o s3.c
cc    -c -o s1.o s1.c
cc    -c -o s2.o s2.c
g++ s3.o s1.o s2.o -o s3
make[1]: Leaving directory '/home/blctrl/CLionProjects/Firtst/practice/call/d5'
[blctrl@main-machine call]$ ls -R
.:
d4  d5  Makefile  Makefile-head

./d4:
a.cpp  a.o  b.cpp  b.o  c  c.cpp  c.o  Makefile

./d5:
Makefile  s1.c  s1.o  s2.c  s2.o  s3  s3.c  s3.o
[blctrl@main-machine call]$ make clean
make -C ./d4 clean
make[1]: Entering directory '/home/blctrl/CLionProjects/Firtst/practice/call/d4'
rm -f *.o c
make[1]: Leaving directory '/home/blctrl/CLionProjects/Firtst/practice/call/d4'
make -C ./d5 clean
make[1]: Entering directory '/home/blctrl/CLionProjects/Firtst/practice/call/d5'
rm -f *.o s3
make[1]: Leaving directory '/home/blctrl/CLionProjects/Firtst/practice/call/d5'
[blctrl@main-machine call]$ ls -R
.:
d4  d5  Makefile  Makefile-head

./d4:
a.cpp  b.cpp  c.cpp  Makefile

./d5:
Makefile  s1.c  s2.c  s3.c

从以上编译结果可以看出make进入了指定的d4,d5目录进行了编译,并且产生了二进制对象文件和可执行文件。

修改以上Makefile,功能与以上Makefile相同,内容如下:

DIRS:=d4 d5


ALL:$(DIRS)

$(DIRS):
        make -C $@

clean:
        echo $(shell for dir in $(DIRS);do make -C $$dir clean;done)


.PHONY:clean d4 d5

注意:ALL执行要依赖$(DIR)中指定目标的存在,由于声明了其指定的目标是伪目标,因此执行make ALL时,就会执行这些伪目标指定的命令语句。

4、Makefile中条件判断

  • ifeq:判断是否相等,相等返回true,否则返回false
  • ifneq:判断不是否相等,不相等返回true,否则返回false
  • ifdef:判断是否存在,存在返回true,否则返回false
  • ifndef:判断是否不存在,不存在返回true,否则返回false

ifeq, ifneq, ifdef, ifndef与条件之间要有空格,不然会报错。

ifeq ($(A),123)

else

endif

没有elseif的用法,如果要实现elseif,就要写嵌套。命令行传参数make -f Makefile FLAG=argument,如果有Makefile,则可写出make FLAG=argument

例:在一个目录下建立一个内容如下的Makefile文件:

[blctrl@main-machine d6]$ cat Makefile
VAR:=hello

VAR1:=
VAR2:=


ifeq ($(VAR),hello)
        VAR1:=Hello-Yes
else
        VAR1:=Hello-No
endif

ifdef VAR
        VAR2:=VAR-defined
else
        VAR2:=VAR-undefined
endif

ifndef FLAG
        FLAG=default
endif

all:
        @echo $(VAR1)
        @echo $(VAR2)
        @echo $(FLAG)

分别不带参数和带参数来执行make程序:

[blctrl@main-machine d6]$ make
Hello-Yes
VAR-defined
default
[blctrl@main-machine d6]$ make FLAG=argument
Hello-Yes
VAR-defined
argument

5、Makefile中的循环

foreacn的使用

例:

TARGET:=f1 f2 f3
FILE:=$(foreach v,$(TARGET),$v_name)

all:
        touch $(FILE)


clean:
        $(RM) $(FILE)


.PHONY:clean

执行make,结果如下:

[blctrl@main-machine d7]$ ls
Makefile
[blctrl@main-machine d7]$ make
touch f1_name f2_name f3_name
[blctrl@main-machine d7]$ ls
f1_name  f2_name  f3_name  Makefile

6、Makefile自定义函数

自定义函数,不是真正的函数,本质上是多行命令,放在外面了。没有返回值。

定义:

define FUNC

endef

调用:

$(call FUNC, abc, def, $(A))

例:在一目录下,创建一个Makefile文件,内容如下:

define FUNC
        @echo name=$(0),arg1=$(1),arg2=$(2)
endef

VAR:=Hello Make

all:
        $(call FUNC,abc,$(VAR))

在上面的目录中,执行make,结果:

[blctrl@main-machine d8]$ make
name=FUNC,arg1=abc,arg2=Hello Make

猜你喜欢

转载自blog.csdn.net/yuyuyuliang00/article/details/128325467