为什么 g++ 在 LIBRARY_PATH/./lib64 中查找,以及它在哪里记录

Why does g++ look in LIBRARY_PATH/../lib64 and where is this documented?

本文关键字:记录 在哪里 查找 lib64 g++ LIBRARY 为什么 PATH      更新时间:2023-10-16

我的LIBRARY_PATH环境变量中有一个自定义目录:/cs/public/lib/pkg/opencv/lib .

但是,当我使用 g++ --print-search-dirs 时,我得到的是:

libraries: =
/cs/public/lib/pkg/opencv/lib/x86_64-suse-linux/4.6/:
/cs/public/lib/pkg/opencv/lib/../lib64/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../../x86_64-suse-linux/lib/x86_64-suse-linux/4.6/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../../x86_64-suse-linux/lib/../lib64/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../x86_64-suse-linux/4.6/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../../lib64/:
/lib/x86_64-suse-linux/4.6/:
/lib/../lib64/:
/usr/lib/x86_64-suse-linux/4.6/:
/usr/lib/../lib64/:
/cs/public/lib/pkg/opencv/lib/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../../x86_64-suse-linux/lib/:
/usr/lib64/gcc/x86_64-suse-linux/4.6/../../../:
/lib/:
/usr/lib/

为什么 g++ 在我在 LIBRARY_PATH 变量中明确指定之前查看这些替代项和一大堆其他系统位置,这在哪里记录

如果在 LIBRARY_PATH 和 LIBRARY_PATH/.. 之前搜索系统默认值,我会理解。/lib64 等,但 g++ 放了LIBRARY_PATH/.。/lib64,然后是系统路径,然后是LIBRARY_PATH。此订购记录在哪里?

我的 g++ 版本是g++ (SUSE Linux) 4.6.2

我的操作系统openSUSE 12.1 (x86_64)

这里提出了类似的问题:g++ 搜索/lib/../lib/, 然后是/lib/

这些看起来很吓人的搜索路径至少部分是在编译器本身构建时确定的,例如在配置阶段。 很明显,它超越了环境变量,因为可以安装GCC的多个副本,并且每个副本都为gcc --print-search-dirs提供不同的结果。 还注意到g++ --print-search-dirsgcc --print-search-dirs给出不同的结果,指出 g++ 包装器也会影响搜索路径。 除了配置/构建时差之外,GCC 肯定知道自己的可执行文件所在的路径,并将搜索该路径的子目录。 很多这种炼金术可以在GCC文档中找到:

http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Directory-Options.html#Directory-Options
http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Environment-Variables.html#Environment-Variables

据我所知,在不编译自己的 GCC 副本的情况下,最有力的做法是使用 -L 选项指定自定义库。 我这样说的原因是因为在例如LIBRARY_PATH之前搜索了-L(请参阅上面关于环境变量的链接(。 为了使其更容易容忍,您可以在 .bashrc 文件中为 g++ 添加一个别名,包括 -L 选项。

如果您想要一个明确的答案,那么下载 GCC 源代码的副本是一种方式。 例如,在 gcc.c 中,会出现以下高度暗示性的注释:

/* Build a list of search directories from PATHS.
   PREFIX is a string to prepend to the list.
   If CHECK_DIR_P is true we ensure the directory exists.
   If DO_MULTI is true, multilib paths are output first, then
   non-multilib paths.
   This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
   It is also used by the --print-search-dirs flag.  */

但是,注释后面的功能不是很明显。

这是工作中的多库 - 一种允许在一台机器上为多个架构提供库(以及整个编译和构建工具链(的机制。该 Wiki 指出"multilib 后缀附加到 GCC 搜索库的所有目录中,并通过 -L 选项传递给链接器。链接器本身对 multilibs 没有任何特别的知识,如果在 -L 路径中找不到库,它将继续查阅其默认搜索目录。如果在单个编译中使用多个正交 ABI 更改选项,则可以串联使用多个 multilib 后缀。

因此,根据上面的描述,体系结构标记字符串或其不同的变体将附加到编译器接收的每个库搜索路径,因为它不区分默认路径和自定义路径。您的自定义路径位于行的第一行,但它经历与其他路径相同的"扩展"过程。

由于需要处理 i386 兼容性,现在似乎在大多数 x64 发行版上默认使用 multilib 机制,这实际上意味着大多数安装都在那里。

我在以下方面遇到了完全相同的问题:

Fedora 17, gcc 4.7 and gcc 4.3
CentOS 6.3, gcc 4.4
Unubuntu 12, gcc 4.6

所以看起来这是大多数 gcc 版本的问题。可能这种奇怪的行为至少根据这一点首次出现在 gcc 4.2 中。

我尝试重复规格并玩它们。看起来*multilib规范用于根据平台附加特定字符串。例如,我的原始空间如下所示:

*multilib:
. !m64 !m32;64:../lib64 m64 !m32;32:../lib !m64 m32;

当我将64:../lib64更改为64:../lib时,而不是../lib64 gcc附加../lib.但我无法完全破译*multilib或任何其他规格的含义。

这个答案试图总结GCC和Clang的搜索路径行为。

海湾合作委员会

包含路径:用于以下格式的命令行:

CPLUS_INCLUDE_PATH=EDIR g++ -IIDIR -isystemSDIR

以下目录列表用作#include <...>的搜索路径:

IDIR                                           # '-I' directories.
SDIR                                           # '-isystem' directories.
EDIR                                           # *_INCLUDE_PATH directories.
GCCDIR/include/c++/GCCVER                      # libstdc++ directory (C++).
GCCDIR/include/c++/GCCVER/GCCARCH              # libstdc++ directory (C++).
GCCDIR/include/c++/GCCVER/backward             # libstdc++ directory (C++).
GCCDIR/lib/gcc/GCCARCH/GCCVER/include          # GCC arch-specific directory.
/usr/local/include/GCCARCH                     # Local arch-specific include directory.
/usr/local/include                             # Local include directory.
GCCDIR/include                                 # GCC include directory.
GCCDIR/lib/gcc/GCCARCH/GCCVER/include-fixed    # GCC include-fixed directory.
/usr/include/GCCARCH                           # System include arch-specific directory.
/usr/include                                   # System include directory.

库路径:用于以下格式的命令行:

LIBRARY_PATH=EDIR gcc -BBDIR -LLDIR

以下参数将传递给链接器:

-LLDIR                                         # '-L' directories.
-LBDIR                                         # '-B' directories.
-LEDIR/../libXX                                # Multilib directories from LIBRARY_PATH.
-LGCCDIR/lib/gcc/GCCARCH/GCCVER                # GCC arch-specific library directory.
-LGCCDIR/libXX                                 # GCC multilib library directory.
-L/libXX                                       # System multilib library directory.
-L/usr/libXX                                   # System multilib library directory. 
-LEDIR                                         # LIBRARY_PATH directories.
-LGCCDIR/lib                                   # Other GCC libraries.

包含路径:用于以下格式的命令行:

CPLUS_INCLUDE_PATH=EDIR clang++ --gcc-toolchain=GCCDIR -BBDIR -IIDIR -isystemSDIR

以下目录列表用作#include <...>的搜索路径:

IDIR                                           # '-I' directories.
SDIR                                           # '-isystem' directories.
EDIR                                           # *_INCLUDE_PATH directories.
 # If -stdlib=libstdc++ is used:
   GCCDIR/include/c++/GCCVER                   # libstdc++ directory from the selected GCC toolchain (C++).
   GCCDIR/include/c++/GCCVER/GCCARCH           # libstdc++ directory from the selected GCC toolchain (C++).
   GCCDIR/include/c++/GCCVER/backward          # libstdc++ directory from the selected GCC toolchain (C++).
 # If -stdlib=libc++ is used:
   CLANGDIR/include/c++/v1                     # libc++ directory (C++).
/usr/local/include                             # Local include directory.
CLANGDIR/lib/clang/CLANGVER/include            # Clang include directory.
/include                                       # System include directory.
/usr/include                                   # System include directory.

库路径:用于以下格式的命令行:

LIBRARY_PATH=EDIR clang --gcc-toolchain=GCCDIR -BBDIR -LLDIR    

以下参数将传递给链接器:

-LLDIR                                         # '-L' directories.
-LGCCDIR/lib/gcc/GCCARCH/GCCVER                # GCC arch-specific library directory.
-LGCCDIR/libXX                                 # GCC multilib library directory.
-L/libXX                                       # System multilib library directory.
-L/usr/libXX                                   # System multilib library directory.
-LGCCDIR/lib                                   # Other GCC libraries.
-LCLANGDIR/lib                                 # Clang libraries.
-L/lib                                         # System library directory.
-L/usr/lib                                     # System library directory.
-LEDIR                                         # LIBRARY_PATH directories.

总结

包含的搜索路径在 GCC 和 Clang 中几乎相同。如果在这两种情况下都使用 C 前端,则会省略特定于C++路径。GCC 和 Clang 之间的库搜索路径差异很大,特别是 -B 目录的存在以及 GCC 前端对LIBRARY_PATH的奇怪操作。

C 前端和 C++ 前端的库搜索路径相同。其他库搜索路径由链接器本身引入。以下摘录来自 GNU Binutils 的原版链接器脚本:

# Multilib library directories.
SEARCH_DIR("BINUTILSDIR/BINUTILSARCH/libXX");
SEARCH_DIR("BINUTILSDIR/libXX");
SEARCH_DIR("/usr/local/libXX");
SEARCH_DIR("/libXX");
SEARCH_DIR("/usr/libXX");
# Traditional library directories.
SEARCH_DIR("BINUTILSDIR/BINUTILSARCH/lib");
SEARCH_DIR("BINUTILSDIR/lib");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");

还必须注意,不会在上面列出的目录中搜索库依赖项。这些选项完全依赖于传递给链接器的-rpath-rpath-link选项,否则它们将从默认系统库路径解析。因此,生成-L-rpath-link参数以保证链接正确的库可能是有用的。

最后,仅在-B目录中搜索特殊文件(如 CRT 对象(。在 Clang 中,还会在选定的 GCC 工具链中搜索特殊文件。其他因素(规范文件、特定于发行版的配置(可能会更改上述部分或全部内容。

看起来交叉

编译需要它。 从更新日志:

  Wed Mar 29 14:53:23 1995  Jim Wilson  <wilson@cygnus.com>
          * gcc.c (process_command): Delete code modifying gcc_exec_prefix.
          (main): Put it here after last use of gcc_exec_prefix.  For cross
          compiler, set startfile_prefixes if gcc_exec_prefix is set and
          standard_startfile_prefix is a relative path.

startfile_prefixes是用搜索目录标志打印的内容。 从gcc/gcc.c

    if (print_search_dirs)
      {
        printf (_("install: %s%sn"), standard_exec_prefix, machine_suffix);
        printf (_("programs: %sn"), build_search_list (&exec_prefixes, "", 0));
        printf (_("libraries: %sn"), build_search_list (&startfile_prefixes, "", 0));
        return (0);
      }

编译器将首先查看默认路径,然后查看其他路径。打印时如何排序我现在没有,但记录在这里,3.19 影响 GCC 的环境变量。

路径由内置规范定义。规范定义管道如何处理源代码以获取结果。GCC 只是驱动编译。

您可以通过 -spec= 为 GCC 提供自己的规范文件,并且您可以使用 -dumpspecs IIRC 获取内置规范。

这可能在 GCC 手册中的某处进行了解释。