交叉编译找不到头文件问题

交叉编译找不到头文件问题

1、 问题描述:

在虚拟机中编译龙芯板子驱动的测试程序,即应用程序,报错:ncurses.h: No such file or directory;

2、分析及操作

  1. 按照网络部分说法是未安装libncurses5-dev libncursesw5-dev,apt-get install libncurses5-dev libncursesw5-dev后,依旧找不到;
  2. find / -name ncurses.h,结果:
    /home/vincent/Desktop/ncurses-6.3/output/include/ncurses/ncurses.h
    /usr/include/ncursesw/ncurses.h
    /usr/include/ncurses.h
    /usr/include/一般就是应用程序编译时找头文件的路径,这个路径下有ncurses.h文件,依旧报错找不到ncurses.h,说明此次编译找的文件不是一般编译时找的路径,推测应该是交叉编译相关的特定路径
  3. 网上查找相关资料发现交叉编译应用程序和交叉内核程序的头文件路径不一样,一般:
    1)交叉编译应用程序时-I指定路径搜索,如:arm-linux-gnueabihf-gcc testtty1.c -o testtty1 -I/linux,头文件存于根目录下的linux文件中。
    2)设置环境变量C_INCLUDE_PATH(不常用)
    C_INCLUDE_PATH=/…(具体路径)
    export C_INCLUDE_PATH
    就和设置交叉编译工具链方式一样
    3)默认路径
    头文件分两种#include <>和#include “”。#include <>使用的是默认交叉编译环境路径,#include ""默认使用的是当前路径。
    可以通过命令搜索 echo ‘main(){}’|arm-linux-gnueabihf-gcc -E -v -
    其中arm-linux-gnueabihf-gcc取决于你自己使用交叉编译工具,我使用的是echo ‘main(){}’|mips64el-linux-gcc -E -v -
    结果中有以下部分:
root@ubuntu:/home/vincent/loongson/LINUX/wchterm# echo 'main(){}'|mips64el-linux-gcc -E -v -
Using built-in specs.
COLLECT_GCC=mips64el-linux-gcc
Target: mips64el-linux
Configured with: ../gcc-loongson-4.9.3/configure --disable-werror --prefix=/opt/gcc-4.9.3-64-gnu/ --host=i486-pc-linux-gnu --build=i486-pc-linux-gnu --target=mips64el-linux --host=i486-pc-linux-gnu --with-sysroot=/opt/gcc-4.9.3-64-gnu//sysroot --with-abi=64 --enable-static --with-build-sysroot=/opt/gcc-4.9.3-64-gnu//sysroot --enable-poison-system-directories --with-arch=loongson3a --with-gmp=/opt/gcc-4.9.3-64-gnu/ --with-mpfr=/opt/gcc-4.9.3-64-gnu/ --with-mpc=/opt/gcc-4.9.3-64-gnu/ --with-cloog=/opt/gcc-4.9.3-64-gnu/ --disable-nls --enable-shared --disable-multilib --enable-__cxa_atexit --enable-c99 --enable-long-long --enable-threads=posix --enable-languages=c,c++,fortran
Thread model: posix
gcc version 4.9.3 20150626 (Red Hat 4.9.3-2) (GCC) 
COLLECT_GCC_OPTIONS='-E' '-v' '-march=loongson3a' '-mabi=64' '-mllsc' '-mno-shared' '-EL'
 /opt/gcc-4.9.3-64-gnu/libexec/gcc/mips64el-linux/4.9.3/cc1 -E -quiet -v - -mel -march=loongson3a -mabi=64 -mllsc -mno-shared
ignoring nonexistent directory "/opt/gcc-4.9.3-64-gnu//sysroot/usr/local/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/include
 /opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/include-fixed
 /opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/../../../../mips64el-linux/include
 /opt/gcc-4.9.3-64-gnu//sysroot/usr/include
End of search list.
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/opt/gcc-4.9.3-64-gnu/sysroot/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"
main(){}
COMPILER_PATH=/opt/gcc-4.9.3-64-gnu/libexec/gcc/mips64el-linux/4.9.3/:/opt/gcc-4.9.3-64-gnu/libexec/gcc/mips64el-linux/4.9.3/:/opt/gcc-4.9.3-64-gnu/libexec/gcc/mips64el-linux/:/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/:/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/:/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/../../../../mips64el-linux/bin/
LIBRARY_PATH=/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/:/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/../../../../mips64el-linux/lib/../lib64/:/opt/gcc-4.9.3-64-gnu/lib/gcc/mips64el-linux/4.9.3/../../../../mips64el-linux/lib/:/opt/gcc-4.9.3-64-gnu//sysroot/lib/:/opt/gcc-4.9.3-64-gnu//sysroot/usr/lib/
COLLECT_GCC_OPTIONS='-E' '-v' '-march=loongson3a' '-mabi=64' '-mllsc' '-mno-shared' '-EL'

这是交叉编译链默认头文件位置,需要将头文件放入上述位置;
4. 预处理的include顺序

#include <>系统默认头文件路径/user/include;
#include  ""先到源文件所在文件夹去找,然后再到系统指定的目录中去找某些头文件;
1.参数-I指定的路径
 指定路径有多个路径时,按指定路径的顺序搜索
2.gcc的环境变量
 C_INCLUDE_PATH
 CPLUS_INCLUDE_PATH
 OBJC_INCLUDE_PATH
3.找系统目录
 /usr/include
 /usr/local/include
 /usr/lib/gcc-xxxx/xxxx
  1. 本地编译、交叉编译时,动静态库连接时、运行时链接的参考路径顺序(静态库编译时就已经加入)
编译时查找的路径:
1. -L指定的路径 
2./lib; /usr/lib; /usr/local/lib;
编译时,能找到libname.so,这个文件要么是个软连接,要么就是实际的动态库文件,否则会报错
链接顺序无所谓,找到就可以;
 <运行时> 查找库文件顺序:
1.-L指定的动态库连接路径;-Wl,-rpath,
2. 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径。
3. 配置文件 /etc/ld.so.conf 中指定的动态库搜索路径
   //如果修改了, 必须 ldconfig 重新加载后才可用
4. 默认的动态库搜索路径 /lib; /usr/lib

3、交叉编译ncurses

1、下载ncurses源码 http://ftp.gnu.org/pub/gnu/ncurses/;
2、在终端解压,在同级目录下建文件夹target和d-target,并进入文件夹;
3、运行配置文件configure ,使其自动生成Makefile文件;
不同的库源码,配置文件可能不一样,可能为configure或者Configure, ncurses-6.3里面的是 configure。此外运行的参数也可能不一样, 因此,在运行配置文件之前最好通过运行
“./configure -h”查看具体的参数用法,此外静态编译和动态编译的配置命令也不同
4、静态、动态编译配置

静态:./configure --host=mips64el-linux --prefix=/home/vincent/loongson/LINUX/ncurses/target/ --with-static --disable-stripping  
动态:./configure --host=mips64el-linux --prefix=/home/vincent/loongson/LINUX/ncurses/d-target --with-shared --disable-stripping

1)–host 指定的是交叉编译工具链的前缀,这个指定错误会使系统使用默认的编译工具,而且还看不 出来,到最后加载时可能报错不匹配不兼容(动态的可以用file命令查看);
2)–prefix 指定所生成的文件的安装到的路径,也可以理解为生成文件的路径;
3)–with-static 指定为静态编译方式;
4)–with-shared指定为动态编译方式;
5)–disable-stripping 在make install时报错 strip: Unable to recognise the format of the input file `/home/wz/ncurses/target/bin/tic’,从网上查到此时因为gcc/strip使用的不是同一个编译环境导致,使用type命令查看gcc和strip使用的路径:

root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# type gcc
gcc is /usr/bin/gcc
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# type strip
strip is /usr/bin/strip

5、make,然后make install;就可以在target目录中看到
静态:

root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/
bin  include  lib  share
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/bin/
captoinfo  clear  infocmp  infotocap  ncurses6-config  reset  tabs  tic  toe  tput  tset
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/include/
ncurses
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/include/ncurses/
cursesapp.h  curses.h   cursesp.h  cursslk.h  etip.h  menu.h      ncurses_dll.h  panel.h    term_entry.h  tic.h
cursesf.h    cursesm.h  cursesw.h  eti.h      form.h  nc_tparm.h  ncurses.h      termcap.h  term.h        unctrl.h
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/lib/
libform.a    libmenu.a    libncurses++.a  libncurses++_g.a  libpanel.a    terminfo
libform_g.a  libmenu_g.a  libncurses.a    libncurses_g.a    libpanel_g.a
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../target/share/
man  tabset  terminfo

动态:

root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../d-target/
bin  include  lib  share
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../d-target/bin
captoinfo  clear  infocmp  infotocap  ncurses6-config  reset  tabs  tic  toe  tput  tset
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../d-target/include/ncurses/
cursesapp.h  curses.h   cursesp.h  cursslk.h  etip.h  menu.h      ncurses_dll.h  panel.h    term_entry.h  tic.h
cursesf.h    cursesm.h  cursesw.h  eti.h      form.h  nc_tparm.h  ncurses.h      termcap.h  term.h        unctrl.h
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../d-target/lib/
libform.a    libform.so.6    libmenu_g.a   libmenu.so.6.3  libncurses++_g.a  libncurses.so.6    libpanel_g.a   libpanel.so.6.3
libform_g.a  libform.so.6.3  libmenu.so    libncurses++.a  libncurses_g.a    libncurses.so.6.3  libpanel.so    terminfo
libform.so   libmenu.a       libmenu.so.6  libncurses.a    libncurses.so     libpanel.a         libpanel.so.6
root@ubuntu:/home/vincent/loongson/LINUX/ncurses/ncurses-6.3# ls ../d-target/share/
man  tabset  terminfo

4、编译程序

静态:

mips64el-linux-gcc -Wall -O2 -pthread -pipe -o wchterm wchterm.c -L/home/vincent/loongson/LINUX/ncurses/target/lib/ -lncurses

动态:

mips64el-linux-gcc -Wall -O2 -pthread -pipe -o wchterm wchterm.c -L/home/vincent/loongson/LINUX/ncurses/d-target/lib/ -lncurses

-Wall:选项可以打印出编译时所有的错误或者警告信息。这个选项很容易被遗忘,编译的时 候,没有错误或者警告提示,以为自己的程序很完美,其实,里面有可能隐藏着许多陷阱。变量没有初始化,类型不匹配,或者类型转换错误等警告提示需要重点注意,错误就隐藏在这些代码里面。没有使用的变量也需要注意,去掉无用的代码,让整个程序显得干净一点。下次写Makefile的时候,一定加-Wall编译选项;

-O0: 表示编译时没有优化;

-O1: 表示编译时使用默认优化;

-O2: 表示编译时使用二级优化;

-O3: 表示编译时使用最高级优化;

-I (大写i):include头文件非标准库中,也非当前文件夹下,需要将地址用此项包含

-L:指定库文件的目录,第一个寻找的库文件目录,如果gcc编译选项中加入了“-static”表示寻找libxxx.a静态库文件;

-l (小写L):指定程序要链接的库,-l参数紧接着就是库名;

-I,-L,-l这三个选项后面可以加空格,也可以不加空格;

5、附录-静态库、动态库生成方法

  1. gcc -c命令把源文件生成对应的.o文件;
  2. 使用ar命令将所有目标文件打包为静态库;
    ar 命令是 gnu 的归档工具,常用于将目标文件打包为静态库,下面我们使用 ar 命令的 -r 选项和 -c 选项进行打包;
    -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。
    -c(create):建立静态库文件。
  3. 将头文件和生成的静态库组织起来(发布)
    当我们把自己的库给别人用的时候,实际上需要给别人两个文件夹,一个文件夹下面放的是一堆头文件的集合,另一个文件夹下面放的是所有的库文件。因此,这里我们可以将 mymath.h 和 myprint.h 这俩头文件放到一个名为 include 的目录下,将生成的静态库文件 libmymath.a 放到一个名为 lib 的目录下,然后将这两个目录都放到 lib-static 下,此时就可以将 lib-static 给别人使用了。
  4. Makefile实现如下:
libmymath.a : mymath.o myprint.o
	ar - rc libmymath.a mymath.o myprint.o
mymath.o : mymath.c
	gcc - c mymath.c - o mymath.o - std = c99
myprint.o : myprint.c
	gcc - c myprint.c - o myprint.o
 
.PHONY : static
static :
	mkdir - p lib - static / lib
	mkdir - p lib - static / include
	cp * .a lib - static / lib
	cp * .h lib - static / include
 
.PHONY : clean
clean :
	rm - rf *.o *.a lib - static
  1. 让所有源文件翻译成对应的.o文件 + 打包为动态库;
    此时用源文件生成目标文件时需要携带 -fPIC 选项,-fPIC(position independent code):产生位置无关码;

说明:
-fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
如果不加-fPIC选项,则加载.so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的拷贝,并且每个拷贝都不一样,取决于这个.so文件代码段和数据段内存映射的位置。
不加-fPIC编译出来的.so是要在加载时根据加载到的位置再次重定位的,因为它里面的代码BBS位置无关代码。如果该.so文件被多个应用程序共同使用,那么它们必须每个程序维护一份.so的代码副本(因为.so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)。
我们总是用-fPIC来生成.so,但从来不用-fPIC来生成.a。但是.so一样可以不用-fPIC选项进行编译,只是这样的.so必须要在加载到用户程序的地址空间时重定向所有表目。
生成好对应的 .o 目标文件,下面就需要将其打包为动态库了,与生成静态库不同的是,我们不再使用ar命令,而是使用gcc的-shared选项即可

Makefile总体实现如下:

libmymath.so : mymath.o myprint.o
	gcc - shared - o libmymath.so mymath.o myprint.o
mymath.o : mymath.c
	gcc - fPIC - c mymath.c - o mymath.o - std = c99
myprint.o : myprint.c
	gcc - fPIC - c myprint.c - o myprint.o
 
.PHONY : clean
clean :
	rm - f * .o * .so

动静态库同时实现Makefile:

.PHONY:all
all : libmymath.so libmymath.a
 
libmymath.so : mymath.o myprint.o
	gcc - shared - o libmymath.so mymath.o myprint.o
mymath.o : mymath.c
	gcc - fPIC - c mymath.c - o mymath.o - std = c99
myprint.o : myprint.c
	gcc - fPIC - c myprint.c - o myprint.o
 
libmymath.a : mymath_s.o myprint_s.o
	ar - rc libmymath.a mymath_s.o myprint_s.o
mymath_s.o : mymath.c
	gcc - c mymath.c - o mymath_s.o - std = c99
myprint_s.o : myprint.c
	gcc - c myprint.c - o myprint_s.o
 
.PHONY : lib
lib :
	mkdir - p lib - static / lib
	mkdir - p lib - static / include
	cp * .a lib - static / lib
	cp * .h lib - static / include
	mkdir - p lib - dyl / lib
	mkdir - p lib - dyl / include
	cp * .so lib - dyl / lib
	cp * .h lib - dyl / include
 
.PHONY:clean
clean :
	rm - rf * .o * .a * .so lib

6.相关命令
ldd文件名来查看一个可执行程序所依赖的库文件
ar 命令的 -t 和 -v选项查看静态库中的文件
-t:列出静态库中的文件。
-v(verbose):显示详细的信息。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值