lcc 源码 高版本编译器编译-Linux下源码编译安装解读

前言

运行源代码,必须首先将其转换二进制机器代码。 这是编译器的工作

例如下面的源代码(假设文件名为test.c)。

#include intmain(void) { fputs("Hello,world!n",stdout); 返回0; }

需要经过编译器处理后才能运行。

$gcctest.c $./a.out 你好世界

对于复杂项目,编译过程也必须分为三个步骤

$./configure $make $makeinstall

编译过程流程图

1.编译的具体过程

1.配置

编译器开始工作之前,需要知道当前系统环境,比如标准库在哪里,软件安装在哪里,需要安装哪些组件等。这是因为不同计算机系统环境是不同的。 通过指定编译参数,编译器可以灵活适应环境,编译出可以在各种环境下运行的机器代码。 这个确定编译参数的步骤称为“配置”。

此配置信息存储配置文件中,按照惯例,该文件是一个名为configure的脚本文件。 通常它是由 autoconf 工具生成的。 编译器通过运行此脚本来了解编译参数。

配置脚本已尽力考虑到不同系统之间差异,并为各种编译参数提供了默认值。 如果用户的系统环境不寻常或者有一些特定的要求,他或她需要自动向configure脚本提供编译参数。

$./configure--prefix=/www--with-mysql

上面的代码是PHP源码的编译配置。 用户指定安装的文件保存在www目录下,编译时添加对mysql模块支持

2.确定标准库和头文件的位置

源代码肯定会使用标准库函数和头文件。 它们可以存储在系统上的任何目录中。 编译器实际上没有办法手动测量它们的位置,只能通过配置文件知道。

编译的第二步是从配置文件中知道标准库和头文件的位置。 一般来说,配置文件会给出几个具体目录的列表。 编译时,编译器会去这些目录中寻找目标

3. 确定依赖关系

对于小型项目,源代码文件之间往往存在依赖关系,编译器需要确定编译的顺序。 假设文件A依赖于文件B,编译器应该确保以下两点。

(1) 只有当B文件编译完成后,才开始A文件的编译。 (2) 当文件B改变时,文件A将被重新编译。

编译顺序存储在一个名为 makefile 的文件中,该文件列出了应该先编译哪个文件以及应该稍后编译哪个文件。 makefile文件是通过运行configure脚本生成的,这就是为什么编译时必须先运行configure。

在确定依赖关系的同时,编译器还会确定编译期间将使用哪些头文件。

4.头文件的预编译

不同的源代码文件可能引用相同的头文件(例如stdio.h)。 编译时,头文件也必须一起编译。 为了节省时间,编译器会在编译源代码之前先编译头文件。 这样可以保证头文件只需要编译一次,不需要每次使用时都重新编译。

然而,并不是头文件的所有内容都会被预编译。 用于声明宏的#define命令不会被预编译。

5. 预处理

预编译完成后,编译器开始替换源代码中的bash头文件和宏。 以本文开头源码为例。 它包含头文件stdio.h。 替换看起来如下。

externintfputs(constchar*,FILE*); 外部文件*标准输出; intmain(void) { fputs("Hello,world!n",stdout); 返回0; }

为了方便阅读,上面的代码只截取了头文件中与源代码相关部分,即fputs和FILE的声明,省略了stdio.h的其他部分(因为它们很长) )。 另外,上面代码的头文件并没有预编译,但实际上是在预编译结果插入了源代码。 编译器会在这一步删除注释

此步骤称为“预处理”,因为完成后才开始真正的处理。

6. 编译

lcc 源码 高版本编译器编译-Linux下源码编译安装解读

预处理后,编译器开始生成机器代码。 对于个别编译器来说,有一个中间步骤,首先将源代码转换为汇编代码(汇编),然后将汇编代码转换为机器代码。

以下是由本文开头的源代码转换而来的汇编代码。

.file "test.c" .section .rodata .LC0: .string"Hello,world!n" .text .globl main .type main,@function main: .LFB0: .cfi_startproc Pushq %rbp .cfi_def_cfa_offset16 .cfi_offset6, -16 movq %rsp,%rbp .cfi_def_cfa_register6 movq stdout(%rip),%rax movq %rax,%rcx movl $14,%edx movl $1,%esi movl $.LC0,%edi 调用 fwrite movl $0,%eax popq %rbp .cfi_def_cfa7,8 ret .cfi_endproc .LFE0: .size main,.-main .ident "GCC🙁Debian4.9.1-19)4.9.1" .section .note.GNU-stack,"",@progbits

这个转码后的文件称为目标文件。

注:make(gcc),调用gcc进行编译的过程依赖于配置文件makefile

7. 链接

目标文件还不能运行,必须进一步转换为可执行文件。 如果仔细看上一步的转码结果,你会发现引用了stdout函数和fwrite函数。 也就是说,程序要正常运行,除了前面的代码之外,还必须有stdout和fwrite这两个函数的代码,这两个函数是C语言的标准库提供的。

编译器的下一步是将外部函数的代码(通常是后缀为.lib和.a的文件)添加到可执行文件中。 这称为链接。 这种通过复制方式将外部函数库添加到可执行文件中的方法称为静态链接。 稍后我们会提到动态链接。

make命令的作用是从第四步头文件预编译开始,直到这一步完成。

8. 安装

上一步中的连接是在显存中进行的,即编译器在显存中生成可执行文件。 接下来,必须将可执行文件保存到用户预先指定的安装目录中。

表面上看,这一步很简单,只需复制可执行文件(连同相关数据文件)即可。 但实际上,这一步还必须完成创建目录、保存文件、设置权限等步骤,这整个保存过程就称为“安装”。

9. 操作系统连接

可执行文件安装后,必须以某种方式通知操作系统,让它知道该程序可以使用。 例如,如果我们安装一个文本阅读程序,我们经常希望双击txt文件,该程序就会手动运行。

这就需要在操作系统中注册这个程序的元数据:文件名、文件描述关联的后缀名等。在Linux系统中,这些信息一般存储在/usr/share/applications目录下的.desktop文件中。 另外,在Windows操作系统中,还需要在开始菜单中创建快捷方式。

这些东西被称为“操作系统连接”。 make install命令用于完成“安装”和“操作系统连接”两个步骤。

10.生成安装包

至此,整个源码编译的过程就基本完成了。 然而,只有极少数用户愿意耐心地从头到尾经历这个过程。 事实上,如果你只有源代码交给用户,他们会认为你是一个不友好的人。 大多数用户想要的是一个可以立即运行的二进制可执行程序。 这就需要开发者将上一步生成的可执行文件制作成可以分发的安装包。

因此,编译器还必须具有生成安装包的功能。 通常,可执行文件(连同相关数据文件)以一定的目录结构保存成压缩文件包,交给用户。

11. 动态链接

正常情况下,此时程序已经准备好运行了。 运行时发生的事情与编译器无关。 不过,开发人员可以在编译阶段选择可执行文件与外部函数库的连接形式,无论是静态连接(编译时连接)还是动态连接(运行时连接)。 因此,最后要提到的就是所谓的动态连接。

前面提到,静态链接就是将外部函数库复制到可执行文件中。 这样做的好处适用范围更广,不用担心用户的机器缺少某个库文件; 缺点是安装包会比较大,并且库文件无法在多个应用程序之间共享。 动态链接的方法恰恰相反。 外部函数库不进入安装包,仅在运行时动态引用。 优点是安装包会比较小,多个应用可以共享库文件; 缺点是用户必须提前安装库文件lcc 源码 高版本编译器编译,且版本和安装位置必须符合要求,否则无法正常运行。

实际上,大多数软件都使用动态连接和共享库文件。 这种动态共享库文件在Linux平台上是后缀为.so的文件,在Windows平台上是.dll文件,在Mac平台上是.dylib文件

2、Linux编译安装具体实现

1、源程序编译安装前提条件

1)。 提供开发环境:开发工具和开发库

2)。 编译并安装所需的包组:

开发工具、服务器平台开发、桌面平台开发、调试工具

2.configure脚本中常用选项

--help 获取./configure脚本帮助 --prefix=:指定安装路径; 大多数程序都有默认安装路径; --sysconfidr=:指定配置文件安装路径; --with-PACKAGE[=ARG]:在自由软件中,社区有着使用现有软件包和库的悠久传统。 当使用‘configure’配置一个源码树时,可以提供其他已经安装的软件包的信息 --without-PACKAGE: 有时你可能不希望这个软件包与系统中已有的软件包进行交互。例如,你可能不希望你的新编译器使用GNUld --enable-FEATURE:某些软件包可能提供一些默认情况下严格禁止的功能,可以使用'--enable-FEATURE'启用 --disable-EEATURE:关闭指定的默认值特征

3、编译安装源程序方法:

1)展开源代码,查找INSTALL和README; 如果此类文件不存在,请查找官方项目文档

2)按照安装说明进行安装操作;

3.当程序安装在专用目录时,安装后的配置:

1)将二进制程序的路径导出到PATH环境中

#exportPATH=/usr/local/nginx/sbin:$PATH 永久有效的方法:/etc/profile.d/*.sh

2)导出库文件到操作系统

操作系统如何搜索库文件:根据/etc/ld.so.conf配置文件中指定的路径搜索,或者搜索/lib、/lib64、/usr/lib、/usr/lib64,并将找到的所有库合并起来文件路径及其名称映射关系保存为缓存文件/etc/ld.so.cache;

/etc/ld.so.conf 配置文件还有其他组件: /etc/ld.so.conf.d/*.conf

假设nginx安装在/usr/local/nginxlcc 源码 高版本编译器编译,该目录下有其库文件子目录lib。 导出该目录下的库文件:

(1)创建一个新文件/etc/ld.so.conf.d/nginx.conf,并在文件中添加以下几行:

/usr/local/nginx/lib

(2)运行命令:ldconfig

ldconfig的主要用途

默认情况下,会搜索并拯救/lilb和/usr/lib,以及配置文件/etc/ld.so.conf中列出的目录中的库文件。

搜索可共享的动态链接库。 库文件的格式为:lib***.so.**,然后创建动态放置程序所需的连接和缓存文件(ld.so)。

缓存文件默认为/etc/ld.so.cache,它存储动态链接库名称的排序子列表。

ldconfig通常在系统启动时运行,但是当用户安装新的动态链接库时,需要手动运行该命令。

常用选项:

-v:使用该选项时,ldconfig将显示正在扫描的目录和搜索到的动态链接库,以及它创建的连接的名称。 -p:显示当前OS已加载的所有库文件的名称及其文件所在路径的映射关系;

ldconfig 需要注意事项

(a) 在/lib和/usr/lib中添加东西时不需要更改/etc/ld.so.conf文件,但添加后需要调用ldconfig,否则将找不到添加的库。

(b) 如果添加的库不在/lib和/usr/lib之上,则必须更改/etc/ld.so.conf文件,将库的路径添加到该文件中,然后再次调用ldconfig命令。 。 例如,安装mysql时,需要将其库文件/usr/local/mysql/lib追加到/etc/ld.so.conf文件中。 命令如下:

#echo"/usr/local/mysql/lib">>/etc/ld.so.conf #ldconfig -v|grepmysql

(c) 如果添加的库不在/lib或/usr/lib下,但没有写入/etc/ld.so.conf文件的权限,那么需要在export中写入一个全局变量LD_LIBRARY_PATH,并且就是这样。 。

(3)。 帮助文件导入

man 命令搜索特定路径以查找指南页文件。 这些路径定义在/etc/man.config中MANPATH参数指定的路径中;

新方法:编辑/etc/man.config文件,添加一个MANPATH参数,其值为新安装程序的man指南所在目录;

/usr/local/nginx/share/man/{man1,man8} man-M/path/to/manKEYWORD

(4)、头文件导入

有些程序安装后,会为自己的库文件生成socket相关的头文件。 系统搜索头文件的路径是/usr/include。

如何导出独立安装的应用程序的头文件:创建到/usr/include的链接;

例如:

/usr/local/nginx/include #ln-sv/usr/local/nginx/include/*/usr/include/ #ln-sv/usr/local/nginx/include/usr/include/nginx

如何编译安装perl源程序:

(1)perlMakefile.in (2)make (3)makeinstall

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 lcc 源码 高版本编译器编译-Linux下源码编译安装解读 https://www.wkzy.net/game/201748.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务