我有一个使用 libtools 的 C++ 项目。当 libtool 构建程序时,它将二进制文件放置在子目录 (.libs) 中,并将同名的包装器脚本放置在构建目录中,如下所示:
project/
+- libtool
+- build/
+- a.out <<< this is a script, not a binary
+- .libs/
+- a.out
+- lt-a.out
为了从命令行调试 libtool 程序,您需要调用:
../libtool --mode=执行 gdb a.out
但是,无法直接调试 build/a.out,因为它不是二进制文件。我发现如果我将启动配置指向 .libs/a.out 文件,我可以在 vscode 中调试程序,如下所示:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [ {
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/.libs/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
有没有办法通过 libtool 包装器调用二进制文件?
这样做有什么好处吗?
要使用 vscode 调试 libtool 程序,您需要一个包装器脚本,该脚本可以对用于启动调试器的命令行进行打乱,并对 launch.json 配置进行一些更改。
这是我使用的包装脚本(
vscode-lt-launch.sh
):
#!/bin/bash
# vscode-lt-launch.sh
# libtool wrapper for vscode debugging
# Copyright (c) 2023, Radu Hociung
# This file is in the public domain, free to use for any purpose.
#
# Will be called with the following args, which are re-ordered to create the
# correct libtool execution command line:
# --interpreter=mi {miDebuggerArgs} --tty=/dev/pts/17
#
# The VScode launch.json configuration should contain the following fields:
#
# "miDebuggerPath" should be set as "./vscode-lt-launch.sh" (this file)
#
# "miDebuggerArgs" should be set as
# "gdb ${workspaceFolder}/libtool {program-name-libtool-wrapper}"
# in launch.json
#
# "program" shoud be set to "src/.libs/{libtool-built-program-name}"
#
# "additionalSOLibSearchPath" shoud be set to "lib/.libs/" or wherever your
# program's own shared libs are, if your software also
# builds shared libs
# Example VScode launch.json configuration (the program name is "myprogram"):
# {
# "name": "(gdb) Launch",
# "type": "cppdbg",
# "request": "launch",
# "program": "src/.libs/myprogram",
# ^^^^^^^^^^^^^^^^^^^^^
# "additionalSOLibSearchPath": "lib/.libs/",
# ^^^^^^^^^^^^
# "args": ["-4", "-myprogram-args"],
# "stopAtEntry": true,
# "cwd": "${workspaceFolder}",
# "externalConsole": false,
# "miDebuggerPath": "./vscode-lt-launch.sh",
# ^^^^^^^^^^^^^^^^^^^^^^^
# "miDebuggerArgs": "gdb ${workspaceFolder}/libtool src/myprogram",
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# "MIMode": "gdb",
# "setupCommands": [
# {
# "description": "Enable pretty-printing for gdb",
# "text": "-enable-pretty-printing",
# "ignoreFailures": true
# },
# {
# "description": "Set Disassembly Flavor to Intel",
# "text": "-gdb-set disassembly-flavor intel",
# "ignoreFailures": true
# }
# ]
# },
# $1 is "--interpreter=mi", inserted by vscode
# $2 is "gdb" set with miDebuggerArgs
# $3 is "${workspaceFolder}/libtool" set with miDebuggerArgs
# $4 is "src/myprogram" set with miDebuggerArgs
# $5 is "--tty=/dev/pts/19", inserted by vscode
# LD_LIBRARY_PATH is set here but shouldn't be. Instead, libtool should
# add -rpath to the link command, so that --mode=execute runs the program
# with the correct LD_LIBRARY_PATH.
# I'm no libtool expert.
# If you know how to get libtool to add -rpath at link time, please let me know.
build_dir=$(dirname "$3")
export LD_LIBRARY_PATH=${build_dir}/lib/.libs/:$LD_LIBRARY_PATH
# Reorder the args and use solib-absolute-prefix to prevent GDB from seaching
# the / prefix first for shared libs.
# gdb will search the shared libs in the following locations, in this order:
# 1. additionalSOLibSearchPath,
# 2. $LD_LIBRARY_PATH
# 3. system linker's default search path (/lib:/usr/lib:...)
# This ensures the program runs with its own shared libs even if a copy could
# be found installed in /usr/lib/ or other system location.
[ -x "$3" ] && "$3" --mode=execute "$2" \
-ex "set solib-absolute-prefix /dev/null" "$1" "$5" "$4"
脚本应复制到项目的根目录中。它需要编辑 LD_LIBRARY_PATH 以适合您的构建目录,这是一个我不知道如何消除的黑客行为。如果您这样做,我将不胜感激在下面发表评论。
vscode
launch.json
将需要类似于以下的配置,如包装器脚本中所述:
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "src/.libs/myprogram",
// ^^^^^^^^^^^^^^^^^^^^^
"additionalSOLibSearchPath": "lib/.libs/",
// ^^^^^^^^^^^^
"args": ["-4", "-myprogram-args"],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"miDebuggerPath": "./vscode-lt-launch.sh",
// ^^^^^^^^^^^^^^^^^^^^^^^
"miDebuggerArgs": "gdb ${workspaceFolder}/libtool src/myprogram",
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
如果在安装之前需要 libtool 来构建和测试您的应用程序,则需要 在卸载状态下运行该应用程序。
使用 libtool 包装器有优势吗?这个问题有点像问使用编译器来构建应用程序或使用调试器来调试它是否有优势。
有时人们不知道 libtool 有什么功能,只是“以防万一”将其添加到项目中,但没有使用其功能,因此使用 libtool 构建的项目通过调用二进制文件来链接和执行就很好的情况并不罕见直接(src/.lib/myprogram 等),特别是对于没有依赖项的小项目。
如果程序依赖于安装在暂存区中的其他库,libtool 将确保它针对暂存区库运行,即使系统上安装了同名的库。例如。如果您正在测试对 libc 或 libresolv 等通用系统库的更改,您将暂存构建的 libc/libresolv,然后针对暂存的库(而不是系统安装的库)构建/测试应用程序。只有在完成独立测试后,您才需要安装改进的 libc。在那之前,libtool 生成的包装器(例如“src/myprogram”)包含正确的链接信息,以便它可以针对暂存库执行。
libtool 对于在构建的暂存环境中运行已调试应用程序至关重要,但如果程序很简单并且仅依赖于系统上已安装的库,则项目一开始可能不需要 libtool。