Linux之编译程序详细介绍---./configure、make、make install

2023-05-16

本节介绍如何通过源代码生成可执行程序,在博主前期使用NVIDIA Jetson TX2时,由于Arm架构的各个包不完备,经常需要源码编译OpenCV等.
为什么要编译软件呢?

  • 可用性:尽管有些发行版已经包含了版本库中的一些预编译程序,但并不会包含用户所有可能需要的应用程序。此时,用户只能源码编译安装
  • 及时性:虽然有些发行版本专注于一些前沿的程序版本,但是多数并不会。这意味着要想获取最新版本的程序,编译必不可少.

0.参考文献

《Linux命令行大全》 [美] William E. Shotts. Jr 著 郭光伟 郝记生 译, 人民邮电出版社

更多有用的Linux知识详解,可参加博主的Linux学习导航页.

1.什么是编译

编译就是一个将源代码(程序员编写的人类可读的程序描述–高级语言)翻译成计算机处理器能识别的语言(机器语言)的过程.
高级语言编写的程序通过编译器转换成机器语言。有些编译器则将高级语言程序转换成
汇编语言
,然后再使用一个汇编程序将其转换成机器语言.
经常与编译一起使用的步骤是链接.提供了通用任务支持,包含了多个例程,每一个实现的都是许多程序能够共享的通用任务,这些程序通常在/lib和/usr/lib中.链接器(linker)程序可以实现编译器的输出与编译程序所需要库之间的链接.该操作的最终结果就是生成一个可供使用的可执行文件.

2.是不是所有程序都需要编译

答案是否定的.像shell脚本可以直接运行,这些文件都是用脚本或解释型语言编写的,例如Perl,Python,PHP等。
脚本语言由一个称为解释器的特殊程序来执行,解释器负责输入程序文件并执行其包含的所有指令.通常,解释型程序要比编译后的程序执行起来.这是因为,在解释型语言中,每条源代码指令在执行时都要重新翻译一次该代码指令.然而编译后的程序中,每条源代码指令只翻译一次,并且该翻译结果将永久地记录到最后的可执行文件中.

3.编译一个C程序

在执行编译操作之前,需要一些工具,诸如编译器、链接器以及make等. **gcc(GNU C编译器)**是Linux环境中通用的C编译器.

$ which gcc
/usr/bin/gcc

表明已经安装该编译器.

3.1 获取源代码

从一个叫做diction的GNU项目中选择一个程序进行编译练习.
使用ftp下载源码到src/目录.

$ mkdir src
$ cd src
$ ftp ftp.gnu.org
Connected to ftp.gnu.org.
220 GNU FTP server ready.
Name (ftp.gnu.org:lmj): anonymous
230-NOTICE (Updated October 13 2017):
230-
230-Because of security concerns with plaintext protocols, we still
230-intend to disable the FTP protocol for downloads on this server
230-(downloads would still be available over HTTP and HTTPS), but we
230-will not be doing it on November 1, 2017, as previously announced
230-here. We will be sharing our reasons and offering a chance to
230-comment on this issue soon; watch this space for details.
230-
230-If you maintain scripts used to access ftp.gnu.org over FTP,
230-we strongly encourage you to change them to use HTTPS instead.
230-
230----
230-
230-Due to U.S. Export Regulations, all cryptographic software on this
230-site is subject to the following legal notice:
230-
230-    This site includes publicly available encryption source code
230-    which, together with object code resulting from the compiling of
230-    publicly available source code, may be exported from the United
230-    States under License Exception "TSU" pursuant to 15 C.F.R. Section
230-    740.13(e).
230-
230-This legal notice applies to cryptographic software only. Please see
230-the Bureau of Industry and Security (www.bxa.doc.gov) for more
230-information about current U.S. regulations.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd gnu/diction
250 Directory successfully changed.
ftp> ls
200 EPRT command successful. Consider using EPSV.
150 Here comes the directory listing.
-rw-r--r--    1 3003     65534       68940 Aug 28  1998 diction-0.7.tar.gz
-rw-r--r--    1 3003     65534       90957 Mar 04  2002 diction-1.02.tar.gz
-rw-r--r--    1 3003     65534      141062 Sep 17  2007 diction-1.11.tar.gz
-rw-r--r--    1 3003     65534         189 Sep 17  2007 diction-1.11.tar.gz.sig
226 Directory send OK.
ftp> get diction-1.11.tar.gz
local: diction-1.11.tar.gz remote: diction-1.11.tar.gz
200 EPRT command successful. Consider using EPSV.
150 Opening BINARY mode data connection for diction-1.11.tar.gz (141062 bytes).
226 Transfer complete.
141062 bytes received in 0.74 secs (185.8389 kB/s)
ftp> bye
221 Goodbye.

源码是以tar压缩文件形式存在,有时也被成为tarball,该文件包含了源代码树,即构成该源代码的目录及文件的组织架构.
对其解压

$ tar -xzf diction-1.11.tar.gz
$ ls
diction-1.11  diction-1.11.tar.gz

3.2 检查源代码树

解压后的文件包含了原文件树,具体内容为

$ ls
config.guess  configure.in  diction.1.in  diction.spec.in  en_GB.po   getopt_int.h  misc.c  nl.po       style.1.in
config.h.in   COPYING       diction.c     diction.texi.in  getopt1.c  INSTALL       misc.h  README      style.c
config.sub    de            diction.pot   en               getopt.c   install-sh    NEWS    sentence.c  test
configure     de.po         diction.spec  en_GB            getopt.h   Makefile.in   nl      sentence.h

GNU项目的程序也包含了如README、INSTALL、NEWSCOPYING等这些文件,这些文件包含的是程序的描述、安装步骤说明许可条款.在开始编译之前,阅读README和INSTALL是非常有必要的.
其它有趣的文件是以.c.h结尾的文件,软件包提供的程序便是以.c结尾,并且划分成了多个模块.这种将大的程序分成较小的、易于管理的小程序片已经很普遍.这些源码都是普通文本文件,可以用less查看.
.h文件是头文件,包含了对源代码文件或库中的例程的描述.编译器在链接这些例程模块时,必须给它提供一个所用到所有模块的描述.例如,在diction.c的开头,可以看到如下文本行.

#include "getopt.h"

该文本行会指示编译器在读取diction.c中的源代码内容时先读取getopt.h中的内容,进而读取getopt.c中的内容.
在getopt.h的include语句上面,还可以看到其他include语句,例如

#include <regex.h>

这些都是用来引用头文件,但是它们引用是系统提供的头文件,路径在/usr/include.

3.3 生成程序

大多数程序都是使用一个简单的2行命令来生成的.

./configure
make

configure程序其实是源代码树下的一个shell脚本,它的任务就是分析生成环境.多数源码都设计成可移植的.也就是说,源代码可以在多种类型的UNIX系统上生成,只是源代码在生成时可能需要经过细微的调整以适应各系统之间的不同。configure同样会检查系统是否已经安装了必要的外部工具和组件.

$ ./configure
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for a BSD-compatible install... /usr/bin/install -c
checking for strerror... yes
checking for library containing regcomp... none required
checking for broken realloc... no
checking for msgfmt... yes
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking libintl.h usability... yes
checking libintl.h presence... yes
checking for libintl.h... yes
checking for library containing gettext... none required
configure: creating ./config.status
config.status: creating Makefile
config.status: creating diction.1
config.status: creating diction.texi
config.status: creating diction.spec
config.status: creating style.1
config.status: creating test/rundiction
config.status: creating config.h

重点注意的一点是:这里没有错误信息,如果有的话,该configure操作将以失败告终,并且不会生成可执行程序,直至纠正错误.
可以看到configure在源目录中创建了几个新文件,其中最重要的是Makefile,Makefile是指导make命令如何创建可执行程序的配置文件.当然,其也是普通文本文件,可以用less查看.

$ less Makefile

make程序的作用其实就是输入Makefile,该文件描述了生成最后可执行程序时各部件之间的联系及依赖关系.
makefile的第一部分内容定义了一些变量**,这些变量在makefile的后面部分将会被替代掉**,例如

CC=             gcc

该行将C编译器定义为gcc,然后在makefile的后面内容,可以看到如下例子

diction:        diction.o sentence.o misc.o getopt.o getopt1.o
                $(CC) -o $@ $(LDFLAGS) diction.o sentence.o misc.o \
                getopt.o getopt1.o $(LIBS)

该例中包含了一个替代操作,在运行时 $(CC)会被替代成gcc.
大多数Makefile文件都有很多行,这些行定义了目标文件(该例中是diction可执行文件),也定义了目标文件所依赖的一些文件,剩下的行则描述的是那些将原文件生成目标文件的命令.本例中,可执行文diction依赖于文件diction.o、sentence.o、misc.o、getopt.o以及getopt1.o,可以看到这些目标文件的定义

#{{{ dependencies
diction.o:      diction.c config.h getopt.h misc.h sentence.h
getopt.o:       getopt.c getopt.h getopt_int.h
getopt1.o:      getopt1.c getopt.h getopt_int.h
misc.o: misc.c config.h misc.h
sentence.o:     sentence.c config.h misc.h sentence.h
style.o:        style.c config.h getopt.h misc.h sentence.h
#}}}

然而,我们并没有看到为它们指定的任何命令,其实,它们是由文件前面的总体目标行生成的,该目标行描述了用来将所有.c文件编译成.o文件的命令.

.c.o:
                $(CC) -c $(CPPFLAGS) $(CFLAGS) $<

接下来就是运行make

$ make 

运行结束后,所有目标文件都出现了

$ ls
config.guess   configure     diction       diction.spec
config.h       configure.in  diction.1     diction.spec.in
config.h.in    COPYING       diction.1.in  diction.texi
config.log     de            diction.c     diction.texi.in
config.status  de.mo         diction.o     en
config.sub     de.po         diction.pot   en_GB

如果再次运行make,则

$ make
make: Nothing to be done for 'all'.

这是因为**,make并不是简单地重新生成所有东西,只会生成那些需要生成的文件**。在所有目标文件已经存在的情况下,make会判断原文件没有任何改动,就不会进行任何操作.当然,可以删除其中某个目标文件,然后再次运行make来观察.

 rm getopt.o
$ make
gcc -c -I. -DSHAREDIR=\"/usr/local/share\" -DLOCALEDIR=\"/usr/local/share/locale\" -g -O2 -pipe -Wno-unused -Wshadow -Wbad-function-cast -Wmissing-prototypes -Wstrict-prototypes -Wcast-align -Wcast-qual -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-declarations -Wnested-externs -Wundef -pedantic -fno-common getopt.c
gcc -o diction -g diction.o sentence.o misc.o \
        getopt.o getopt1.o
gcc -o style -g style.o sentence.o misc.o \
        getopt.o getopt1.o -lm

可以看到make重新生成了getopt.o,并重新链接diction和style程序,因为它们都依赖于被删除的程序.
这种特性说明了make的另外一种用法–可以维护目标文件的更新.make坚持一个原则—目标文件要比依赖文件新.

3.4 安装程序

打包好的源代码一般包含一个特殊的make目标程序,便是install.该目标程序将会在系统目录下安装最后生成的可执行程序.通常安装在**/usr/local/bin中,即本地主机上生成软件的常见安装目录**.然而,需要管理员权限.

$ sudo make install

安装结束后,就可以查看程序是否可以运行.

$ which diction
/usr/local/bin/diction
man diction
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux之编译程序详细介绍---./configure、make、make install 的相关文章

  • 在主目录中安装库

    在 Linux Ubuntu 中 我尝试运行一个工具 但它显示错误 库丢失 我无权在系统中安装任何内容 或者根本无法从我的用户帐户执行 sudo 是否可以在我的主目录 没有 sudo 中安装缺少的库 在我的例子中为 libstdc so 6
  • 信号处理程序有单独的堆栈吗?

    信号处理程序是否有单独的堆栈 就像每个线程都有单独的堆栈一样 这是在 Linux C 环境中 来自 Linux 手册页signal 7 http kernel org doc man pages online pages man7 sign
  • 为什么我收到的数据包数据大小大于mss?

    我在两台 PC 上使用 ifconfig ethX mtu 300 修改了 MTU 并使用 netperf 测试网络 我用 WireShark 嗅探了 SYN 数据包中的 MSS 260 但我得到了一些大于 260 的数据包 为什么 嗅探器
  • 在 Mac OS X 上构建 Linux 内核

    我正在做一个修改Linux内核的项目 我有一台桌面 Linux 机器 在上面构建内核没有问题 不过 我要去旅行 我想在途中工作 我只有一台 MacBook 当我尝试构建 Linux 内核时 它抱怨说elf h was not found 我
  • 何时使用 pthread 条件变量?

    线程问题 看来 只有在其他线程调用 pthread cond notify 之前调用 pthread cond wait 时 条件变量才起作用 如果在等待之前发生通知 那么等待将被卡住 我的问题是 什么时候应该使用条件变量 调度程序可以抢占
  • 在 Linux 上更快地分叉大型进程?

    在现代 Linux 上达到与 Linux 相同效果的最快 最好的方法是什么 fork execve combo 从一个大的过程 我的问题是进程分叉大约 500MByte 大 并且一个简单的基准测试只能从进程中实现约 50 个分叉 秒 比较最
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 创建 jar 文件 - 保留文件权限

    我想知道如何创建一个保留其内容的文件权限的 jar 文件 我将源代码和可执行文件打包在一个 jar 文件中 该文件将在使用前提取 人们应该能够通过运行批处理 shell 脚本文件立即运行示例和演示 然后他们应该能够修改源代码并重新编译所有内
  • Linux 中的无缓冲 I/O

    我正在写入大量的数据 这些数据数周内都不会再次读取 由于我的程序运行 机器上的可用内存量 显示为 空闲 或 顶部 很快下降 我的内存量应用程序使用量不会增加 其他进程使用的内存量也不会增加 这让我相信内存正在被文件系统缓存消耗 因为我不打算
  • 抑制 makefile 中命令调用的回显?

    我为一个作业编写了一个程序 该程序应该将其输出打印到标准输出 分配规范需要创建一个 Makefile 当调用它时make run gt outputFile应该运行该程序并将输出写入一个文件 该文件的 SHA1 指纹与规范中给出的指纹相同
  • 使用 grep 查找包含所有搜索字符串的行

    我有一个文件 其中包含很多与此类似的行 id 2796 some model Profile message type MODEL SAVE fields account 14 address null modification times
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • 如何使用 xterm.js 创建基于 Web 的终端以 ssh 进入本地网络上的系统

    我偶然发现了这个很棒的图书馆xterm js https xtermjs org 这也是 Visual Studio Code 终端的基础 我有一个非常普遍的问题 我想通过基于网络的终端 不在网络中 可能位于 aws 服务器上 访问本地网络
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • Linux中的定时器类

    我需要一个计时器来以相对较低的分辨率执行回调 在 Linux 中实现此类 C 计时器类的最佳方法是什么 有我可以使用的库吗 如果您在框架 Glib Qt Wx 内编写 那么您已经拥有一个具有定时回调功能的事件循环 我认为情况并非如此 如果您
  • chown:不允许操作

    我有问题 我需要通过 php 脚本为系统中的不同用户设置文件所有者权限 所以我通过以下命令执行此操作 其中 1002 是系统的用户 ID file put contents filename content system chown 100
  • sendfile64 只复制约2GB

    我需要使用 sendfile64 复制大约 16GB 的文件 到目前为止我所取得的成就是 include
  • 在哪里可以找到并安装 pygame 的依赖项?

    我对 Linux 比较陌生 正在尝试安装 python 的 pygame 开发环境 当我运行 setup py 时 它说我需要安装以下依赖项 我找到并安装了其中之一 SDL 然而 其他人则更加难以捉摸 Hunting dependencie
  • 域套接字“sendto”遇到“errno 111,连接被拒绝”

    我正在使用域套接字从另一个进程获取值 就像 A 从 B 获取值一样 它可以运行几个月 但最近 A 向 B 发送消息时偶尔会失败 出现 errno 111 连接被拒绝 我检查了B域套接字绑定文件 它是存在的 我也在另一台机器上做了一些测试 效
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之

随机推荐

  • Linux之vi介绍----完整入门及快捷键

    0 前言 自从我的学习linux笔记开始更新后 xff0c 阅读量挺高 xff0c 说明大家使用linux热情很高 在前边几篇博客中我未指明参考书籍 xff0c 这里做下说明 xff0c 将慢慢补充之前几篇的参考说明 我的博客源于对以下书本
  • Linux系统软件包管理——dpkg、apt-get、rpm、yum

    软件包管理是一种在系统上安装 维护软件的方法 主要有两种方式 xff0c 一种是通过安装Linux经销商发布的软件包来满足软件需求 xff1b 一种是先下载源代码 xff0c 然后对其进行编译 xff08 博主在使用jetson tx2时
  • Linux之网络相关命令——ping、tranceroute、netstat、ftp、lftp、wget、ssh、scp、sftp

    网络连接方面 xff0c Linux可以说是万能的 Linux工具可以建立各种网络系统及应用 xff0c 包括防火墙 路由器 域名服务器 NAS xff08 网络附加存储 xff09 盒等 这里主要讲一些经常用到的命令 xff0c 涉及网络
  • Linux文件搜索命令介绍——locate、find、xargs、touch、stat

    本文主要介绍两个用在Linux系统中搜索文件的工具 locate 通过文件名查找文件find 在文件系统目录框架中查找文件 同时 xff0c 我们也会介绍一个通常与文件搜索命令一起使用 处理搜索结果文件列表的命令 xargs 从标准输入中建
  • ubuntu使用bash脚本+gnome实现开机自启python程序和崩溃重启

    这里以tx2的ubuntu18 04为例 xff0c 对ubuntu系统是有效的 例如我们要实现开机自动启动 home me test main py程序 xff0c 并且当main py出现任何意料之外的错误报错时 xff0c 系统可以重
  • http请求转串口通信系统开发者文档

    http请求转串口通信系统介绍 系统价值和功能与口号 让所有单片机联网通信 1 系统使用c语言mqtt协议开发esp8266为硬件载体 xff0c 调用者只需要任意编程语言的串口通信即可 xff01 2 是一个好用的免费的稳定的单片机网络通
  • ubuntu实现屏幕的旋转和开启自动旋转屏幕

    1 旋转屏幕 有两种方法 xff0c 一种是命令行 xff0c 一种是图形界面 这里只介绍命令行 xff0c 因为其简单 xrandr o left 向左旋转90度 xff0c 用于横屏转竖屏 xrandr o right 向右旋转90度
  • MaskRCNN在Jetson tx2上的测速结果

    博主测试了在不同模式 精度下降MaskRCNN部署到Jetson TX2上的测速结果 xff0c 与大家分享讨论 对FasterRCNN的测速可见FasterRcnn在Jetson TX2上测速 使用的MaskRCNN框架 matterpo
  • FasterRcnn在Jetson TX2上测速

    博主测试了在不同模式 精度下将FasterRCNN部署到Jetson TX2上的测速结果 xff0c 与大家分享讨论 对于MaskRCNN的部署结果可参见 MaskRCNN在Jetson tx2上的测速结果 使用的Caffe版本Faster
  • Linux学习笔记导航页

    本博客中与博主Linux学习相关的博文导航 xff0c 方便查看 Linux系统ls命令详解Linux系统中目录的内容详解 bin dev etc home lib opt usr varLinux操作文件与目录 cp mv mkdir r
  • Jetson TX2使用经验导航页

    本博客中与Jetson TX2使用相关的博文导航 xff0c 方便查看 JetsonTX2 之刷机 Jetpack 4 3TX2 ubuntu 18 04 更换清华镜像源Jetson TX2刷机后查看CUDA和CUDNN版本 以JetPac
  • Pytorch学习导航页

    本博客中与pytorch学习相关的博文 xff0c 方便查看 Pytorch源码学习之一 xff1a torchvision models alexnetPytorch源码学习之二 xff1a torchvision models vggP
  • Python小技巧导航页

    本博客中与Python使用技巧相关的博文 xff0c 方便查看 使用matplotlib绘图库的pyplot快速绘图Python调用face 43 43 API完成本地图片的人脸检测Python爬虫 按照关键词爬取视觉中国高清图像pytho
  • Linux归档与备份——gzip、gunzip、bzip2、bunzip2、tar、zip、unzip、rsync

    维护系统数据安全是计算机系统管理者的基本任务之一 xff0c 及时创建系统文件的备份文件是维度系统数据安全的一种常用方法 本节主要介绍以下命令 文件压缩程序 gzip 压缩和解压缩文件工具bzip2 块排序文件压缩工具 文件归档程序 tar
  • Linux之存储介质——mount、umount、fdisk、mkfs

    本节讨论设备级别的数据处理 对于诸如硬盘之类的物理存储器 网络存储器以及像RAID 独立冗余磁盘陈列 和LVM 逻辑卷管理 之类的虚拟存储器 xff0c Linux都有惊人的处理能力 本节主要用到以下命令 mount 挂载文件系统umoun
  • Jetson TX2挂载SD卡--亲测有效!

    不得不说 xff0c TX2用于深度学习算法的部署 xff0c 一个很大的问题是硬盘容量太小 xff0c 由于我的应用需求需要存储大量数据 xff0c 因此需要挂载一个SD卡 关于Linux挂载存储介质相关原理可参考我的博客 Linux之存
  • 实用的测试流程梳理总结(质量保障)

    废话不多说 xff0c 简明扼要的列出我认为测试最重要的几点 xff1a 1 测试思维 xff1a 优秀的测试思维对case设计的好坏起决定作用 xff0c case的好坏对测试效率和测试质量起决定作用 xff0c 所以测试思维非常重要 我
  • Linux之正则表达式---grep、元字符、任意字符、锚、中括号、否定、POSIX字符类

    正则表达式是一个非常重要的用于文本操作的工具 0 参考文献 Linux命令行大全 美 William E Shotts Jr 著 郭光伟 郝记生 译 xff0c 人民邮电出版社 更多有用的Linux知识详解 xff0c 可参加博主的Linu
  • Linux之文本处理---cat、sort、uniq、cut、paste、join、comm、diff、patch、tr、sed、aspell

    由于所有类UNIX操作系统都严重依赖于文本文件来进行某些数据类型的存储 所以需要很多可以进行文本操作的工具 常见的文本格式有 文件 xff1a 使用纯文本格式编辑的文件 在使用文本格式编辑较大文件时 xff0c 常用的方法是 xff0c 首
  • Linux之编译程序详细介绍---./configure、make、make install

    本节介绍如何通过源代码生成可执行程序 xff0c 在博主前期使用NVIDIA Jetson TX2时 由于Arm架构的各个包不完备 经常需要源码编译OpenCV等 为什么要编译软件呢 xff1f 可用性 尽管有些发行版已经包含了版本库中的一