g++编译时动态库的搜索路径问题


今天使用g++编译,有用到mysql的动态库。但是遇到如下的报错:

   /usr/bin/ld: cannot find -lmysqlclient

  其中,/etc/ld.so.conf 文件中的配置如下:

include ld.so.conf.d/*.conf
而 /etc/ld.so.conf.d/目录下,包含有mysql-x86_64.conf 文件,这个文件内容是这样的:
/usr/lib64/mysql
查看 /usr/lib64/mysql目录,会发现里面有很多文件。如下
libmysqlclient_r.so -> libmysqlclient_r.so.16.0.0
libmysqlclient_r.so.16 -> libmysqlclient_r.so.16.0.0
libmysqlclient_r.so.16.0.0
libmysqlclient.so -> libmysqlclient.so.16.0.0
libmysqlclient.so.16 -> libmysqlclient.so.16.0.0
libmysqlclient.so.16.0.0
很明显的,有libmysqlclient.so动态库文件。既然这样的话,为什么编译的时候却还是报找不到动态库文件呢??

GG了下,SO上有这么一种说法:

/etc/ld.so.conf is used by the dynamic linker (see manpage ld.so(8)) to figure out which paths to search for your library file. This happens at runtime.

You still need to pass -L/usr/local/lib to gcc, which will pass it on to ld (see manpage ld(1)). This happens at compile time.

看到这句,我们知道,/etc/ld.so.conf配置是在程序运行的时候查找动态库路径的时候使用。而通过g++命令中的-L选项,是在编译时间段指定动态库的查找路径。我们现在可以看下man ld的一些重要信息。
NAME
       ld - The GNU linker 
SYNOPSIS
       ld [options] objfile ...

DESCRIPTION
       ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in
       compiling a program is to run ld.
 ld accepts Linker Command Language files written in a superset of AT&T’s Link Editor Command Language syntax, to provide
       explicit and total control over the linking process.
     首先,从这一段信息中,我们知道,ld是GNU的一种链接器。常用语结合一定数量的对象文件和存档文件。重新定位他们的数据以及绑定符号引用。通常在编译一个程序时,最后一个步骤就是执行ld。

    继续查看man中关于ld的信息。

OPTIONS
       Note---if the linker is being invoked indirectly, via a compiler driver (e.g. gcc) then all the linker command line options
       should be prefixed by -Wl, (or whatever is appropriate for the particular compiler driver) like this:

                 gcc -Wl,--start-group foo.o bar.o -Wl,--end-group
       -l namespec
       --library=namespec
           Add the archive or object file specified by namespec to the list of files to link.  This option may be used any number of
           times.  If namespec is of the form :filename, ld will search the library path for a file called filename, otherwise it will
           search the library path for a file called libnamespec.a.

           On systems which support shared libraries, ld may also search for files other than libnamespec.a.  Specifically, on ELF and
           SunOS systems, ld will search a directory for a library called libnamespec.so before searching for one called
           libnamespec.a.  (By convention, a ".so" extension indicates a shared library.)  Note that this behavior does not apply to
           :filename, which always specifies a file called filename.

           The linker will search an archive only once, at the location where it is specified on the command line.  If the archive
           defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will
           include the appropriate file(s) from the archive.  However, an undefined symbol in an object appearing later on the command
           line will not cause the linker to search the archive again.

           See the -( option for a way to force the linker to search archives multiple times.

           You may list the same archive multiple times on the command line.

           This type of archive searching is standard for Unix linkers.  However, if you are using ld on AIX, note that it is
           different from the behaviour of the AIX linker.

       -L searchdir
       --library-path=searchdir
           Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts.  You may use this
           option any number of times.  The directories are searched in the order in which they are specified on the command line.
           Directories specified on the command line are searched before the default directories.  All -L options apply to all -l
           options, regardless of the order in which the options appear.  -L options do not affect how ld searches for a linker script
           unless -T option is specified.

           If searchdir begins with "=", then the "=" will be replaced by the sysroot prefix, a path specified when the linker is
           configured.

           The default set of paths searched (without being specified with -L) depends on which emulation mode ld is using, and in
           some cases also on how it was configured.

           The paths can also be specified in a link script with the "SEARCH_DIR" command.  Directories specified this way are
           searched at the point in which the linker script appears in the command line.
      -rpath=dir
           Add a directory to the runtime library search path.  This is used when linking an ELF executable with shared objects.  All
           -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime.
           The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the
           link; see the description of the -rpath-link option.  If -rpath is not used when linking an ELF executable, the contents of
           the environment variable "LD_RUN_PATH" will be used if it is defined.

           The -rpath option may also be used on SunOS.  By default, on SunOS, the linker will form a runtime search patch out of all
           the -L options it is given.  If a -rpath option is used, the runtime search path will be formed exclusively using the
           -rpath options, ignoring the -L options.  This can be useful when using gcc, which adds many -L options which may be on NFS
           mounted file systems.

           For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it is
           treated as the -rpath option.
       -rpath-link=dir
           When using ELF or SunOS, one shared library may require another.  This happens when an "ld -shared" link includes a shared
           library as one of the input files.

           When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to
           locate the required shared library and include it in the link, if it is not included explicitly.  In such a case, the
           -rpath-link option specifies the first set of directories to search.  The -rpath-link option may specify a sequence of
           directory names either by specifying a list of names separated by colons, or by appearing multiple times.

           This option should be used with caution as it overrides the search path that may have been hard compiled into a shared
           library. In such a case it is possible to use unintentionally a different search path than the runtime linker would do.

           The linker uses the following search paths to locate required shared libraries:

           1.  Any directories specified by -rpath-link options.

           2.  Any directories specified by -rpath options.  The difference between -rpath and -rpath-link is that directories
               specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only
               effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have
               been configured with the --with-sysroot option.

           3.  On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the
               environment variable "LD_RUN_PATH".

           4.  On SunOS, if the -rpath option was not used, search any directories specified using -L options.

           5.  For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".

           6.  For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared
               libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.

           7.  The default directories, normally /lib and /usr/lib.

           8.  For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.

           If the required shared library is not found, the linker will issue a warning and continue with the link.

    这里,主要粘贴了-l选项和-L选项。我们知道,-l选项是指定搜索的动态库名称,-L选项则是指定搜索的路径。我们也看到-rpath=dir选项以及-rpath-link=dir两个选项的区别。

    通过查看-rpath-link中第7个介绍,我们知道编译器链接动态库的默认路径是 /lib和 /usr/lib(经过实验,还有/usr/local/lib),当然,如果是64位系统,则应是lib64目录。




评论

发表评论