常用路径总结

在Linux中,我们如果用apt之类的包管理工具安装些第三方库,他们放置的位置都出奇的一致,下面来总结一下

头文件

编译时默认头文件查找目录

  • /usr/include
  • /usr/include/x86_64-linux-gnu(架构相关的子目录)
  • /usr/local/include(大部分发行版是默认的,但也有的不是)

搜索规则

  • 编译器只维护一组搜索根目录列表
  • 不会递归扫描子目录
  • 会将#include中写出的相对路径与搜索根目录拼接后匹配

例如:#include <foo/bar.h> 会依次尝试:

1
2
3
/usr/include/foo/bar.h
/usr/include/x86_64-linux-gnu/foo/bar.h
/usr/local/include/foo/bar.h(如果该路径在默认列表中)

第三方库头文件的组织方式

  • 第三方库通常在搜索根目录下创建以库名命名的子目录
1
2
/usr/include/x86_64-linux-gnu/opencv4
/usr/local/include/mylib

使用方式为:#include <库名/头文件.h>

  • 这样既避免命名冲突,又符合默认搜索模型
  • 若库安装在非默认路径下,才需要使用-Itarget_include_directories()

库文件

编译与链接时库文件默认查找目录

  • /lib
  • /usr/lib
  • /usr/lib/x86_64-linux-gnu(架构相关的子目录)
  • /usr/local/lib(大部分发行版是默认的,但也有的不是)

三方库几乎都会在上述路径下安装对应的库文件,通常以lib库名.so(动态库)或lib库名.a(静态库)的形式存在,例如/usr/lib/x86_64-linux-gnu/libopencv_core.so

  • 在链接阶段,链接器ld会在这些默认路径中查找通过-l库名指定的库文件
  • 用户通常只需要写-lopencv_core而不需要关心具体路径和文件名
  • 这些目录是链接时的默认搜索路径,因此不需要额外通过-L或者target_link_directories()手动添加

运行时动态库默认查找目录

  • /lib

  • /usr/lib

  • /usr/lib/x86_64-linux-gnu

  • /etc/ld.so.conf/etc/ld.so.conf.d/中配置的目录(这些路径会被缓存到/etc/ld.so.cache中,通常通过ldconfig生成)

    • 程序运行时由动态链接器ld负责加载所需的.so文件

    • apt安装或升级动态库后,系统会自动更新这套缓存机制

静态库与动态库在运行阶段的区别

  • 使用静态库生成的程序在运行时不再依赖外部库文件
  • 使用动态库生成的程序在运行时必须能在默认路径或配置路径中找到对应的.so
  • 如果动态库不在默认路径中,需要通过LD_LIBRARY_PATH环境变量或rpath等机制额外指定

不管时运行还是链接阶段,系统都默认只会在上面几个目录找,并不会递归搜索其子目录

举个例子,如果OpenCV安装在/usr/lib/x86_64-linux-gnu/opencv/libopencv_shape.so下,系统默认就找不到了,得通过-Lopencv/xxx.so才行

CLI工具

在Linux中,系统默认搜索CLI可执行文件的路径由PATH环境变量决定,一般系统会自带以下路径:

1
2
3
4
5
6
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin

这些目录会按顺序出现在PATH中,shell在执行命令时会从前到后依次查找,一旦在某个目录中找到同名可执行文件,就立即使用,不再继续向后查找

从功能分工上理解会更清晰:

  • /bin/sbin属于最基础层,存放系统启动和紧急维护所需的最小命令集合,即使在没有挂载/usr的情况下也必须可用
  • /usr/bin/usr/sbin是主体,绝大多数由发行版apt安装的命令行工具都会放在这里,普通用户常用的程序在/usr/bin,系统管理相关的命令在/usr/sbin
  • /usr/local/bin/usr/local/sbin则用于用户或管理员手动安装的软件,用来与包管理器安装的程序明确区分,但同样默认可直接执行

配置文件

系统级配置文件的默认路径:/etc

  • /etc系统范围内唯一被约定为配置文件根目录的地方
  • 几乎所有系统服务、守护进程和CLI工具的全局配置都位于这里
  • apt安装的软件如果需要配置,都会在/etc下创建对应的配置文件或子目录

配置文件有以下几种组织方式:

1.按“一个程序一个目录”的组织方式(/etc/程序名/):这种结构避免了大量配置文件直接堆在/etc根目录下

  • 例如/etc/ssh/etc/nginx/etc/systemd
  • 目录内通常包含主配置文件、模块配置、启用/禁用配置等

2.单文件形式的配置:结构较简单的工具常采用单一配置文件(/etc/程序名.conf

  • 例如/etc/resolv.conf/etc/ld.so.conf
  • 文件名本身就明确对应的程序或子系统

3..d目录机制(/etc/程序名.d/):主配置文件会包含或自动加载该目录下的所有配置片段

  • 例如/etc/ld.so.conf.d//etc/sysctl.d/
  • 这种方式非常适合包管理器和用户同时修改配置而不互相覆盖

4.用户级配置文件的路径

  • ~/.config/~/.程序名/~/.程序名rc
  • 这些配置只对当前用户生效,不影响系统其他用户
  • 通常用于CLI工具、桌面程序或开发工具
  • 用户级配置的优先级通常高于系统级配置

内核相关

内核头文件

如果要在本机编译内核模块,需要下载内核头文件,可以通过包管理工具下载

1
sudo apt install linux-headers-$(uname -r)

下载的头文件会被放在/usr/src/linux-headers-$(uname -r)/

内核源码

如果要在本机编译内核,需要下载内核源码,可以通过包管理工具下载,会被放到/usr/src/linux-source/

1
sudo apt install linux-source-$(uname -r)

但这样下载的是和当前内核相同版本的,不同版本的需要去github下载

内核模块

编译好的内核模块(.ko文件),通常都放在/lib/modules/$(uname -r)/ 目录下

  • 内核的Makefile提供modules_install这个label,只要sudo make modules_install就会自动将内核模块安装到这个目录
  • apt包管理工具下载的内核模块也是默认放到这个目录下

内核镜像

Linux其实可以通过apt直接下载新版本的内核镜像,从而实现内核的更新

1
2
3
4
# 安装特定版本
sudo apt install linux-image-<version>
# 安装最新版本
sudo apt install linux-image-generic

下载的内核会被安装到以下路径

1
2
3
4
/boot/vmlinuz-6.8.0-90-generic # 内核镜像
/boot/config-6.8.0-90-generic # 内核配置文件
/boot/initrd.img-6.8.0-90-generic # 在启动时加载的临时根文件系统
/lib/modules/6.8.0-90-generic/ # 内核模块