威尼斯人线上娱乐

变量重定义,Makefile容易入门教程

3 4月 , 2019  

出现变量重定义的气象?

一、简介

新近在Linux下编制程序发现二个怪诞的风貌,正是在链接1个静态库的时候总是报错,类似上边那样的不当:(.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命令执行时,供给八个 Makefile
文件,以报告make命令需求如何的去编写翻译和链接程序(简单将:管理工科程的文书,决定先编写翻译哪些文件,编写翻译顺序)。

关于undefined
reference那样的标题,我们其实平日会遇见,在此,笔者以详尽地示范给出常见错误的各类原因以及化解方法,希望对初学者有所援救。
1. 链接时缺点和失误了有关目的文件(.o)
**
**测试代码如下:

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

链接的五个文件都定义了同1个变量

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是1个文本文件,里面著录了如何文件需求先编写翻译,哪些文件须求后编写翻译,哪些文件供给再行编写翻译。makefile的功利是“自动编写翻译”,只要求三个make命令,整个工程活动编写翻译,非常的大提升了频率。

指标二:目的依赖  然后回车+tab键
 命令;

下一场编写翻译。

  编写3个makefile须求提前了然:一.编写翻译、链接的概念;
二.gcc、g++的相干命令参数 -g -o -c 

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

gcc -c test.c

gcc –c main.c 

 

在意:命令必须是tab键起始的。

赢得七个 .o 文件,1个是 main.o,四个是 test.o ,然后大家链接 .o
获得可执行程序:
gcc -o main main.o

编写翻译、链接的定义

三、Makefile演进
壹、2个类型有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

那时候,你会意识,报错了:
变量重定义,Makefile容易入门教程。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
编译。一般的话,每贰个源文件都对应着三当中路目的文件,.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特殊变量和自行推导成效
知识点表达:
$@  代表指标名,
$^  代表依赖文件
%  代表私行字符
%.o  代表任意.o文件
%.c  代表任意.c文件

【扩大】:其实上面为了让我们进一步清楚底层原因,作者把编写翻译链接分开了,下边那样编写翻译也会报undefined
reference错,其实底层原因与地点是千篇1律的。
gcc -o main main.c //贫乏test()的达成文件

  链接:将多量的object
file合成为一个可执行文件的动作叫作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()函数的落到实处公文一起编写翻译。
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有点瑕疵,即使也有1个文件叫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管理,最棒开始定义3个变量来表示编辑器,然后在gcc命令上变成$(CC):
Makefile升级如下:
CC:=gcc    #注解:定义一个变量,表示最近编辑器为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的规则

叁. 链接的库文件中又接纳了另3个库文件
这种题材相比隐蔽,也是本人近年遇见的与网上海大学家座谈的比不上的难点,举例表明如下,首先,依然看看测试代码。

  指标 : 供给的原则 (注意冒号两边的空格)

威尼斯人线上娱乐 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)则如出一辙在链接的时候供给付出第3方库的途径和库文件,不然就会得到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的谬误,实现编写翻译链接。
5.
在c++代码中链接C语言的库

即便您的库文件由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. 要是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相关的头文件包涵添加八个extern
“C”的注明即可。例如,修改后的main.cpp如下:

makefile中运用变量

威尼斯人线上娱乐 11

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

是大大小小写敏感的,1般选用大写字母。Make 变量能够做过多思想政治工作,例如:

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

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

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

  恐怕这样说很迷糊,举个例证,假使有个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的护卫,大家用3个变量代表字符串,也能够知晓为宏。

  于是能够将扩充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)

  只修改了1处,13分的方便人民群众

 

让make自动推导

  make很强劲,它能够活动推到信赖的文件和信赖文件前面包车型地铁吩咐,于是我们就没须要在各样.o文件后都写上好像的下令,而是让make自动识别,自动推导。

  比如,make发现3个.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地图