从零开始构建Linux

目的:深入了解以Linux内核为基础的系统是如何组成,运行,以构建一个最基础的,纯净的系统。

LFS构建步骤
宿主机准备
- linux操作系统安装
- 使用独立硬盘,创建分区
- 配置用户和组
- 下载所有需要的软件包源代码
准备开发环境
构建一个基本开发环境
构造完整的目标系统
配置系统启动脚本
启动系统

一、宿主系统准备
1.1.安装所需要依赖包

[root@node ~]# yum install -y bash binutils bison bzip2 coreutils diffutils findutils gawk gcc glibc grep gzip kernel m4 make patch perl sed tar texinfo xz gcc-c++ flex

检查

cat > version-check.sh << "EOF"
#!/bin/bash
# Simple script to list version numbers of critical development tools
export LC_ALL=C
bash --version | head -n1 | cut -d" " -f2-4
MYSH=$(readlink -f /bin/sh)
echo "/bin/sh -> $MYSH"
echo $MYSH | grep -q bash || echo "ERROR: /bin/sh does not point to bash"
unset MYSH
echo -n "Binutils: "; ld --version | head -n1 | cut -d" " -f3-
bison --version | head -n1
if [ -h /usr/bin/yacc ]; then
echo "/usr/bin/yacc -> `readlink -f /usr/bin/yacc`";
elif [ -x /usr/bin/yacc ]; then
echo yacc is `/usr/bin/yacc --version | head -n1`
else
echo "yacc not found"
fi
bzip2 --version 2>&1 < /dev/null | head -n1 | cut -d" " -f1,6-
echo -n "Coreutils: "; chown --version | head -n1 | cut -d")" -f2
diff --version | head -n1
find --version | head -n1
gawk --version | head -n1
if [ -h /usr/bin/awk ]; then
echo "/usr/bin/awk -> `readlink -f /usr/bin/awk`";
elif [ -x /usr/bin/awk ]; then
echo awk is `/usr/bin/awk --version | head -n1`
else
echo "awk not found"
fi
gcc --version | head -n1
g++ --version | head -n1
ldd --version | head -n1 | cut -d" " -f2- # glibc version
grep --version | head -n1
gzip --version | head -n1
cat /proc/version
m4 --version | head -n1
make --version | head -n1
patch --version | head -n1
echo Perl `perl -V:version`
sed --version | head -n1
tar --version | head -n1
makeinfo --version | head -n1
xz --version | head -n1
echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c
if [ -x dummy ]
then echo "g++ compilation OK";
else echo "g++ compilation failed"; fi
rm -f dummy.c dummy
EOF
[root@node ~]# bash version-check.sh 
bash, version 4.2.46(2)-release
/bin/sh -> /usr/bin/bash
Binutils: version 2.27-34.base.el7
bison (GNU Bison) 3.0.4
yacc not found  ##使用bison来替代 ,语法分析器
[root@node ~]# ln -sv /usr/bin/bison /usr/bin/yacc
‘/usr/bin/yacc’ -> ‘/usr/bin/bison’

Also check for some library consistency:
cat > library-check.sh << "EOF"
#!/bin/bash
for lib in lib{gmp,mpfr,mpc}.la; do
echo $lib: $(if find /usr/lib* -name $lib|
grep -q $lib;then :;else echo not;fi) found
done
unset lib
EOF
[root@node ~]# bash library-check.sh 
libgmp.la: not found
libmpfr.la: not found
libmpc.la: not found

  

1.2.术语说明
- 宿主系统 host system(用于制作系统的系统)
- 目标系统 target system(最终制作出来的系统)
- 临时系统 temporary system(在制作系统过程中,需要一个小型过渡的系统,这个系统在帮助完成目标系统制作后就不使用)
- 编译工具 compiler(gcc等)
- 工具链 tools chain(开发中有很多依赖,为了不重复开发,可以做成公共的来调用 )
- 原工具链: 宿主系统的工具链
- 预工具链:用于生成临时工具链的工具链
- 临时工具链:用于生成临时系统的工具链
- 目标工具链:用于生成目标系统的工具链
- 辅助工具 associated tools(除编译外,类似make这种辅助的)
- 运行环境 running environment(运行系统上可有多个环境,这些环境有各自root目录和环境的设置)
头文件:C开发,在编译时以.h结尾,存放函数,接口的描述,结构体信息
纯净度:当前系统与依赖于其他系统的相关性

 

1.3.源代码编译过程:源代码编译成可执行文件流程


描述:三个阶段
- 配置configure
生成配置文件,文件名通常是makefile
- 编译make
最复杂阶段,根据配置生成的makefile,执行一系列动作,如创建一些必要的文件,调用工具链环境中的命令来编译源代码和链接目标文件,
最终生成所需要的可执行文件,函数库和各种辅助文件


- 安装make install
copy到相应的目录中

 

1.4.工具链(vim例子)
描述:linux下二进制文件都采用共享库的运行方式,可以减少程序文件的代码量,使用应用程序占用的空间更小,
运行过程中要访问共享库,必须存在系统中,而且要在搜索路径中可以找到,如果共享库丢失或者应用程
序找不到就会报错
vim:
vim的所编译过程: 依赖于各种库,要编译vim,vim依赖于ncurses,ncurses依赖于glibc,这种依赖关系就是工具链,由编译器,汇编器,和相应的库函数组成的,在linux上常使用的是gcc,bintuils,和glibc组合的工具链,工具链的原则是从某一个工具链编译出来的二进制文件或者库函数文件,必须链接到该工具的函数库,无论是静态还是动态,从图上可以看出ncurses和vim都是链接在glibc上,也就是工具链的函数库部分就是glibc,glibc是"自给自足的"的,不依赖于函数库就可以完成编译的链接,最终要制作的系统包含完整的工具链,因为希望目标系统是一个纯净的系统,可以独立运行,不依赖于外部,所以其中的工具链到最终是要依赖于工具链内部的glibc,可以通过工具链的两种依赖方式,可以很方便从源生最原始的工具链到制作出来的工个链

- gcc、binutiils运行时依赖于glibc
- 外部依赖:依赖于工具链之外的glibc
- 内部依赖:依赖于工具链中的glibc
图中的软件包存在依赖关系,有依赖必须先安装,要编译vim要先编译ncurses,要编译ncurses,要先安装glibc,决定了要按次顺来操作,一般生成共享库或程序文件时,链接器来链接所依赖的函数库,因次在编译某个软件包前,编译它所依赖的软件不仅是要安装头文件,还是因为在用到它所提供的函数库,否则就无法完成编译链接的过程.
linux内核部分:虽然运行任何程序都要使用到内核,但是在制作目标系统的过程中,目标系统的内核并不需要先编译和安装,因为使用Linux内核并不像使用glibc需要使用动态链接库来调用,内核的调用是通过glibc的各种函数库,或其他函数库通过系统调用来进行的,所以并不需要一开始编译安装内核,只需要内核所需要的头文件就可以.

[root@node ~]# ldd /usr/bin/vim
	linux-vdso.so.1 =>  (0x00007ffd621f3000)
	libm.so.6 => /lib64/libm.so.6 (0x00007fd292cf8000)
	libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fd292ad0000)
	libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007fd2928a6000)
	libacl.so.1 => /lib64/libacl.so.1 (0x00007fd29269d000)
	libgpm.so.2 => /lib64/libgpm.so.2 (0x00007fd292495000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007fd292291000)
	libperl.so => /usr/lib64/perl5/CORE/libperl.so (0x00007fd291f03000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd291ce6000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fd291919000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fd293000000)
	libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fd2916b8000)
	libattr.so.1 => /lib64/libattr.so.1 (0x00007fd2914b2000)
	libncurses.so.5 => /lib64/libncurses.so.5 (0x00007fd29128b000)
	libresolv.so.2 => /lib64/libresolv.so.2 (0x00007fd291072000)
	libnsl.so.1 => /lib64/libnsl.so.1 (0x00007fd290e57000)
	libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fd290c20000)
	libutil.so.1 => /lib64/libutil.so.1 (0x00007fd290a1d000)
	libfreebl3.so => /lib64/libfreebl3.so (0x00007fd290819000)

  

1.5.工具链制作关系
描述:工具链是由编译器,汇编器,函数库等组成的,工具链有两种依赖方式,图中从原工具链A等通过工具链B生成目标系统的工具链C,C与A没有关系,所以是纯净的,但是还是需要临时工具链B的帮助


工具链分步实现过程
- 最开始原系统只有一个工具链A


- 使用工具链A生成gcc_B和binutils_B,由于工具链之间的依赖关系,gcc_B和binutils_B都链接到glibA上,这时还不构成完整的工具链,因为要依赖于工具链A的glibA,不是纯净的工具链依赖于外部


- 编译成一个新的程序A,依赖于gcc_B和binutils_B,glib_A


- 编译出一个新的glib_B


- 把gcc_B和binutils_B的链接对象调整为glib_B,这时可以形成完整的工具链B


- 工具链B可以编译成一个新的应用程序B,它依赖于glibc_B,这种属于外部依赖


- 使用现有的临时工具链,编译出gcc_C和binutils_C,形成工具链C,它使用工具链B的glibc_B作为函数库,形成与原始没关系纯净的目标系统的工具链C


summary: 整个过程的关键点是编译工具可以修改指定的函数库,也就是可以修改依赖方式,通过设置内部和外部依赖的相互转换,工具链B从内部依赖变成外部依赖,这个过程称为调整工具链,以最终实现纯净的一个工具链C

 

1.6.制作步骤概述


描述:三个阶段按顺序依次执行,每个阶段都为下个阶段做准备,而且三个阶段都是相互交叉,上一个阶段为下一阶段做准备
- 预工具链阶段
- 临时系统阶段
- 目标系统阶段
过程:
- 宿主系统:要求并不高,与目标系统架构兼容,不兼容使用交叉编译制作,宿主系统包含工具链和辅助命令,在制作过程中称为源工具链
- 创建预工具链,为了建立临时工具链,预工具链是由源工具链生成,创建初是内部依赖方式的工具链,用它编译出来的工具链需要链接到
宿主系统的glibc上,
- 生成临时工具链,为了完成临时系统,它需要脱离宿主系统的运行环境,临时工具链本身也是临时系统的重要组成部分,预工具链负责生成临时系统的glibc,当glibc完成后,能预工具链的依赖关系进行调整,把预工具链变成外部依赖的工具链,调整完成后就生成临时编译工具,临时编译工具依赖于临时系统的glibc,临时编译工具与glibc组成临时工具链,这样预工具链的使命就完成了,由临时工具链替代预工具链进行临时系统的制作,这个临时工具链是内部依赖,它不依赖于宿系统的函数库
- 编译一个软件系统编译工具,通常还需要其他程序参与,只是靠临时工具链是无法完成对目标系统的制作的,所以需要一个相对完整的环境,所以是一个临时系统,临时系统的完成需要宿主系统的辅助命令参与,临时工具链将不依赖于宿主系统的辅助命令来编译软件,这样就可以为临时系统脱离宿主系统作好准备,临时工具链将继续完成临时系统的制作,制作临时系统的目的就是为制作目标系统提供一个不依赖于宿主系统的环境,临时工具链生成临时系统,可以保证各种工具软件所依赖的函数库是临时系统自身的函数库,而不是宿主系统的函数库,在完成临时系统的制作后,就可以让临时系统脱离原有的系统,用临时系统制作,就是为了让目标系统成为独立可扩展的系统,所以必须为目标系统生成一个目标工具链
- 用临时系统生成目标系统的glibc,然后调整临时工具链,使用其编译出来的程序文件和库文件链接到目标系统的glibc上,及从内部依赖变成外部系统的方式,在编译目标系统上的gcc,binutils,完成了目标工具链的建立,临时工具链完成它的使命,但是临时工具链中的辅助命令还要继续使用,直到目标工具链中有相应辅助,形成一个完整的目标工具链环境
- 为了让目标系统能自足进行更新扩展,目标系统也需要有最基本的编译环境,虽然已经生成目标工具链,但是辅助命令还是使用临时系统的,这时需要编译出来一些辅助命令,安装到目标系统中,从而形成目标工具链环境
- 在具体操作过程中,可以按照生成临时系统的内容编译各种辅助命令,也可以根据需要安装更多的辅助命令,或者是其他的程序,在目标工具链环境生成之后,就像生成一个车间,可以把目标环境系统进行进一步的完善,还要运行启动系统需要grub之类

 

1.7.磁盘分区准备

- 40GB: 8g是swap, 32g其他使用ext4
[root@node ~]# fdisk /dev/sdb
   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048    16779263     8388608   83  Linux
/dev/sdb2        16779264    83886079    33553408   83  Linux
[root@node ~]# mkswap /dev/sdb1
[root@node ~]# mkfs.ext4 /dev/sdb2

设置环境变量挂载
[root@node ~]# export LFS=/mnt/lfs
[root@node ~]# mkdir -pv $LFS
[root@node ~]# mount | grep $LFS
/dev/sdb2 on /mnt/lfs type ext4 (rw,relatime,seclabel,data=ordered)
[root@node ~]# source .bash_profile
[root@node ~]# tail -1 .bash_profile
export LFS=/mnt/lfs
或:
[root@node ~]# tail -1 /etc/fstab 
/dev/sdb2	/mnt/lfs	ext4	defaults 0 0
[root@node ~]# mount -a

  

二、软件包及补丁
下载地址:http://ftp.lfs-matrix.net/pub/lfs/lfs-packages/

[root@node ~]# mkdir -v $LFS/downloads

进行md5校验:
http://ftp.lfs-matrix.net/pub/lfs/lfs-packages/MD5SUMS
[root@node downloads]# md5sum lfs-packages-8.0.tar 
2d1672ebe969628fc53d483a898fb500  lfs-packages-8.0.tar
[root@node downloads]# tar xf lfs-packages-8.0.tar 
[root@node downloads]# mv 8.0/* .

创建源码目录:
[root@node ~]# mkdir $LFS/sources
[root@node ~]# chmod a+wt $LFS/sources

  

三、目录和专用用户准备
3.1.目录结构准备
- /mnt/lfs目录作为"创作基地"
- $LFS/tools是"临时系统"

[root@node ~]# mkdir $LFS/tools
- 在宿主系统中创建符号链接/tools的,将其指向$LFS/tools,目的是宿主系统运行环境和目标系统运行环境都可以使用/tools,指向临时目录使用的命令

[root@node ~]# ln -sv $LFS/tools /
‘/tools’ -> ‘/mnt/lfs/tools’

3.2.添加LFS用户

[root@node ~]# groupadd lfs
[root@node ~]# useradd -s /bin/bash -g lfs -m -k /dev/null lfs
#-k指定一个空设备,是防止从/etc/skel中复制模板,不使用发行版的模板,完全自定义
[root@node ~]# echo lfs | passwd --stdin lfs
[root@node ~]# chown lfs $LFS/tools 
[root@node ~]# chown lfs $LFS/sources 
[root@node ~]# ls -l $LFS
total 28
drwxr-xr-x. 3 root root  4096 Jan  6 17:00 downloads
drwx------. 2 root root 16384 Jan  6 15:57 lost+found
drwxrwxrwt. 2 lfs  root  4096 Jan  6 16:32 sources
drwxr-xr-x. 2 lfs  root  4096 Jan  6 17:07 tools

3.3.创建简单的环境变量

[root@node ~]# su - lfs
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF

cat > ~/.bashrc << "EOF"
set +h     #关闭bash的hash功能,随后有些工具要马上生效,如果更新缓存需要时间
umask 022  
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu  #编译的架构要一致,如果不一样要调
PATH=/tools/bin:/bin:/usr/bin      #搜索路径,而且hash,可以让它马上生效
export LFS LC_ALL LFS_TGT PATH
EOF

检查:
[root@node ~]# su - lfs
Last login: Sun Jan  6 17:17:29 CST 2019 on pts/0
lfs:~$ export
declare -x HOME="/home/lfs"
declare -x LC_ALL="POSIX"
declare -x LFS="/mnt/lfs"
declare -x LFS_TGT="x86_64-lfs-linux-gnu"
declare -x OLDPWD
declare -x PATH="/tools/bin:/bin:/usr/bin"
declare -x PS1="\\u:\\w\\\$ "
declare -x PWD="/home/lfs"
declare -x SHLVL="1"
declare -x TERM="xterm"

  

3.4.软件包的编译时间
- SBU是标准编译单位,使用binutils作为一个值,其他与它来作比较
- 通过time来确定

 

3.5.测试
描:include一个标准的io输入,在函数主体打印一个hello world,返回0,没有语法错误是正常

cat > test.c << "EOF"
#include <stdio.h>
main()
{
    printf("hello World\n");
    return 0;
}
EOF
lfs:~$ gcc test.c 
lfs:~$ ls
a.out  test.c
lfs:~$ ./a.out 
hello World

  

四、构建临时系统
描述:要制作临时工具链,要先生成一个预工具链,LFS文档中并不没有提及,是为了更好理解
- 利用宿主系统安装的组件生成预工具链,再使用预工具链生成临时工具链,再根据临时工具链生成辅助命令,形成临时系统
- 预工具链主要有两个工具:汇编链接器bintuils和gcc
- 构建临时系统
- 构建与宿主系统无关的临时工具链,包括库,编译器,汇编器等
- 使用临时工具链生成辅助命令
- 最终要实现临时系统是要安装在lfs目录下tools目录,与宿主系统目录分开,与目标系统目录也分开

4.1.编译的次序
- 预工具链

  Bintuils-2.27  gcc和glibc的configure命令都会需要一些汇编器和链接器的检查测试,所以首先要编译安装bintuils
[root@node ~]# type ld  GUN链接器,把目标文件链接到可执行程序
ld is /usr/bin/ld
[root@node ~]# whatis ld
ld (1)               - The GNU linker
[root@node ~]# whereis ld
ld: /usr/bin/ld /usr/bin/ld.bfd /usr/bin/ld.gold /usr/share/man/man1/ld.1.gz
[root@node ~]# ld --verbose | grep SEARCH  链接器重要配置是库文件从那里搜索,以下是宿主系统中默认的
SEARCH_DIR("=/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");

当使用gcc编译程序时,如果使用gcc参数--verbose,它调用链接器时也会传参数,可以把ld里链接那些文件都显示出来
[root@node tmp]# gcc test.c -Wl,--verbose 2>&1 |grep succ 把预处理,编译,汇编的过程都显示,还包括gcc的include搜索次序
attempt to open /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o succeeded
attempt to open /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o succeeded
attempt to open /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o succeeded
attempt to open /tmp/ccG2XNzN.o succeeded

  GCC-6.3.0
  Linux-4.9.9 API Headers  把头文件copy到tools目录下,可以使用是glibc与内核进行个性化交互

- 临时工具链

  Glibc-2.25       考虑编译器和头文件的来源
  Libstdc++-6.3.0  标准c++库
  Binutils-2.27    第二次,要通过一个开关项指定ld的搜索路径--with-lib-path=/tools/lib,使用得临时工具链的生成与宿主系统作一个隔离
  GCC-6.3.0        第二次gcc,也要调整,要直接修改gcc的源代码文件,告诉gcc以后使用的动态链接器要使用自己的,不修改会嵌入宿主系统的/lib一般动态库,造成可能不纯净

- 辅助命令

 

4.2.GUN screen命令
编译流程:编译时间过长
- 进入到LFS的源文件目录,即用sources目录
- 以lfs用户身份,解压要编译的软件包
- 进入到解压后创建目录中
- 根据指南说明编译、检查、安装软件包
- 回退到源文件目录
- 除非特别说明,删除解压出来的目录和所有编译过程中生成的目录

GUN screen使用的场景
- 需要长时间连接
- 防止意外网络中断
功能:
- 会话恢复:只要screen进程没有被终止,在其内部运行的会话就可以恢复,登录主机screen -r恢复,如果暂时性离开,可以使用分离命令detach保证其中的程序正常的运行,把session进行挂起,切换到后台,在screen中每个会话都是独立运行的,每个会话各自编号自己的输入输出缓存,
- 多窗口
- 会话共享:有些人可能会使用QQ提供远程协助的技术支持,screen也可以让一个或多个用户从不同终端多次登录到一个会话中,并且共享会话中所有特性,看到是相同完全一样的输出,提供窗口访问控制权的限制,对窗口进行密码保护

[root@node ~]# yum install screen -y
screen [-AmRvx -ls -wipe][-d <作业名称>][-h <行数>][-r <作业名称>][-s ][-S <作业名称>]
参数说明
-A  将所有的视窗都调整为目前终端机的大小。
-d <作业名称>  将指定的screen作业离线。
-h <行数>  指定视窗的缓冲区行数。
-m  即使目前已在作业中的screen作业,仍强制建立新的screen作业。
-r <作业名称>  恢复离线的screen作业。
-R  先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-s  指定建立新视窗时,所要执行的shell。
-S <作业名称>  指定screen作业的名称。
-v  显示版本信息。
-x  恢复之前离线的screen作业。
-ls或--list  显示目前所有的screen作业。
-wipe  检查目前所有的screen作业,并删除已经无法使用的screen作业。          

常用参数:
列出当前所有的session,当着有当前活动有人使用,另一个是已经分离
screen ls

新建一个叫reid的session
screen -S reid

回到reid这个session
screen -r reid

远程detach某个session
screen -d reid

结束当前session 并回到reid这个session
screen -d -r reid

在每个screen session 下,所有命令都以 ctrl+a(C-a) 开始。
注:技巧,是按完ctrl+a后松开,再按如shift ?,要松开ctril+a再按其他键
C-a ? -> 显示所有键绑定信息
C-a c -> 创建一个新的运行shell的窗口并切换到该窗口
C-a n -> Next,切换到下一个 window 
C-a p -> Previous,切换到前一个 window 
C-a 0..9 -> 切换到第 0..9 个 window
Ctrl+a [Space] -> 由视窗0循序切换到视窗9
C-a C-a -> 在两个最近使用的 window 间切换 
C-a x -> 锁住当前的 window,需用用户密码解锁
**C-a d -> detach,暂时离开当前session,将目前的 screen session (可能含有多个 windows) 丢到后台执行,并会回到还没进 screen 时的状态,此时在 screen session 里,每个 window 内运行的 process (无论是前台/后台)都在继续执行,即使 logout 也不影响。 
C-a z -> 把当前session放到后台执行,用 shell 的 fg 命令则可回去。
C-a w -> 显示所有窗口列表
C-a t -> Time,显示当前时间,和系统的 load 
C-a k -> kill window,强行关闭当前的 window
C-a [ -> 进入 copy mode,在 copy mode 下可以回滚、搜索、复制就像用使用 vi 一样
    C-b Backward,PageUp 
    C-f Forward,PageDown 
    H(大写) High,将光标移至左上角 
    L Low,将光标移至左下角 
    0 移到行首 
    $ 行末 
    w forward one word,以字为单位往前移 
    b backward one word,以字为单位往后移 
    Space 第一次按为标记区起点,第二次按为终点 
    Esc 结束 copy mode 
C-a ] -> Paste,把刚刚在 copy mode 选定的内容贴上

操作:
[root@node ~]# screen -S backup  退出ctrl+a  再按d
[detached from 12849.backup]  暂时离开,到后台执行
[root@node ~]# screen -ls
There is a screen on:
	12849.backup	(Detached)    job的名称
1 Socket in /var/run/screen/S-root.
[root@node ~]# screen -r backup   恢复

[root@node ~]# screen -S vim-opt vim tom.txt
[detached from 12866.vim-opt]

[root@node ~]# screen -ls
There are screens on:
	12866.vim-opt	(Detached)
	12849.backup	(Detached)
2 Sockets in /var/run/screen/S-root.

使用id恢复:
[root@node ~]# screen -r 12866

看多个ctrl+a 再按w
ctrl+a 再按c,创建一个新的screen

清除dead会话 screen -wipe

关闭或杀死窗口 ctrl+a  K

screen高级应用
- 会话共享        screen -x
[root@node ~]# screen -S kk
[root@node ~]# screen -x kk  进入到同一个会话
- 会话锁定与解锁  ctrl+a s   ctrl+a q   屏幕不输出,但是还是会被接收,想不给其他人看见时先按ctrl+a s
- 发送命令到screen     screen -S reid -X screen ping ip
- 屏幕分割         ctrl+a S   ctrl+a |
- 复制、粘贴模式   ctrl+a <Esc> 或copy:ctrl+a [  paste: ctrl+a ]

4.3.Binutils的第一遍

[root@node ~]# screen 
[root@node ~]# su - lfs
Last login: Sun Jan  6 17:22:48 CST 2019 on pts/0
lfs:~$ cd $LFS/sources 
lfs:/mnt/lfs/sources$ tar xf $LFS/downloads/binutils-2.27.tar.bz2 
lfs:/mnt/lfs/sources$ cd binutils-2.27/  
#包括链接器,汇编器,和其他处理工具,之所以第一个处理binutils是因为他们的gcc,glibc的configure阶段会对链接器等做检查
lfs:/mnt/lfs/sources/binutils-2.27$ mkdir build
lfs:/mnt/lfs/sources/binutils-2.27$ cd build
lfs:/mnt/lfs/sources/binutils-2.27/build$  
#一般linux源代码都需要配置值,过程可以检查环境的状态,与及配值自身的选项,还可以通过参数设置出来的软件是启用或禁用
lfs:/mnt/lfs/sources/binutils-2.27/build$ time ../configure --prefix=/tools \
 --with-sysroot=$LFS \
 --with-lib-path=/tools/lib \
 --target=$LFS_TGT \
 --disable-nls \
 --disable-werror
解释:
-prefix=/tools  软件包安装目录,同时也为其他目录设置一个基础的目录,相当于windows安装时的一个自定义目录
--with-sysroot=$LFS  交叉编译用于告诉编译系统在那查找所需要的文件,
--with-lib-path=/tools/lib  编译好后链接器一些库的路径存放的位置
--disable-nls   国际语言支持,根据不同的语言环境变量来显示语言环境的技术,由于是做一个预工具链的binutils,不需要长期使用,
                所以在编译时,可以禁用这个功能,从而加快编译的速度
--disable-werror 禁止宿主机上的一些警告事件,以防编译的终止
configure命令:主要是检查平台安装的一些特性,检测到是cc,还是gcc,configure是一个shell脚本,make是用来编译的,configure检查
               后,最终会生成一个makefile,make就通过这个makefile来读取指令,make install是用来进行安装,也是通过makefile来
               读取指令,安装到相应的位置上,
               
时间:
real    0m13.983s  --
user    0m6.628s
sys     0m7.193s

lfs:/mnt/lfs/sources/binutils-2.27/build$ time make
real    10m20.188s
user    7m10.288s
sys     3m19.655s

- 如果在x86_64上编译,需要创建一个符号文件来确保工具链的完整性
lfs:/mnt/lfs/sources/binutils-2.27/build$ ls /tools/ -l
total 0
lfs:/mnt/lfs/sources/binutils-2.27/build$ case $(uname -m) in
 x86_64) mkdir -v /tools/lib && ln -sv lib /tools/lib64 ;;
 esac
mkdir: created directory '/tools/lib'
'/tools/lib64' -> 'lib'
注:如果是x86_64实际会建一个lib文件夹,再做一个软件连接
lfs:/mnt/lfs/sources/binutils-2.27/build$ ls /tools/ -l
total 4
drwxr-xr-x. 2 lfs lfs 4096 Jan  6 20:15 lib
lrwxrwxrwx. 1 lfs lfs    3 Jan  6 20:15 lib64 -> lib

安装软件包:install相当于个copy的过程
lfs:/mnt/lfs/sources/binutils-2.27/build$ time make install
real    0m13.277s
user    0m5.955s
sys     0m7.826s
lfs:/mnt/lfs/sources/binutils-2.27/build$ ls /tools/ -l
total 16
drwxr-xr-x. 2 lfs lfs 4096 Jan  6 20:16 bin
drwxr-xr-x. 2 lfs lfs 4096 Jan  6 20:15 lib
lrwxrwxrwx. 1 lfs lfs    3 Jan  6 20:15 lib64 -> lib
drwxr-xr-x. 4 lfs lfs 4096 Jan  6 20:16 share
drwxr-xr-x. 4 lfs lfs 4096 Jan  6 20:16 x86_64-lfs-linux-gnu

删除编译目录和源代码目录:为了避免一些不必要的问题
lfs:/mnt/lfs/sources/binutils-2.27/build$ cd $LFS/sources 
lfs:/mnt/lfs/sources$ rm -rf binutils-2.27/

4.4.gcc第一遍

- 自己先做一个gcc
lfs:/mnt/lfs/sources$ tar xf ../downloads/gcc-6.3.0.tar.bz2
注:增加一些软件包,都与数据运算有关,gpm是任何精度的算法库,mpfr是一个高精度浮点算法库
lfs:/mnt/lfs/sources$ cd gcc-6.3.0/
lfs:/mnt/lfs/sources/gcc-6.3.0$ tar xf $LFS/downloads/mpfr-3.1.5.tar.xz 
lfs:/mnt/lfs/sources/gcc-6.3.0$ mv mpfr-3.1.5 mpfr
lfs:/mnt/lfs/sources/gcc-6.3.0$ tar xf $LFS/downloads/gmp-6.1.2.tar.xz  
lfs:/mnt/lfs/sources/gcc-6.3.0$ mv gmp-6.1.2 gmp
lfs:/mnt/lfs/sources/gcc-6.3.0$ tar xf $LFS/downloads/mpc-1.0.3.tar.gz 
lfs:/mnt/lfs/sources/gcc-6.3.0$ mv mpc-1.0.3 mpc

- 修改gcc默认动态链接库,把/lib或/lib64修改到/tools下
lfs:/mnt/lfs/sources/gcc-6.3.0$ 
注:在gcc原文件目录下,找到这几个文件linux,i386/linux{,64}}.h,对它们做备份,再做一个替换,把目录加个tools
for file in gcc/config/{linux,i386/linux{,64}}.h
do
cp -uv $file{,.orig}
sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \
-e 's@/usr@/tools@g' $file.orig > $file
echo '
#undef STANDARD_STARTFILE_PREFIX_1
#undef STANDARD_STARTFILE_PREFIX_2
#define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/"
#define STANDARD_STARTFILE_PREFIX_2 ""' >> $file
touch $file.orig
done

- 对平台做调整
lfs:/mnt/lfs/sources/gcc-6.3.0$
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac

- 创建新的目录
lfs:/mnt/lfs/sources/gcc-6.3.0$ mkdir build
lfs:/mnt/lfs/sources/gcc-6.3.0$ cd build/

- configure
建议:参数
../configure \
--target=$LFS_TGT \
--prefix=/tools \
--with-glibc-version=2.11 \
--with-sysroot=$LFS \
--with-newlib \
--without-headers \
--with-local-prefix=/tools \
--with-native-system-header-dir=/tools/include \
--disable-nls \
--disable-shared \
--disable-multilib \
--disable-decimal-float \
--disable-threads \
--disable-libatomic \
--disable-libgomp \
--disable-libmpx \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-libstdcxx \
--enable-languages=c,c++

- make
lfs:/mnt/lfs/sources/gcc-6.3.0/build$ time make
real    45m18.791s
user 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 安装JDK 首先需要安装JDK,可以在Oracle官网或者OpenJDK官网下载对应系统的JDK安装包。下载完成后,按照安装向导进行安装。 2. 安装Maven Maven是一个项目管理工具,可以用于构建、打包、发布和管理Java项目。可以在Maven官网下载对应系统的Maven安装包,下载完成后,按照安装向导进行安装。 3. 创建Spring Boot项目 可以使用Spring Initializr创建一个基本的Spring Boot项目。在浏览器中打开 https://start.spring.io/,选择需要的依赖和配置,然后点击Generate按钮下载项目。将下载的项目解压到任意目录下。 4. 安装MySQL 可以在MySQL官网下载对应系统的MySQL安装包,下载完成后,按照安装向导进行安装。安装完成后,启动MySQL服务。 5. 创建数据库和表 使用MySQL客户端连接到MySQL服务器,创建一个新的数据库和表。可以使用以下命令: ``` CREATE DATABASE springbootdb; USE springbootdb; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ``` 6. 编辑application.properties文件 在Spring Boot项目的根目录下,找到src/main/resources/application.properties文件。编辑该文件,添加以下配置: ``` spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb spring.datasource.username=root spring.datasource.password=your_password_here spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect ``` 将your_password_here替换为MySQL的root用户密码。 7. 编Controller和Service 在src/main/java/com/example/demo下创建一个UserController类和一个UserService类。 UserController.java文件内容如下: ``` @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/users") public List<User> getUsers() { return userService.getUsers(); } @PostMapping("/users") public void addUser(@RequestBody User user) { userService.addUser(user); } } ``` UserService.java文件内容如下: ``` @Service public class UserService { @Autowired private UserRepository userRepository; public List<User> getUsers() { return userRepository.findAll(); } public void addUser(User user) { userRepository.save(user); } } ``` 8. 编译和运行项目 在命令行中进入Spring Boot项目的根目录,运行以下命令: ``` mvn clean package java -jar target/demo-0.0.1-SNAPSHOT.jar ``` 其中demo-0.0.1-SNAPSHOT.jar是根据项目名称和版本号生成的文件名,可以根据实际情况进行修改。 9. 测试API 在浏览器或者Postman中访问http://localhost:8080/users,可以获取到所有用户的信息。使用POST方法访问http://localhost:8080/users,并发送一个JSON格式的请求体,可以添加一个新用户。例如: ``` { "name": "Alice", "email": "[email protected]" } ``` 在数据库中查询,可以确认新用户已经被添加。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值