libtool 源码编译与使用

1,下载编译安装 libtool

sudo apt install help2man
git clone git://git.savannah.gnu.org/libtool.git
./bootstrap
mkdir build

cd build/
../configure --prefix=${PWD}/../../local_libt
make -j
make install

ls ../../local_libt

2. libtool 解决的问题和方法

Libtool 是一个 GNU 工具,用于简化和管理共享库的创建和使用。它解决了在不同平台上构建和使用共享库时遇到的许多常见问题。以下是 libtool 能解决的一些问题及其解决方法:


1. 跨平台共享库构建
问题: 不同操作系统和编译器对共享库的构建和使用有不同的要求和命令。
解决方法:
Libtool 提供了一个统一的接口来创建和使用共享库。开发者只需使用 libtool 的命令,而不必关心底层平台的细节。
例如,使用 libtool --mode=compile 和 libtool --mode=link 来编译和链接库,libtool 会根据目标平台自动选择正确的编译和链接选项。


2. 共享库版本管理
问题: 共享库的版本管理在不同平台上可能有不同的约定,导致版本冲突或不兼容。
解决方法:
Libtool 使用一个标准化的版本号系统,允许开发者指定接口版本和实现版本。它会自动生成适合目标平台的版本号格式。
例如,开发者可以使用 -version-info 选项来指定库的版本信息,libtool 会根据平台生成正确的库文件名。


3. 处理符号链接和库路径
问题: 在开发和安装过程中,库文件的位置可能会改变,导致符号链接和库路径问题。
解决方法:
Libtool 生成的包装器脚本可以自动处理符号链接和库路径,确保程序在开发和安装后都能正确找到所需的库。
例如,libtool 会在构建时创建一个包装器脚本,设置正确的 LD_LIBRARY_PATH 或等效变量,以便程序在运行时能找到正确的库。


4. 静态库和动态库的选择
问题: 在某些情况下,开发者可能需要选择使用静态库或动态库,但不同平台的实现方式不同。
解决方法:
Libtool 允许开发者在构建时选择是创建静态库、动态库还是两者都创建。它会根据平台自动选择合适的构建选项。
例如,使用 libtool --mode=link 时,可以通过选项指定是链接静态库还是动态库。


5. 便携性和可移植性
问题: 编写可移植的构建脚本以支持多种平台和编译器是一项复杂的任务。
解决方法:
Libtool 提供了一个抽象层,隐藏了不同平台之间的差异,使得构建脚本可以在多个平台上无缝运行。
例如,开发者可以编写一个使用 libtool 的构建脚本,该脚本在 Linux、macOS 和 Windows 上都能正常工作,而不需要为每个平台编写特定的逻辑。


通过这些功能,libtool 大大简化了共享库的管理和使用,使得开发者可以专注于应用程序的开发,而不必担心底层平台的差异。

3. libtool 应用示例

将 lib 项目的源码 adddd.c 编译,链接成为动态库和静态库

源码:

adddd.c

#include <stdio.h>

float adddd(float a, float b){

	float c;

	c = a + b;
	printf("addd=%7.4f", c);
	
	return c;
}

3.1 编译链接库

生成位置无关目标文件和普通目标文件

../local_libt/bin/libtool --mode=compile gcc -c adddd.c

完成这个编译动作,可以从输出发现,libtool 驱动 gcc 做了三件事情:

生成一个位置无关的目标文件: .libs/adddd.o,用于建立动态链接库;

生成一个普通的目标文件: adddd.o,用于建立静态链接库;

生成一个后缀为.lo 的文本文件:adddd.lo,用于说明用于建立动态链接库和动态链接的文件路径

3.2 链接生成链接库

生成静态链接库和动态链接库

../local_libt/bin/libtool --mode=link  gcc  adddd.lo -o libadddd.la -rpath /home/hipper/ex_libtool/tmp/ex/libdir

 注意一个概念,libtool 库文件,后缀为la,是一个抽象了静态库和动态库的高层概念,库文件。

这里是 libadddd.la

3.3 安装链接库

将 la 等安装到指定目录,这个普通的lib开发的安装是同等动作,安装后方便使用。

../local_libt/bin/libtool --mode=install cp  libadddd.la /home/hipper/ex_libtool/tmp/ex/libdir

3.4 链接调用链接库中的函数

app.c

#include <stdio.h>

extern float adddd(float a, float b);

int main()
{
	float x = 7.777f;
	float y = 1.111f;
	float z = 0.0f;

	z = adddd(x, y);

	printf("main: z = %7.4f", z);

	return 0;
}

3.4.1 编译生成 app 目标文件

../../local_libt/bin/libtool --mode=compile gcc -c app.c

3.4.2 链接生成 app 程序文件

3.4.2.1 使用链接库的动态库
../../local_libt/bin/libtool --mode=link gcc app.lo -o app_dynamic /home/hipper/ex_libtool/tmp/ex/libdir/libadddd.la

注意到这里链接的是 libaddd.so

如果是链接了 libadddd.a, 那么是静态链接,ldd就无法查看到,如下边 3.4.2.2  静态链接示例。

运行:

3.4.2.2 使用链接库的静态库
../../local_libt/bin/libtool --mode=link gcc app.lo -o app_ /home/hipper/ex_libtool/tmp/ex/libdir/libadddd.la -static-libtool-libs

3.4.2.3 生成脚本包装器

../../local_libt/bin/libtool --mode=link gcc app.lo -o app_dynamic -L/home/hipper/ex_libtool/tmp/ex/ -ladddd

这时的 app_dynamic 不再是一个elf64 可执行文件,而是一个 bash shell 脚本,脚本中会调用真正的可执行程序: .libs/app_dynamic

 

包装器脚本详细内容如下:

#! /bin/bash

# app_dynamic - temporary wrapper script for .libs/app_dynamic
# Generated by libtool (GNU libtool) 2.5.3.1-dd2c8
#
# The app_dynamic program cannot be directly executed until all the libtool
# libraries that it depends on are installed.
#
# This wrapper script should never be moved out of the build directory.
# If it is, it will not operate correctly.

# Sed substitution that helps us do robust quoting.  It backslashifies
# metacharacters that are still active within double-quoted strings.
sed_quote_subst='s|\([`"$\\]\)|\\\1|g'

# Be Bourne compatible
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
  emulate sh
  NULLCMD=:
  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
fi
BIN_SH=xpg4; export BIN_SH # for Tru64
DUALCASE=1; export DUALCASE # for MKS sh

# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

relink_command=""

# This environment variable determines our operation mode.
if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
  # install mode needs the following variables:
  generated_by_libtool_version='2.5.3.1-dd2c8'
  notinst_deplibs=' /home/hipper/ex_libtool/tmp/ex//libadddd.la'
else
  # When we are sourced in execute mode, $file and $ECHO are already set.
  if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
    file="$0"

# A function that is used when there is no print builtin or printf.
func_fallback_echo ()
{
  eval 'cat <<_LTECHO_EOF
$1
_LTECHO_EOF'
}
    ECHO="printf %s\\n"
  fi

# Very basic option parsing. These options are (a) specific to
# the libtool wrapper, (b) are identical between the wrapper
# /script/ and the wrapper /executable/ that is used only on
# windows platforms, and (c) all begin with the string --lt-
# (application programs are unlikely to have options that match
# this pattern).
#
# There are only two supported options: --lt-debug and
# --lt-dump-script. There is, deliberately, no --lt-help.
#
# The first argument to this parsing function should be the
# script's ../../local_libt/bin/libtool value, followed by no.
lt_option_debug=
func_parse_lt_options ()
{
  lt_script_arg0=$0
  shift
  for lt_opt
  do
    case "$lt_opt" in
    --lt-debug) lt_option_debug=1 ;;
    --lt-dump-script)
        lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
        test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
        lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
        cat "$lt_dump_D/$lt_dump_F"
        exit 0
      ;;
    --lt-*)
        $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
        exit 1
      ;;
    esac
  done

  # Print the debug banner immediately:
  if test -n "$lt_option_debug"; then
    echo "app_dynamic:app_dynamic:$LINENO: libtool wrapper (GNU libtool) 2.5.3.1-dd2c8" 1>&2
  fi
}

# Used when --lt-debug. Prints its arguments to stdout
# (redirection is the responsibility of the caller)
func_lt_dump_args ()
{
  lt_dump_args_N=1;
  for lt_arg
  do
    $ECHO "app_dynamic:app_dynamic:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
    lt_dump_args_N=`expr $lt_dump_args_N + 1`
  done
}

# Core function for launching the target application
func_exec_program_core ()
{

      if test -n "$lt_option_debug"; then
        $ECHO "app_dynamic:app_dynamic:$LINENO: newargv[0]: $progdir/$program" 1>&2
        func_lt_dump_args ${1+"$@"} 1>&2
      fi
      exec "$progdir/$program" ${1+"$@"}

      $ECHO "$0: cannot exec $program $*" 1>&2
      exit 1
}

# A function to encapsulate launching the target application
# Strips options in the --lt-* namespace from $@ and
# launches target application with the remaining arguments.
func_exec_program ()
{
  case " $* " in
  *\ --lt-*)
    for lt_wr_arg
    do
      case $lt_wr_arg in
      --lt-*) ;;
      *) set x "$@" "$lt_wr_arg"; shift;;
      esac
      shift
    done ;;
  esac
  func_exec_program_core ${1+"$@"}
}

  # Parse options
  func_parse_lt_options "$0" ${1+"$@"}

  # Find the directory that this script lives in.
  thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
  test "x$thisdir" = "x$file" && thisdir=.

  # Follow symbolic links until we get to the real thisdir.
  file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
  while test -n "$file"; do
    destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`

    # If there was a directory component, then change thisdir.
    if test "x$destdir" != "x$file"; then
      case "$destdir" in
      [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
      *) thisdir="$thisdir/$destdir" ;;
      esac
    fi

    file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
    file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
  done

  # Usually 'no', except on cygwin/mingw/windows when embedded into
  # the cwrapper.
  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
  if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
    # special case for '.'
    if test "$thisdir" = "."; then
      thisdir=`pwd`
    fi
    # remove .libs from thisdir
    case "$thisdir" in
    *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
    .libs )   thisdir=. ;;
    esac
  fi

  # Try to get the absolute directory name.
  absdir=`cd "$thisdir" && pwd`
  test -n "$absdir" && thisdir="$absdir"

  program='app_dynamic'
  progdir="$thisdir/.libs"


  if test -f "$progdir/$program"; then
    # Add our own library path to LD_LIBRARY_PATH
    LD_LIBRARY_PATH="/home/hipper/ex_libtool/tmp/ex//.libs:$LD_LIBRARY_PATH"

    # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
    # The second colon is a workaround for a bug in BeOS R4 sed
    LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`

    export LD_LIBRARY_PATH

    if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
      # Run the actual program with our arguments.
      func_exec_program ${1+"$@"}
    fi
  else
    # The program doesn't exist.
    $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
    $ECHO "This script is just a wrapper for $program." 1>&2
    $ECHO "See the libtool documentation for more information." 1>&2
    exit 1
  fi
fi

其中比较重要的是 export LD_LIBRARY_PATH

给出了特定的链接库路径

3.5 卸载链接库

../../local_libt/bin/libtool --mode=uninstall rm /home/hipper/ex_libtool/tmp/ex/libdir/libadddd.la

所有相关文件都会被删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值