精华内容
下载资源
问答
  • libtool

    2019-09-23 15:14:07
    【从网上摘录的,忘了从哪摘的了】 libtool常见于autoconf/automake,...libtool的作用offer a standard procedure for creating shared libraries on different platformslibtool 是一个通用库支持脚本,将使用...
    【从网上摘录的,忘了从哪摘的了】
     
    libtool常见于autoconf/automake,单独用的例子很少,所以我想仔细研究一下,为将来兄弟们看起来方便。
     
    一。libtool的作用
    offer a standard procedure for creating shared libraries on different platforms
    libtool 是一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中,也就是说,你可以通过如下所示的标准方法,在不同平台上创建并调用动态库,我们 可以认为libtool是gcc的一个抽象,也就是说,它包装了gcc或者其他的任何编译器,用户无需知道细节,只要告诉libtool说我需要要编译哪 些库即可,并且,它只与libtool文件打交道,例如lo、la为后缀的文件。
     
    二。libtool的使用
    1.Creating object files
    # libtool --mode=compile gcc -g -O -c foo.c
     gcc -g -O -c foo.c  -fPIC -DPIC -o .libs/foo.o
     gcc -g -O -c foo.c -o foo.o >/dev/null 2>&1
    # libtool --mode=compile gcc -g -O -c hello.c
     gcc -g -O -c hello.c  -fPIC -DPIC -o .libs/hello.o
     gcc -g -O -c hello.c -o hello.o >/dev/null 2>&1
    【说明】libtool编译出两个版本的relocatable object,一个是fPIC(位置无关的),放在.libs目录下;另一个则是普通的,放在本地。
     
    2.linking shared library
    # libtool --mode=link --tag=CC gcc -g -O -o libhello.la -rpath /usr/local/lib foo.lo
     rm -fr  .libs/libhello.a .libs/libhello.la .libs/libhello.lai .libs/libhello.so libs/libhello.so.0 .libs/libhello.so.0.0.0
     gcc -shared  .libs/foo.o   -Wl,-soname -Wl,libhello.so.0 -o .libs/libhello.so.0.0.0
     (cd .libs && rm -f libhello.so.0 && ln -s libhello.so.0.0.0 libhello.so.0)
     (cd .libs && rm -f libhello.so && ln -s libhello.so.0.0.0 libhello.so)
     ar cru .libs/libhello.a  foo.o
     ranlib .libs/libhello.a
     creating libhello.la
     (cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
    【说明】link出两个共享库,一个是static,一个则是dynamic;需要注意的是,-rpath必须有才能产生dynamic库来,如果用-static,则只创建static库。
     
    ranlib的作用:
    On some older UNIX systems, ranlib added a table of contents to archive libraries, which converted each archive to a form that could be linked more rapidly. This is no longer needed as the ar command automatically provides all the functionality ranlib used to provide.
    在一些旧版本的系统上,ranlib负责把静态库转换为其他的某种格式,使得新的库能够更快的链接;现在ar命令已经包含了上述功能;
    This command is provided as a convenience for software developers who need to maintain Makefiles that are portable across a variety of operating systems.
    为了兼容性,在makefile中还是保留ranlib
     
    3.install shared library
    libtool --mode=install cp libhello.la /usr/local/lib/libhello.la
    libtool --mode=install install -c libhello.la /usr/local/lib/libhello.la
    两个命令都可以,效果相同
     
    4.linking executable file
    # libtool --mode=link gcc -g -O -o hello hello.lo -rpath /usr/local/lib libhello.la
     gcc -g -O -o .libs/hello .libs/hello.o  ./.libs/libhello.so
     creating hello
     -rpath项负责添加运行时库路径,否则只能手工修改LD_LIBRARY_PATH环境变量了。
     验证一下:
    # ldd .libs/hello
            linux-gate.so.1 =>  (0xffffe000)
            libhello.so.0 => /usr/local/lib/libhello.so.0 (0x40019000)
            libc.so.6 => /lib/tls/libc.so.6 (0x40031000)
            /lib/ld-linux.so.2 (0x40000000)
     
    5.install executable file       
    #libtool --mode=install cp hello /usr/local/bin/hello
    安装可执行程序。
     
    6.运行
    libtool --mode=execute hello
    或直接运行hello
    注意:此处hello已经安装在/usr/local/bin下了,可以用which hello来查看
     
    【附】源码
    foo.c
    #include <stdio.h>
    char msg[128]="Hello world";
    void print()
    {
            printf("%s/n", msg);
    }
     
    hello.c:
    #include <stdio.h>
    extern char msg[128];
    extern void print();
    int main()
    {
            print();
    }
     
    Makefile:
    LO_OBJS = foo.lo
    PACKAGE_VERSION = 1:1:1
    LIBDIR=/usr/local/lib
    BINDIR=/usr/local/bin
     
    all : hello
     
    install : libhello.la hello
      libtool --mode=install install -c libhello.la
     
    ${LIBDIR}/libhello.la
      libtool --mode=install cp hello ${BINDIR}/hello
     
    uninstall : ${LIBDIR}/libhello.la ${BINDIR}/hello
      libtool --mode=uninstall /bin/rm ${LIBDIR}/libhello.la
      libtool --mode=uninstall /bin/rm ${BINDIR}/hello
     
    hello : libhello.la hello.o
      libtool --mode=install install -c libhello.la
     
    ${LIBDIR}/libhello.la
      libtool --mode=link gcc -g -O -o hello hello.o -rpath ${LIBDIR} libhello.la
     
    libhello.la : $(LO_OBJS)
       libtool  --mode=link --tag=CC gcc -g -O -o libhello.la
     
    $(LO_OBJS) -rpath ${LIBDIR} ${PACKAGE_VERSION}
     
    foo.lo : foo.c
       libtool --mode=compile gcc -g -O -c foo.c
     
    hello.lo : hello.c
       libtool --mode=compile gcc -g -O -c hello.c
     
    clean :
      rm -f lib*.a *~ *core *.lo *.o *.la hello
      rm -rf .libs
     
    这样,用户可以用make编译,make install/uninstall安装/卸载,make clean清除编译临时文件,安装成功后,可以直接执行hello,不必指明路径也不必再另设环境变量LD_LIBRARY_PATH,非常方便! 
     
    gcc -MM kvm_main.c
     

    转载于:https://www.cnblogs.com/hugb/p/5558484.html

    展开全文
  • Libtool

    2012-08-24 13:38:51
    使用 GNU Libtool 创建库  ...简介: 这篇文档向大家介绍 GNU Libtool 的用途及基本使用方法,同时描述如何结合 GNU Autoconf 和 Automake 来使用 Libtool。  本文的标签: gcc, libtool, link, 工具
    原文地址:http://carma2002.iteye.com/blog/1314977
    使用 GNU Libtool 创建库 
    吴 小虎, 程序员, 天用唯勤 
    简介: 这篇文档向大家介绍 GNU Libtool 的用途及基本使用方法,同时描述如何结合 GNU Autoconf 和 Automake 来使用 Libtool。 
    本文的标签:  gcc, libtool, link, 工具与及实用程序, 应用开发, 操作系统, 移植 
    标记本文! 
    发布日期: 2010 年 7 月 12 日 
    级别: 中级 
    访问情况 : 5069 次浏览 
    评论: 2 (查看 | 添加评论 - 登录) 
    平均分 (18个评分) 
    为本文评分 

    介绍 
    在不同的系统中建立动态链接库的方法有很大的差别,这主要是因为每个系统对动态链接库的看法和实现并不相同,以及编译器对动态链接库支持的选项也不太一样。对于开发人员,如果尝试将使用动态库的软件在这些系统之间移植,需要参考枯涩难懂的系统手册,以及修改相应的 Makefile,这一工作是乏味的,并且具有一定的难度。 
    使用 GNU Libtool 可以容易的在不同的系统中建立动态链接库。它通过一个称为 Libtool 库的抽象,隐藏了不同系统之间的差异,给开发人员提供了一致的的接口。对于大部分情况,开发人员甚至不用去查看相应的系统手册,只需要掌握 GNU Libtool 的用法就可以了。并且,使用 Libtool 的 Makefile 也只需要编写一次就可以在多个系统上使用。 
    Libtool 库可以是一个静态链接库,可以是一个动态链接库,也可以同时包含两者。在这篇文档中,我们围绕 Libtool 库的建立和使用,只是在适当的说明 Libtool 库和系统动态或者静态链接库之间的映射关系。 
    Libtool 是一个工具 
    虽然 Libtool 隐藏了在不同平台创建链接库的复杂性,但其最终还是需要底层系统对链接库的支持,它不能超越系统的限制,例如,Libtool 并不能在不支持动态链接库的系统中创建出动态链接库。 
    回页首 
    Libtool 基本用法 
    这一节以实例来说明如何使用 Libtool 从源代码创建最终链接库以及执行程序的完整步骤,这是软件开发过程中经常使用的内容,包括 : 
    创建 Libtool 对象文件 ; 
    创建 Libtool 库; 
    安装 Libtool 库 ; 
    使用 Libtool 库 ; 
    卸载 Libtool 库 ; 
    首先需要准备一个源文件 compress.c,代码如下: 

    清单 1: compress.c 

    #include <sys/mman.h> 
    #include <sys/stat.h> 
    #include <fcntl.h> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <string.h> 
    #include <limits.h> 
    #include <assert.h> 
    #include <zlib.h> 

    /* 一个简单的文件压缩函数 */ 
    int compress_file (const char *filename) 

      int src_fd, dest_fd; 
      struct stat sb; 
      Bytef *src, *dest; 
      uLong dest_len; 
      char dest_file[PATH_MAX]; 

      src_fd = open (filename, O_RDONLY); 
      assert (dest_fd != -1); 

      assert (fstat (src_fd, &sb) != -1); 

      src = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, src_fd, 0); 
      assert (src != MAP_FAILED); 

      dest_len = compressBound (sb.st_size); 
      dest = malloc (dest_len); 
      assert (dest); 

      assert (compress (dest, &dest_len, src, sb.st_size) == Z_OK); 

      munmap (src, sb.st_size); 
      close (src_fd); 

      snprintf (dest_file, sizeof (dest_file), "%s.z", filename); 
      dest_fd = creat (dest_file, S_IRUSR | S_IWUSR); 
      assert (dest_fd != -1); 

      write (dest_fd, dest, dest_len); 
      close (dest_fd); 
      free (dest); 

      return 0; 


    这个文件实现了一个函数 compress_file(),它接收一个文件名作为参数,然后对文件进行压缩,生成一个 .z结尾的压缩文件。在这个文件中使用了 compress()函数,这个函数是有由 libz 提供的。 
    从源文件建立 Libtool 库需要经过两个步骤,先建立 Libtool 对象文件,再建立 Libtool 库。 
    建立 Libtool 对象文件 
    如果使用传统的方式,建立对象文件通常使用下面的命令 : 
    $ gcc -c compress.c 

    使用 Libtool 则使用下面的命令 : 
    $ libtool --mode=compile gcc -c foo.c 

    可以看到,使用 Libtool 只需要将“传统”的命令 (gcc -c foo.c) 作为参数传递给 Libtool 即可。 
    在上面的命令中,libtool 使用 compile模式 (--mode=compile 选项 ),这是建立对象文件的模式,Libtool 还有其它的模式,后面将介绍。 
    上面的命令输出如下 : 
    mkdir .libs 
    gcc -c compress.c  -fPIC -DPIC -o .libs/compress.o 
    gcc -c compress.c -o compress.o >/dev/null 2>&1 

    它建立了两个文件,一个是 .libs/compress.o,在建立这个文件时,Libtool 自动插入了 -fPIC和 -DPIC选项,告诉编译器生成位置独立的代码,之后将用这个文件来建立动态链接库。生成第二个文件 compress.o没有添加额外的选项,它准备用来建立静态链接库。 
    除了上面的两个文件之外,Libtool 还建立了一个文件 compress.lo,这个文件就是 Libtool 对象文件,实际上也就是一个文本文件,里面记录了建立动态链接库和静态链接库分别所需要的真实文件名称,后面 Libtool 将使用这个文件而不是直接的使用 .libs/compress.o 和 compress.o。 
    建立 Libtool 库 
    用下面的命令建立 Libtool 库 : 
    $ libtool --mode=link gcc -o libcompress.la compress.lo -rpath /tmp -lz 

    注意这里使用 compress.lo 作为输入文件,并且告诉 Libtool 生成的目标文件为 libcompress.la,.la 是 Libtool 的库文件后缀。 
    -rpath选项告诉 Libtool 这个库将被安装到什么地方,如果省略了 -rpath选项,那么不会生成动态链接库。 
    因为我们的库中使用了 libz 提供的 compress 函数,所以也提供了 -lz 选项,Libtool 会记住这个依赖关系,后续在使用我们的库时自动的将依赖的库链接进来。 
    上面的命令输出如下 : 
    gcc -shared  .libs/compress.o  -lz  -Wl,-soname -Wl,libcompress.so.0 
                                           -o .libs/libcompress.so.0.0.0 
    (cd .libs && rm -f libcompress.so.0 && 
    ln -s libcompress.so.0.0.0 libcompress.so.0) 
    (cd .libs && rm -f libcompress.so && 
    ln -s libcompress.so.0.0.0 libcompress.so) 
    ar cru .libs/libcompress.a  compress.o 
    ranlib .libs/libcompress.a 
    creating libcompress.la 
    (cd .libs && rm -f libcompress.la && 
    ln -s ../libcompress.la libcompress.la) 

    可以看到,Libtool 自动的插入了建立动态链接库需要的编译选项 -shared。并且,它也建立了静态链接库 .libs/libcompress.a,后面我们将会介绍如何控制 Libtool 只建立需要的库。 
    你可能会奇怪为什么建立的动态链接库有 .0 和 .0.0.0 这样的后缀,这里先不用理会它,后面在介绍 Libtool 库版本信息时将会解释这点。 
    值得注意的是,Libtool 希望后续使用 libcompress.la 文件而不是直接使用 libcompress.a 和 libcompress.so 文件,如果你这样做,虽然可以,但会破坏 Libtool 库的可移植性。 
    安装 Libtool 库 
    如果打算发布建立好的 Libtool 库,可以使用下面的命令安装它 : 
    $ libtool --mode=install install -c libcompress.la /tmp 

    我们需要告诉 Libtool 使用的安装命令,Libtool 支持 install 和 cp,这里使用的是 install。 
    虽然前面我们在建立库时,通过 -rpath 选项指定了库准备安装的路径 (/tmp),但是这里我们还得要提供安装路径。请确保它们一致。 
    这个命令的输出如下 : 
    install .libs/libcompress.so.0.0.0 /tmp/libcompress.so.0.0.0 
    (cd /tmp && { ln -s -f libcompress.so.0.0.0 libcompress.so.0 || 
    { rm -f libcompress.so.0 && 
    ln -s libcompress.so.0.0.0 libcompress.so.0; }; }) 
    (cd /tmp && { ln -s -f libcompress.so.0.0.0 libcompress.so || 
    { rm -f libcompress.so && ln -s libcompress.so.0.0.0 libcompress.so; }; }) 
    install .libs/libcompress.lai /tmp/libcompress.la 
    install .libs/libcompress.a /tmp/libcompress.a 
    chmod 644 /tmp/libcompress.a 
    ranlib /tmp/libcompress.a 
    ... 

    可以看到它安装了真实的动态链接库和静态链接库,同时也安装了 Libtool 库文件 libcompress.la,这个文件可以被后续的 Libtool 命令使用。 
    在安装完成之后,可能还需要做一些配置才能正确使用,Libtool 的 finish 模式可以在这方面给我们一些提示 : 
    $ libtool -n --mode=finish /tmp 

    这个命令的输出有点长,所以不在这里列出,如果不能正常的使用安装好的库,请运行这个命令。 
    使用 Libtool 库 
    要在应用程序中使用前面创建的 Libtool 库很简单,准备一个源文件 main.c,它将使用 libcompress.la 库中定义的函数,代码如下 : 

    清单 2: main.c 

    #include <stdio.h> 

    extern int compress_file (const char *filename); 

    int main (int argc, char *argv[]) 

      if (argc < 2) 
        {   
          printf ("usage : %s file\n", argv[0]); 
          return 1; 
        }   
      return compress_file (argv[1]); 


    我们还是要先为 main.c 建立 Libtool 对象文件,这和前面的方法一样 : 
    $ libtool --mode=compile gcc -c main.c 


    使用安装的库 

    然后使用下面的命令链接执行文件 : 
    $ libtool --mode=link gcc -o main main.lo /tmp/libcompress.la 

    我们也可以直接使用 libcompress.a 或者 libcompress.so,但是使用 Libtool 更加简单,因为它会将帮助你解决依赖关系,例如我们的 libcompress 依赖 libz。 
    上面命令的输出如下 : 
    gcc -o main .libs/main.o  /tmp/libcompress.so -lz 
    -Wl,--rpath -Wl,/tmp -Wl,--rpath -Wl,/tmp 

    这里,Libtool 自动选择链接动态链接库,并且加上了运行时需要的 --rpath 选项,以及依赖的库 -lz。 
    如果要使用静态链接库,只需要加上 -static-libtool-libs选项即可,如下 : 
    $ libtool --mode=link  gcc  -o main main.lo /tmp/libcompress.la -static-libtool-libs 

    这个命令的输出如下 : 
    gcc -o main .libs/main.o  /tmp/libcompress.a -lz 

    使用未安装的库 
    也可以使用还没有安装的库,这和使用安装好的库几乎相同,只是指定的输入文件位置不一样,假如我们在同一个目录中开发 compress.c 和 main.c,那么使用下面的命令 : 
    $ libtool --mode=link gcc -o main main.lo ./libcompress.la 

    和使用安装的库不一样,这个时候建立的 main 程序只是一个封装脚本,如果你直接执行它不会有什么问题,但是如果你想调试它,例如 : 
    $ gdb main 

    gdb 会报怨 main 不是可执行格式,不能接受。这个时候我们需要使用 Libtool 的执行模式,使用下面的命令调试程序 : 
    $ libtool --mode=execute gdb main 

    卸载 Libtool 库 
    使用下面的命令可以卸载安装的库 : 
    $ libtool --mode=uninstall rm /tmp/libcompress.la 

    这个命令的输出如下 : 
    rm /tmp/libcompress.la /tmp/libcompress.so.0.0.0 /tmp/libcompress.so.0 
    /tmp/libcompress.so /tmp/libcompress.a 

    这将删除所有安装的库文件。 
    回页首 
    Libtool 高级用法 
    这一节将对 Libtool 进行更加全面的描述,包括下面的内容 : 
    创建可动态加载模块 ; 
    禁止创建动态或者静态链接库 ; 
    Libtool 命令模式 ; 
    库版本信息 ; 
    创建可动态加载模块 
    有些高级的软件系统在建立时不需要与特定的库链接,而在运行时可以动态加载符合规范的库,来提供额外的功能,这通常称为插件系统。 
    可动态加载的库和通常的库有一些区别,它们可以通过 dlopen() 打开,并且可以通过 dlsym() 查询它输出的符号。 
    使用 Libtool 可以很容易的建立这样的库,还是以前面的 compress.c 为例,我们可以通过这样的命令建立一个可动态加载模块 : 
    $ libtool --mode=link  gcc -o compress.la compress.lo  -rpath /tmp 
    -lz -module -avoid-version 

    这里添加了额外的两个参数,-module告诉 Libtool 建立一个可动态加载的模块,-avoid-version告诉 Libtool 不要添加版本号。 
    在 UNIX/Linux 系统中,库通常以 lib 作为前缀,可在上面我们指定的输出文件为 compress.la而不是 libcompress.la,这也是可动态加载模块的一个特征,它不需要遵循通常的库命名规则。 
    在实际应用中,可动态加载模块通常会使用主程序提供的一些函数,为了满足动态模块的需求,在编译主程序时,需要添加 -export-dynamic选项。 
    禁止创建动态或者静态链接库 
    大部分情况下,Libtool 都配置成同时创建动态链接库和静态链接库。可以通过下面的命令查看 Libtool 的当前配置 : 
    $ libtool – features 

    它的输出如下 : 
    host: i686-pc-linux-gnu 
    enable shared libraries 
    enable static libraries 

    可是有时侯,只想创建动态链接库或者只想创建静态链接库,这需要修改 Libtool 自身。后面介绍 Libtool 结合 Autoconf 和 Automake 使用时,将有更加简单的办法。 
    禁止创建动态链接库 
    Libtool 自身是一个安装在 /usr/bin 目录下的 Shell 脚本,为了修改它,我们需要将它复制到一个有修改权限的目录,然后找到下面的两行 : 
      52 # Whether or not to build shared libraries. 
      53 build_libtool_libs=yes 

    将 yes 改为 no。之后用这个修改过的 libtool 就不会创建动态链接库。 
    还有其它几个方法可以禁止创建动态链接库,第一个方法是在链接时不提供 -rpath 选项,第二个方法是在链接时使用 -all-static选项,第三个方法是指定目标文件为 libcompress.a 而不是 libcompress.la。 
    禁止创建静态链接库 
    在 Libtool 脚本中找到下面两行 
      55 # Whether or not to build static libraries. 
      56 build_old_libs=no 

    将 yes 改为 no。之后用这个修改过的 libtool 就不会创建静态链接库。 
    Libtool 命令模式 
    在前面,我们已经用到了 Libtool 的大部分命令模式,每个命令模式用于不同的阶段,Libtool 根据当前的命令模式添加需要的编译器选项。 
    Libtool 支持下面的几个命令模式 : 
    编译模式 ; 
    连接模式 ; 
    安装模式 ; 
    完成模式 ; 
    卸载模式 ; 
    执行模式 ; 
    清除模式 ; 
    每个命令模式对应开发中的不同阶段,但并不是在每个项目中都需要使用上面所有的模式,例如一个不需要安装的库就不需要安装和卸载模式。 
    编译模式 
    编译模式用于建立从源文件建立对象文件。它需要一个编译器名称作为第一个参数,并且还要提供 -c 选项,Libtool 将根据源文件名称自动选择目标文件名称。如果是建立动态链接库,它也会加入相应的选项,例如 -fPIC等等。 
    编译模式使用示例 : 
    $ libtool --mode=compile gcc -c src.c 

    链接模式 
    链接模式用于建立 Libtool 库或者可执行文件,如果输出文件名称以 .la 结尾,那么它将尝试建立 Libtool 库。如果输出文件名称以 .a 结尾,它就只建立静态链接库。如果输出文件名称以 .lo 或者 .o 结尾,则建立一个可重新加载的对象文件,这经常叫做部分链接。否则它就建立一个执行文件。 
    链接模式使用示例 : 
    $ libtool --mode=link gcc -o library.la src.lo -rpath /usr/local/lib 

    安装模式 
    安装模式用于安装 Libtool 库或者执行程序。它的第一个参数必须是 install 或者 cp,之后是要安装的文件以及目标路径。 
    安装模式使用示例 : 
    $ libtool --mode=install install -c library.la /usr/local/lib 

    完成模式 
    完成模式是在安装完 Libtool 库之后,在使用之前进行适当的配置。finish 模式需要一个参数,即 Libtool 库的安装路径。 
    完成模式使用示例 : 
    $ libtool --mode=finish /usr/local/lib 

    卸载模式 
    卸载模式用于卸载已经安装的 Libtool 库或者执行程序。 
    卸载模式使用示例 : 
    $ libtool --mode=uninstall rm /usr/local/lib/library.la 

    执行模式 
    执行模式用来执行应用程序,它在启动应用程序之前自动的设置好库的路径。 
    执行模式使用示例 : 
    $ libtool --mode=execute gdb program 

    清除模式 
    清除模式和卸载模式差不多,只是它用来清除开发过程中的中间文件。 
    清除模式使用示例 : 
    $ libtool --mode=clean rm library.la 

    库版本信息 
    和应用程序一样,库也需要不断的升级,考虑一个第三方应用程序使用了我们之前发布的 libcompress。现在我们对 libcompress 的性能进行了优化,并且提供了新的接口,所以我们又发布了这个新版本。 
    这引入了几个问题,如果以前的应用程序采用静态方式链接,那么如果它想使用新库的功能,就必须用新库重新链接应用程序。如果是采用动态链接方式,那么新库安装后,应用程序应该使用新库还是旧库呢?并且,如何避免新库和旧库之间的冲突呢? 
    库版本号可以解决上述这些问题,一个动态链接库有一个版本号,它在链接时硬编码到动态链接库中,当一个应用程序链接动态链接库时,它也存储了链接库的版本信息,动态加载器 ( 如 ld-linux.so.2) 可以在程序启动时正确的加载版本匹配的库。 
    用 ldd命令可以查看应用程序使用的动态链接库以及它们的版本信息 : 
    $ ldd .libs/lt-main 
    linux-gate.so.1 =>  (0x00182000) 
    libcompress.so.0 => /home/.../.libs/libcompress.so.0 (0x00c25000) 
    libz.so.1 => /lib/libz.so.1 (0x00565000) 
    libc.so.6 => /lib/libc.so.6 (0x003ad000) 
    /lib/ld-linux.so.2 (0x0038d000) 

    我们需要用 .libs/lt-main 作为输入文件,当前目录下的 main 只是一个封装脚本。从上面的输出可以看到,main 程序依赖 libcompress.so 的版本 0。 
    库接口 
    库接口是 应用程序可以和库交流的入口,常用的库接口包括 : 
    全局变量、结构体、常数 ; 
    全局函数,包括参数类型、数量和返回类型 ; 
    socket、管道,以及其它进程间通讯的协议格式 ; 
    当然还有其它的接口。在设计和实现库时,应该考虑尽量在将来减少库接口的改变。 
    库版本号 
    通常一个库有两个版本号,一个主版本号,一个次版本号,主版本号指示接口的改变,次版本号指示性能增强或者错误修复。但不是每个系统都是如此。 
    在前面的例子中我们可以看到,为动态链接库 libcompress.so.0.0.0 建立了两个符号链接 : 
    libcompress.so -> libcompress.so.0.0.0 
    libcompress.so.0 -> libcompress.so.0.0.0 
    其中 libcompress.so 是供链接器 ( 例如 ld) 使用的,它应该指向当前系统中 libcompress 的最新版本,这样新程序总是可以链接最新的库版本。 
    libcompress.so.0 是供动态加载器 ( 例如 ld-linux.so.2) 使用的,它应该指向当前系统中相同接口号 ( 这里是 0) 的最新版本,这样动态链接器就可以加载相同接口最新的库版本。 
    Libtool 库版本号 
    每个系统的库版本机制并不一样,Libtool 通过一种抽象的版本机制,最终在创建库时映射到具体的系统版本机制。 
    Libtool 的版本号分为 3 个部分 : 
    current: 表示当前库输出的接口的数量 ; 
    revision: 表示当前库输出接口的修改次数 ; 
    age: 表示当前库支持先前的库接口的数量,例如 age为 2,表示它可以和支持当前库接口的执行文件,或者支持前面两个库接口的执行文件进行链接。所以 age应该总是小于或者等于 current。 
    Libtool 的库版本通过参数 -version-info current:revision:age指定,例如下面的例子 : 
    $ libtool --mode=link gcc -l libcompress.la -version-info 0:1:0 

    如果没有指定,默认版本是 0.0.0。 
    注意,应该尽可能少的更新库版本号,尤其是不能强行将库版本号和软件发行号保持一致,下面是更新库版本号的几个策略 : 
    如果修改了库的源代码,那么应该增加 revision。这是当前接口的新的修订版本。 
    如果改变了接口,应该增加 current,将 revision重置为 0。这是接口的新版本。 
    如果新接口是前面接口的超集 ( 前面的接口还是可用 ),那么应该增加 age。这是一个向后兼容的版本。 
    如果新接口删除了前面接口的元素,那么应该将 age重置为 0。这是一个新的,但是不向后兼容的版本。 
    避免版本信息 
    有些动态链接库,例如可动态加载模块,不需要版本号,这时可使用 Libtool 的 -avoid-version选项,例如下面的命令 : 
    $ libtool --mode=link gcc -o libcompress.la compress.lo -rpath /tmp -avoid-version 

    将只会创建一个 .so 结尾的动态链接库,而没有 .0.0.0 这样的版本后缀。 
    回页首 
    结合 Autoconf 和 Automake 使用 Libtool 
    在使用 Autoconf 和 Automake 的项目中使用 Libtool 更加容易,只需要添加或者修改几个地方,后续由 Automake 来帮你正确的调用 Libtool。 
    和 Autoconf 和 Automake 一样,当在其它主机上编译发布的软件包时,不需要安装 Libtool。 
    我们以前面的 compress.c 文件为例,介绍如何将它转换成一个 Autoconf/Automake/Libtool 项目。 
    建立 configure.ac 
    使用下面的命令建立一个 configure.ac 模板 : 
    $ autoscan 

    这将生成一个 configure.scan 文件,将它改名为 configure.ac。 
    在 AC_INIT() 之后加入下面几行 : 
    # 初始话 Automake 
    AM_INIT_AUTOMAKE([-Wall]) 
    # 这是在 Autoconf 中使用 Libtool 唯一必须的宏 
    AC_PROG_LIBTOOL 

    在 AC_OUTPUT 之前加入几行 : 
    # 告诉 Autoconf 通过 Makefile.in 自动生成 Makefile 
    AC_CONFIG_FILES([Makefile]) 

    建立 Makefile.am 
    建立一个 Makefile.am 文件,内容如下 : 
    # _LTLIBRARIES 是 Automake 支持 Libtool 的原语 
    lib_LTLIBRARIES = libcompress.la 
    libcompress_la_SOURCES = compress.c 
    # 可以通过 _LDFLAGS 传递选项给 Libtool 
    libcompress_la_LDFLAGS = 
    # 通过 _LIBADD 可以指定库依赖关系 
    libcompress_la_LIBADD  = -lz 

    注意上面用 lib_LTLIBRARIES,而不是 lib_LIBRARIES,这告诉 Automake 使用 Libtool 创建 Libtool 库。 
    建立 configure 和 Makefile 
    用下面的命令建立几个空文件 : 
    $ touch NEWS README AUTHORS ChangeLog 

    然后运行 : 
    $ autoreconf -i -s 
    这将建立 configure 脚本,运行它将得到 Makefile: 
    $ ./configure 

    同时,configure 也建立了 libtool 脚本,后续 Automake 将使用这个 libtool 脚本,而不是系统的那个。 
    建立 Libtool 库 
    现在已经有了 Makefile,我们只需要简单的输入 : 
    $ make 

    便可以创建 libcompress 了,这比手动调用 Libtool 要方便很多。 
    注意 Automake 自动为 Libtool 选择了 -rpath 的路径,这是跟随 UNIX 系统习惯定义的,库文件安装到 $prefix/lib 目录中,头文件安装到 $prefix/include 目录中。我们可以通过 configure 脚本的 --prefix选项改变上面的 $prefix,也可以使用 configure 脚本的 --libdir明确的指定库文件的安装目录。 
    静态库和动态库 
    前面在 configure.ac 中的 AC_PROG_LIBTOOL 宏为 configure 脚本添加了两个选项 : 
    --enable-static 
    --enable-shared 
    这两个选项可以控制是否建立动态或者静态链接库,例如,如果只想建立动态链接库,可以这样运行 configure: 
    $ ./configure --enable-shared – disable-static 

    在开发过程中,禁止创建动态链接库有几个优势 : 
    编译速度提高了,这可以节省时间 ; 
    调试更加容易,因为不用处理任何动态链接库引入的复杂性 ; 
    你可以了解 Libtool 在只支持静态链接库的平台的行为 ; 
    为了避免在 configure 时忘记 --disable-shared选项,你可以在 configure.ac 中 AC_PROG_LIBTOOL 之前加入一行 : 
    AC_DISABLE_SHARED 

    可动态加载模块 
    Libtool 的 链接模式支持 -module选项,它用来建立一个可动态加载模块,可以通过 Automake 将这个选项传递给 Libtool。只需要选项添加到 Makefile.am 中的 libcompress_la_LDFLAGS变量即可,所以,要建立可动态加载模块,我们需要修改 Makefile.am: 
    libcompress_la_LDFLAGS = -module -avoid-version 

    修改 Makefile.am 之后,需要运行 Automake: 
    $ automake 

    这将重新生成 Makefile.in 文件,以至于 Makefile。 
    安装 Libtool 库 
    安装 Libtool 库非常的简单,只需要运行 : 
    $ make install 

    卸载 Libtool 库 
    和安装 Libtool 库同样简单 : 
    $ make uninstall 

    建立执行程序 
    通过 Automake 使用 Libtool 库也非常容易,我们需要在 Makefile.am 中加入下面的几行 : 
    bin_PROGRAMS = main 
    main_SOURCES = main.c 
    main_LDFLAGS = 
    main_LDADD   = libcompress.la 

    注意在建立 libcompress.la 是,我们通过 _LIBADD 指定依赖库,而建立执行文件 main 时,我们通过 _LDADD 指定依赖库,要记住这点区别。 
    也记得把前面为测试可动态加载模块时修改的 libcompress_la_LDFLAGS 变量改回来 : 
    libcompress_la_LDFLAGS = 

    修改 Makefile.am 之后,需要运行 Automake 更新 Makefile.in: 
    $ automake 

    然后运行 
    $ make 

    就可以建立可执行程序 main。 
    调试执行程序 
    在结合 Autoconf 和 Automake 使用 Libtool 时,我们几乎永远都不会直接调用 Libtool,除了一个例外,那就是 Libtool 的执行模式。 
    例如我们在开发时要调试执行程序,可以使用下面的命令 : 
    $ libtool --mode=execute gdb main 

    如果直接使用 : 
    $ gdb main 

    gdb 会抱怨 main 的格式不可接受,因为使用 Libtool 建立的 main 只是一个封装脚本,它最终启动的是 .lib/lt-main。 
    回页首 
    小结 
    本文档描述了 GNU Libtool 解决的问题,它的工作方式,以及在实际工作中使用 Libtool 的方法。有兴趣的读者应该进一步参考 GNU Libtool 手册获得更详细的信息。在安装了 GNU Libtool 的系统中可以直接通过 info libtool 来查看手册。 

    参考资料 
    学习 
    Shared libraries: 这篇 HOWTO 描述了 Linux 系统中动态链接库名字、位置,以及使用动态链接库相关的环境变量,可以在 http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html查看。 

    Autoconf, Automake, Libtool: 这本在线书籍详细描述了 GNU Autotools(Autoconf, Automake, Libtool) 之间的关系,以及如何在软件项目中结合使用 GNU Autotools。可以在 http://sources.redhat.com/autobook/ 查看本书的在线版本,或者从 http://sources.redhat.com/autobook/download.html下载。 

    GNU Libtool :可以在 http://www.gnu.org/software/libtool/从这里可以下载 GNU Libtool 的最新版本,阅读在线手册,或者下载 PDF 版本的手册。 

    GNU Autoconf:GNU Autotool 解决了 UNIX 世界大部分常见的软件移植性问题,它通过使用各种手段去探测当前操作系统的特征,以及系统中安装的软件包的特征,最后生成一个头文件,定义各种各样的宏来表示系统的特征。应用程序可以通过这个头文件来针对不同的环境来进行开发。可以在 http://www.gnu.org/software/autoconf/下载 Autoconf 最新版本的软件包和手册,或者查看在线手册。 

    GNU Automake:GNU Automake 解决了编写可移植 Makefile 的问题,它使用和 Makefile 规则不同的语法来描述软件项目的依赖关系。其生成的 Makefile 通常比手工写的 Makefile 更加规范,例如它总是包含 dist, install, uninstall 等等常用的 Makefile target。它支持几种常见的语言,例如 Java, vala 等等。可以在 http://www.gnu.org/software/automake/下载 Automake 最新版本的软件包和手册,或者查看在线手册。 

    AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。 

    AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。 

    AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。 

    AIX and UNIX 下载中心:在这里你可以下载到可以运行在 AIX 或者是 UNIX 系统上的 IBM 服务器软件以及工具,让您可以提前免费试用他们的强大功能。 

    IBM Systems Magazine for AIX 中文版:本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。IBM Systems Magazine 的内容都是由十分资深的业内人士撰写的,包括 IBM 的合作伙伴、IBM 的主机工程师以及高级管理人员。所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用 IBM 系统时有一个更好的认识。 
    展开全文
  • libtool介绍

    2021-03-31 15:44:49
    libtool的使用

    前言

    来源一:AUTOTOOLS - John Calcote or AUTOTOOLS – 亚马逊

    来源二:使用 GNU Libtool 创建库 【这是一篇很好的blog】

    简单整理下这本书的第六章:building libraries with libtool

    简单整理下这本书的第七章:library interface versioning and runtime dynamic linking

    书上该章花了很多笔墨来介绍动态库的原理。我知晓一点点这些原理。如果希望了解这些原理,我可能会通过ELF/PE的结构来了解动态库。该章的动态库原理介绍,翻翻就好。

    另外,我没有体会到动态装载显示调用动态库的好处,书上动态装载部分代码能运行。运行时加载动态库相关内容,翻翻就好[ltdl & dl]。

    这里是一篇以前的blog:头文件与库的关系

    本章代码见:jupiter-libtool-ch6-01 | jupiter-libtool-ch7-01

    # 大概的代码结构
    ➜  jupiter-libtool-ch6-01 git:(master) ✗ tree
    .
    ├── common
    │   ├── jupcommon.h
    │   ├── Makefile.am
    │   └── print.c
    ├── configure.ac
    ├── include
    │   ├── libjupiter.h
    │   └── Makefile.am
    ├── libjup
    │   ├── jup_print.c
    │   └── Makefile.am
    ├── Makefile.am
    └── src
        ├── main.c
        └── Makefile.am
    

    libtool介绍

    Libtool的存在仅出于一个原因 ——为想要以可移植方式创建和访问共享库的开发人员提供标准化的抽象接口。 它抽象了共享库的构建过程和用于在运行时动态加载和访问共享库的编程接口。

    首先,让我们看一下Libtool在构建过程中如何提供帮助。Libtool提供了一个脚本(ltmain.sh), config.status在启用Libtool的项目中使用该脚本。 config.status脚本将configure测试结果和ltmain.sh脚本转换为libtool脚本的自定义版本。然后,您项目的makefile使用此libtool脚本来构建用LTLIBRARIES定义的共享库。libtool脚本实际上只是编译器,链接器和其他工具的精美包装。您应该将ltmain.sh脚本作为最终用户构建系统的一部分分发到分发tarball中。

    libtool脚本将构建系统的作者与在不同平台上构建共享库的细微差别隔离开来。 该脚本接受一组定义明确的选项,并将它们转换为目标平台和工具集上适当的特定于平台和链接器的选项。 因此,维护人员无需担心在每个平台上构建共享库的细节,他只需要了解可用的libtool脚本选项。 这些选项在GNU Libtool手册中有明确规定,本章将介绍其中的许多选项。

    在根本不支持共享库的系统上,libtool脚本使用适当的命令和选项来仅构建和链接静态归档库。 此外,使用Libtool时,维护人员不必担心构建共享库和构建静态库之间的差异。 通过在启用Libtool的项目的configure命令行上使用–disable-shared选项,可以在仅静态系统上模拟构建软件包。 此选项使Libtool假定不能在目标系统上构建共享库。


    libtool使用

    Automake内置了对Libtool的支持;Automake软件包 提供LTLIBRARIES,而不是Libtool软件包。 Libtool并不是真正的纯Automake扩展,而是更多的Automake附加软件包,其中Automake为该特定附加软件包提供了必要的基础结构。 没有Libtool,您将无法访问Automake的LTLIBRARIES主要功能,因为使用该主要功能会生成调用libtool构建脚本的生成规则。 【大概是:automake可以使用libtool,但需要libtool的脚本支持。】

    Libtool是单独提供的,而不是作为Automake的一部分提供的,因为您可以独立于Automake非常有效地使用Libtool。 如果您想自己尝试使用Libtool,我将为您提供GNU Libtool手册。 前几章介绍了libtool脚本作为独立产品的使用。 这就像修改makefile命令一样简单,以便通过libtool脚本调用编译器,链接器和库管理器,然后根据Libtool的要求修改某些命令行参数。【大概是:libtool也可以单独使用,而不依赖于automake】

    这篇博客中给出了libtool的单独使用和结合automake使用:使用 GNU Libtool 创建库

    本篇博客仅包含automake与libtool的结合使用


    库的构建

    非必要,除了系统提供的动态库,我是不大乐意使用其他动态库。桌面软件,我感觉静态库就挺好。

    不使用libtool,使用make构建静态库可以参考:头文件与库的关系

    如果使用动态库,不同平台创建使用动态库的方式可能不同,此时便需要libtool。

    include目录

    我们需要通过头文件引用库。此时需要考虑代码的文件布局。

    include目录,应仅包含公共头文件。这些头文件是项目的公开接口。

    如果有多个共享库。可以选择整个项目使用一个顶层的include目录。也可以,每个共享库中创建一个单独的include目录。我通常使用以下经验法则来做出决定:如果将库设计为可以一起工作,那么我将使用单个顶级include目录。 另一方面,如果这些库可以有效地独立使用,那么我将在库自己的目录中提供单独的include目录。

    最后,include目录的位置不是特别重要。因为头文件的安装目录结构和存在于项目中的目录结构不相同。所以我们最后确保,我们的头文件不要使用相同的名称。[因为最后它们可能被安装在相同的目录中,虽然可以使用 pkginclude避免]

    首先,我们在顶层建立一个include目录,并提供一个包的头文件。

    // include/libjupiter.h文件
    
    # ifndef LIBJUPITER_H
    #define LIBJUPITER_H
    
    int jupiter_print(const char * salutation, const char * name);
    
    #endif
    

    为了保证将来这个头文件可以安装到用户的适当位置,还需要一个Makefile.am。

    # include/Makefile.am文件
    # 这个头文件将安装在$(includedir)
    include_HEADERS = libjupiter.h
    

    库的构建

    首先是库代码。这里在头文件引用的时候,使用尖括号而不是双引号。因为在make之后,install之前,生成的脚本会添加查找路径。在install之后,头文件被安装到系统的适当位置,也可以通过PATH环境变量查找到。所以这里使用尖括号是正确的选择。

    // libjup/jup_print.c文件
    
    #include <libjupiter.h>
    #include <jupcommon.h>
    
    int jupiter_print(const char* name){
        return print_routine(name);
    }
    

    接着,需要对库代码进行编译生成库,并设置将来安装的位置。一个Makefile.am搞定。【我是越来越喜欢automake了】

    lib_LTLIBRARIES = libjupiter.la
    libjupiter_la_SOURCES = jup_print.c
    libjupiter_la_CPPFLAGS = -I../include -I../common
    libjupiter_la_LIBADD = ../common/libjupcommon.la
    

    顶层configure.ac和Makefile.am的修改

    接下来,我们将这些新目录挂接到项目的构建系统中。为此,我们需要修改顶级Makefile.am和configure.ac文件。

    先来修改Makefile.am。

    SUBDIRS = common include libjup src
    

    接着修改configure.ac。

    LT_PREREQ([2.2])
    LT_INIT
    
    # AC_PROG_RANLIB
    
    AC_CONFIG_FILES([Makefile
                    common/Makefile
                    include/Makefile libjup/Makefile
                     src/Makefile])
    

    我在comment中注释了AC_PROG_RANLIB宏的使用。 因为Libtool现在正在构建所有项目库,并且Libtool了解库构建过程的所有方面,所以我们不再需要指示Autoconf来确保ranlib 可用。 实际上,如果保留此宏,则在执行autoreconf -i时会收到警告。

    LT_PREREQ宏的工作方式与Autoconf的AC_PREREQ宏一样(使用了几行)。 它表示可以正确处理此项目的最早版本的Libtool。 您应该在这两个宏中为参数选择最低的合理值,因为较高的值不必要地将您和您的共同维护者限制为使用最新版本的Autotools。

    LT_INIT宏为此项目初始化Libtool系统。您可以在传递到LT_INIT宏的参数列表中指定用于启用或禁用静态和共享库的默认值。 LT_INIT接受一个可选的参数:空格分隔的关键字列表。 以下是此列表中允许使用的最重要的关键字,并对其正确用法进行了解释。

    1. dlopen:使用此选项可以检查dlopen支持。 GNU Libtool手册指出,如果程序包使用-dlopen和-dlpreopen libtool标志,则应使用此选项; 否则,libtool将假定系统不支持dl-opening。 使用dlopen或-dlpreopen标志的原因只有一个:您打算在运行时通过调用项目源代码中的ltdl库来动态加载和导入共享库功能。 此外,除非您打算使用ltdl库(而不是直接使用dl库)来管理运行时动态链接,否则这两个选项几乎没有作用。 因此,仅当您打算使用ltdl库时,才应使用此选项。【我不打算在代码中显示的动态加载库,所以没有使用此选项进行初始化】
    2. disable-fast-install:此选项更改了LT_INIT的默认行为,以禁用在相关系统上进行快速安装的优化。 之所以存在快速安装的概念,是因为可能需要从构建树中执行已卸载的程序和库(例如,make check)。在某些系统上,安装位置会影响最终链接的二进制映像,因此Libtool必须在执行make install时重新链接这些系统上的程序和库,或者重新链接程序和库以进行make check。 Libtool默认情况下选择重新链接以进行make check,从而允许快速安装原始二进制文件而无需在make安装过程中重新链接。 在运行configure时,通过指定-enable-fast-install,用户可以根据平台支持来覆盖此默认设置。
    3. shared and disable-shared:这两个选项更改了创建共享库的默认行为。 shared选项的影响是Libtool知道如何创建共享库的所有系统上的默认行为。 用户可以通过在configure命令行上指定–disable shared或–enable-shared来覆盖默认的共享库生成行为。
    4. static and disable-static:这两个选项更改了创建静态库的默认行为。 静态选项的作用是禁用共享库的所有系统以及启用了共享库的大多数系统上的默认行为。 如果启用了共享库,则用户可以通过在configure命令行上指定–disable-static来覆盖此默认值。 Libtool将始终在没有共享库的系统上生成静态库。 因此,您不能(有效)使用LT_INIT的disable-shared和disable static参数或–disable-shared和–disable-static命令行选项来同时配置。 (但是请注意,您可以同时使用共享和静态LT_INIT选项或–enable-shared和-enable-static命令行选项。)
    5. pic-only and no-pic:这两个选项更改了创建和使用PIC对象代码的默认行为。 用户可以通过在configure命令行上指定–without-pic或–with-pic来覆盖这些选项设置的默认值。

    在源码中使用动态库

    我们修改src/main.c,以使用该库。

    // src/main.c文件
    #include <libjupiter.h>
    
    int main(int argc,char* argv[]){
        return jupiter_print(argv[0]);
    }
    

    同样,修改src/Makefile.am以可以正确的链接到该库。

    # src/Makefile.am
    bin_PROGRAMS = jupiter
    jupiter_SOURCES = main.c
    
    # jupiter_CPPFLAGS = -I$(top_srcdir)/common
    jupiter_CPPFLAGS = -I../include
    jupiter_LDADD = ../libjup/libjupiter.la
    
    check_SCRIPTS = greptest.sh
    TESTS = $(check_SCRIPTS)
    
    greptest.sh:
    	echo './jupiter | grep "Hello from .*jupiter!"' > greptest.sh
    	chmod +x greptest.sh
    
    CLEANFILES = greptest.sh
    

    编译运行

    编译运行

    和之前相似,我们编译运行该程序。

    touch NEWS README AUTHORS ChangeLog
    ➜  autoreconf -i
    ➜  ./configure
    # ➜  ./configure --enable-silent-rules # 我希望看到一些编译过程,所以不需要silentmake
    

    下面是make的输出中重要的几行。后面我们将慢慢分析这些过程。

    ➜  jupiter-libtool-ch6-01 git:(master)make      
    make  all-recursive
    ...
    Making all in libjup
    make[2]: 进入目录“/home/dacao/exercise/programming-language-entry-record/autotools/src/chapter6/jupiter-libtool-ch6-01/libjup”
    /bin/bash ../libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I../include -I../common   -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c -o libjupiter_la-jup_print.lo `test -f 'jup_print.c' || echo './'`jup_print.c
    libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../include -I../common -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c jup_print.c  -fPIC -DPIC -o .libs/libjupiter_la-jup_print.o
    libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../include -I../common -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c jup_print.c -o libjupiter_la-jup_print.o >/dev/null 2>&1
    mv -f .deps/libjupiter_la-jup_print.Tpo .deps/libjupiter_la-jup_print.Plo
    /bin/bash ../libtool  --tag=CC   --mode=link gcc  -g -O2   -o libjupiter.la -rpath /usr/local/lib libjupiter_la-jup_print.lo ../common/libjupcommon.la -lpthread 
    libtool: link: gcc -shared  -fPIC -DPIC  .libs/libjupiter_la-jup_print.o  -Wl,--whole-archive ../common/.libs/libjupcommon.a -Wl,--no-whole-archive  -lpthread  -g -O2   -Wl,-soname -Wl,libjupiter.so.0 -o .libs/libjupiter.so.0.0.0
    libtool: link: (cd ".libs" && rm -f "libjupiter.so.0" && ln -s "libjupiter.so.0.0.0" "libjupiter.so.0")
    libtool: link: (cd ".libs" && rm -f "libjupiter.so" && ln -s "libjupiter.so.0.0.0" "libjupiter.so")
    libtool: link: (cd .libs/libjupiter.lax/libjupcommon.a && ar x "/home/dacao/exercise/programming-language-entry-record/autotools/src/chapter6/jupiter-libtool-ch6-01/libjup/../common/.libs/libjupcommon.a")
    libtool: link: ar cr .libs/libjupiter.a  libjupiter_la-jup_print.o  .libs/libjupiter.lax/libjupcommon.a/print.o 
    libtool: link: ranlib .libs/libjupiter.a
    libtool: link: rm -fr .libs/libjupiter.lax
    libtool: link: ( cd ".libs" && rm -f "libjupiter.la" && ln -s "../libjupiter.la" "libjupiter.la" )
    make[2]: 离开目录“/home/dacao/exercise/programming-language-entry-record/autotools/src/chapter6/jupiter-libtool-ch6-01/libjup”
    ...
    

    执行生成目标。

    ./src/jupiter
    Hello from /home/dacao/exercise/programming-language-entry-record/autotools/src/chapter6/jupiter-libtool-ch6-01/src/.libs/jupiter!
    

    分析编译过程

    1. libtool脚本被调用,使用了–mode=compile选项,是建立对象文件的模式。libtool充当标准gcc命令行的经过某种修改的版本的包装脚本;

      -MT,-MD,-MF,-MP这些选项我不是很清楚。gcc文档3.13 Options Controlling the Preprocessor有它们的介绍。

      libjupiter_la-jup_print.lo,实际上也就是一个文本文件,里面记录了建立动态链接库和静态链接库分别所需要的真实文件名称。

      libjupiter_la-jup_print.Plo,里面记录了make规则的依赖文件。

      make[2]: 进入目录“***/libjup”
      /bin/bash ../libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -I../include -I../common   -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c -o libjupiter_la-jup_print.lo `test -f 'jup_print.c' || echo './'`jup_print.c
      
      mv -f .deps/libjupiter_la-jup_print.Tpo .deps/libjupiter_la-jup_print.Plo
      
    2. 下面这两条命令是上面–mode=compile选项导致的。

      对这两个命令行的仔细比较表明,第一个编译器命令正在使用两个附加标志-fPIC和-DPIC。 第一行也似乎将输出文件定向到.libs子目录,而第二行将其保存在当前目录中。 最后,将stdout和stderr输出都重定向到第二行中的/ dev / null。

      有时,您可能会遇到以下情况:源文件在第一次编译时可以正常编译,但是由于与PIC相关的源代码缺陷而在第二次编译中失败。 这类问题很少见,但是当它们出现时可能是真正的痛苦,因为make会因错误而中止构建,但不会提供任何错误消息来解释问题! 看到这种情况时,只需在make命令行的CFLAGS变量中传递-nosuppress标志,以告诉Libtool不要将输出从第二个编译重定向到/dev/null。

      多年来,这种双重编译功能在Libtool邮件列表上引起了相当大的焦虑。 通常,这是由于缺乏对Libtool尝试执行的操作及其必要性的理解。 使用Libtool的各种configure脚本命令行选项,您可以强制执行单个编译,但是这样做会带来一定的功能损失。

      libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../include -I../common -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c jup_print.c  -fPIC -DPIC -o .libs/libjupiter_la-jup_print.o
      
      libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -I../include -I../common -g -O2 -MT libjupiter_la-jup_print.lo -MD -MP -MF .deps/libjupiter_la-jup_print.Tpo -c jup_print.c -o libjupiter_la-jup_print.o >/dev/null 2>&1
      
    3. libtool脚本的link选项。-rpath指定了库的安装位置。生成的库为libjupiter.la。

      /bin/bash ../libtool  --tag=CC   --mode=link gcc  -g -O2   -o libjupiter.la -rpath /usr/local/lib libjupiter_la-jup_print.lo ../common/libjupcommon.la -lpthread 
      
    4. 这两行是上面link选项导致。分别生成动态库和静态库。

      libtool: link: gcc -shared  -fPIC -DPIC  .libs/libjupiter_la-jup_print.o  -Wl,--whole-archive ../common/.libs/libjupcommon.a -Wl,--no-whole-archive  -lpthread  -g -O2   -Wl,-soname -Wl,libjupiter.so.0 -o .libs/libjupiter.so.0.0.0
      
      libtool: link: ar cr .libs/libjupiter.a  libjupiter_la-jup_print.o  .libs/libjupiter.lax/libjupcommon.a/print.o
      
    5. 这里是动态库的版本控制。

      libtool: link: (cd ".libs" && rm -f "libjupiter.so.0" && ln -s "libjupiter.so.0.0.0" "libjupiter.so.0")
      libtool: link: (cd ".libs" && rm -f "libjupiter.so" && ln -s "libjupiter.so.0.0.0" "libjupiter.so")
      

      我们先介绍下Linux中库的版本控制。也可以参考:linux共享库的版本控制和使用

      ❶ -rwxr-xr-x ... libname.so.X.Y
      ❷ lrwxrwxrwx ... libname.so.X -> libname.so.X.Y
      ❸ lrwxrwxrwx ... libname.so -> libname.so.X
      ❹ -rw-r--r-- ... libname.a
      
      • ❶ X是主版本好,Y是次版本号。 一般规则是,X的更改表示对库ABI的非向后兼容更改,而Y的更改表示对库兼容的向后兼容修改。
      • ❷ libname.so.X条目称为库的共享库名称(soname),实际上是指向库二进制文件的软链接。 soname是使用程序和库在内部引用的格式。 该链接由ldconfig实用程序创建,该实用程序(除其他事项外)确保适当的soname可以找到已安装库的最新次要版本。
      • ❸ 这是仅以.so结尾的软链接,通常指的是具有最高主版本号的soname。
      • ❹ 条目表示库的静态归档形式,在Linux和Solaris系统上具有.a扩展名。

      有时,您会看到共享库后面跟着第三个编号。

      -rwxr-xr-x ... libname.so.X.Y.Z
      

      在此示例中,Y.Z实际上只是一个由两部分组成的次要版本号。 次要版本号中的此类附加数字信息有时称为库的补丁程序级别。

      共享库版本与产品版本没有任何关系。原因如下:共享库上的版本号实际上不是库版本,而是接口版本。 我在这里指的接口是由库提供给用户的应用程序二进制接口,另一个程序员希望调用该接口提供的功能。 在Libtool的版本控制方案中,每个版本由唯一的整数值标识。 如果接口的任何公共可见方面在公共发行版之间更改,则不能再将其视为相同的接口; 因此,它成为一个新接口,由新的整数标识符标识。 接口已更改的库的每个公共发行版都仅获取下一个连续的接口版本号。

      Libtool库的版本信息在libtool命令行上使用-version-info选项指定,如下所示。冒号分隔符,分别表示接口的 current, revision, and age values

      libname_la_LDFLAGS = -version-info 0:0:0
      
      • current值表示当前接口版本号。 这是必须声明新的接口版本时更改的值,因为自库的上一次公开发布以来,该接口已以某种公开可见的方式进行了更改。 按照惯例,库中的第一个接口的版本号为零。 考虑一个共享库,自上次公开发行以来,开发人员已在该共享库中向该库公开的功能集添加了新功能。在这个新版本中,接口不能被认为是相同的。 因此,其当前数量必须从零增加到一。
      • age值表示共享库支持的back version的数量。 比如,库中添加了一个新函数,因此此版本的库中提供的接口与先前版本中的接口不同。但是,仍然完全支持以前的版本,因为以前的接口是当前接口的适当子集。 因此,年龄值也应从零增加到一
      • revision值仅表示当前接口的一系列修订。 也就是说,如果在发布之间未对库的接口进行任何公开可见的更改(也许仅对内部函数进行了优化),则库名称应以某种方式更改,即使只是为了区分两个发布。 但是,current值和age值将是相同的,因为从用户的角度来看,界面没有更改。 因此,revision值会增加以反映这是同一接口的新版本的事实。如果其他两个值中的一个或两个都增加了,revision值将保留为零。

      为了简化共享库的发布过程,对于将要公开发布的库的每个新版本,应该逐步遵循Libtool版本控制算法

      1. 从每个新的Libtool库的版本信息0:0:0开始。(如果您只是简单地从传递给libtool脚本的链接器标志列表中省略了version-info选项,则会自动完成此操作。)对于现有库,请从先前公共发行版的版本信息开始。

      2. 如果自上次更新以来,库源代码发生更改,则进行增量修订(c:r:a变为c:r+1:a)。

      3. 如果自上次更新以来已添加,删除或更改了任何导出的功能或数据,请增加current值并将revision设置为0。

      4. 如果自上次公开发布以来已添加任何导出的功能或数据,请增加age。

      5. 如果自上次公开发布以来已删除任何导出的功能或数据,请将age设置为0。

    6. libjupiter.la中包含该库(.a和.so)的链接信息。

      libtool: link: ( cd ".libs" && rm -f "libjupiter.la" && ln -s "../libjupiter.la" "libjupiter.la" )
      
    展开全文
  • libtool资源

    2014-05-06 09:17:58
    学习Linux下libtool,关于gnu的相关资源
  • GNU Libtool 简介 ================ 是一个通用库支持脚本。 将使用共享库的复杂性隐藏在一致、可移植的界面后面。 Libtool 的主页是: http://www.gnu.org/software/libtool/libtool.html 有关 Libtool 的最新...
  • libtool简介

    千次阅读 2017-03-08 13:31:24
    一. libtool的工作原理  ...可以认为libtool是gcc的一个抽象,其包装了gcc(或者其他的编译器),用户无需知道细节,只要告诉libtool需要编译哪些库即可,libtool将处理库的依赖等细节。libtool只与后缀名为lo、la的l

    一. libtool的工作原理 
    libtool 是一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中;使用libtool的标准方法,可以在不同平台上创建并调用动态库。可以认为libtool是gcc的一个抽象,其包装了gcc(或者其他的编译器),用户无需知道细节,只要告诉libtool需要编译哪些库即可,libtool将处理库的依赖等细节。libtool只与后缀名为lo、la的libtool文件打交道。

    libtool主要的一个作用是在编译大型软件的过程中解决了库的依赖问题;将繁重的库依赖关系的维护工作承担下来,从而释放了程序员的人力资源。libtool提供统一的接口,隐藏了不同平台间库的名称的差异等细节,生成一个抽象的后缀名为la高层库libxx.la(其实是个文本文件),并将该库对其它库的依赖关系,都写在该la的文件中。该文件中的dependency_libs记录该库依赖的所有库(其中有些是以.la文件的形式加入的);libdir则指出了库的安装位置;library_names记录了共享库的名字;old_library记录了静态库的名字。 

    当编译过程到link阶段的时候,如果有下面的命令: 

    $libtool --mode=link gcc -o myprog -rpath /usr/lib –L/usr/lib –la 

    libtool会到/usr/lib路径下去寻找liba.la,然后从中读取实际的共享库的名字(library_names中记录了该名字,比如liba.so)和路径(lib_dir中记录了,比如libdir=’/usr/lib’),返回诸如/usr/lib/liba.so的参数给激发出的gcc命令行。 

    如果liba.so依赖于库/usr/lib/libb.so,则在liba.la中将会有dependency_libs=’-L/usr/lib -lb’或者dependency_libs=’/usr/lib/libb.la’的行,如果是前者,其将直接把“-L/usr/lib –lb”当作参数传给gcc命令行;如果是后者,libtool将从/usr/lib/libb.la中读取实际的libb.so的库名称和路径,然后组合成参数“/usr/lib/libb.so”传递给gcc命令行。 

    当要生成的文件是诸如libmylib.la的时候,比如: 

    $libtool --mode=link gcc -o libmylib.la -rpath /usr/lib –L/usr/lib –la 

    其依赖的库的搜索基本类似,只是在这个时候会根据相应的规则生成相应的共享库和静态库。 

    注意:libtool在链接的时候只会涉及到后缀名为la的libtool文件;实际的库文件名称和库安装路径以及依赖关系是从该文件中读取的。 

    2 为何使用 -Wl,--rpath-link -Wl,DIR? 
    使用libtool解决编译问题看上去没什么问题:库的名称、路径、依赖都得到了很好的解决。但下结论不要那么着急,一个显而易见的问题就是:并不是所有的库都是用libtool编译的。 

     

    libtool常见于autoconf/automake,单独用的例子很少。 
     
    二. libtool的使用
    1.Creating object files
    # libtool --mode=compile gcc -g -O -c foo.c
     gcc -g -O -c foo.c  -fPIC -DPIC -o.libs/foo.o
     gcc -g -O -c foo.c -o foo.o >/dev/null2>&1
    # libtool --mode=compile gcc -g -O -c hello.c
     gcc -g -O -c hello.c  -fPIC -DPIC -o.libs/hello.o
     gcc -g -O -c hello.c -o hello.o>/dev/null 2>&1
    【说明】libtool编译出两个版本的relocatableobject,一个是fPIC(位置无关的),放在.libs目录下;另一个则是普通的,放在本地。
     
    2.linking shared library
    # libtool --mode=link --tag=CC gcc -g -O -olibhello.la -rpath /usr/local/lib foo.lo
     rm -fr  .libs/libhello.a.libs/libhello.la .libs/libhello.lai .libs/libhello.so libs/libhello.so.0.libs/libhello.so.0.0.0
     gcc -shared  .libs/foo.o  -Wl,-soname -Wl,libhello.so.0 -o .libs/libhello.so.0.0.0
     (cd .libs && rm -f libhello.so.0&& ln -s libhello.so.0.0.0 libhello.so.0)
     (cd .libs && rm -f libhello.so &&ln -s libhello.so.0.0.0 libhello.so)
     ar cru .libs/libhello.a  foo.o
     ranlib .libs/libhello.a
     creating libhello.la
     (cd .libs && rm -f libhello.la&& ln -s ../libhello.la libhello.la)
    【说明】link出两个共享库,一个是static,一个则是dynamic;需要注意的是,-rpath必须有才能产生dynamic库来,如果用-static,则只创建static库。
     
    ranlib的作用:
    On some older UNIX systems, ranlib added a tableof contents to archive libraries, which converted each archive to a form thatcould be linked more rapidly. This is no longer needed as the ar commandautomatically provides all the functionality ranlib used to provide.
    在一些旧版本的系统上,ranlib负责把静态库转换为其他的某种格式,使得新的库能够更快的链接;现在ar命令已经包含了上述功能;
    This command is provided as a convenience forsoftware developers who need to maintain Makefiles that are portable across avariety of operating systems.
    为了兼容性,在makefile中还是保留ranlib
     
    3.install shared library
    libtool --mode=install cp libhello.la/usr/local/lib/libhello.la
    libtool --mode=install install -c libhello.la/usr/local/lib/libhello.la
    两个命令都可以,效果相同
     
    4.linking executable file
    # libtool --mode=link gcc -g -O -o hello hello.lo-rpath /usr/local/lib libhello.la
     gcc -g -O -o .libs/hello .libs/hello.o ./.libs/libhello.so
     creating hello
     -rpath项负责添加运行时库路径,否则只能手工修改LD_LIBRARY_PATH环境变量了。
     验证一下:
    # ldd .libs/hello
           linux-gate.so.1 =>  (0xffffe000)
           libhello.so.0 => /usr/local/lib/libhello.so.0 (0x40019000)
           libc.so.6 => /lib/tls/libc.so.6 (0x40031000)
           /lib/ld-linux.so.2 (0x40000000)
     
    5.install executablefile       
    #libtool --mode=install cp hello /usr/local/bin/hello
    安装可执行程序。
     
    6.运行
    libtool --mode=execute hello
    或直接运行hello
    注意:此处hello已经安装在/usr/local/bin下了,可以用which hello来查看
     
    【附】源码
    foo.c
    #include <stdio.h>
    char msg[128]="Hello world";
    void print()
    {
        printf("%s/n",msg);
    }
     
    hello.c:
    #include <stdio.h>
    extern char msg[128];
    extern void print();
    int main()
    {
        print();
    }
     
    Makefile:
    LO_OBJS = foo.lo
    PACKAGE_VERSION = 1:1:1
    LIBDIR=/usr/local/lib
    BINDIR=/usr/local/bin
     
    all : hello
     
    install : libhello.la hello
      libtool --mode=install install -clibhello.la
     
    ${LIBDIR}/libhello.la
      libtool --mode=install cp hello${BINDIR}/hello
     
    uninstall : ${LIBDIR}/libhello.la ${BINDIR}/hello
      libtool --mode=uninstall /bin/rm${LIBDIR}/libhello.la
      libtool --mode=uninstall /bin/rm${BINDIR}/hello
     
    hello : libhello.la hello.o
      libtool --mode=install install -clibhello.la
     
    ${LIBDIR}/libhello.la
      libtool --mode=link gcc -g -O -o hellohello.o -rpath ${LIBDIR} libhello.la
     
    libhello.la : $(LO_OBJS)
       libtool  --mode=link --tag=CCgcc -g -O -o libhello.la
     
    $(LO_OBJS) -rpath ${LIBDIR} ${PACKAGE_VERSION}
     
    foo.lo : foo.c
       libtool --mode=compile gcc -g -O -cfoo.c
     
    hello.lo : hello.c
       libtool --mode=compile gcc -g -O -chello.c
     
    clean :
      rm -f lib*.a *~ *core *.lo *.o *.la hello
      rm -rf .libs
     
    这样,用户可以用make编译,makeinstall/uninstall安装/卸载,makeclean清除编译临时文件,安装成功后,可以直接执行hello,不必指明路径也不必再另设环境变量LD_LIBRARY_PATH,非常方便! 


    lo: 使用libtool编译出的目标文件,其实就是在o文件中添加了一些信息
    la: 使用libtool编译出的库文件,其实是个文本文件,记录同名动态库和静态库的相关信息

     

    o: 编译的目标文件
    a: 静态库,其实就是把若干o文件打了个包
    so: 动态链接库(共享库)


    展开全文
  • nghttp2 报错error: Libtool library used but ‘LIBTOOL’ is undefined如果重新安装libtool和autoconf升级到2.69后,还是报错 则进行下面的操作:1,查看aclocal的路径 aclocal --print-ac-dir显示/usr/local/share...
  • libtool编译

    千次阅读 2015-05-19 15:13:44
    我们可以认为libtool是gcc的一个抽象,也就是说,它包装了gcc或者其他的任何编译器,用户无需知道细节,只要告诉libtool说我需要要编译哪些库即可,并且,它只与libtool文件打交道,例如lo、la为后缀的文件 ...
  • libtool-2.26

    2013-09-13 10:16:20
    libtool-2.26-15.5
  • libtool-2.4.6.tar.gz

    2021-06-09 11:44:23
    免费下载 libtool-2.4.6.tar.gz_FreeDownload.zip 文件后,解压此文件即可得到 libtool-2.4.6.tar.gz 源文件。
  • libtool-cache-开源

    2021-05-15 02:41:58
    libtool-cache是​​一个Perl脚本,用于缓存GNU libtool执行的命令,从而主要在运行Microsoft Windows并使用Cygwin的系统上提高编译速度。 它缓存编译和链接命令。
  • libtool工作原理

    2010-11-20 23:09:00
    libtool
  • linux使用libtool

    2019-09-22 04:16:56
    linux使用libtool 1 libtool的工作原理 libtool 是一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中;使用libtool的标准方法,可以在不同平台上创建并调用动态库。可以认为libtool是...
  • libtool-1.5

    2013-07-08 11:00:50
    tar zxvf libtool-1.5.tar.gz ./configure --prefix=/usr make make check(检测提供的例子可以用) make install
  • 在编译spice库函数pixman...pixman/Makefile.am:1: error: Libtool library used but 'LIBTOOL' is undefined pixman/Makefile.am:1: The usual way to define 'LIBTOOL' is to add 'LT_INIT' pixman/Makefile.am:1...
  • 在afl的qemu_mode目录下,执行./build_qemu_support.sh,报错libtool not found, please install first。 执行sudo apt-get install libtool提示libtool已经安装好了。但是执行which libtool没有信息输出。 解决方案...
  • GNU Libtool

    2013-10-23 20:42:54
    GNU Libtool Introduction to GNU Libtool GNU libtool is a generic(一般的,通用的) library support script. Libtool hides the complexity(复杂性) of using shared libraries(共享库) behind a ...
  • libtool使用手册

    2009-02-17 21:31:29
    GNU libtool使用手册 英文版,GNU libtool使用手册
  • 安装gd库出现 Libtool library used but `LIBTOOL' is undefined 安装gd库出现 Libtool library used but `LIBTOOL' is undefined - bzyyc.happy的日志 - ...
  • libtool版本不匹配

    2021-04-23 11:41:32
    编protobuf的时候,突然出现了这个问题。... libtool: Version mismatch error. This is libtool 2.2.6 Debian-2.2.6a-4, but the libtool: definition of this LT_INIT comes from libtool 2.2.6b. libtool: You sho.
  • libtool 2.4.6打包脚本

    2020-10-07 14:32:17
    # To Build: ...# wget https://raw.github.com/nmilford/rpm-libtool/master/libtool.spec -O ~/rpmbuild/SPECS/libtool.spec # wget http://ftp.gnu.org/gnu/libtool/libtool-2.4.2.tar.gz -O ~/rpmbuild.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,626
精华内容 16,650
关键字:

libtool