Linux应用开发基础知识——交叉编译与gcc编译(一)

简介: Linux应用开发基础知识——交叉编译与gcc编译(一)

一、交叉编译 hello.c

1.gcc编译

hello.c 的源码如下:

#include <stdio.h>
 
 
/* 执行命令: ./hello abcd 
 * argc = 2
 * argv[0] = ./hello
 * argv[1] = abcd
 */
 
int main(int argc, char **argv)
{
  if (argc >= 2)
    printf("Hello, %s!\n", argv[1]);
  else
    printf("Hello, world!\n");
  return 0;
}
 
 

在 Ubuntu 中可以执行以下命令编译、执行:

 
book@100ask:~$ gcc -o hello hello.c
book@100ask:~$
book@100ask:~$ ./hello

       上述命令编译得到的可执行程序 hello 可以在 Ubuntu 中运行,但是如果把 它放到 ARM 板子上去,它是无法执行的。因为它是使用 gcc 编译的,是给 PC 机 编译的,里面的机器指令是 x86 的。

查看hello文件类型

file hello

2 .交叉编译、测试 tslib

我们要想给 ARM 板编译出 hello 程序,需要使用交叉编译工具链,比如:

arm-buildroot-linux-gnueabihf-gcc -o hello hello.c

这样编译出来的 hello 程序才可以在 ARM 板子上运行。

Ubuntu目录/home/book/nfs_rootfs挂载到开发板的/mnt中:

[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

交叉编译配置 :

// 对于 IMX6ULL,命令如下
book@100ask:~$ export ARCH=arm
book@100ask:~$ export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
book@100ask:~$ export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin

交叉编译 tslib:

// 对于 IMX6ULL,命令如下
book@100ask:~$ arm-buildroot-linux-gnueabihf-gcc -o hello hello.c
book@100ask:~$ file hello

拷贝到挂载目录上:

book@100ask:~$ cp hello /home/book/nfs_rootfs/

在开发板上再次执行./hello的程序成功运行

二、 hello程序的引申

1.怎么确定交叉编译器中头文件的默认路径?

       位于系统目录,进入交叉编译器的目录里,执行:find -name “stdio.h”,它位于一个 “include”目录下的根目录里。这个“include”目录,就是要找的路径。

2.怎么自己指定头文件目录?

       编译时,加上“-I ”这样的选项。

3.怎么确定交叉编译器中库文件的默认路径?

       位于系统目录,进入交叉编译器的目录里,执行:find -name lib,可以得到 xxxx/lib、 xxxx/usr/lib,一般来说这 2 个目录就是要找的路径。如果有很多类似的 lib, 进去看看,有很多 so 文件的目录一般就是要找的路径。

4.怎么自己指定库文件目录、指定要用的库文件?

       编译时,加上“-L ”这样的选项,用来指定库目录;

       编译时,加上“-labc”这样的选项,用来指定库文件 libabc.so。

三、GCC 编译器的使用

GCC 编译过程

(1)编译流程

       一个 C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇 编(assembly)和链接(linking)等 4 步才能变成可执行文件。

通过不同的 gcc 选项可以控制这些过程:

       

       在日常交流中通常使用“编译”统称这 4 个步骤,如果不是特指这 4 个步骤 中的某一个,本教程也依惯例使用“编译”这个统称。

进入事先准备好的文件中  

book@100ask:~/02_options/01_hello$  cd 02_options/01_hello
gcc -o hello hello.c // 输出名为 hello 的可执行程序,然后可以执行./hello

(2)编译步骤

执行“gcc -o hello hello.c -v”时,可以查看到这些步骤

gcc -o hello hello.c -v

cc1 main.c -o /tmp/ccXCx1YG.s
as -o /tmp/ccZfdaDo.o /tmp/ccXCx1YG.s
 
cc1 sub.c -o /tmp/ccXCx1YG.s
as -o /tmp/ccn8Cjq6.o /tmp/ccXCx1YG.s
 
collect2 -o test /tmp/ccZfdaDo.o /tmp/ccn8Cjq6.o ....

可以手工执行以下命令体验一下这4个步骤:

gcc -E -o hello.i hello.c
gcc -S -o hello.s hello.i
gcc -c -o hello.o hello.s
gcc -o hello hello.o

1)执行 gcc -E -o hello.i hello.c  生成的hello.i文件

进行预处理把.c文件里的头文件找到,编译开关用起来,宏定义展开

2)执行gcc -S -o hello.s hello.i  生成的hello.s文件

进行编译生成各种汇编

3)执行 gcc -c -o hello.o hello.s 生成hello.o文件

进行汇编生成机器语言

4)执行 gcc -o hello hello.o 生成hello文件

进行链接为应用程序

(3)gcc 使用示例

gcc hello.c // 输出一个名为 a.out 的可执行程序,然后可以执行./a.out
gcc -o hello hello.c // 输出名为 hello 的可执行程序,然后可以执行./hello
gcc -o hello hello.c -static // 静态链接
gcc -c -o hello.o hello.c // 先编译(不链接)
gcc -o hello hello.o // 再链接

(4)常用编译选项

       在我们编程中会经常出现找不到头文件的错误,我们可以指定执行当前目录,当前目录没有的时候再去系统文件库里寻找。  

(5)怎么编译多个文件

1)一起编译、链接:

gcc -o test main.c sub.c

2)分开编译,统一链接:

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

(6)制作、使用动态库

第1步 制作、编译:

book@100ask:~/02_multi_files$ gcc -c -o main.o main.c
book@100ask:~/02_multi_files$ gcc -c -o sub.o sub.c
book@100ask:~/02_multi_files$ gcc -shared -o libsub.so sub.o sub2.o sub3.o(可以使用多个.o 生成动态库)
book@100ask:~/02_multi_files$ gcc -o test2 main.o -L ./ -lsub

第2步 运行:

先把 libsub.so 放到 Ubuntu 的/lib 目录,然后就可以运行 test2程序。

如果不想把 libsub.so 放到/lib,也可以放在某个目录比如/a,然后如下执行:

book@100ask:~/02_multi_files$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

(7)制作、使用静态库

book@100ask:~/02_multi_files$ gcc -c -o main.o main.c
book@100ask:~/02_multi_files$ gcc -c -o sub.o sub.c
book@100ask:~/02_multi_files$ ar crs libsub.a sub.o
book@100ask:~/02_multi_files$ gcc -o test main.o libsub.a

运行:不需要把静态库 libsub.a 放到板子上。

注意:执行   arm-buildroot-linux-gnueabihf-gcc -c -o sub.o sub.c   交叉编译需要在最后面加上-fPIC 参数。

(8)动态库与静态库区别

test:链接了静态库libsub.a,但是其他库是动态链接的

test2:链接了动态库libsub.so,其他库也是动态链接的

(9)很有用的选项

gcc -E main.c // 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt // 把所有的宏展开,存在 1.txt 里
gcc -Wp,-MD,abc.dep -c -o main.o main.c // 生成依赖文件 abc.dep,后面 Makefile 会用
echo 'main(){}'| gcc -E -v - // 它会列出头文件目录、库目录(LIBRARY_PATH)


目录
相关文章
|
1月前
|
Linux 编译器 开发工具
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
116 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
Linux 编译器 C语言
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
|
1月前
|
Linux
Linux - 如何编译源码安装软件
源码编译安装通常包括三个步骤:1) `./configure` 检测平台特征和依赖项,生成 Makefile;2) `make` 编译源码,生成可执行文件;3) `make install` 将可执行文件安装到指定目录并配置环境变量。
58 0
|
2月前
|
Linux 编译器 C语言
Linux c/c++之多文档编译
这篇文章介绍了在Linux操作系统下使用gcc编译器进行C/C++多文件编译的方法和步骤。
49 0
Linux c/c++之多文档编译
|
2月前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
|
3月前
|
Linux
用clang编译Linux内核
用clang编译Linux内核
|
3月前
|
Linux 编译器 C语言
Linux内核对GCC版本的检测
Linux内核对GCC版本的检测
|
4月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
155 3
|
4月前
|
Linux C语言
深度探索Linux操作系统 —— 编译过程分析
深度探索Linux操作系统 —— 编译过程分析
37 2