您的位置:首页 > 运维架构 > Linux

Linux 下源码编译相关知识

2017-08-06 14:28 183 查看

编译库代码的一般过程

./configure    //configure是源代码安装的第一步,主要作用是对即将安装的软件进行配置,检查系统环境是否符合安装软件的依赖关系,然后生成Makefile,为下一步的编译做准备。执行时常用选项 –prefix=/usr 这个表明软件会安装到/usr下面,可通过./configure –help查看帮助

make  //执行Makefile中的编译任务,生成.o文件或者.a文件

如果是安装某个软件:一般而言执行make install;安装完之后可以执行make clean来清理中间文件

makedist:将程序和相关的档案包装成一个压缩文件以供发布,以.tar.gz结尾

有空学习下configure文件的编写

gcc 的一些常用选项

-c编译成目标文件,如gcc –c main.c //将main.c编译成main.o

-I头文件的查找路径,如gcc –c main.c –I./inc //头文件的查找路径除默认的以外,还包括./inc

-L库文件的查找路径,如gcc –o main main.o –Ltest (-L./lib-ltest)  //libtest.a 或者libtest.so库文件的查找路径除默认之外还包括./lib目录

-MM导出文件的依赖关系(gcc –MM main.c 找出main.c的所依赖的头文件 #include中的内容)

-o生成最终目标

-D宏定义 相当于在C中的#define  如-DPI = 3.14 就相当于在文件里面写语句 #define PI 3.14

动态库

生成:在链接时,用如下选项: -shared –fpic,如gcc–fpic –shared –o libtest.so myalib.c

使用:有隐式使用和显示使用,隐式使用就是共享方式,程序一开始运行就调进去,在链接时候用 gcc –o main main.o –L./lib –ltest (像静态库的一样)

显示使用就是在程序中用语句把动态库调进来,用系统调用:dlopen、dlsym、dlerror、dlclose函数,那样在编译链接的时候,不用加上 –L编译选项。不过要加-ldl编译选项

 

(如果要指定程序行时在./lib目录下找库文件libtest.so,命令如下:gcc -o main main.c -L./lib -ltest -Wl,-rpath./lib

 ) ,其中,-Wl的意思是,后面的选项直接交给ld程序处理,-rpath选项是说更改搜索路径为后面的参数./lib

LD_LIBRARY_PATH可以指定函数库的查找路径

 

一些命令(与库有关的)

1、 ld是gcc的链接程序

2、 ldd是查看可执行文件中所依赖的库的程序,如ldd main 可以查看main程序用到了哪些动态库

3、 ldconfig用来更新文件/etc/ld.so.conf的修改生效,更新动态加载库的cache

4、 nm 用来查看.so库中的函数名字, 如nm /lib/libc*.so

问题:

gcc如何生成动态链接库文件?

gcc–shared –fpic –o libc.so main.c hello.c

 

Tips:

1、 source xxx.sh //表示在当前shell下执行.sh,shell脚本中的设置对当前窗口有效,若不加source,则表示在另一个shell执行,相当于 sh xxx.sh,这样脚本中的变量在当前不生效

2、 .a文件和.lib文件的区别(静态链接)

3、 .so文件和.dll文件的区别(动态链接)

关于问题2 3,(.a文件为静态库,可由ar文件对目标文件归档生成,例如:ar –rc libtest.a a.o b.o;采用gcc 编译工程的时候可以引入相应库文件 gcc hello.c –Ltest –o hello)

.a和.so是Linux下的静态和动态链接文件,.lib和dll是windows下的静态和动态链接文件

静态库、共享库和动态库

参考 http://www.cnblogs.com/likwo/archive/2012/05/09/2492225.html
    静态库为程序链接时加载,共享库为程序运行时加载(可以给多个程序共享,多个程序维护一份内存副本);动态链接可以在程序运行过程中的任何时间加载,特别适合在函数中加载一些模块和Plugin扩展模块的场合(需要时才加载,否则不需要)。 通过一个API来打开一个函数库dlopen(),寻找符号表void* dlsym(void *handle, char *symbol);,处理错误dlerror()和关闭函数表dlclose()。 例子如下:

 #include

 #include

 #include

 int main(int argc, char **argv)

 {

   void *handle;

   double (*cosine)(double);

   char *error;

   handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);

   if (!handle) {

       fputs (dlerror(), stderr);

       exit(1);

   }

   cosine = dlsym(handle, "cos");

    if((error = dlerror()) != NULL)

  {

       fputs(error, stderr);

       exit(1);

    }

   printf ("%f ", (*cosine)(2.0));

   dlclose(handle);

}

 如果这个程序名字叫foo.c,那么用下面的命令来编译:

  gcc -o foo foo.c -ldl

 

关于程序库放置的问题

      文件系统层次化标准FHS(Filesystem Hierarchy Standard)(http://www.pathname.com/fhs)规定了在一个发行包中大部分的函数库文件应该安装到/usr/lib目录 下,但是如果某些库是在系统启动的时候要加载的,则放到/lib目录下,而那些不是系统本身一部分的库则放到/usr/local/lib下面。

Makefile

博客链接:http://www.tuicool.com/articles/RR3Mvib

#注释

标的(target):目标文件1目标文件2

<tab>gcc –o 欲建立的执行文件 目标文件1目标文件2 …-L./lib –ltest



#可以用变量来标识,提高效率;另外$@:代表目前的标的

main:main.ohaha.o

      gcc –o main main.o haha.o –lm

clean:

      rm –f main main.o haha.o

编译参数:

-Wall  生成所有警告信息

CFLAGS 表示用于 C 编译器的选项,

CXXFLAGS表示用于 C++ 编译器的选项。

这两个变量实际上涵盖了编译和汇编两个步骤。

CFLAGS: 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来。

LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是说找不到,可以将那个包的lib路径加入的LDFALGS中试一下。

LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv

简单地说,LDFLAGS是告诉链接器从哪里寻找库文件,而LIBS是告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。

有时候LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R":

LDFLAGS= -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

如果在执行./configure以前设置环境变量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib-Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意设置环境变量等号两边不可以有空格,而且要加上引号(shell的用法)。那么执行configure以后,Makefile将会设置这个选项,链接时会有这个参数,编译出来的可执行程序的库文件搜索路径就得到扩展了。

makefile中经常使用的变量及含义

变量名

含义

默认值

AR

生成静态库库文件的程序名称

ar

AS

汇编编译器的名称

as

CC

C语言编译器的名称

cc

CPP

C语言预编译器的名称

\$(CC) -E

CXX

C++语言编译器的名称

g++

FC

FORTRAN语言编译器的名称

f77

RM

删除文件程序的名称

rm -f

ARFLAGS

生成静态库库文件程序的选项

无默认值

ASFLAGS

汇编语言编译器的编译选项

无默认值

CFLAGS

C语言编译器的编译选项

无默认值

CPPFLAGS

C语言预编译器的编译选项

无默认值

CXXFLAGS

C++语言编译器的编译选项

无默认值

FFLAGS

FORTRAN语言编译器的编译选项

无默认值

 

makefile 自动化变量

变量

含义

*

表示目标文件的名称,不包含目标文件的扩展名

+

表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖文件



表示依赖项中第一个依赖文件的名称

?

依赖项中,所有目标文件时间戳晚的依赖文件,依赖文件之间以空格分开

@

目标项中目标文件的名称

^

依赖项中,所有不重复的依赖文件,这些文件之间以空格分开

 

设置搜索路径

VPATH =path1:path2:…

如下面内容:

VPATH = add:sub

add_int.o: %.o:%c

      $(CC) –c –o $@ $<   #第一个依赖文件为add_int.c 

make 的搜索路径包含add和sub目录。add_int 规则自动扩展成以下代码

add_int.o: add/add_int.c

 

递归makefile

cd add &&$(MAKE)

等价于

$(MAKE) –C add

 

 

技巧

CURDIR =  $(shell pwd)  //获取当前目录

makefile中的函数:

获取匹配模式的文件名 wildcard

如$(wildcard *.c)  #返回当前目录下所有扩展名为.c的文件列表

模式替换函数 patsubst $(patsubst pattern, replacement, text)

如,需要将c文件替换为.o 的目标文件

$(patsubst %.c, %.o, $(wildcard *.c))  #将当前目录下的所有.c文件替换为.o,作为输出字符串

 

循环函数foreach

原形 $foreach VAR, LIST, TEXT)

函数的功能为 foreach将 LIST字符串中一个空格分割的单词,先传给临时变量
VAR,然后执行 TEXT表达式, TEXT表达式处理结束后输出。其返回值是空格分割表达式
TEXT的计算结果。

DIRS = sub add ./ FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c)) #获取目录下的所有C文件

 

tarball软件的安装

./configure

make clean

make

make install
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编译