Makefile不难入门教程,变量重定义

出现变量重定义的情状?

一、简介

近年来在Linux下编制程序发现三个怪诞的场景,正是在链接四个静态库的时候总是报错,类似上边这样的失实:(.text+0x一三):
undefined reference to `func’

什么是make?

源文件与include的公文定义了同四个变量

main.c

1 #include <stdio.h>
2 #include "a.c"
3 
4 int a = 100;
5 
6 int main() {
7 
8     return 0;
9 }

a.c

 1 int a = 200; 

编写翻译命令:

gcc main.c -o main

编写翻译报错:

 美高梅开户网址 1

make命令执行时,要求3个 Makefile
文件,以告知make命令供给怎么样的去编译和链接程序(不难将:管理工科程的文件,决定先编写翻译哪些文件,编译顺序)。

关于undefined
reference那样的题材,我们实在日常会赶上,在此,笔者以详尽地示范给出常见错误的各样缘由以及缓解方式,希望对初学者有所协助。
1. 链接时缺失了相关指标文件(.o)
**
**测试代码如下:

  make是一步成功大气的源文件编写翻译和链接,从而不必再一条条输入gcc命令。

链接的八个公文都定义了同一个变量

main.c

1 #include <stdio.h>
2 
3 int a = 100;
4 
5 int main() {
6 
7     return 0;
8 }

a.c

int a = 200;

编译命令:

gcc -c main.c -o main.o

gcc -c a.c -o a.o

gcc main.o a.o -o main

末尾一步链接会报错:

 美高梅开户网址 2

二、编写规则:

美高梅开户网址 3

什么是makefile?

对象一:目的重视  然后回车+tab键
 命令;

  makefile是3个文书文件,里面著录了何等文件必要先编写翻译,哪些文件须求后编写翻译,哪些文件必要重新编写翻译。makefile的补益是“自动编写翻译”,只须求3个make命令,整个工程活动编写翻译,相当大增强了功能。

对象2:指标信赖  然后回车+tab键
 命令;

然后编写翻译。

  编写贰个makefile需求超前通晓:一.编写翻译、链接的定义;
二.gcc、g++的有关命令参数 -g -o -c 

对象n:目的重视  然后回车+tab键
 命令;

gcc -c test.c

gcc –c main.c 

 

留意:命令必须是tab键起头的。

得到八个 .o 文件,3个是 main.o,3个是 test.o ,然后大家链接 .o
获得可执行程序:
gcc -o main main.o

编写翻译、链接的概念

三、Makefile演进
一、贰个品类有main.c/a.c/a.h/b.c/b.h八个公文;main.c包罗a.h和b.h并选取有关函数;然后建立二个新的Makefile文件,内容如下:
main:a.o b.o
 gcc -o main a.o b.o 
a.o:a.c
 gcc -c a.c -o a.o 
b.o:b.c
 gcc -c b.c -o b.o

这时候,你会发现,报错了:
main.o: In function
main': main.c:(.text+0x7): undefined reference totest’
collect2: ld returned 1 exit status

  编译:对于C、C++,源文件要求编写翻译成object
file 目的文件,unix下会生成.o文件,这一个动作叫compile
编写翻译。一般的话,每3个源文件都对应着一其中级指标文件,.o文件或许.OBJ文件。

2、Makefile升级1
利用makefile变量:想用就用,未有项目,不供给定义(引用变量使用$(obj)来含有越来越多.o文件)
方法:obj:=a.o b.o
那么地点的Makefile程序升级如下:
obj:=a.o b.o
main:$(obj)
 gcc -o main a.o b.o 
a.o:a.c
 gcc -c a.c -o a.o 
b.o:b.c
 gcc -c b.c -o b.o

那就是最卓绝的undefined
reference错误,因为在链接时意识找不到某些函数的落到实处文件,本例中test.o文件中包蕴了test()函数的兑现,所以假设按上面那种艺术链接就没事了。
gcc -o main main.o test.o

  编写翻译时,编写翻译器需求的是语法正确,函数、变量表明的没错。对于后者,你须求告诉编写翻译器头文件的职位(头文件中应只是宣称而不是概念,定义应放在c\c++文件中),只要具备的语法正确,编写翻译器就足以编写翻译出中间目的文件。

3、Makefile升级2
经过上述五个makefile的编写翻译,项目执行是水到渠成的,可是假若main.c需求引用越多文本中的函数时,是不是要填写那么多的编写翻译命令吗?显著那些法子不可取。
美高梅开户网址 ,一字不苟:makefile特殊变量和活动推导作用
Makefile不难入门教程,变量重定义。知识点表明:
$@  代表目的名,
$^  代表依赖文件
%  代表私自字符
%.o  代表任意.o文件
%.c  代表任意.c文件

【扩张】:其实上边为了让大家尤为了解底层原因,笔者把编写翻译链接分开了,上面那样编写翻译也会报undefined
reference错,其实底层原因与地点是一模1样的。
gcc -o main main.c //贫乏test()的贯彻公文

  链接:将大气的object
file合成为3个可执行文件的动作叫作link 链接。

以上Makefile升级如下:
obj:=a.o b.o
main:$(obj)
 gcc -o main $(obj) 
%.o:%c      #表明:格局通配,自动将.c文件编写翻译成.o文件
 gcc -o $@ -c $^    #注释:通配符
clean:
 rm -rf *.o main

要求改成如下情势才能成功,将test()函数的贯彻文件1起编译。
gcc -o main main.c test.c //ok,没难点了

  链接时,主固然链接函数和全局变量。所以我们得以因此.o
/.obj文件来链接大家的应用程序。链接不管函数所在的源文件,只管函数的中级指标文件(Object
File),在半数以上的时候,由于函数的Object
File太多,而在链接时须求分明提出中间目的文件名,那很不便于。所以大家给那个Object
Files打成包,Windows下叫作链接库文件(Library
File),也正是.lib文件。在Linux下便是Archive File,也等于.a文件。

4、Makefile升级3
exe=main      #表明:最终的编写翻译结果名字
obj:=main.o a.o b.o c.o   #表明:重视文件
all:$(obj)
gcc -o $(exe) $(obj)
%.o:%.c
gcc -c $^ -o $@
clean:
rm -rf $(obj) $(exe)

贰. 链接时缺乏相关的库文件(.a/.so)
在此,只举个静态库的事例,假诺源码如下。

  

如上程序看似未有啥难题的,但是clean有点瑕疵,若是也有二个文本叫clean这如何做?假诺make
clean就无法施行那条命令。

美高梅开户网址 4

gcc的相干选项 -g -o -c  

5、Makefile升级4
采纳伪指标.PHONY来缓解clean瑕疵难题,升级Makefile如下:
exe:=main
obj:=main.o a.o b.o c.o
all:$(obj)
 gcc -o $(exe) $(obj)
%.o:%.c
 gcc -c $^ -o $@
.PHONY:clean     #注解:申明clean是伪指标
clean:
 rm -rf $(obj) $(exe)

  1.-g 是为了gdb 的调试,不然gdb用不到

注释#.PHONY:clean申明伪指标,防止当前目录存在名称为clean文件的时候吩咐不可能履行的意况

先把test.c编写翻译成静态库(.a)文件
gcc -c test.c
ar -rc test.a test.o

  2.-o
output_filename,鲜明输出文件的称呼为output_filename,同时这些名号不能够和源文件同名。如若不交付那几个选项,gcc就交给预设的可执行文件a.out。

6、Makefile升级5
突发性利用的编写翻译器大概是g++、gcc甚至是arm-linux-gcc。为了便于统1管理,最佳早先定义二个变量来表示编辑器,然后在gcc命令上变成$(CC):
Makefile升级如下:
CC:=gcc    #诠释:定义3个变量,表示近来编辑器为gcc
exe:=main
obj:=main.o a.o b.o c.o
all:$(obj)
 $(CC) -o $(exe) $(obj) 
%.o:%.c
 $(CC) -c $^ -o $@
.PHONY:clean
clean:
 rm -rf $(obj) $(exe)

从那之后,大家赢得了test.a文件。大家初叶编写翻译main.c
gcc -c main.c

    一般语法:gcc filename.c -o filename

大抵未来的Makefie能够编写很多平常的先后了。秩序要对Makefile的公文名适龄稍加修改即可。假使在相比较大型的次序里面写Makefile会绝对知识点多或多或少,比如添加静态库、动态库、线程等等;后续再做升高。

那会儿,则生成了main.o文件,然后我们再经过如下命令举办链接希望得到可执行程序。
gcc -o main main.o

    下面的意味是只要您不打 -o filename
那么私下认可就是出口filemame.out.这几个-o就是用来支配输出文件的。

推荐介绍一本书:GNU make普通话手册(翻译整理:徐海兵)

您会发觉,编写翻译器报错了:
/tmp/ccCPA13l.o: In function
main': main.c:(.text+0x7): undefined reference totest’
collect2: ld returned 1 exit status

  三.-c 只编写翻译不链接

本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-06/145306.htm

其根本原因也是找不到test()函数的贯彻文件,由于该test()函数的落到实处在test.a这几个静态库中的,故在链接的时候要求在其后投入test.a那些库,链接命令修改为如下方式即可。
gcc -o main main.o ./test.a //注:./ 是付诸了test.a的门道

  

美高梅开户网址 5

【增添】:同样,为了把标题说精晓,上边我们把代码的编写翻译链接分开了,倘若指望一次性生成可执行程序,则能够对main.c和test.a执行如下命令。
gcc -o main main.c ./test.a //同样,若是不加test.a也会报错

makefile的规则

叁. 链接的库文件中又采用了另2个库文件
那种难点相比隐蔽,也是自己近期遇上的与网上我们谈论的例外的标题,举例表达如下,首先,仍旧看看测试代码。

  目的 : 须要的规格 (注意冒号两边的空格)

美高梅开户网址 6

    命令 (注意眼下用TAB缩进)

  解释一下:

从上图能够看看,main.c调用了test.c的函数,test.c中又调用了fun.c的函数。
首先,咱们先对fun.c,test.c,main.c举办编写翻译,生成 .o文件。
gcc -c func.c
gcc -c test.c
gcc -c main.c

  • 指标能够是一个要么五个Object File,也可以是可执行文件
  • 亟待的尺度便是生成靶子所急需的文书可能指标
  • 一声令下便是生成靶子所须求执行的剧本

然后,将test.c和func.c各自打包成为静态库文件。
ar –rc func.a func.o
ar –rc test.a test.o

  一句话就是,makefile的平整规定的编写翻译的依靠关系,目的文件依赖于规则,生成规则用命令来叙述。在编译时,要是须要的标准比目的新,那么就会实施生成命令来更新目的。

此刻,大家准备将main.o链接为可执行程序,由于大家的main.c中包含了对test()的调用,因而,应该在链接时将test.a作为大家的库文件,链接命令如下。
gcc -o main main.o test.a

  举例表明:假使咱们写下如下的多个文本,add.h
用于注解 add 函数,add.c 提供三个整数相加的函数体,而 main.c中调用 add
函数: 

此时,编译器照旧会报错,如下:
test.a(test.o): In function
test': test.c:(.text+0x13): undefined reference tofunc’
collect2: ld returned 1 exit status

美高梅开户网址 7美高梅开户网址 8

身为,链接的时候,发现大家的test.a调用了func()函数,找不到相应的完成。由此大家发现,原来小编们还要求将test.a所引述到的库文件也加进去才能打响链接,由此命令如下。
gcc -o main main.o test.a func.a

/* filename:add.h */
extern int add(int i, int j);

/* filename:add.c */
int add(int i, int j)
{
    return i + j;
}

/* filename:main.c */
#include "add.h"
main()
{
    int a, b;
    a = 2;
    b = 3;
    printf("the sum of a+b is %d", add(a + b));
}

ok,那样就足以成功博得终极的顺序了。同样,假使大家的库只怕程序中援引了第叁方库(如pthread.a)则如出1辙在链接的时候要求提交第二方库的路子和库文件,否则就会拿走undefined
reference的谬误。
四 七个库文件链接顺序难点
那种题材也要命的潜伏,不细致斟酌您也许会深感拾分地莫明其妙。大家照例回到第贰小节所研商的标题中,在结尾,倘使大家把链接的库的次第换一下,看看会发生哪些结果?
gcc -o main main.o func.a test.a

Add

大家会获取如下报错.
test.a(test.o): In function
test': test.c:(.text+0x13): undefined reference tofunc’
collect2: ld returned 1 exit status

  未来,将上述四个公文写入makefile:

故而,大家供给注意,在链接命令中给出所正视的库时,供给注意库之间的信赖顺序,正视其余库的库一定要放手被正视库的前边,那样才能真的防止undefined
reference的错误,完结编写翻译链接。
五.
在c++代码中链接C语言的库

1经您的库文件由c代码生成的,则在c++代码中链接库中的函数时,也会遇到undefined
reference的难题。上边举例表达。
首先,编写c语言版库文件:

test : main.o add.o
    gcc main.o add.o -o test
main.o : main.c add.h
    gcc -c main.c \  //这里的'\'只是换行,命令还是gcc -c main.c -o main.o
  -o main.o
add.o : add.c add.h
    gcc -c add.c -o add.o 

美高梅开户网址 9

  上述 makefile 利用 add.c 和 add.h
文件实施 gcc -c add.c -o add.o 命令产生 add.o
指标代码,利用main.c 和 add.h 文件执行 gcc -c main.c -o main.o
命令爆发 main.o 指标代码,最终动用 main.o 和
add.o文件(多少个模块的靶子代码)执行 gcc main.o add.o -o test
命令发生可执行文件 test。

clean:
    rm *.o

编写翻译,打包为静态库:test.a
gcc -c test.c
ar -rc test.a test.o

  借使认为除了指标文件test外,生成了过多的中档指标文件,那么在make编写翻译后,执行make
clean能够去除全数中等指标文件,须要留意的是,执行make
clean后,当前目录下的装有*.o文件都被去除了,包含不在makefile中冒出过的.o文件。同时,clean不会活动执行,因为clean前边未有原则,clean也不是3个目的文件,它只是是贰个动作,自然就不会活动执行所定义的命令。

时至前几日,大家获取了test.a文件。下边大家发轫编制c++文件main.cpp

 

美高梅开户网址 10

make是如何做事的?

  在暗中认可景况,约等于我们只输入make命令的气象下,有:

下一场编译main.cpp生成可执行程序:
g++ -o main main.cpp test.a

  1. make在当前目录下找到makefile文件或Makefile文件
  2. 要是找到,它会找第一个对象,在上述例子中就是test,并把test作为最终的靶子文件
  3. 1经test不设有或许test的口径文件比test的要立异,那么将执行后边的通令来生成test文件
  4. 假设test所依赖的某部.o文件不存在,则make将寻找该.o文件的借助,找到后再用相关的条条框框生产该.o文件
  5. .c /
    .h文件必须存在,由make将它们编译生成.o文件,然后再用.o文件生成最后的指标文件test

会发觉报错:
/tmp/ccJjiCoS.o: In function
main': main.cpp:(.text+0x7): undefined reference totest()’
collect2: ld returned 1 exit status

 

由来便是main.cpp为c++代码,调用了c语言库的函数,因而链接的时候找不到,消除方式:即在main.cpp中,把与c语言库test.a相关的头文件包蕴添加3个extern
“C”的扬言即可。例如,修改后的main.cpp如下:

makefile中使用变量

美高梅开户网址 11

  大家可在 makefile 中投入变量,别的。环境变量在 make 进程中也被解释成
make 的变量。那几个变量

是大大小小写敏感的,壹般选拔大写字母。Make 变量能够做过多作业,例如:

g++ -o main main.cpp test.a

  • 存款和储蓄三个文件名列表
  • 积存2个可执行文件名
  • 仓库储存编写翻译器选项。

再编写翻译会发现,难题早已打响消除。

  只怕这么说很迷糊,举个例子,如若有个makefile的代码如下:

  test : main.o kbd.o command.o display.o /
                  insert.o search.o files.o 
            cc -o edit main.o kbd.o command.o display.o /  //cc是gcc的软连接
                       insert.o search.o files.o 

  条件文件有多个中等指标文件,而且柒个.o文件的字符串被再度了一遍,若是您要再充实一个.o文件作为test的借助,那么就恐怕会意识遗漏。所以为了方便makefile的保卫安全,大家用1个变量代表字符串,也得以精通为宏。

  于是能够将加码3个utils.o文件的动静改写成下列代码:

    OBJS = main.o kbd.o command.o display.o /
                  insert.o search.o files.o utils.o  //增加utils.o
   CC = gcc
   CFLAGS = -Wall  -g  //-c比较特殊,一般不把它加入变量;注意这里不加 - o ,因为这个选项后面必须要加可执行文件名

    test : $(OBJS)  //变量前加一个说明符$
        $(CC) $(OBJS) -o test
    main.o : main.c defs.h
        $(CC) $(CFLAGS) -c main.c
    kbd.o : kbd.c defs.h command.h
        $(CC) $(CFLAGS) -c kbd.c
    command.o : command.c defs.h command.h
        $(CC) $(CFLAGS) -c command.c
    display.o : display.c defs.h buffer.h
      $(CC) $(CFLAGS) -c display.c
    insert.o : insert.c defs.h buffer.h
        $(CC) $(CFLAGS) -c insert.c
    search.o : search.c defs.h buffer.h
        $(CC) $(CFLAGS) -c search.c
    files.o : files.c defs.h buffer.h command.h
        $(CC) $(CFLAGS) -c files.c
    utils.o : utils.c defs.h  //增加生成utils.o的规则
        $(CC) $(CFLAGS) -c utils.c
    clean :
            rm $(objects)

  只修改了壹处,10分的便利

 

让make自动推导

  make很强劲,它能够自行推到注重的公文和凭借文件前边的一声令下,于是大家就没供给在种种.o文件后都写上类似的下令,而是让make自动识别,自动推导。

  比如,make发现二个.o文件,它就会活动地把.c文件加在依赖关系中,比如说make找到贰个main.o,那么就推导出main.c是main.o的借助文件。并且gcc
-c main.c 也会被演绎出来。

  通过make的那个性格,大家简化上面一个例子的makefile:

objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o
test : $(objects)
    gcc -o test $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
clean :
    rm $(objects)

 

MakeFile学习之路还很短,博文部分剧情借鉴大拿陈浩,他的makefile专栏

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图