tmux 和 nvim 的配置

 

本文记录了 tmux 和 vim 的配置

本文记录了 tmux 和 vim 的配置

Tmux

常用指令

功能 指令
安装 sudo apt install tmux
新建会话 tmux new -s workspace
断开会话 tmux detach<ctrl+b> d
重进会话 tmux a -t workspace
关闭会话 tmux kill-session -t workspace
关闭服务 tmux kill-server 关闭tmux服务器
查看会话 tmux ls<ctrl+b> s

美化

安装tmux(oh-my-tmux)项目

依赖项

  • tmux >= 2.1 (soon >= 2.4) running inside Linux, Mac, OpenBSD, Cygwin or WSL

  • curl, awk, perl and sed

  • outside of tmux, $TERM must be set to xterm-256color

安装命令

$ cd
$ git clone https://github.com/gpakosz/.tmux.git
$ ln -s -f .tmux/.tmux.conf
$ cp .tmux/.tmux.conf.local .

然后继续自定义 ~/.tmux.conf.local副本

如果您是Vim用户,请将$EDITOR环境变量设置为vim将启用并进一步自定义vi样式的键绑定(请参阅tmux手册)。

安装好后,使用Johnn4Func的配置

这里还可以安装一个天气的插件,~/.bashrc 或者 ~/.zshrc 中加入:

alias weather='curl zh.wttr.in/深圳'

tmux中的常用快捷键

前缀 指令 功能
<ctrl+b> c 新建窗口
<ctrl+b> e 打开配置文件~/.tmux.conf.local
<ctrl+b> m 切换鼠标模式
<ctrl+b> q 显示面板编号
<ctrl+b> r 加载tmux配置文件
<ctrl+b> w 打开窗口列表
<ctrl+b> x 关闭面板
<ctrl+b> + 最大/小化面板
<ctrl+b> , 命名窗口
<ctrl+b> . 修改窗口编号
<ctrl+b> - 上下分屏(面板)
<ctrl+b> | 左右分屏(面板)
<ctrl+b> </ > 向前/后置换面板
<ctrl+b> <ctrl+o> 顺时针旋转当前窗口中的所有面板
<ctrl+b> h/j/k/l 切换面板
<ctrl+b> <ctrl+h/j/k/l> 前/下/上/后切换窗口
<ctrl+b> <ctrl+H/J/K/L> 前/下/上/后调整面板
<ctrl+b> :join-pane -s win1 把win1窗口合并到当前窗口中
<ctrl+b> :join-pane -s win1.1 把win1窗口中的1号面板合并到当前窗口中
<ctrl+b> b 显示粘贴板列表
<ctrl+b> p 粘贴顶层粘贴板内容
<ctrl+b> P 选择要粘贴的粘贴板内容

鼠标模式

  1. 开启用鼠标拖动调节pane的大小(拖动位置是pane之间的分隔线)

  2. 开启用鼠标点击pane来激活该pane

  3. 开启用鼠标点击来切换活动window(点击位置是状态栏的窗口名称)

  4. 开启window/pane里面的鼠标支持(也即可以用鼠标滚轮回滚显示窗口内容,此时还可以用鼠标选取文本)

复制模式

  1. prefix + [ 进入复制模式(ESC或者 <ctrl+c> 退出复制模式)

  2. v 开始移动光标选择复制区域

  3. y 复制并退出 copy-mode

  4. 将光标移动到指定位置,按 prefix + ] 粘贴

配置的托管

1. 在 github 上创建一个 config 项目

在Github 上新建个 config 项目,保存各种编辑器、shell、tmux的配置。在新环境中克隆下来,放到 ~/.local/config 下面。

2. 建立自己的配置脚本

写一个 bootstrap.sh 文件,到一个新环境下只需 curl 下来一执行如下命令:

sh -c "$(curl -fsSL https://.../bootstrap.sh)"

这个脚本将会建立必要的目录,克隆你的配置,再做一些必要的初始化

3. 使用 init.sh

新建一个:init.sh 用仓库托管起来,而本地 ~/.bashrc 末尾加一句话:

source ~/.local/xxx/init.sh 

这个给文件末尾追加一句话的事情,可以让前面的 bootstrap.sh 来承担。

这样 init.sh 放置通用配置;临时配置,写在 ~/.bashrc 中,同时改写 ~/.bashrc 不会把 config 仓库弄脏;而更新 config 仓库也不会把本地配置覆盖没。

更重要的是,init.sh 可以写成同时兼容:sh, bash, zsh, dash 的模式,每个 shell 的配置里面只要 source 它一下就行了,那么 init.sh 里面即可写通用所有 shell 的一些初始化工作,又可以针对不同的 shell 写一些初始化配置。

对于实验性的新配置,写到本地配置里即可,等你用一段时间,觉得好用了,再把它挪到公共配置仓库里固化起来。这样随着时间的积累,你的 init.sh 积累的配置越来越多,shell 越来越顺手。

写 shell 脚本时,可以参考《《Bash 中文速查表》

安装 neovim

github 上下载最新的 Neovim.AppImage

curl -LO https://github.com/neovim/neovim/releases/download/stable/nvim.appimage
chmod u+x nvim.appimage
./nvim.appimage

也可以把 nvim.appimage 创建一个链接放到 /usr/local/bin 目录下

ln -s [nvim.appimage的绝对路径] /usr/local/bin`

下载 vim-init

git clone https://github.com/skywind3000/vim-init.git

VIM 实用插件整理

插件管理器 vim-plug

Vim

curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

Neovim

sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'

使用

" 指定一个安装插件的目录
call plug#begin('~/.vim/plugged')
Plug 'junegunn/vim-easy-align'
......

" 初始化插件系统
call plug#end()

命令

命令 说明
PlugInstall [name …] [#threads] 安装插件
PlugUpdate [name …] [#threads] 安装或更新插件
PlugClean[!] 删除未列出的插件(!版本将清除无提示)
PlugUpgrade 升级 vim-plug
PlugStatus 检查插件的状态
PlugDiff 检查前一次更新的更改和未决的更改
PlugSnapshot[!] [output path] 生成用于恢复插件的当前快照的脚本

选项

选项 说明
branch/tag/commit 要使用的存储库的分支/标记/提交
rtp 包含Vim插件的子目录
dir 自定义插件的目录
as 为插件使用不同的名称
do 更新后处理钩(字符串或funcref) Post-update hook (string or funcref)
on 按需加载:在执行命令或<Plug>-map
for 按需装载:在指定的文件类型时
frozen 不更新,除非显式指定

比如:

" On-demand loading
Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
Plug 'tpope/vim-fireplace', { 'for': 'clojure' }

" Using a non-master branch
Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }

主题

推荐安装 base16-shellbase16-vim , space_vim_theme 以及 oceanic-next,后两个包含在 base-16 主题中

base16-shell

  1. 下载

    git clone https://github.com/chriskempson/base16-shell.git ~/.config/base16-shell
    
  2. ~/.bashrc~/.zshrc 中加入

    # Base16 Shell
    BASE16_SHELL="$HOME/.config/base16-shell/"
    [ -n "$PS1" ] && \
        [ -s "$BASE16_SHELL/profile_helper.sh" ] && \
            eval "$("$BASE16_SHELL/profile_helper.sh")"
    
  3. 打开一个新的shell,输入base16,然后输入一个tab来执行补全

  4. ~/.vimrc~/.config/nvim/init.vim 中加入

    if filereadable(expand("~/.vimrc_background"))
      let base16colorspace=256
      source ~/.vimrc_background
    endif
    

base16-vim

  1. 安装

    Plug 'chriskempson/base16-vim'
    
  2. 拷贝主题

    cp ~/.vim/bundles/base16-vim/colors/* ~/.config/nvim/colors
    
  3. 这样,在 shell 值切换主题后,vim 的主题也跟着切换

目录树(NERDTree)

安装

	Plug 'preservim/nerdtree'
	Plug 'ryanoasis/vim-devicons'
	Plug 'Xuyuanp/nerdtree-git-plugin'
	Plug 'tiagofumo/vim-nerdtree-syntax-highlight'

快捷键

快捷键 说明
tt 打开/关闭 nerdtree
q 关闭 nerdtree
o 打开选中的文件; 折叠/展开选中的目录
i 打开选中的文件,与已打开文件纵向排布窗口,并跳转至该窗口
gi 打开选中的文件,与已打开文件纵向排布窗口,但不跳转至该窗口
s 打开选中的文件,与已打开文件横向排布窗口,并跳转至该窗口
gs 打开选中的文件,与已打开文件横向排布窗口,但不跳转至该窗口
t 在新 Tab 中打开选中文件/书签,并跳到新 Tab
T 在新 Tab 中打开选中文件/书签,但不跳到新 Tab
x 折叠选中结点的父目录
X 递归折叠选中结点下的所有目录
k / j 光标在 Neadtree 上下移动
<leader>tn 创建一个新的标签页
<leader>tx 关闭标签页
<leader>tf 前一个标签页
<leader>tb 后一个标签页
<leader>to 关闭其他标签页
显示帮助

模糊搜索 LeaderF

LeaderF 是一个高效的模糊查找器,可以帮助定位文件、缓冲区、mrus、gtags等。

安装

安装 vim 的插件以及模糊匹配算法的C扩展

Plug 'Yggdroot/LeaderF', { 'do': './install.sh' }

使用方法

usage: Leaderf[!] [-h] [--reverse] [--stayOpen] [--input <INPUT> | --cword]
                  [--top | --bottom | --left | --right | --belowright | --aboveleft | 
                  --fullScreen | --popup]
                  [--nameOnly | --fullPath | --fuzzy | --regexMode] [--nowrap] [--next | 
                  --previous]
                  [--recall] [--popup-height <POPUP_HEIGHT>] [--popup-width <POPUP_WIDTH>]
                                    {file,tag,function,mru,searchHistory,cmdHistory,help,line,colorscheme,gtags,self,bufTag,
                                    buffer,rg,filetype,command,window,quickfix,loclist}
                  ...

如果给出[!],则直接进入正常模式

选项 说明
-h, –help 显示此帮助信息并退出
–reverse 按自下而上的顺序显示结果
–stayOpen 不要在接受一个条目后退出LeaderF
–input <INPUT> 指定INPUT为预先输入的模式
–cword 预先输入当前光标下的字词
–top LeaderF 窗口在屏幕的顶部
–bottom LeaderF 窗口在屏幕的底部
–left LeaderF 窗口在屏幕的左边
–right LeaderF窗口在屏幕的右边
–belowright LeaderF 窗口在屏幕右下角
–aboveleft LeaderF窗口在屏幕的左上角
–fullScreen LeaderF窗口占据了整个屏幕
–popup LeaderF窗口是一个弹出窗口或浮动窗口
–nameOnly LeaderF默认处于NameOnly模式下
–fullPath LeaderF默认为FullPath模式
–fuzzy LeaderF默认为Fuzzy模式
–regexMode LeaderF默认处于Regex模式下
–nowrap LeaderF 窗口中的长线不会被包住
–next 跳转到下一个结果
–previous 跳转到上一个结果
–recall 回忆上一次搜索。如果结果窗口关闭,则重新打开
–popup-height 指定弹出窗口的最大高度,仅在弹出模式下有效
–popup-width 指定弹出窗口的宽度,仅在弹出模式下可用

子命令

子命令 说明
file 检索文件
tag 使用标签文件浏览标签
function 在缓冲区中浏览函数或方法
mru 搜索最近使用的文件
searchHistory 在历史中执行搜索命令
cmdHistory 在历史中执行命令
help 浏览帮助标签
line 检索行
colorscheme 换色
gtags 使用gtags导航标签
self 执行自己的命令
bufTag 缓冲区中的标签导航
buffer 搜索缓冲区
rg 使用 grep
filetype 浏览文件类型
command 执行内置/用户定义的Ex命令
window 搜索窗口
quickfix 导航快速修复
loclist 导航位置列表

一旦启动了 LeaderF:

快捷键 功能
<C-C></br><ESC> 退出LeaderF
<C-R> 切换模糊搜索模式和regex模式。
<C-F> 切换全路径搜索模式和名称搜索模式
<Tab> 转入正常模式
<C-V></br><S-Insert> 剪贴板粘贴
<C-U> 撇清关系
<C-W> 删去提示中光标前的字样。
<C-J> 在结果窗口中向下移动光标。
<C-K> 在结果窗口中向上移动光标。
<Up>/<Down> 回顾历史上最后一个/下一个输入模式
<2-LeftMouse></br><CR> 勾选光标下的文件或选中的文件(当选中多个文件时)
<C-X> 横开
<C-]> 竖开
<C-T> 新页
<F5> 刷新缓存
<C-LeftMouse></br><C-S> 选择多个文件
<S-LeftMouse> 连续选择多个文件
<C-A> 选择所有文件
<C-L> 清除所有选择
<BS> 在提示语中输入前面的字符
<Del> 删除当前提示符
<Home> 将光标移到提示开始处。
<End> 将光标移到提示语的末尾部分
<Left> 在提示符中向左移动一个字
<Right> 将光标向右移动一个字符的提示音
<C-P> 预览结果
<C-Up> 在弹出的预览窗口中向上滚动
<C-Down> 在弹出的预览窗口中向下滚动

输入格式

  • 在NameOnly模式下(模糊模式)
    • 如果你输入的第一个字符是’;’,那么搜索将与FullPath模式相同。
    • 如果您输入的字符串是’abc;def’,那么’abc’将匹配文件名,’def’将匹配目录名。
  • 在FullPath模式(模糊模式)下
    • 除了模式将匹配完整的路径,而不是只匹配文件名之外,与NameOnly模式相同。
  • 在Regexp模式下
    • 输入的字符串与Vim的regexp相同。

Leaderf gtags

Gtags也就是GNU GLOBAL,是一个非常强大的源码符号索引工具。它通过建立索引数据库,不但可以查找函数的定义,还可以查找函数的所有引用(被调用的地方);而且它还可以增量地更新索引数据库,当代码有所改变时,它可以在很短的时间内更新索引数据库,保持索引数据库和代码同步。

LeaderF 可以自己管理 gtags 数据库(GTAGS,GRTAGS,GPATH),它不会在你的项目目录下生成任何额外的文件或目录。gtags 数据库文件存储在$HOME/.LfCache/gtags/%PATH%OF%YOUR%PROJECT/下面, %PATH%OF%YOUR%PROJECT 是把你项目路径中的 \/ 替换成 %

只要设置let g:Lf_GtagsAutoGenerate = 1, LeaderF 就会在打开第一个文件时自动生成 gtags 数据库。当代码有更改并且已经有 gtags 数据库生成时,更改的代码会自动同步到 gtags 数据库(即使g:Lf_GtagsAutoGenerate是0)。

只有在项目根目录下有g:Lf_RootMarkers(默认值是['.git', '.hg', '.svn'])里面指定的文件或目录时,LeaderF 才会自动生成 gtags 数据库;否则只能手动生成 gtags 数据库:Leaderf gtags --update,但是当代码有更改时,gtags 数据库依然可以自动更新。

LeaderF 快捷键

快捷键 功能
<leader>fr 搜索项目中光标下tag的引用
<leader>fd 搜索项目中光标下tag的定义
<leader>fo 再执行上一次的搜索
<leader>fh 跳转到下一个搜索处
<leader>fl 跳转到上一个搜索处
<leader>fb / <alt-n> 打开 buffer 列表进行模糊匹配
<leader>ft 在当前buf中搜索tag
<leader>fl 搜索某一行
<leader>ff 打开最近使用的文件
<alt-p> 打开函数列表,按 i 进入模糊匹配,esc 退出
<alt-P> 打开 tag 列表,按 i 进入模糊匹配,esc 退出
<alt-m> 全局 tags 模糊匹配
<leader>rw 以regex方式搜索光标下词条
<leader>ra 将结果附加到之前的搜索结果中
<leader>rb 只在当前缓冲区中搜索光标下的字
<leader>rc 在所有列出的缓冲区中按字面意思搜索光标下的文字
<leader>rh 回顾上一次搜索
<leader>rs *.h*.cpp文件中搜索光标下的单词
<leader>re 在cpp文件中搜索光标下的单词,排除*.hpp文件
gf 在visual模式下选择的文本中搜索,不要在接受一个条目后退出LeaderF

Leaderf gtags 使用介绍

参数 说明
–update 如果标签文件不存在,则创建标签文件,否则更新标签文件。
–remove 删除生成的标签文件。
–accept-dotfiles 接受名称以点开头的文件和目录。
默认情况下,gtags 会忽略这些文件和目录。
–skip-unreadable 跳过不可读的文件。
–gtagsconf <FILE> 设置环境变量GTAGSCONF为<FILE>。
–gtagslabel <LABEL> 将环境变量GTAGSLABEL设置为<LABEL>。
–skip-symlink [<TYPE>] 跳过符号链接。如果类型为’f’,则只跳过文件的符号链接,
如果为’d’,则只跳过目录的符号链接。
类型的默认值是’a’(所有符号链接)。
–gtagslibpath <PATH> [<PATH> …] 指定搜索库函数的路径。
-d <PATTERN>, –definition <PATTERN> 显示定义的位置。
-r <PATTERN>, –reference <PATTERN> 显示对有定义的符号的引用。
-s <PATTERN>, –symbol <PATTERN> 显示对没有定义的符号的引用。
-g <PATTERN>, –grep <PATTERN> 显示所有符合<PATTERN>的行
–by-context 根据光标位置的上下文决定标签类型。
如果上下文是模式的定义,则使用-r,
否则如果至少有一个模式的定义,则使用-d,
否则使用-s。模式不允许使用正则表达式。
-i, –ignore-case 忽略模式中的大小写区分。
–literal 执行文字搜索而不是正则表达式搜索。
–path-style <FORMAT> 使用<FORMAT>显示路径名,可以是以下之一。”relative”、”absolute”、”shorter”、”abslib “或 “through”。
relative表示相对路径。absolute表示绝对路径。
shorter表示相对路径和绝对路径中较短的一个。
abslib是指库的绝对路径(GTAGSLIBPATH)和其他库的相对路径。
through是指从项目根目录开始的相对路径(GPATH的内部格式)。
默认为 “relative”。
-S <DIR>, –scope <DIR> 只显示<DIR>目录下存在的标签。
–recall 回忆上次搜索的内容。如果结果窗口关闭,则重新打开。
–match-path 模糊搜索时匹配文件路径。
–append 追加到之前的搜索结果中。
–current-buffer 显示当前缓冲区的标签。
–all-buffers 显示所有缓冲区中的标签。
–all 显示整个项目中的标签。
–result <FORMAT> 使用格式化的方式显示结果,格式化的方式可以是。
ctags(默认)、ctags-xctags-mod中的一种。
–auto-jump [<TYPE>] 当只有一个匹配时,直接跳转到标签。<TYPE>可以是’h’、’v’或’t’,
分别表示跳转到一个水平、垂直分割的窗口或一个新的标签页。
如果省略<TYPE>,则跳转到一个位置。

注意:如果:Leaderf后面有感叹号,会直接进入normal模式;如果没有感叹号,则是输入模式,此时可以输入字符来进行模糊匹配过滤。可以用tab键在两个模式间来回切换。

手动生成gtags数据库

Leaderf[!] gtags --update 
				[--gtagsconf <FILE>] [--gtagslabel <LABEL>] [--accept-dotfiles]
                 [--skip-unreadable] [--skip-symlink [<TYPE>]] 
                 [--gtagslibpath <PATH> [<PATH> ...]]
  1. --gtagsconf <FILE> 用来指定 gtags.conf 文件的路径,一般情况下不需要指定,默认值就可以很好地工作。对于Windows上,如果相对于gtags.exe所在路径有../share/gtags/gtags.conf,也不需要指定该选项。如果需要用户自己特有的针对 gtags 的配置,可以指定用户的配置文件。 也可以在vimrc里设置g:Lf_Gtagsconf达到同样的目的。
  2. --gtagslabel <LABEL> 用来指定gtagslabel,如果不指定,默认值是 'default'
    • 推荐native-pygments 对于原生支持的6种语言使用内置parser,其他语言使用pygments作为parser。
    • 也可以在vimrc里设置g:Lf_Gtagslabel达到同样的目的。
  3. –gtagslibpath [ ...] 用来指定项目所用 library 的 Paths,这样就可以生成 library 的索引,查找定义或引用时可以跳转 到 library 代码中去。后面指定的路径还可以是一个或多个其他项目路径,跳转时可以跳到其他项目中的文件

查找tags

Leaderf[!] gtags [--current-buffer | --all-buffers | --all] [--result <FORMAT>] [COMMON_OPTIONS]

列出当前buffer、所有打开的buffer或者整个项目的tags

  1. Leaderf[!] gtags等同于Leaderf[!] gtags --all,列出整个项目的tags。

  2. --result <FORMAT> 指定显示格式,可以是ctags(default), ctags-x或者ctags-mod

查找定义、引用

Leaderf[!] gtags 
			-d <PATTERN> [--auto-jump [<TYPE>]] 
			[-i] [--literal] [--path-style <FORMAT>] 
			[-S <DIR>][--append] [--match-path] 
			[--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]


Leaderf[!] gtags 
			-r <PATTERN> [--auto-jump [<TYPE>]] 
			[-i] [--literal] [--path-style <FORMAT>] 
			[-S <DIR>][--append] [--match-path] 
			[--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
			
Leaderf[!] gtags --by-context [--auto-jump [<TYPE>]] 
			[-i] [--literal] [--path-style <FORMAT>] 
			[-S <DIR>][--append] [--match-path] 
			[--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
  1. <PATTERN>可以是正则表达式。
  2. --auto-jump [<TYPE>] 意思是如果只有一个结果直接跳过去。
  3. --by-context 意思是:光标下如果是定义,就跳到引用处,如果是引用,就跳到定义处。

CoC

快捷键 功能
:CocDiagnostics 获取获取当前位置列表中所有缓冲区的诊断信息
[g 前一个诊断信息
]g 后一个诊断信息
gd 跳转到函数定义
gr 返回引用处
gi 跳转到实现(implementation)
gy 类型定义
K 显示光标下符号的帮助文档
<leader>rn 符号重命名
<leader>f 格式化通过visual模式选择的代码
<leader>qf 对当前行的问题应用自动修复
<c-l> 代码展开
<c-e> 翻译光标下单词(命令行)
<leader>i 翻译光标下单词(弹窗)

其他快捷键

快捷键 功能 插件
<leader>gg 显示tagbar tagbar
<c-p> markdown 预览 markdown-preview
<leader>tm 打开markdown表格美化 vim-table
gh 命令行显示函数声明 vim-preview
gl 在右侧栏预览函数体 -
gz 关闭右侧预览窗口 -
<alt-u> 预览窗口向上滚动 -
<alt-d> 预览窗口向下滚动 -
s{charA}{charB} 光标跳转到当前窗口的{charA}{charB} easymotion
<leader><leader>w 激活easymotion模式 -
<alt-=> alt_+/- 用于按分隔符扩大缩小 v 选区 -
F4 执行cmake . AsyncRun
F5 运行文件 call ExecuteFile() -
F6 测试文件make test -
F7 编译文件 make -
F8 运行项目 make run -
F9 编译 C/C++ gcc -o -
<leader>s 打开Startify窗口 Startify
g; 跳转到上一次修改处  
g, 跳转到下一次修改处  
<c-w>[<c-w>] 调整窗口大小  

ld.so, ld-linux.so* - 动态链接器和加载器

动态链接器可以通过运行一些动态链接的程序或共享对象间接运行(在这种情况下,不能传递动态链接器的命令行选项,在ELF情况下,存储在程序的.interp部分的动态链接器会被执行),或者直接运行:

/lib/ld-linux.so.*  [OPTIONS] [PROGRAM [ARGUMENTS]]

说明

ld.sold-linux.so*程序找到并加载程序所需的共享对象(共享库),为程序的运行做准备,然后运行。

Linux 二进制文件需要动态链接 (运行时的链接), 除非在编译过程中给 ld 添加了 -static 选项。

ld.so 程序处理 a.out 二进制文件,这是很久以前使用的格式;ld-linux.so*处理 ELF(/lib/ld-linux.so.1 用于 libc5/lib/ld-linux.so.2 用于 glibc2),现在大家已经使用了很多年。 除此之外,两者都有相同的行为,并使用相同的支持文件和程序ldd(1)、ldconfig(8)和/etc/ld.so.conf。

在解析共享对象依赖关系时,动态链接器首先检查每个依赖关系字符串是否包含斜线(如果在链接时指定了包含斜线的共享对象路径名,则会出现这种情况)。 如果发现斜线,那么依赖字符串就会被解释为(相对或绝对)路径名,并使用该路径名加载共享对象。

如果一个共享对象的依赖关系不包含斜线,那么就会按照以下顺序进行搜索:

  1. (仅 ELF) 如果二进制文件的 DT_RPATH 动态部分属性存在且 DT_RUNPATH 属性不存在,则使用该属性指定的目录。 DT_RPATH 的使用已被废弃。
  2. 使用环境变量LD_LIBRARY_PATH(除非可执行文件是在安全执行模式下运行的),在这种情况下,它会被忽略
  3. (仅 ELF) 使用二进制文件 DT_RUNPATH 动态部分属性中指定的目录(如果存在)。
  4. 来自缓存文件/etc/ld.so.cache,它包含了之前在增强库路径中找到的候选共享对象的编译列表。 然而,如果二进制文件是用-z nodeflib链接器选项链接的,那么默认路径中的共享对象将被跳过。 安装在硬件能力目录中的共享对象(见下文)比其他共享对象更优先。
  5. 在默认路径中/lib,然后是/usr/lib。 (在某些64位架构上,64位共享对象的默认路径是/lib64,然后是/usr/lib64。) 如果二进制文件是用-z nodeflib链接器选项链接的,则跳过这一步。

选项

选项 说明
–list 列出所有的依赖关系,以及它们是如何解析(resolved)的
–verify 确认程序是动态链接的,而且这个动态链接器可以处理
–inhibit-cache 不要使用/etc/ld.so.cache
–library-path <路径> 使用<路径>代替`LD_LIBRARY_PATH`环境变量设置(见下文)
–inhibit-rpath <列表> 忽略<列表>指定的对象中的RPATH和RUNPATH信息。 在安全执行模式下运行时,这个选项会被忽略(见下文)
–audit <列表> 使用列表中命名的对象作为审核员

环境

各种环境变量影响着动态链接器的运行

安全执行模式

为了安全起见,如果动态链接器确定二进制文件应该在安全执行模式下运行,那么一些环境变量的效果就会失效或被修改。 这个决定是通过检查辅助向量中的AT_SECURE条目(见getauxval(3))是否有一个非零值来实现的。 这个条目可能因为各种原因而具有非零值,包括:

  1. 进程的实际和有效值。
  2. 进程的真实和有效用户ID不同,或者真实和有效组ID不同。 这通常是执行set-user-ID或set-group-ID程序的结果
  3. 一个非root用户ID的进程执行了一个赋予允许或有效能力的二进制程序。
  4. Linux安全模块可能设置了一个非零值

比较重要的环境变量

环境变量 说明
LD_ASSUME_KERNEL 每个共享对象都可以告知动态链接器它所需要的最小内核ABI版本。 (这个要求被编码在ELF注解部分,可以通过readelf -n查看标有NT_GNU_ABI_TAG的部分。) 在运行时,动态链接器确定运行中的内核的ABI版本,并将拒绝加载指定了超过该ABI版本的最小ABI版本的共享对象。
LD_ASSUME_KERNEL可以用来使动态链接器假定它是在一个具有不同的内核ABI版本的系统上运行。 例如,下面的命令行使动态链接器在加载myprog所需的共享对象时,假定它运行在Linux 2.2.5上。
$ LD_ASSUME_KERNEL=2.2.5 ./myprog
在提供共享对象的多个版本(在搜索路径的不同目录中)的系统上,这些共享对象有不同的最低内核ABI版本要求,LD_ASSUME_KERNEL可以用来选择使用的对象版本(取决于目录搜索顺序)。 从历史上看,LD_ASSUME_KERNEL功能最常见的用法是在同时提供LinuxThreads和NPTL的系统上手动选择旧的LinuxThreads POSIX线程实现(后者通常是这类系统的默认版本);参见pthreads(7)。
LD_LIBRARY_PATH 在执行时搜索ELF库的目录列表。 列表中的项目由冒号或分号分隔。 类似于PATH环境变量。 在安全执行模式下,这个变量被忽略
LD_PRELOAD 在所有其他对象之前加载的额外的、用户指定的ELF共享对象列表。 列表中的项目可以用空格或冒号分隔。 这可以用来选择性地覆盖其他共享对象的功能。 使用在DESCRIPTION下给出的规则搜索对象。 在安全执行模式下,包含斜线的预加载路径名会被忽略,只有当共享对象文件上的set-user-ID模式位被启用时,才会加载标准搜索目录中的共享对象。
LD_TRACE_LOADED_OBJECTS (仅 ELF) 如果设置 (为任何值),将导致程序列出其动态依赖关系,就像通过 ldd(1) 运行一样,而不是正常运行。

Rpath标签扩展

ld.so可以理解rpath规范中的某些字符串(DT_RPATHDT_RUNPATH);这些字符串被替换为以下内容:

  1. $ORIGIN(或等价的${ORIGIN})

    这将扩展到包含程序或共享对象的目录。 因此,一个位于somedir/app的应用程序可以用以下方式编译

    gcc -Wl,-rpath,'$ORIGIN/../lib'
    

    这样它能在somedir/lib中找到相关的共享对象,无论somedir在目录层次中的位置如何。 这有利于创建 “交钥匙 “应用程序(turn-key applications),这些应用程序不需要安装到特殊的目录中,而是可以解压到任何目录中,并且仍然可以找到自己的共享对象。

  2. $LIB (或者${LIB})

    根据不同的架构,它可以扩展为lib或lib64(例如,在x86-64上,它扩展为lib64,在x86-32上,它扩展为lib)。

  3. $PLATFORM (或者${PLATFORM})

    这将扩展为对应于主机系统处理器类型的字符串(例如,”x86_64”)。 在某些架构上,Linux内核并没有向动态链接器提供平台字符串。 这个字符串的值取自辅助向量中的AT_PLATFORM值(见getauxval(3))。

文件

  1. /lib/ld.so

    a.out 的动态链接器/加载器

  2. /lib/ld-linux.so.{1, 2}

    ELF 的动态链接器/加载器

  3. /etc/ld.so.cache

    文件中包含一个用于搜索共享对象的目录汇编列表,以及候选共享对象的有序列表。

  4. /etc/ld.so.preload

    包含一个以空格分隔的ELF共享对象列表的文件,要在程序之前加载。

  5. lib*.so*

    共享对象

注意

ld.so功能适用于使用libc 4.4.3或更高版本编译的可执行文件。 ELF功能从Linux 1.1.52和libc5开始提供。

libc、glibc和glib的关系

glibc 和 libc

glibc 和 libc 都是 Linux 下的 C 函数库。

libc 是 Linux 下的 ANSI C 函数库;glibc 是 Linux 下的 GUN C 函数库。

ANSI C 和 GNU C 的区别

ANSI C 函数库是基本的 C 语言函数库,包含了 C 语言最基本的库函数。这些库函数在其各种支持 C 语言的 IDE 中都是有的。

GNU C 函数库是一种类似于第三方插件的东西。由于 Linux 是用 C 语言写的,所以 Linux 的一些操作是用 C 语言实现的。因此,GUN 组织开发了一个 C 语言的库,以便让我们更好的利用 C 语言开发基于 Linux 操作系统的程序。不过现在的不同的 Linux 的发行版本对这两个函数库有不同的处理方法,有的可能已经集成在同一个库里了。

glibc是linux下面c标准库的实现,即GNU C Library。glibc本身是GNU旗下的C标准库,后来逐渐成为了Linux的标准c库,而Linux下原来的标准c库Linux libc逐渐不再被维护。Linux下面的标准c库不仅有这一个,如uclibc、klibc,以及上面被提到的Linux libc,但是glibc无疑是用得最多的。glibc在/lib目录下的.so文件为libc.so.6。

查看当前系统的 glibc 版本的两种方法:

  1. /lib/libc.so.6

    # /lib32/libc.so.6 
    GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
    Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Compiled by GNU CC version 5.4.0 20160609.
    Available extensions:
            crypt add-on version 2.1 by Michael Glad and others
            GNU Libidn by Simon Josefsson
            Native POSIX Threads Library by Ulrich Drepper et al
            BIND-8.2.3-T5B
    libc ABIs: UNIQUE IFUNC
    For bug reporting instructions, please see:
    <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
    
  2. ldd

    # ldd --version            
    ldd (Ubuntu GLIBC 2.23-0ubuntu11) 2.23
    Copyright (C) 2016 自由软件基金会。
    这是一个自由软件;请见源代码的授权条款。本软件不含任何没有担保;甚至不保证适销性
    或者适合某些特殊目的。
    由 Roland McGrath 和 Ulrich Drepper 编写。
    

glibc 和 glib

glib 和 glibc 基本上没有太大联系,可能唯一的共同点就是,其都是 C 编程需要调用的库而已。

glib 是 Gtk+ 库和 Gnome 的基础。glib 可以在多个平台下使用,比如 Linux、Unix、Windows 等。glib 为许多标准的、常用的 C 语言结构提供了相应的替代物。

glib是GTK+的基础库,它由基础类型、对核心应用的支持、实用功能、数据类型和对象系统五个部分组成,可以在gtk网站下载其源代码。是一个综合用途的实用的轻量级的C程序库,它提供C语言的常用的数据结构的定义、相关的处理函数,有趣而实用的宏,可移植的封装和一些运行时机能,如事件循环、线程、动态调用、对象系统等的API。GTK+是可移植的,当然glib也是可移植的,你可以在linux下,也可以在windows下使用它。使用gLib2.0(glib的2.0版本)编写的应用程序,在编译时应该在编译命令中加入pkg-config --cflags --libs glib-2.0,如:

gcc `pkg-config --cflags --libs glib-2.0` hello.c -o hello

使用glib最有名的就是GNOME了。

总结

libc, glibc在一个层次,都是C的标准实现库,是操作系统级别的基石之一。

glib是用C写的一些utilities,即C的工具库,和libc/glibc没有关系。