精华内容
下载资源
问答
  • 昨天在自己的CentOs7.1上写makefile的时候,发现在一个C程序在编译并链接一个已生成好的lib动态库的时候出错。链接命令大概是这样的:[root@typecodes tcpmsg]# gcc -o hello main.c -lmyhello /usr/bin/ld: cannot ...

    昨天在自己的CentOs7.1上写makefile的时候,发现在一个C程序在编译并链接一个已生成好的lib动态库的时候出错。链接命令大概是这样的:

    [root@typecodes tcpmsg]# gcc -o hello main.c -lmyhello
    /usr/bin/ld: cannot find -lmyhello
    collect2: error: ld returned 1 exit status

    Linux gcc链接动态库出错

    1 gcc链接动态库时的搜索路径

    自以为在当前工程中设置好了环境变量LD_LIBRARY_PATH包含了工程中的lib库路径,并且还在/etc/ld.so.conf/apphome.conf中配置了lib库的路径。那么在调用动态库的时候,gcc就应该能自动去搜索该目录。

    gcc链接动态库时的搜索路径

    很遗憾ld链接器报了如上的错误,但是如果在上面的gcc命令中添加上-L /root/gcc_test/tcp_msg/lib/参数,即明确动态库的绝对路径,是能够链接成功的。

    2 Google上查找 /usr/bin/ld: cannot find -l* 的出错原因

    gg了很久gcc ld链接动态库出错的原因,结果还是没找到理想的答案。后来猜想是不是在CentOs7中LD_LIBRARY_PATH不起作用的缘故,但是也不应该,因为自己用的GCC(version 4.8.3)跟操作系统没关系。于是重新搜索了gcc LD_LIBRARY_PATH的作用,竟然发现gcc在编译链接时链接的动态库跟LIBRARY_PATH有关而跟LD_LIBRARY_PATH没关系!

    3 关于Linux gcc中的LIBRARY_PATHLD_LIBRARY_PATH参数说明

    下面摘取了两篇较权威的说明资料:

    1、GNU上关于LIBRARY_PATH的说明:

    LIBRARY_PATH
    The value of LIBRARY_PATH is a colon-separated list of directories, much like PATH.
    When configured as a native compiler, GCC tries the directories thus specified when searching for special linker files, if it can't find them using GCC_EXEC_PREFIX.
    Linking using GCC also uses these directories when searching for ordinary libraries for the -l option (but directories specified with -L come first).
    2、 man7 上关于LD_LIBRARY_PATH的说明:
    LD_LIBRARY_PATH
    A colon-separated list of directories in which to search for
    ELF libraries at execution-time.  Similar to the PATH
    environment variable.  Ignored in set-user-ID and set-group-ID
    programs.
    后面发现 StackOverflow 上关于 LIBRARY_PATH LD_LIBRARY_PATH 的解释更直白:
    LIBRARY_PATH is used by gcc before compilation to search for directories containing libraries that need to be linked to your program.
    
    LD_LIBRARY_PATH is used by your program to search for directories containing the libraries after it has been successfully compiled and linked.
    
    EDIT: As pointed below, your libraries can be static or shared.
    If it is static then the code is copied over into your program and you don't need to search for the library after your program is compiled and linked.
    If your library is shared then it needs to be dynamically linked to your program and that's when LD_LIBRARY_PATH comes into play.

    通过这三篇资料的说明,很快明白了LIBRARY_PATHLD_LIBRARY_PATH的作用。于是,自己在项目配置文件中添加export LIBRARY_PATH=${LIBRARY_PATH}:${APPHOME}/lib。接着将这个配置文件加载到CentOs的环境变量中,这样就在gcc编译不用加-L参数生成目标文件CommuTcp了。

    4 总结

    关于LIBRARY_PATHLD_LIBRARY_PATH的关系,这里自己再总结一下。

    4.1 Linux gcc编译链接时的动态库搜索路径

    GCC编译、链接生成可执行文件时,动态库的搜索路径就包含LIBRARY_PATH,具体的搜索路径顺序如下(注意不会递归性地在其子目录下搜索):

    1、gcc编译、链接命令中的-L选项;
    2、gcc的环境变量的LIBRARY_PATH(多个路径用冒号分割);
    3、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib。
    4.2 执行二进制文件时的动态库搜索路径

    链接生成二进制可执行文件后,运行该程序加载动态库文件时就会搜索包含LD_LIBRARY_PATH路径下的动态库,具体顺序如下:

    1、编译目标代码时指定的动态库搜索路径:用选项-Wl,rpath和include指定的动态库的搜索路径,比如gcc -Wl,-rpath,include -L. -ldltest hello.c,在执行文件时会搜索路径`./include`;
    2、环境变量LD_LIBRARY_PATH(多个路径用冒号分割);
    3、在 /etc/ld.so.conf.d/ 目录下的配置文件指定的动态库绝对路径(通过ldconfig生效,一般是非root用户时使用);
    4、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib等。

    其中,Linux GCC默认的动态库搜索路径可以通过ld --verbose命令查看:

    [root@typecodes tcpmsg]# ld --verbose
        ............
        SEARCH_DIR("/usr/x86_64-redhat-linux/lib64");
        SEARCH_DIR("/usr/local/lib64");
        SEARCH_DIR("/lib64");
        SEARCH_DIR("/usr/lib64");               ##### 64位系统
        SEARCH_DIR("/usr/x86_64-redhat-linux/lib");
        SEARCH_DIR("/usr/local/lib");
        SEARCH_DIR("/lib");
        SEARCH_DIR("/usr/lib");
    Linux GCC中ld --verbose命令
    Linux GCC中ld --verbose命令
    展开全文
  • Linux 如何使用gcc生成静态库和动态库,使用GCC编译生成静态库和动态库的方法
  • gcc生成动态链接库

    2018-04-26 23:41:23
    1.libxxx.so (一般为软连接),作用是编译程序的时候,用到的动态库必须是这种名字,gcc 中-l选项,例如 -lshared 意思是链接文件名为libshared.so的动态库 2.libxxx.so.x (一般为软连接,只包含主版本号),...

    Makefile文件如下:

    OBJS_DIR=./objs
    CCFLAGS= -shared -Wall -fPIC -Wl,-soname,libcudart.so.4 -g
    LDFLAGS=
    
    ifeq ($(hook),1)
    CCFLAGS+=-DRUN_REAL_LIBCUDA
    LDFLAGS+= -ldl
    endif
    
    RTAPI_SRCS = runtime_api.c driver_intf.c 
    RTAPI_OBJS = $(addprefix ${OBJS_DIR}/, $(RTAPI_SRCS:.c=.o))
    
    
    $(OBJS_DIR)/%.o: %.c
    	gcc $(CCFLAGS) -I./  -c $< -o $@
    
    .PHONY:
    
    all:mk-dirs rtapi
    
    rtapi: mk-dirs $(RTAPI_OBJS)
    	gcc $(CCFLAGS) -o  libcudart.so.4.0.0  $(RTAPI_OBJS) $(LDFLAGS)
    	ln -sf libcudart.so.4.0.0 libcudart.so.4
    
    mk-dirs:
    	mkdir -p $(OBJS_DIR)
    
    clean:
    	rm -rf $(OBJS_DIR)
    	rm -rf libcudart.so*
    

    这里主要解析CCFlags变量的含义:

    -shared  生成共享库

    -Wall 输出编译过程中的警告

    -fPIC 生成与地址无关的二进制代码,这样的动态库可以被加载到所有进程都可以访问的一块内存中,而不用每一个进程都在各自的内存中保留动态库的copy,造成内存浪费,但是不要妄想通过在动态库里定义全局变量实现进程间通信,因为,linux采用写时拷贝(copy-on-write技术),在某一进程试图改变动态库里的全局变量时,linux会将动态库的全局变量拷贝至该进程的私有内存空间(如果只读不写,则不拷贝),因此无法通过此路径实现进程间通信,参考:

        http://www.cnblogs.com/lovevivi/archive/2013/01/10/2854584.html

        https://blog.csdn.net/zxh821112/article/details/8969541这篇文章中有介绍不适用-fPIC选项的后果,将产生装载时重定向的代码(修改代码中所有地址),使只加载一次动态库,所有进程共享这一内存成为不可能。

    -Wl,-soname -Wl指明接下来的参数传递给链接器,-soname制定共享库的soname(简单共享名,short for shared object name),soname是库的唯一标示,而不是库的文件名,但一般soname和库的文件名相关(库文件名包含详细版本信息,soname只包含主版本信息),这样同一主版本下,此版本更新方便升级,不同版本的库虽然文件名不同但是soname一定要一致,如果主版本更新,则一般不兼容上一版本,所以使用此库的可执行程序要重新改写源码并编译。

    上面库的文件名为libcudart.so.4.0.0,库的soname为libcudart.so.4与库的软链接相同

    -g 用于gdb调试。

     

    LDFLAGS变量的含义:

    -ldl 链接一个名字为libdl.a的库,这个库里有几个函数dlopen、dlsym、dlclose、dlerror,可以用于显示的打开动态库,并且获取其中的函数地址。

     

    RTAPI_OBJS = $(addprefix ${OBJS_DIR}/, $(RTAPI_SRCS:.c=.o))

    这句话的效果是 首先将RTAPI_SRCS变量中所有的.c结尾的字符串替换成.o结尾的字符串, 然后调用makefile的addprefix函数为.o添加前缀./objs/

    https://blog.csdn.net/zhoudengqing/article/details/41775353

     

    下面我们来说一下生成动态库和使用动态库的注意事项:

    -Wl,-soname,xxx 选项用来指定共享库的唯一标识:简单共享名,不指定时默认为:

    1.若-o指定的要生成的库的文件名为标准的lib**.so.x.x.x这种格式,则soname是去掉版本信息的部分,即lib**.so(若没有版本信息,则库文件名和soname同名)

    2.若-o指定的为非标准格式,则gcc会取库文件名的主体部分(点号前面的部分,没有点号则取全部文件名)加上lib前缀和.so后缀作为soname。

    soname是主程序运行时加载动态库的唯一标识,所以要想程序成功加载动态库,则需要创建soname同名的指向动态库文件的软连接,或者直接将动态库的名称改为soname(不推荐)

     

    主程序编译时的注意事项:

    编译时使用动态库要使用-l指令,要想编译成功,需要建立一个软连接,名称为-l后的字符串加上lib前缀和.so后缀。

    下面举例:

    shared.c文件生成动态库文件libshared.so.1.0.0,指定soname为libshared.so.1

    gcc -shared -fpic -Wall -Wl,-soname,libshared.so.1 -o libshared.so.1.0.0 shared.c

    main.c生成exe文件

    先创建软连接:

    ln -s libshared.so.1.0.0 libshared.so

    ln -s libshared.so.1.0.0 libshared.so

    再编译,没有名字libshared.so的软连接,编译将出错。

    gcc -lshared -L. -o exe main.c

    运行exe文件时要先建立另一个软链接,此软链接要和soname必须同名:

    ln -s libshared.so.1.0.0 libshared.so.1

    另外运行时要将软链接所在路径添加到环境变量LD_LIBRARY_PATH中去,才能正确运行

    export LD_LIBRARY_PATH=$(pwd):LD_LIBRARY_PATH
    

    总结:

    一个动态库有三种文件名称

    1.libxxx.so (一般为软连接),作用是编译程序的时候,用到的动态库必须是这种名字,gcc 中-l选项,例如 -lshared 意思是链接文件名为libshared.so的动态库

    2.libxxx.so.x (一般为软连接,只包含主版本号),作用是,编译好的程序,交给用户的去运行的时候,一定要保证用户的电脑上有名称为libxxx.so.x动态库,并且要保证此名称的动态库的唯一标识符也是libxxx.so.x,例如用户电脑上存在 libshared.so.1的软连接,指向真实文件libshared.so.1.0.0,我们要保证真实文件的唯一标识符为 libshared.so.1,即编译生成真实文件libshared.so.1.0.0的时候,gcc的-Wl,-soname选项后面指定的参数也要是libshared.so.1,否则,即使程序运行时加载动态库时找到了此名称的动态库,也不能成功加载

    3.libxxx.so.x.xx(真实的动态库文件,包含主版本号和次版本号),开发动态库的公司生成的动态库的文件名称

    4. 从上述可以知道: 

        a.动态库的主版本号 不仅体现在动态库的文件名里面,而且使用 gcc的-Wl,-soname选项,以二进制数据的形式,保存在动态库中,使用动态库的可执行程序运行的时候,先用文件名libxxx.so.x找到动态库,然后检查动态库的唯一标识符是否是libxxx.so.x,是的话才能成功加载(待验证)

        b.动态库的次版本号 只体现在动态库的文件名中,所以主版本号相同,次版本号不同的动态库,可以相互兼容。

     

    关于上述总结中第2条,第4条验证结果:

    有点意外,如果主版本号不同的两个库,只要保证两个库的名称相同,两个库中的接口相同,即两个库中二进制数据保存的主版本号不同,但是两个库的文件名改成一样的,两个库中函数接口相同,程序运行的时候仍然可以成功加载动态库,即上述总结中的这一点是错误地。验证程序如下:

    验证程序的目录结构:

    sallenkey@ubuntu:~/workspace$ tree ./
    ./
    ├── hello
    │   ├── hello.c
    │   └── Makefile
    ├── main.c
    └── Makefile
    

    其中 ./hello目录存放编译动态库libhello.so的源文件, ./目录存放调用libhello.so的源文件

    ./hello/hello.c:

    #include <stdio.h>
    
    void hello(void){
        printf("hello world\r\n");
    }
    

    ./hello/Makefile

    NO_VER_LINK_OUTPUT := libhello.so
    LINK_OUTPUT = $(addsuffix $(VER), $(addsuffix ., $(NO_VER_LINK_OUTPUT)))
    OBJS_DIR = ./objs
    CCFLAGS = -shared -Wall -fPIC -Wl,-soname,$(LINK_OUTPUT)
    
    HELLO_SRCS = hello.c
    HELLO_OBJS = $(addprefix ${OBJS_DIR}/, $(HELLO_SRCS:.c=.o))
    
    SECOND_VER_NU = .0.0
    OUTPUT = $(addsuffix ${SECOND_VER_NU}, $(LINK_OUTPUT)) 
    
    $(OBJS_DIR)/%.o:%.c
        gcc $(CCFLAGS) -I./ -c $< -o $@
    
    .PHONY:
    
    all:$(OUTPUT)
    
    $(OUTPUT):$(OBJS_DIR) $(HELLO_OBJS)
        gcc $(CCFLAGS) -o $@ $(HELLO_OBJS)
        #ln -sf $@ $(LINK_OUTPUT)
        ln -sf $@ libhello.so.1 
        ln -sf $@ $(NO_VER_LINK_OUTPUT)
    
    $(OBJS_DIR):
        mkdir -p $@
    
    clean:
        rm -rf $(OBJS_DIR) $(OUTPUT)  $(NO_VER_LINK_OUTPUT) libhello.so.1 #$(LINK_OUTPUT)
    

    ./main.c

    extern void hello();
    #include <stdio.h>
    
    int main(){
        hello();
        return 0;
    }
    

    ./Makefile

    TEST_SRCS:=$(wildcard *.c)
    OBJS_DIRS:=./objs
    LDFLAGS:=-lhello -L./hello
    
    TEST_OBJS:=$(addprefix $(OBJS_DIRS)/, $(TEST_SRCS:.c=.o))
    OUTPUT:=$(basename $(TEST_SRCS))
    
    all:$(OBJS_DIRS) $(OUTPUT)
    
    $(OUTPUT):$(TEST_OBJS)
        gcc -o $@ $^ $(LDFLAGS) -Wl,-rpath=./hello
    
    $(OBJS_DIRS)/%.o:%.c
        gcc -o $@ -c $^
    
        
    $(OBJS_DIRS):
        mkdir -p $@
    
    clean:
        rm -rf $(OBJS_DIRS) $(OUTPUT)
    

    验证方式:

    1.切换到./hello目录,执行命令:  make VER=1,生成主版本为1的libhello.so

    2.切换到./目录,执行命令: make,生成可执行文件main, 运行./main,发现成功输出hello world

    3.切换到./hello目录,执行命令 make clean VER=1,清除主版本号为1的libhello.so

    4.执行命令  make VER=2,生成主版本号为2的libhello.so

    5.切换到./目录,运行./main,发现仍然可以成功输出hello world

    展开全文
  • gcc编译链接动态库详解

    千次阅读 2015-01-14 16:00:35
    比较详细的介绍了gcc编译链接动态库的原理。 转载: http://kmoving.blog.163.com/blog/static/205049197201267113438532/ 一、GNU gcc的编译工具用法 我们先来写一个简单的C程序:hello.c 1. #include ...

    比较详细的介绍了gcc编译链接动态库的原理。
    转载: http://kmoving.blog.163.com/blog/static/205049197201267113438532/


    一、GNU gcc的编译工具用法


    我们先来写一个简单的C程序:hello.c
    1. #include <stdio.h>
    2.
    3. void print_hello() {
    4. printf("Hello World/n");
    5. }
    6.
    7. int main(int argc, char argv[]) {
    8. print_hello();

    9. return 0;

    10. }


    定义了一个print_hello函数,调用main函数打印Hello World。
    如何编译它呢?
    1. gcc -o hello -O2 hello.c
    -o参数指定生成的可执行程序的文件名, -O2是优化级别。该命令会编译生成hello可执行程序,看看这个文件:ls -l hello
    C代码 复制代码
    1. -rwxr-xr-x 1 robbin users 11939 2008-11-02 13:48 hello
    有11KB大小。


    看看他链接了哪些系统动态链接库,用ldd命令:

    1. ldd hello

    输出信息为:

    1. libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9566d000)
    2. /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)


    libc是C语言标准函数库,ld是动态链接器。
    接着我们看看hello这个程序里面有哪些符号,用nm命令:

    1. nm hello

    输出:
    1. 00000000005008f8 A __bss_start
    2. 000000000040043c t call_gmon_start
    3. ......
    4. 00000000004004f0 T main
    5. 0000000000500658 d p.0
    6. 00000000004004e0 T print_hello
    7. U puts@@GLIBC_2.2.5
    8. 0000000000400410 T _start


    中间省略了一些,不过我们还是可以在符号表里面找到函数定义。
    hello有11KB,体积偏大,去处符号表可以给它瘦身,我们用strip命令:

    1. strip hello

    然后再ls -l hello,输出为:

    1. -rwxr-xr-x 1 webuser users 4464 2008-11-02 13:56 hello

    只有4.4KB了,瘦身效果明显! 不过这次符号表再也看不到了,nm hello,输出为:nm: hello: no symbols。


    最后如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令:

    1. strings hello

    输出信息为:


    1. /lib64/ld-linux-x86-64.so.2
    2. SuSE
    3. libc.so.6
    4. puts
    5. __libc_start_main
    6. __gmon_start__
    7. GLIBC_2.2.5
    8. t fff
    9. Hello World


    友情提醒一下,如果你用Java写一个HelloWorld.java,编译以后你也可以用strings窥探一番。


    二、动态共享库怎么使用


    这次我们把hello.c拆开成为两个文件:hello.c和main.c。hello.c的代码是:


    1. #include <stdio.h>
    2.
    3. void print_hello() {
    4. printf("Hello World/n");
    5. }


    而main.c的代码是:


    1. int main(int argc, char argv[]) {
    2. print_hello();
    3. return 0;
    4. }


    hello.c是我们的动态共享库,在hello.c里面我们声明和实现了各种公用的函数,最后main.c可以去调用这些公用函数。首先我们要把hello.c编译成为动态共享库:

    C代码 复制代码


    1. gcc -o libhello.so -O2 -fPIC -shared hello.c

    -fPIC参数声明链接库的代码段是可以共享的,-shared参数声明编译为共享库。请注意这次我们编译的共享库的名字叫做libhello.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。
    然后编译main.c的时候,我们需要更多的参数让gcc知道如何寻找共享库:

    1. gcc -o main -O2 -L. -lhello main.c

    -L参数指定到哪个附加路径下面去寻找共享库,现在我们指定在当前目录下面寻找;
    -l (L的小写字母)参数指定链接到哪个共享库上面,我们传的参数hello,那么gcc就会自动链接到libhello.so这个共享库上面(注意我们上面说的libXXXX.so命名规则);


    -I ( i 的大写字母)参数指定到哪个附加路径下面去寻找h文件,这个我们没有使用。


    最后我们成功编译好了main,执行一下,报错:

    引用
    ./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

    找不到libhello.so这个共享库,怎么回事?这是因为libhello.so并不在操作系统默认的共享库的路径下面,我们可以临时指定一下

    链接路径:

    1. export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

    这样就成功了。我们用ldd main看一下:


    1. libhello.so => ./libhello.so (0x0000002a9566d000)
    2. libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9576e000)
    3. /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)


    这次main程序链接到了libhello.so这个共享库上面。


    三、关于Linux的动态共享库的设置

    可执行程序找不到要链接的动态共享库,这是Linux上面编译和运行程序很容易碰到的问题,通过上面的小例子,我们已经大致了解共享库的一点基本原理,接下来我们要探讨一下怎么设置程序寻找动态共享库的行为。


    Linux操作系统上面的动态共享库大致分为三类:


    1、操作系统级别的共享库和基础的系统工具库

    比方说libc.so, libz.so, libpthread.so等等,这些系统库会被放在/lib和/usr/lib目录下面,如果是64位操作系统,还会有/lib64和/usr /lib64目录。如果操作系统带有图形界面,那么还会有/usr/X11R6/lib目录,如果是64位操作系统,还有/usr/X11R6 /lib64目录。此外还可能有其他特定Linux版本的系统库目录。这些系统库文件的完整和版本的正确,确保了Linux上面各种程序能够正常的运行。


    2、应用程序级别的系统共享库
    并非操作系统自带,但是可能被很多应用程序所共享的库,一般会被放在/usr/local/lib和/usr/local/lib64这两个目录下面。很多你自行编译安装的程序都会在编译的时候自动把/usr/local/lib加入gcc的-L参数,而在运行的时候自动到/usr/local/lib下面去寻找共享库。


    以上两类的动态共享库,应用程序会自动寻找到他们,并不需要你额外的设置和担心。这是为什么呢?因为以上这些目录默认就被加入到动态链接程序的搜索路径里面了。Linux的系统共享库搜索路径定义在/etc/ld.so.conf这个配置文件里面。这个文件的内容格式


    大致如下:

    1. /usr/X11R6/lib64
    2. /usr/X11R6/lib
    3. /usr/local/lib
    4. /lib64
    5. /lib
    6. /usr/lib64
    7. /usr/lib
    8. /usr/local/lib64
    9. /usr/local/ImageMagick/lib


    假设我们自己编译安装的ImageMagick图形库在/usr/local/ImageMagick目录下面,并且希望其他应用程序都可以使用ImageMagick的动态共享库,那么我们只需要把/usr/local/ImageMagick/lib目录加入/etc /ld.so.conf文件里面,然后执行:ldconfig 命令即可。


    ldcofig将搜索以上所有的目录,为共享库建立一个缓存文件/etc/ld.so.cache。为了确认ldconfig已经搜索到ImageMagick的库,我们可以用上面介绍的strings命令从ld.so.cache里面抽取文本信息来检查一下:


    1. strings /etc/ld.so.cache | grep ImageMagick

    输出结果为:

    1. /usr/local/ImageMagick/lib/libWand.so.10
    2. /usr/local/ImageMagick/lib/libWand.so
    3. /usr/local/ImageMagick/lib/libMagick.so.10
    4. /usr/local/ImageMagick/lib/libMagick.so
    5. /usr/local/ImageMagick/lib/libMagick++.so.10
    6. /usr/local/ImageMagick/lib/libMagick++.so


    已经成功了!


    3、应用程序独享的动态共享库

    有很多共享库只被特定的应用程序使用,那么就没有必要加入系统库路径,以免应用程序的共享库之间发生版本冲突。因此Linux还可以通过设置环境变量 LD_LIBRARY_PATH来临时指定应用程序的共享库搜索路径,就像我们上面举的那个例子一样,我们可以在应用程序的启动脚本里面预先设置 LD_LIBRARY_PATH,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。


    具体如下:

    (1)新建自己的头文件路径/home/user/workspace/include和库文件路径/home/user/workspace/lib,这两个目录用来存放我自己编写的头文件和库文件;
    (2)接下来写个头文件和库文件作测试,在/home/user/workspace/include下新建文件test.h,在/home/user/workspace/lib下新建test.c,test.h中是一些函数原型,test.c是函数的实现;
    (3)通过命令gcc -fPIC -shared -o libtest.so test.c在/home/user/workspace/lib生成了一个动态链接库文件libtest.so;
    (4)现在把库文件路径添加进.bash_profile文件,添加内容如下:


    # my code

    C_INCLUDE_PATH=/home/cheney/workspace/include
    export C_INCLUDE_PATH
    LD_LIBRARY_PATH=/home/cheney/workspace/lib
    export LD_LIBRARY_PATH


    然后通过source .bash_profile把.bash_profile文件即时更新了。


    展开全文
  • gcc 编译动态库链接

    千次阅读 2017-02-04 13:19:32
    此处,我们使用了第2中方法来使用该动态库,先执行以下命令,设置LD_LIBRARY_PATH的值 [plain] view plain copy export LD_LIBRARY_PATH=.  之后,使用一下命令即可 ...

    1.testa.c

    1. #include <stdio.h>  
    2. void Test_a()  
    3. {  
    4.   printf("This is Test_a!");  
    5. }  
    2. testb.c
    1. #include <stdio.h>  
    2. void Test_b()  
    3. {  
    4.   printf("This is Test_b!");  
    5. }  

    3. testc.c
    1. #include <stdio.h>  
    2. void Test_c()  
    3. {  
    4.   printf("This is Test_c!");  
    5. }  
    4. testh.h
    1. void Test_a();  
    2. void Test_b();  
    3. void Test_c();  

    5. main.c

    1. #include "testh.h"  
    2. int main()  
    3. {  
    4.   Test_a();  
    5.   Test_b();  
    6.   Test_c();  
    7.   return 0;  
    8. }  
    现在,我们将三个test函数编译为一个动态库,使用一下命令:
    1. gcc -fPIC -shared testa.c testb.c testc.c -o libtest.so  
    生成了libtest.so文件,其中,命令中

    -shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
    -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

    然后,通过通过命令

    1. gcc main.c -L. -ltest -omain  
    编译生成应用程序main,其中命令中

    -L.:表示要连接的库在当前目录中
    -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

        我们知道一个程序要想在内存中运行,除了编译之外还要经过链接和装入这两个步骤。当然linux中动态链接也是经过这三个过程。Linux 使用这个ld-linux.so*中的来装载(其实这只是一个链接)其他库。所以这个库必须放在linux中/lib下。对于其他,通常我们共享库放在/lib这个路径下,而且也是系统默认的搜索路径。
    Linux共享库的搜索路径先后顺序:
    1、编译目标代码时指定的动态库搜索路径:在编译的时候指定-Wl,-rpath=路径
    2、环境变量LD_LIBRARY_PATH指定的动态库搜索路径
    3、配置文件/etc/ld.so.conf中指定的动态库搜索路径
    4、默认的动态库搜索路径/lib
    5、默认的动态库搜索路径 /usr/lib

    此处,我们使用了第2中方法来使用该动态库,先执行以下命令,设置LD_LIBRARY_PATH的值

    1. export LD_LIBRARY_PATH=.  
    之后,使用一下命令即可

    1. ./main 
    展开全文
  • 四、gcc -l 对动态库和静态库的使用方法是一样的,同一个库如果同时存在动态库和静态库,优先链接动态库,除非使用--static强制使用静态库。 本文详细介绍了linux 下gcc头文件指定方法,以及搜索路径顺序的问题。...
  • 根据链接时期的不同,库又有静态库和动态库之分,有别于静态库,动态库链接是在程序执行的时候被链接
  • gcc编译动态库

    2018-11-27 19:46:15
    gcc生成动态库。1、Linux下创建动态链接库 在使用GCC编译程序时,只需加上-shared选项即可,这样生成的执行程序即为动态链接库。 其中-fPIC选项的作用是:表示编译为位置独立的代码,不用此选项的话编译后的代码是...
  • gcc使用---动态库链接静态库

    万次阅读 热门讨论 2017-02-24 16:44:24
    最近自己的项目中遇到一个问题: 编译一个动态库动态库中使用了静态库的函数如下图所述
  • gcc动态库和静态库的链接顺序

    千次阅读 2018-04-09 22:33:38
    so文件:动态库a文件: 静态库exe文件:可执行程序(linux下以文件属性来标示是否是可执行文件,与后缀名无关)gcc链接顺序问题,总结出以下几点:1,动态库中可以包含另一个静态库,通过参数 -lxxx 把静态库...
  • gcc动态链接库路径

    2018-10-21 19:27:53
    当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中。linux除了默认的搜索路径之外,还通过以下三种方法指定: 配置...
  • 1、最近同事遇到了一个程序崩溃的问题,后来找到原因,是因为这个程序引用了多个动态库,而其中两个动态库中有一个类重名了! 难道gcc对符号重名不做检测的吗?自己觉得有趣,就做了个测试: //m1.cpp #include ...
  • Windows下使用gcc生成.dll动态链接库

    千次阅读 2020-03-06 15:49:22
    生成dll命令: g++ test.cpp -I头文件路径 -fpic -shared -o 动态库名 这里面test.cpp保存一些函数方法 ...g++ main.cpp-I头文件路径 -L动态库路径 -I调用的动态库 -o 可执行文件名 这里面m...
  • 1.接上一篇linux下使用GCC 编译器创建静态链接库后,这篇来介绍如何创建动态链接库。 2. 还是一样,准备创建动态链接库的 源材料: .c 、 .h 文件,如下图: 3. 编写简单的源文件后,之后创建Makefile,编写...
  • gcc 动态库查找路径

    千次阅读 2017-12-07 11:40:16
    gcc 动态库查找路径
  • 进行动态库编译,链接动态库 -Ldir 在动态库的搜索路径中增加dir目录 -lname 链接静态库(libname.a)或动态库(libname.so)的库文件 -fPIC(或fpic) 生成使用相对地址无关的目标代码 方法一...
  • 动态链接库 1. 创建动态链接库 复制代码代码如下: ...用命令gcc -shared hello.c -o libhello.so编译为动态库。可以看到,当前目录下多了一个文件libhello.so。 2. 再编辑一个测试文件test
  • 本文主要记录了gcc共享库的制作和使用过程。 ...(b)将.o打包成共享库(动态库gcc -shared -o libMyCalc.so *.o -Iinclude (3)发布和使用共享库 生成可执行文件方法一: gcc main...
  • Linux基础——gcc编译、静态库与动态库(共享库)

    万次阅读 多人点赞 2018-07-03 17:44:34
    gcc编译器 1、gcc工作流程 2、gcc常用参数 参数 用途 -v 查看版本 -o 产生目标文件 -I+目录 指定头文件目录 -D 编译时定义宏 -00/-01/-03 没有优化/缺省值/优化级别最高 -Wall ...
  • 在使用gcc编译连接生成可执行文件时,经常会碰到变量未定义、链接时或者运行可执行文件时找不到相应的动态库等问题,本文首先介绍了gcc在编译时头文件路径相关选项以及搜索路径顺序,然后讨论了编译成可执行文件时...
  • 静态链接库动态链接库都是共享代码的方式, 区别: 如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。静态的代码在编译过程中已经被载入可执行程序,因此体积较...
  • } 用命令gcc -shared hello.c -o libhello.so编译为动态库。可以看到,当前目录下多了一个文件libhello.so。2. 再编辑一个测试文件test.c,内容如下#include int main() { printf("call hello()"); hello...
  • 然而使用者是使用c开发的程序,链接g++编译生成的时,于链接gcc生成的,有所不同。 首先是静态,以链接g++编译生成的libmylib.a为例子 mylib依赖于pthread,rt,math链接时必须放在mylib之后。 同时-Wl...
  • 本文分别通过链接静态库和动态库来编译可执行文件,在使用gcc编译的过程中了解链接静态库和动态库的区别与联系,同时深入理解Linux系统上是如何将源程序一步步的编译组装成可执行文件的。 目录(一)库文件(二)...
  • gcc 混合连接动态库和静态库

    千次阅读 2013-08-14 14:23:58
    我记得静态库混合动态库要加特殊指令的,你可以试试这样: gcc -g -lstdc++ -g -WI,-Bdynamic -L. -lmy -WI,-Bstatic -L. -lmy -o test.exe main.cc
  • gcc 运行指定动态库的三种方法

    千次阅读 2020-05-14 20:33:57
    动态库指定的方式: 使用GCC编译动态链接库的项目时,在其他目录下执行很可以出现找不到动态链接库的问题。 这种情况多发生在动态链接库是自己开发的情况下,原因就是程序运行时找不到去何处加载动态链接库。 可能会...
  • gcc同时连接静态库和动态库

    千次阅读 2018-04-08 17:33:22
    我在centos7上的测试:makefile文件all: test static...CC=gcc Q= E=echo %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $&lt; $(Q)$(E) " CC " $&lt; libdyn.so:dyn.o $(CC) -shared -fPIC -o $@ ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,616
精华内容 23,046
关键字:

gcc链接动态库