避免交叉编译时,libtool 的雷区
来源:互联网 发布:java long转换成date 编辑:程序博客网 时间:2024/06/05 10:47
Avoiding libtool minefields when cross-compiling
If you've ever tried to cross-compile a free software project for a different architecture on GNU/Linux, you may well have run into the situation where you compile a library with your cross toolchain, install it in a “staging” directory that will hold your root filesystem (for example, you compile the library to go into/usr/lib, but you install it in /tmp/rootfs/usr/lib, because that's where you're building your new root filesystem. You do this correctly: specify your --prefix=/usr when you configure, but provideDESTDIR=/tmp/rootfs when you make install), and you try to compile another library that links against that library. Everything goes fine (the author of the program may have even written his configure script properly, so you can configure it to use the correct toolchain), but at the link step, you get this:
/bin/sh libtool --mode=link target-gcc -c -O2 -o libbar.so ... -lfoo
target-gcc -c -O2 -o libbar.so ... /usr/lib/libfoo.so
/usr/lib/libfoo.so: could not read symbols: File in wrong format
collect2: ld returned 1 exit status
Now, why is the command trying to link against /usr/lib/libfoo.so, which is your system's version oflibfoo, and not /tmp/rootfs/usr/lib/libfoo.so? You might play with compiler and linker flags, try to hack and understand the libtool shell script (best of luck if you can decipher it), and end up cursing the ancestors of those who ever came up with such a dumb system.
The problem turns out to be that libfoo and libbar in this example both use libtool, and that the prefix happens to conflict with the system's library locations; when libtool installs a library, you'll see it installslibfoo.la.
What's with that file? You may, reasonably, expect to see one or two different kinds of library file:libfoo.a, which is just an archive of object files, and which you can statically link into your program; andlibfoo.so, a dynamically loadable, sharable library. What's a .la? Just cat one, and you'll see:
$ cat /usr/lib/libesd.la
# libesd.la - a libtool library file
# Generated by ltmain.sh - GNU libtool 1.5.6 (1.1220.2.95 2004/04/11 05:50:42) Debian: 224 $
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='libesd.so.0'
# Names of this library.
library_names='libesd.so.0.2.36 libesd.so.0 libesd.so'
# The name of the static archive.
old_library='libesd.a'
# Libraries that this one depends upon.
dependency_libs=' -L/usr/lib /usr/lib/libaudiofile.la -lm'
# Version information for libesd.
current=2
age=2
revision=36
# Is this an already installed library?
installed=yes
# Should we warn about portability when linking against -modules?
shouldnotlink=no
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='/usr/lib'
Notice the last line? It says that libesd is installed in /usr/lib, so when libtool finds your libfoo.la in your temporary root filesystem tree, that file tells it to go look in /usr/lib. So, you have to prevent the libtool file from confusing the libtool script at link time.
You can probably just remove the libtool library file, and rely on your linker to figure out what you mean by-lfoo (even though the .la strongly admonishes you not to delete it), but perhaps better is to just updatelibdir in this file to point to where your library is temporarily installed. Using GNU sed you can do this:
sed -i~ -e "s;/usr;/tmp/rootfs/usr;" /tmp/rootfs/usr/lib/libfoo.la
I do this just after installing the cross-compiled library into my temporary root filesystem tree.
You likely won't need the libtool files any more when you install (if you're targeting an embedded Linux system), so you don't care if those files are correct once installed on the target. You'll probably just remove them from the final image, anyway.
I wrote this because I spent a long night of fighting libtool, Googling for help and finding none, and finally figuring this out. This is the second time I've even figured this out, having forgotten the solution the first time. Hopefully, this will help you out if you encounter this issue.
The wrong-gcc problem
For some packages, you seem to also run into trouble where libtool can't figure out what you're doing:
$ libtool --mode=compile target-gcc -g -O2 -c foo.c
libtool: compile: unable to infer tagged configuration
libtool: compile: specify a tag with `--tag'
OK, so it couldn't figure out that we're compiling C code. No problem, just add the tag --tag=CC. Works when we compile:
$ libtool --tag=CC --mode=compile target-gcc -g -O2 -c foo.c
target-gcc -g -O2 -c foo.c -fPIC -DPIC -o .libs/foo.o
target-gcc -g -O2 -c foo.c -o foo.o >/dev/null 2>&1
But when we link, libtool tries to call the native gcc:
$ libtool --tag=CC --mode=link target-gcc -rpath /usr/lib -o libfoo.la foo.lo
gcc -shared .libs/foo.o -Wl,-soname -Wl,libfoo.so.0 -o .libs/libfoo.so.0.0.0
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
/usr/bin/ld: .libs/foo.o: Relocations in generic ELF (EM: 40)
.libs/foo.o: could not read symbols: File in wrong format
collect2: ld returned 1 exit status
One rumored workaround (I haven't tried this, since I haven't had to cross compile anything in a while) is to specify a proper rpath in LDFLAGS:
-Wl,-rpath -Wl,/usr/lib -Wl,-rpath-link -Wl,${STAGING_DIR}/usr/lib -L${STAGING_DIR}/lib -L${STAGING_DIR}/usr/lib
Thanks to Waldemar Brodkorb for this workaround. Let me know if this works for you.
Another solution to this problem is to just install a cross libtool, which you'll use in preference to your system's libtool. It's easy enough to do; go grab the distribution, unpack it, and install it with:
$ tar xzf libtool-1.5.22.tar.gz
$ cd libtool-1.5.22
libtool-1.5.22 $ ./configure --prefix=/opt/Toolchain --host=target --program-prefix=target-
configure output...
libtool-1.5.22 $ make
make output...
libtool-1.5.22 $ sudo make install
Then, you can just use target-libtool when cross compiling. That libtool (which is still just a shell script, so you needn't worry about running it on the host) will be set up properly for using your target-gcc. You usually just have to add an environment variable LIBTOOL=target-libtool when you configure your package.
Happy Hacking.
- 避免交叉编译时,libtool 的雷区
- 交叉编译中libtool相关的问题
- 8、交叉编译libtool
- 交叉编译libupnp,make时提示libtool: eval: line 944: syntax error near unexpected token `|'的解决办法
- 全志在编译时出现的error: Libtool library used but 'LIBTOOL' is undefined解决方案
- 交叉编译中pkg-config和libtool设置
- 交叉编译中pkg-config和libtool设置
- libtool编译
- libtool编译
- linux 下编译radius时出现libtool: Command not found 的错误
- 编译gstreamer插件新发现和libtool的新认识
- 交叉编译环境搭建时的问题
- 交叉编译的基本知识
- 交叉编译的基本概念
- 常用的交叉编译
- DM6446的交叉编译
- BlueZ的交叉编译
- JPEG的交叉编译
- 交叉编译中pkg-config和libtool设置
- Servlet 中文乱码问题及解决方案剖析
- 硬件的体系
- 已有项目加入maven支持
- Linux硬链接与软链接
- 避免交叉编译时,libtool 的雷区
- C#委托的异步调用[转]
- 10.【cocos2d翻译系列】Actions, Transformations and Effects--Special actions
- ServletContext中常用方法
- X264编译
- linux启动过程
- Java获取客户端IP地址
- 正则表达式集合
- struts2基础