标题一挥而就情势,Makefile简单入门教程

并发变量重定义的事态?

一、简介

近年在Linux下编制程序发现多少个蹊跷的光景,就是在链接1个静态库的时候总是报错,类似上面那样的不当:(.text+0x一三):
undefined reference to `func’

什么是make?

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

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命令执行时,供给1个 Makefile
文件,以告知make命令供给什么样的去编写翻译和链接程序(简单将:管理工科程的文件,决定先编写翻译哪些文件,编写翻译顺序)。

关于undefined
reference那样的标题,大家实在常常会遇见,在此,小编以详尽地示范给出常见错误的各类缘由以及缓解格局,希望对初学者有所扶助。
一. 链接时缺点和失误了有关目的文件(.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

2、编写规则:

亚洲必赢官网 3

什么是makefile?

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

  makefile是1个文件文件,里面著录了如何文件需求先编译,哪些文件须要后编写翻译,哪些文件须求再度编写翻译。makefile的益处是“自动编写翻译”,只要求二个make命令,整个工程活动编写翻译,十分的大增加了频率。

指标贰:指标正视  然后回车+tab键
 命令;

接下来编写翻译。

  编写2个makefile供给提前了然:壹.编写翻译、链接的概念;
2.gcc、g++的有关命令参数 -g -o -c 

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

gcc -c test.c

gcc –c main.c 

 

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

获得七个 .o 文件,2个是 main.o,一个是 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并行使有关函数;然后建立1个新的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般的话,每一个源文件都对应着二个中级指标文件,.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

标题一挥而就情势,Makefile简单入门教程。  编写翻译时,编写翻译器需求的是语法正确,函数、变量评释的正确性。对于后者,你必要报告编写翻译器头文件的职位(头文件中应只是宣称而不是概念,定义应放在c\c++文件中),只要具备的语法正确,编写翻译器就能够编写翻译出中间目的文件。

3、Makefile升级2
透过以上七个makefile的编写翻译,项目实施是马到成功的,可是一旦main.c必要引用越多文件中的函数时,是还是不是要填写那么多的编写翻译命令吗?明显这些艺术不可取。
改良:makefile特殊变量和机动推导功用
知识点表明:
$@  代表指标名,
$^  代表重视文件
%  代表私下字符
%.o  代表任意.o文件
%.c  代表任意.c文件

【扩大】:其实下边为了让我们特别精晓底层原因,我把编写翻译链接分开了,下边那样编写翻译也会报undefined
reference错,其实底层原因与地点是同等的。
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有点瑕疵,如若也有一个文书叫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。为了便于统壹保管,最佳起初定义一个变量来代表编辑器,然后在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的规则

三. 链接的库文件中又采纳了另三个库文件
那种难题相比较隐蔽,也是本人多年来境遇的与网上海高校家座谈的不及的题材,举例说明如下,首先,依旧看看测试代码。

  指标 : 要求的准绳 (注意冒号两边的空格)

亚洲必赢官网 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

  • 目的能够是3个要么多个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的谬误。
肆 多少个库文件链接顺序难题
那种题材也特出的隐身,不过细研讨您或然会觉得格内地莫明其妙。大家还是回到第3小节所钻探的题材中,在最后,如果我们把链接的库的各类换一下,看看会发出什么样结果?
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也不是1个对象文件,它只是是多少个动作,自然就不会活动执行所定义的授命。

从这之后,我们收获了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的爱惜,我们用一个变量代表字符串,也得以清楚为宏。

  于是能够将大增三个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处,拾分的惠及

 

让make自动推导

  make很强劲,它能够自行推到依赖的文件和凭借文件前边的授命,于是大家就没供给在各类.o文件后都写上好像的吩咐,而是让make自动识别,自动推导。

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

  通过make的那几个特点,大家简化上边3个例证的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地图