Download without sudo
本文是记录没有sudo权限,但需要在Linux系统上安装Git的过程,并且学习了相关的Makefile和环境变量的知识。这一过程是非常典型的./configure && make && make install 三部曲。如果你有sudo权限,那自然sudo apt-get install git
(for Ubuntu/Debian)就好,会自动帮你完成这一系列编译链。
当你在命令行运行 ./configure && make && make install
时,实际上是三个过程
- 配置阶段(
./configure
):检查系统环境并生成 Makefile 文件 - 编译阶段(
make
):根据 Makefile 将源代码编译为二进制文件 - 安装阶段(
make install
):将编译好的文件复制到系统目标目录
使用源码编译安装
1 | wget https://github.com/git/git/archive/refs/tags/v2.42.0.tar.gz -O git.tar.gz |
-
解压源码
1
2tar -zxvf git.tar.gz
cd git-* -
安装依赖
- 编译Git需要一些依赖库,如
curl
、zlib
等。你可以通过以下命令安装(无需sudo权限),这个大家一般都有,如果没有权限安装libcurl4-openssl-dev
,接着configure make三件套就是:1
2
3apt-get download libcurl4-openssl-dev zlib1g-dev
dpkg -x libcurl4-openssl-dev*.deb ./
dpkg -x zlib1g-dev*.deb ./
- 编译Git需要一些依赖库,如
-
编译并安装
- 编译并安装到自定义目录(例如
$HOME/bin
):1
2
3./configure --prefix=$HOME/bin
make
make install - 将
$HOME/bin/bin
添加到你的PATH
环境变量中:1
2echo 'export PATH=$HOME/bin/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
- 编译并安装到自定义目录(例如
-
验证安装
1
git --version
这上面的过程涉及到了环境变量和Make两个东西,怎么理解呢?我们在Windows系统也都在安装python等工具时设置过环境变量,但可能没有仔细想过。
环境变量
环境变量在操作系统中用来指定操作系统运行环境的一些参数,具体一个环境变量包括名称和参数值。
变量名称 | 作用 |
---|---|
HOME | 用户的主目录(即家目录) |
SHELL | 用户在使用的Shell解释器名称 |
HISTSIZE | 输出的历史命令记录条数 |
HISTFILESIZE | 保存的历史命令记录条数 |
邮件保存路径 | |
LANG | 系统语言、语系名称 |
RANDOM | 生成一个随机数字 |
PS1 | Bash解释器的提示符 |
PATH | 定义解释器搜索用户执行命令的路径 |
EDITOR | 用户默认的文本编辑器 |
printenv
或者env
,ENV
可以把PC所有的环境变量打印出来。
1 | $ printenv |
可以看到环境变量有这么多,按照key value这种排列出来。
-
SHELL
: 用户的默认 shell, 当用户登录时,系统会根据 SHELL 环境变量来确定使用哪个 shell。这个变量影响到用户在终端中运行的命令行环境。 -
CONDA_EXE, CONDA_PYTHON_EXE, CONDA_PREFIX, CONDA_DEFAULT_ENV, CONDA_PROMPT_MODIFIER, CONDA_SHLVL
:这些变量与 Anaconda 或 Miniconda(Python 的包管理和环境管理工具)相关。它们提供有关当前 Conda 环境的信息。
CONDA_EXE: Conda 可执行文件的路径。CONDA_PYTHON_EXE: 当前 Conda 环境中 Python 可执行文件的路径。
CONDA_PREFIX: 当前 Conda 环境的路径。CONDA_DEFAULT_ENV: 当前活动的 Conda 环境名称。
CONDA_PROMPT_MODIFIER: 终端提示符中显示的当前 Conda 环境的名称。
CONDA_SHLVL: 当前 Conda 环境的层级。 -
LC_CTYPE
:指定字符集和语言环境的类型。UTF-8 表示使用 UTF-8 编码,支持多种语言字符。 -
_
:通常用于保存上一个命令的执行结果。在某些情况下,它会被用作传递给环境的最后命令的参数。 -
?
:返回上一个命令的执行成功与否。成功返回0,未成功返回其他数,可以写if [ $? -eq 0 ]; do functin();fi
1
2
3
4
5
6$ echo $LC_CTYPE
> UTF-8
$ echo $_
> UTF-8
$ echo $?
> 0
PATH 环境变量
我们来看看当pwd
的时候发生了什么事
我们有两种pwd的方式
1 | $ /usr/bin/pwd |
第一种方法每次都要从根路径自己手打,这样也太没效率了,总不能每次新建一个文件夹都要这样写?/usr/bin/mkdir new_dir。 于是就有了第二种这样,直接把命令打出来,不用自己从根路径一步步的打,那么系统是如何找到pwd这个命令的呢。这就涉及到了PATH这一环境变量。PATH 是一个特殊的环境变量,它包含一系列目录的路径,操作系统在这些目录中查找可执行文件。当你在终端中输入一个命令时,系统会依次在这些目录中搜索相应的可执行文件。
输入下面的命令看一下环境变量下的PATH有哪些路径:
1 | $ echo $PATH |
于是可以看出这两种方法的区别在于一个是程序自己从PATH里面找出来,一个是你自己输入路径来执行命令。
命令在 Linux 中的执行分为 4 个步骤。
- 判断用户是否以绝对路径或相对路径的方式输入命令(如 /bin/ls ),如果是的话则直接执行。
- Linux 系统检查用户输入的命令是否为“别名命令”,即用一个自定义的命令名称来替换原本的命令名称。可以用 alias 命令来创建一个属于自己的命令别名,格式为“alias rm= rm -i”或者“alias 别名=命令”,若要取消一个命令别名,则是用 unalias 命令,格式为“unalias 别名”。我们之前在使用 rm 命令删除文件时,Linux 系统都会要求我们再确认是否执行删除操作,其实这就是 Linux 系统为了防止用户误删除文件而特意设置的 rm 别名命令。
- Bash 解释器判断用户输入的是内部命令还是外部命令。内部命令是解释器内部的指令,会被直接执行;而用户在绝大部分时间输入的是外部命令,这些命令交由步骤 4 继续处理。可以使用“type 命令名称”来判断用户输入的命令是内部命令还是外部命令。
1 | (base) user@host ~ % type ls |
- 系统在多个路径中查找用户输入的命令文件,而定义这些路径的变量叫作 PATH,作用是告诉 Bash 解释器待执行的命令可能存放的位置,然后 Bash 解释器就会乖乖地在这些位置中逐个查找。 PATH 是由多个路径值组成的变量,每个路径值之间用冒号间隔,对这些路径的增加和删除操作将影响到 Bash 解释器对Linux 命令的查找。
如何设置PATH或者是其他环境变量
系统变量就是一个大的容器,其中里面有一个环境变量是PATH,PATH主要用于储存各种命令的路径。那么我们如何设置呢?我们可以用export PATH=/xxx/bin:$PATH
这行命令,作用是将 /xxx/bin 目录添加到 PATH 的开头。将新的目录添加到$PATH
的开头,意味着优先查找该目录中的可执行文件。如果你希望后面的目录优先被查找,可以将$PATH
放在前面,如export PATH=$PATH:/xxx/bin
。
这个设置只在当前终端会话中有效。如果你想要在每次打开终端时都自动设置,可以将这行命令添加到你的 shell 配置文件中,如 ~/.bashrc
、~/.bash_profile
或 ~/.zshrc
, 如果没有执行权限,可以source ~/.bashrc
。
Linux 文件系统目录结构
上面导出了PATH路径,可以看看这些文件是用来干嘛的。
目录 | 描述 |
---|---|
/bin |
基本命令二进制文件 |
/sbin |
基本的系统二进制文件,通常是 root 运行的 |
/dev |
设备文件,通常是硬件设备接口文件 |
/etc |
主机特定的系统配置文件 |
/home |
系统用户的主目录 |
/lib |
系统软件通用库 |
/opt |
可选的应用软件 |
/sys |
包含系统的信息和配置(第一堂课介绍的) |
/tmp |
临时文件(/var/tmp ) 通常重启时删除 |
/usr/ |
只读的用户数据 |
/usr/bin |
非必须的命令二进制文件 |
/usr/sbin |
非必须的系统二进制文件,通常是由 root 运行的 |
/usr/local/bin |
用户编译程序的二进制文件 |
/var |
变量文件 像日志或缓存 |
Make
大多数Unix系统都会包含一个 “构建过程”,需要执行一系列操作。通常这一过程包含了很多步骤,很多分支。执行一些命令来生成图表,然后执行另外的一些命令生成结果,然后再执行其他的命令来生成最终的论文,这一过程可以通过构建系统来完成,这些系统一般涉及到dependencies, targets, and rules。
make
是最常用的构建系统之一,您会发现它通常被安装到了几乎所有基于UNIX
的系统中。make
并不完美,但是对于中小型项目来说,它已经足够好了。当您执行 make
时,它会去参考当前目录下名为 Makefile
的文件。所有构建目标、相关依赖和规则都需要在该文件中定义。我们先来定义前置的文件:
1 | $ cat paper.tex |
然后再定义Makefile
文件:
1 | paper.pdf: paper.tex plot-data.png |
接下来执行make
,看会发生什么?
1 | $ make |
生成了PDF!如果再次执行 make 会怎样?
1 | $ make |
没做任何变动,因为它什么都不需要做。make 检查出所有之前构建的目标仍然与其列出的依赖项保持最新状态。我们再来看一下这句话:
当你在命令行运行 ./configure && make && make install
时,实际上是三个过程
- 配置阶段(
./configure
):检查系统环境并生成 Makefile 文件 - 编译阶段(
make
):根据 Makefile 将源代码编译为二进制文件 - 安装阶段(
make install
):将编译好的文件复制到系统目标目录
所以我们在下载源文件后配置时,是根据源码包中 Makefile.in 文件的指示,configure脚本可以在编译软件之前检测系统的硬件架构、操作系统类型、所需的库文件以及其他相关的环境信息,根据所采集到的系统信息,自动在当前目录中生成一个用于编译和安装软件的Makefile文件(还有其它本文无需关心的文件),其中包括了编译器选项、依赖库的路径、安装路径等,然后 make
程序就按照当前目录中的 Makefile 文件的指示将源代码编译为二进制文件,最后将这些二进制文件移动(即安装)到指定的地方(仍然按照 Makefile 文件的指示)。
configure脚本通常是通过autoconf工具生成的,autoconf工具会根据用户在configure.ac文件中提供的信息和规则,生成对应的configure脚本。 autoconf -o configure configure.ac
接着安装
- 报错!系统中缺少
autoconf
工具。autoconf
是一个用于生成configure
脚本的工具,它是许多开源项目(包括Git)编译过程中必需的。所以我们接着三部曲安装autoconf
1 | wget https://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.gz |
- 报错,
./configure
脚本提示缺少GNU M4
工具。GNU M4
是一个宏处理器,autoconf
和许多其他项目在生成configure
脚本时需要它。你需要手动安装GNU M4
,因为系统中没有找到合适的版本。
1 | wget https://ftp.gnu.org/gnu/m4/m4-1.4.19.tar.gz |
- 确保
GNU M4
已经正确安装并添加到PATH
中后,重新运行./configure
脚本:1
./configure --prefix=$HOME/bin
如果在后续步骤中遇到其他依赖问题(如gawk
、curl
、openssl
等),可以按照类似的方法手动安装这些工具。事实上我又遇到了zlib.h not found
, msgfmt: not found
的错误(缺少gettext
工具集中的msgfmt
命令。msgfmt
用于编译国际化消息文件,是Git编译过程中需要的工具之一。), automake
, aclocal
未安装的问题,一一解决,成功安装Git。