出现变量重定义的情事?

一、简介

近年在Linux下编制程序发现三个好奇的意况,正是在链接3个静态库的时候总是报错,类似上边那样的失实:(.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

编写翻译报错:

 金沙注册送58 1

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

有关undefined
reference那样的标题,大家实在常常会境遇,在此,笔者以详尽地示范给出常见错误的各类缘由以及缓解形式,希望对初学者有所帮忙。
壹. 链接时缺点和失误了有关指标文件(.o)
**
**测试代码如下:

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

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

难题化解格局,Makefile简单入门教程。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

最终一步链接会报错:

 金沙注册送58 2

二、编写规则:

金沙注册送58 3

什么是makefile?

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

  makefile是2个文件文件,里面著录了什么文件须求先编写翻译,哪些文件必要后编写翻译,哪些文件须求再行编写翻译。makefile的便宜是“自动编写翻译”,只要求2个make命令,整个工程活动编写翻译,非常大增加了频率。

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

然后编写翻译。

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

目的n:目的依赖  然后回车+tab键
 命令;

gcc -c test.c

gcc –c main.c 

 

只顾:命令必须是tab键开始的。

获得三个 .o 文件,3个是 main.o,1个是 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
编写翻译。一般的话,每1个源文件都对应着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的编写翻译,项目实行是成功的,可是1旦main.c供给引用越来越多文本中的函数时,是还是不是要填写那么多的编写翻译命令吗?分明这几个点子不可取。
考订:makefile特殊变量和机关推导作用
知识点表明:
$@  代表指标名,
$^  代表重视文件
%  代表私下字符
%.o  代表任意.o文件
%.c  代表任意.c文件

【扩大】:其实下面为了让大家尤为领悟底层原因,小编把编写翻译链接分开了,上面那样编写翻译也会报undefined
reference错,其实底层原因与地点是平等的。
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()函数的兑现文件一起编写翻译。
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)

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

  

以上程序看似未有何难点的,然而clean有点瑕疵,就算也有2个文本叫clean那咋做?假设make
clean就无法施行那条命令。

金沙注册送58 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。为了有利于统一管理,最佳开首定义3个变量来表示编辑器,然后在gcc命令上变成$(CC):
Makefile升级如下:
CC:=gcc    #注脚:定义2个变量,表示近年来编辑器为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正是用来决定输出文件的。

引进1本书: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的门路

  

金沙注册送58 5

【扩充】:同样,为了把标题说明白,上面大家把代码的编写翻译链接分开了,假诺愿意一回性生成可执行程序,则能够对main.c和test.a执行如下命令。
gcc -o main main.c ./test.a //同样,假若不加test.a也会报错

makefile的规则

三. 链接的库文件中又选拔了另1个库文件
那种题材相比隐蔽,也是本人近期际遇的与网上海南大学学家切磋的两样的标题,举例表达如下,首先,依然看看测试代码。

  目的 : 必要的条件 (注意冒号两边的空格)

金沙注册送58 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

  • 指标能够是1个还是多少个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

金沙注册送58 7金沙注册送58 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)则如出一辙在链接的时候要求提交第三方库的途径和库文件,不然就会获得undefined
reference的谬误。
肆 三个库文件链接顺序难题
这种难题也万分的隐没,不细心切磋您恐怕会感觉到12分地莫明其妙。大家照样回到第一小节所研究的题材中,在结尾,倘若我们把链接的库的11换一下,看看会发出什么结果?
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 

金沙注册送58 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也不是贰个目的文件,它但是是一个动作,自然就不会自行执行所定义的吩咐。

至此,我们赢得了test.a文件。上边我们开端编写制定c++文件main.cpp

 

金沙注册送58 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中应用变量

金沙注册送58 11

  大家可在 makefile 中参与变量,别的。环境变量在 make 进度中也被演说成
make 的变量。那几个变量

是深浅写敏感的,一般选取大写字母。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 

  条件文件有多当中等指标文件,而且7个.o文件的字符串被重复了三次,假使你要再追加二个.o文件作为test的依靠,那么就大概会发觉遗漏。所以为了便于makefile的保证,大家用二个变量代表字符串,也足以精通为宏。

  于是能够将追加1个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处,1贰分的福利

 

让make自动推导

  make很强大,它可以自动推到重视的文书和注重文件前面包车型大巴下令,于是大家就没须要在各类.o文件后都写上看似的命令,而是让make自动识别,自动推导。

金沙注册送58 ,  比如,make发现一个.o文件,它就会自动地把.c文件加在依赖关系中,比如说make找到1个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地图