为什么在64位系统上,cmake会寻找32位库而不是64位库?

3

问题描述

我正在将几个代码库从Red Hat 5迁移到6,并且遇到了一个完全让我困惑的cmake问题。

在RHEL6系统上,Cmake始终在/usr/lib下找到32位版本的库,而不是64位版本的库/usr/lib64,而它在RHEL5系统上正确检测到了lib64版本。

最小示例

例如,我有一个非常简单的CMakeLists.txt文件:

cmake_minimum_required(VERSION 2.8)

find_library(XTEST X11)
message("Found X11 at ${XTEST}")

在RHEL6系统上,运行cmake会得到以下结果:
$ cmake ..
-- The C compiler identification is GNU 4.4.7
-- The CXX compiler identification is GNU 4.4.7
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Found X11 at /usr/lib/libX11.so
-- Configuring done
-- Generating done
-- Build files have been written to: $HOME/software/64bit_problem/build

这里的关键部分是Found X11 at /usr/lib/libX11.so行。

然而,如果我在RHEL5系统上执行相同的操作,它会正确地检测到/usr/lib64/版本:(请注意,我在每次运行之间清除CMakeCache.txt和其他临时cmake文件。)

$ cmake ..
-- The C compiler identification is GNU 4.1.2
-- The CXX compiler identification is GNU 4.1.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Found X11 at /usr/lib64/libX11.so
-- Configuring done
-- Generating done
-- Build files have been written to: $HOME/software/64bit_problem/build

故障排除信息

/usr/lib64 版本的库在两个系统上都存在。以下是 RHEL6 系统上的列表:

$ ls /usr/lib64/libX11.so*
/usr/lib64/libX11.so.6  /usr/lib64/libX11.so.6.3.0

在RHEL5系统上:

$ ls /usr/lib64/libX11.so*
/usr/lib64/libX11.so.6  /usr/lib64/libX11.so.6.3.0

确认一下,/usr/lib 确实是32位版本(并且它不是指向其他位置的符号链接):

$ file /usr/lib/libX11.so*
/usr/lib/libX11.so:       symbolic link to `libX11.so.6.3.0'
/usr/lib/libX11.so.6:     symbolic link to `libX11.so.6.3.0'
/usr/lib/libX11.so.6.3.0: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped

$ file /usr/lib64/libX11.so*
/usr/lib64/libX11.so.6:     symbolic link to `libX11.so.6.3.0'
/usr/lib64/libX11.so.6.3.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped

这可能是由于某个环境设置导致的,但我对其所在位置有点困惑。我没有设置LD_LIBRARY_PATHLD_RUN_PATHLDFLAGSCFLAGSCXXFLAGS也是如此。我的用户环境应该是相同的,因为我的$HOME是一个NFS共享,在两台机器上都是相同的。 /usr/lib不在我的$PATH中,而且无论如何,将我的路径限制为最小子集似乎也没有帮助:
$ export PATH=/bin:/usr/bin:$HOME/local/bin

$ cmake ..
<snip>
Found X11 at /usr/lib/libX11.so
-- Configuring done
<snip>

@SergyA提出了一个很好的建议,使用ltrace检查正在访问哪些环境变量。从我看到的情况来看,strace没有发现任何诊断问题,但ltrace可以很好地显示环境变量的访问情况。以下是一个快速摘要:

$ ltrace -o ltrace_output cmake ..

$ grep getenv ltrace_output
getenv("PWD")                                                    = "$HOME/software/64bit_problem"
getenv("PATH")                                                   = "/bin:/usr/bin:$HOME/local/bin"
getenv("CMAKE_ROOT")                                             = NULL
getenv("MAKEFLAGS")                                              = NULL
getenv("VERBOSE")                                                = NULL
getenv("CFLAGS")                                                 = NULL
getenv("LDFLAGS")                                                = NULL
getenv("LDFLAGS")                                                = NULL
getenv("LDFLAGS")                                                = NULL
getenv("CXXFLAGS")                                               = NULL
getenv("LDFLAGS")                                                = NULL
getenv("LDFLAGS")                                                = NULL
getenv("LDFLAGS")                                                = NULL

cmake 特定故障排除

在两台计算机上,cmake 版本相同(实际上,由于篇幅原因我将不再赘述,它是同一个可执行文件):

$ cmake --version
cmake version 2.8.11.2

$ which cmake
$HOME/local/bin/cmake

我已经尝试显式启用 FIND_LIBRARY_USE_LIB64_PATHS,但似乎没有什么不同:

cmake_minimum_required(VERSION 2.8)

set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)

find_library(XTEST X11)
message("Found X11 at ${XTEST}")

正如@Ravi所提到的,这更可能是由于一些与CMAKE_LIBRARY_PATH有关的问题,但它没有被设置,并且将其更改为环境变量或cmake变量似乎没有帮助。然而,我完全承认我对各种cmake配置变量知之甚少,因此很可能我在这里漏掉了一些显而易见的东西。

我最近意识到的一个关键点是,并不是所有的库都会出现这个问题...例如:

cmake_minimum_required(VERSION 2.8)

find_library(PNGTEST png)
message("Found libpng at ${PNGTEST}")

找到了 /usr/lib64/libpng.so 而不是 /usr/lib/libpng.so。这让我认为这可能与 cmake 有关。
使用 find_package 替代 find_library 考虑到我之前提到的特定于库的问题,我想尝试查找整个 X11 包而不是单个库(实际上,我正在处理的代码库本来就应该这样做)。
然而,我得到了更加令人困惑的结果... 它似乎检测到了一些混合的 64 位和 32 位库?例如:
cmake_minimum_required(VERSION 2.8)

FIND_PACKAGE(X11 REQUIRED)

message("X11_LIBRARIES: ${X11_LIBRARIES}")

我们将会得到:
$ cmake ..
<snip>
-- Looking for XOpenDisplay in /usr/lib/libX11.so;/usr/lib/libXext.so
-- Looking for XOpenDisplay in /usr/lib/libX11.so;/usr/lib/libXext.so - not found
<snip>
-- Found X11: /usr/lib/libX11.so
X11_LIBRARIES: /usr/lib64/libSM.so;/usr/lib64/libICE.so;/usr/lib/libX11.so;/usr/lib/libXext.so
-- Configuring done
<snip>

然而,如果我们查看X11_LIBRARIES中的这些特定库,它们是32位和64位版本的混合!

$ file /usr/lib64/libSM.so.6.0.1
/usr/lib64/libSM.so.6.0.1: ELF 64-bit LSB shared object, x86-64, <snip>

$ file /usr/lib64/libICE.so.6.3.0
/usr/lib64/libICE.so.6.3.0: ELF 64-bit LSB shared object, x86-64, <snip>

$ file /usr/lib/libX11.so.6.3.0
/usr/lib/libX11.so.6.3.0: ELF 32-bit LSB shared object, Intel 80386, <snip>

$ file /usr/lib/libXext.so.6.4.0
/usr/lib/libXext.so.6.4.0: ELF 32-bit LSB shared object, Intel 80386, <snip>

总之,我还应该尝试什么?

我是否缺少了一个特定于cmake或可能是X11的配置选项?


1
你检查了你的$PATH吗?它是否有/usr/lib这个路径? - SergeyA
1
此时,我建议尝试使用strace/ltrace - 这可能会给你一些提示。虽然不是必须的,但总比没有好。例如,如果它正在读取某些晦涩的环境变量,你将在ltrace输出中看到getenv调用。 - SergeyA
让我知道进展如何,现在我很好奇! - SergeyA
在许多*nix系统中,/usr/lib 是指向 lib32lib64 的符号链接。你的链接有没有指向错误的目录的可能性? - callyalater
1
@R..,虽然我不完全反对您的观点,但您知道有更好的工具吗?手动输入Makefile已经行不通了,而配置也很麻烦。 - SergeyA
显示剩余4条评论
2个回答

1
原来问题的根源是版本后缀和在RHEL6端缺少指向/usr/lib64/libX11.so的符号链接。 cmake专门寻找libX11.so而不是其他特定版本的变体,比如libX11.so.6
在这种情况下,创建符号链接不是一个选项,但我可以通过首先列出文件名来优先选择特定版本。
cmake_minimum_required(VERSION 2.8)

find_library(XTEST NAMES libX11.so.6 X11)
message("Found X11 at ${XTEST}")

然而,无疑有许多更好的处理方法,如果有人有更好的方法,我会非常感兴趣听到他们的意见。


在寻找其他东西时,我偶然发现了这个。我对Linux编程的经验很少,但我想知道:如果应用程序正在寻找libX11.so.6,那么CMake Find模块不应该也这样做吗?在我看来,这里的答案可能涉及修复Find模块。 - JPNotADragon

1

好的建议。可惜它并没有改变找到的库文件(仍然在寻找/usr/lib/libX11.so)。然而,我认为这确实让我朝着正确的方向前进了。 - Joe Kington

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接