关于 Libtool 存档(.la)文件

扩展名为 .la 的文件

在 LFS 和 BLFS 中,许多软件包使用内部附带的 libtool 副本,以便在各种 Unix 平台上构建。这些平台包括 AIX、Solaris、IRIX、HP-UX、Cygwin 以及 Linux。该工具的起源相当久远,其设计初衷是在比现代 Linux 系统功能更弱的系统上管理库。

在 Linux 系统上,libtool 特定的文件通常是不需要的。通常,库在构建过程的链接阶段被指定。由于 Linux 系统对可执行文件和动态库使用 可执行与可链接格式(ELF),完成该任务所需的信息已嵌入在文件中。链接器和程序加载器都可以查询相应的文件,并正确地链接或执行程序。

静态库在 LFS 和 BLFS 中很少使用。而且,如今大多数软件包将链接静态库所需的信息存储在 .pc 文件中,而不是依赖 libtool。pkg-config --static --libs 命令会输出足够的标志,供链接器在无需任何 libtool 魔法的情况下链接静态库。

问题在于,libtool 通常会为软件包库创建一个或多个文本文件,称为 libtool 存档。这些小型文件扩展名为“.la”,包含的信息与嵌入在库或 pkg-config 文件中的信息类似。当构建使用 libtool 的软件包时,构建过程会自动查找这些文件。有时 .la 文件可能包含构建期间使用但未安装的静态库的名称或路径,那么构建过程将因 .la 文件引用了系统中不存在的内容而中断。同样,如果软件包更新后不再使用 .la 文件,旧的 .la 文件也会导致构建过程失败。

解决方案是移除 .la 文件。但有一个例外。某些软件包,例如 ImageMagick-7.1.2-13,使用 libtool 函数 lt_dlopen,在执行期间按需加载库,并在运行时解析其依赖关系。在这种情况下,应保留 .la 文件。

下面的脚本会移除所有不需要的 .la 文件,并将它们保存到一个目录中(默认为 /var/local/la-files),而非正常的库路径中。它还会搜索所有 pkg-config 文件(.pc),查找其中嵌入的对 .la 文件的引用,并将其修正为构建应用程序或库时所需的常规库引用。您可以根据需要运行该脚本,以清理可能引发问题的目录。

cat > /usr/sbin/remove-la-files.sh << "EOF"
#!/bin/bash

# /usr/sbin/remove-la-files.sh
# Written for Beyond Linux From Scratch
# by Bruce Dubbs <bdubbs@linuxfromscratch.org>

# 确保以 root 权限运行
if test "${EUID}" -ne 0; then
    echo "Error: $(basename ${0}) must be run as the root user! Exiting..."
    exit 1
fi

# 确保 PKG_CONFIG_PATH 在 sudo 丢弃后仍已设置
source /etc/profile

OLD_LA_DIR=/var/local/la-files

mkdir -p $OLD_LA_DIR

# 只搜索 /opt 中的目录,但不搜索指向目录的符号链接
OPTDIRS=$(find /opt -mindepth 1 -maxdepth 1 -type d)

# 将所有找到的 .la 文件移出到另一个目录
find /usr/lib $OPTDIRS -name "*.la" ! -path "/usr/lib/ImageMagick*" \
  -exec mv -fv {} $OLD_LA_DIR \;
###############

# 修复可能包含 .la 引用的任何 .pc 文件

STD_PC_PATH='/usr/lib/pkgconfig
             /usr/share/pkgconfig
             /usr/local/lib/pkgconfig
             /usr/local/share/pkgconfig'

# 对于每个可能有 .pc 文件的目录
for d in $(echo $PKG_CONFIG_PATH | tr : ' ') $STD_PC_PATH; do

  # 对于每个 .pc 文件
  for pc in $d/*.pc ; do
    if [ $pc == "$d/*.pc" ]; then continue; fi

    # 检查包含 .la 引用的行中的每个单词
    for word in $(grep '\.la' $pc); do
      if $(echo $word | grep -q '.la$' ); then
        mkdir -p $d/la-backup
        cp -fv  $pc $d/la-backup

        basename=$(basename $word )
        libref=$(echo $basename|sed -e 's/^lib/-l/' -e 's/\.la$//')

        # 修复 .pc 文件
        sed -i "s:$word:$libref:" $pc
      fi
    done
  done
done

EOF

chmod +x /usr/sbin/remove-la-files.sh