当前位置: 首页 > news >正文

linux之buildroot(3)配置软件包

Linux之buildroot(3)配置软件包

Author:Onceday Date:2023年11月30日

漫漫长路,才刚刚开始…

全系列文章请查看专栏: buildroot编译框架_Once_day的博客-CSDN博客。

参考文档:

  • Buildroot - Making Embedded Linux Easy
  • mdev.txt « docs - busybox - BusyBox: The Swiss Army Knife of Embedded Linux

文章目录

      • Linux之buildroot(3)配置软件包
        • 1. 基础软件包
          • 1.1 设备文件(/dev)管理
          • 1.2 初始化进程(init)
          • 1.3 其他基础包
        • 2. 通用软件包
          • 2.1 常用编译指令
          • 2.2 重新编译
          • 2.3 重新编译指定包
          • 2.4 指定编译输出目录
          • 2.5 设置环境变量
          • 2.6 提高文件系统镜像的存储效率
          • 2.7 查看软件包依赖关系图
          • 2.8 查看软件包编译耗时
          • 2.9 查看软件包占比图
        • 3. 高级构建参数
          • 3.1 并行构建支持
          • 3.2 使用在builroot之外生成的工具链
          • 3.3 使用ccache加快编译
          • 3.4 重定向软件包下载目录
          • 3.5 开发环境中使用
        • c4. 附注信息
          • 4.1 devtmpfs简介
          • 4.2 mdev/udev/eudev简介
          • 4.3 系统初始化程序简介
          • 4.4 getty简介
          • 4.5 稀疏文件(Sparse file)
          • 4.6 Ccache介绍

1. 基础软件包
1.1 设备文件(/dev)管理

在Linux系统中,/dev目录包含特殊文件,称为设备文件,允许用户空间应用程序访问由Linux内核管理的硬件设备。如果没有这些设备文件,那么用户空间应用程序将无法使用硬件设备,即使它们能够被Linux内核正确识别。builroot提供了四种不同的解决方案来处理/dev目录,可在System Configuration/dev management查看:

(1) 静态使用设备表。这是在Linux中处理设备文件的传统方法。使用这种方法,设备文件被持久地存储在根文件系统中(也就是说,它们在重新引导时一直存在),并且当硬件设备被添加或从系统中删除时,没有任何东西会自动创建和删除这些设备文件。因此,Buildroot使用设备表创建了一组标准的设备文件,默认的设备表存储在Buildroot源代码的system/device_table_dev.txt中。当builroot生成最终的根文件系统映像时,将处理该文件,因此设备文件在output/target目录中不可见。

BR2_ROOTFS_STATIC_DEVICE_TABLE选项允许更改Buildroot使用的默认设备表,或者添加一个额外的设备表,以便Buildroot在构建期间创建额外的设备文件。因此,如果使用此方法,并且目标系统中缺少设备文件,可以创建一个文件,如下:

board/<yourcompany>/<yourproject>/device_table_dev.txt

其中包含附加设备文件的描述,然后可以将BR2_ROOTFS_STATIC_DEVICE_TABLE设置为:

system/device_table_dev.txt board/<yourcompany>/<yourproject>/device_table_dev.txt

(2) 仅使用devtmpfsdevtmpfs是Linux内核中的一个虚拟文件系统,它是在内核2.6.32中引入。当挂载到dev中时,这个虚拟文件系统会随着硬件设备的添加和从系统中移除而自动地使设备文件出现和消失。这个文件系统在重新引导时不是持久的,它由内核动态填充。

使用devtmpfs需要启用以下内核配置选项:CONFIG_DEVTMPFSCONFIG_DEVTMPFS_MOUNT。当builroot负责为目标嵌入式设备构建Linux内核时,它会确保启用这两个选项。但是,如果在Buildroot之外构建Linux内核,但没有启动这两个选项,那么Linux系统将无法启动。

(3) 动态使用devtmpfs + mdev。此方法依赖于devtmpfs虚拟文件系统,但是在其之上添加了mdev用户空间程序。mdev是BusyBox的一个程序部分,内核将在每次添加或删除设备时调用它。根据/etc/mdev.conf配置文件,mdev可以被配置如下:

  • 设置设备文件的特定权限或所有权。
  • 每当设备出现或消失时调用脚本或应用程序。

基本上,它允许用户空间对设备添加和删除事件做出反应。例如,Mdev可用于在系统上出现设备时自动加载内核模块。如果目标设备需要固件,那么Mdev也很重要,因为它将负责将固件内容推送到内核。Mdevudev的轻量级实现(功能更少)。

有关mdev及其配置文件语法的更多详细信息,请参见:

  • mdev.txt « docs - busybox - BusyBox: The Swiss Army Knife of Embedded Linux

(4) 动态使用devtmpfs + eudev。此方法依赖于devtmpfs虚拟文件系统,但在其之上添加了eudev用户空间守护进程。Eudev是一个在后台运行的守护进程,当一个设备从系统中添加或删除时,内核会调用它。eudevudev的独立版本,udev是大多数桌面Linux发行版中使用的原始用户空间守护进程,现在是Systemd的一部分。

builroot开发人员建议从第二个方案(仅使用devtmpfs)开始使用。如果需要在添加/删除设备时通知用户空间,或者需要固件,第三个方案(动态使用devtmpfs + mdev)通常是一个很好的方式。如果systemd被选为init system, /dev管理将由systemd提供的udev程序执行

1.2 初始化进程(init)

init 是 Unix 和 Unix-like 操作系统(如 Linux)的一个重要组成部分,它是在系统启动时由内核首先启动的进程,其进程号(PID)通常是 1,其他的用户空间程序和服务将由它来负责启动。

Buildroot提供三种方法用于init程序,在System configuration/Init system中可供选择:

(1) BusyBox。在许多程序中,BusyBox有一个基本init程序的实现,这对于大多数嵌入式系统来说已经足够了,也是buildroot的默认方案。

启用BR2_INIT_BUSYBOX将确保BusyBox将构建并安装其初始化程序。BusyBox init程序将在引导时读取/etc/inittab文件,以了解该做什么。该文件的语法可参考下面文档(需要注意Busybox inittab的语法与其他类似文件不一样):

  • http://git.busybox.net/busybox/tree/examples/inittab

默认的inittab文件保存在system/skeleton/etc/inittab中。除了挂载一些重要的文件系统外,默认inittab文件的主要工作是启动/etc/init.d/rcS脚本,并启动getty程序(该程序提供登录提示)。

(2) systemV。这个方案使用旧的传统sysvinit程序,打包在Buildroot的package/sysvinit中。这是大多数桌面Linux发行版中使用的解决方案,直到它们切换到最近的替代方案,如Upstart或Systemd。sysvinit还可以使用inittab文件(其语法与BusyBox中的略有不同)。systemV默认inittab文件位于package/sysvinit/inittab中。

(3) systemdsystemd是Linux的新一代初始化系统。它比传统的init程序做得更多,如积极的并行化能力,使用套接字和D-Bus来启动服务,提供按需启动守护进程,使用Linux控制组跟踪进程,支持快照和系统恢复等功能。对于复杂的嵌入式系统来说,使用systemd比较合适,因为Systemd本身会带来非常多的依赖库。

对于资源较少的嵌入式设备系统来说,BusyBox initsystemd更为合适

1.3 其他基础包

以下的软件可以指定配置文件,并且在此基础上可以进一步修改和保存配置(没有指定将使用默认配置):

  • BusyBox,使用BR2_PACKAGE_BUSYBOX_CONFIG指定,可通过make busybox-menuconfig进一步修改。
  • uClibc,使用BR2_UCLIBC_CONFIG指定,可通过make uclibc-menuconfig进一步修改。
  • Linux kernel,使用BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG指定自定义配置,也可用BR2_LINUX_KERNEL_USE_DEFCONFIG导入预定义配置,后续可通过make linux-menuconfig进一步修改。
  • Barebox,使用BR2_TARGET_BAREBOX_USE_CUSTOM_CONFIGBR2_TARGET_BAREBOX_USE_DEFCONFIG分别指定自定义配置和预定义配置,可通过make barebox-menuconfig进行后续修改。
  • U-Boot,使用BR2_TARGET_UBOOT_USE_CUSTOM_CONFIGBR2_TARGET_UBOOT_USE_DEFCONFIG分别指定自定义配置和预定义配置,可通过make uboot-menuconfig进行后续修改。

当这些软件包没有使能时,make xxx-menuconfig通常是不可用的,因此需要确认.config文件中的配置情况

2. 通用软件包
2.1 常用编译指令
编译命令描述
make V=1 <target>执行一个make目标时,输出执行的命令信息和步骤,可用于分析编译过程。
make menuconfig进行buildroot配置,可以指定O=/path在指定目录中输出编译文件。
make list-defconfigs显示所有的默认配置文件,需要具有configs目录和对应的defconfigs
make help显示帮助文本,里面列出了buildroot提供的通用Target操作。
make clean清除所有build/host/target等编译输出,但部分配置会保留。
当编译架构和toolchain变化时,应该主动make clean,再全部重新编译。
make manual编译buildroot帮助文档(需要安装依赖库),也就是指导手册,可用make manual-clean清除。
make distclean重置整个buildroot编译输出,包括配置文件,通常用于准备编译一个新目标输出。
make printvars VARS='xxx'打印指定编译变量的值,可以指定多个变量(空格区分),也可以使用通配符%进行匹配。
以下的命令都可以搭配pkg使用,如make pkg-source只对指定的pkg软件包执行
make source下载所有源文件,这样就可以在离线环境下进行编译和配置。
make depends编译和安装所有软件包所需要的依赖目标。
make extract将软件包源文件提取到build目录中。
make patch打上软件包的补丁。
make configure运行配置命令(configure cmds)。
make build运行编译命令(build cmds)。
make install-staging(Target package)在staging目录中运行安装命令。
make install-target(Target package)在target目录中运行安装命令。
make install(Target package)运行install-staginginstall-target
(Host package)在host目录中运行安装命令。
make show-info以json格式输出使能软件包的依赖、许可证等数据信息。
make show-depends显示编译软件包的直接依赖关系。
make show-recursive-depends递归显示编译软件包的依赖关系。
make show-rdepends显示编译软件包的反向直接依赖关系。
make show-recursive-rdepends递归显示编译软件包的反向依赖关系。
make graph-depends输出图形化(PDF)的软件包依赖关系,可以直观清晰的查看不同软件包之间的依赖。
make graph-rdepends输出图形化(PDF)的软件包反向依赖关系,可以直观清晰的查看不同软件包之间的依赖。
make pkg-stats已HTML和JSON格式输出软件包的状态信息,可以查看安全漏洞和版本,需要网络支持。
make graph-build输出软件包编译时间的统计图表,按照编译顺序、耗时、软件包名称等排序和呈现。
make graph-size输出软件包占根文件系统的占比图,展示每个软件包耗费的存储空间大小。
make dirclean清除指定包的build子目录。
make reinstall重新运行安装命令。
make rebuild重新运行编译命令,当使用OVERRIDE_SRCDIR特性时或者在build目录修改文件,才起实际作用。
make reconfigure重新运行配置命令,当使用OVERRIDE_SRCDIR特性时或者在build目录修改文件,才起实际作用。

额外说明:

  • make -s printvars VARS=xxx 可以搭配以下两个参数:

    (1) QUOTED_VARS,如果设置为YES,将单引号引用值。

    ubuntu->buildroot:$ make printvars VARS=BUSYBOX_FINAL_DEPENDENCIES QUOTED_VARS=yes
    BUSYBOX_FINAL_DEPENDENCIES='host-skeleton skeleton toolchain'
    

    (2) RAW_VARS,如果设置为YES,将打印未展开的值。

    ubuntu->buildroot:$ make printvars VARS=BUSYBOX_FINAL_DEPENDENCIES QUOTED_VARS=yes RAW_VARS=yes
    BUSYBOX_FINAL_DEPENDENCIES='$(sort $(BUSYBOX_DEPENDENCIES))'
    

    QUOTED_VARS选项输出的带有引号的值,可重新注入到Shell脚本中,成为环境变量:

    ubuntu->buildroot:$ eval $(make printvars VARS=BUSYBOX_FINAL_DEPENDENCIES QUOTED_VARS=yes)
    ubuntu->buildroot:$ echo $BUSYBOX_FINAL_DEPENDENCIES
    host-skeleton skeleton toolchain
    
2.2 重新编译

当通过make menuconfigmake nconfig或其他配置工具更改系统配置时,builroot不会尝试检测应该重新构建系统的哪些部分。很难找到一种完全可靠的方式去检查什么时候重建整个系统,什么时候重建特定的包,因此作为用户需要根据实际情况把握,下面是一些可供参考的场景:

  • 当目标体系结构配置发生更改时,需要完全重新构建。更改架构种类,例如二进制格式或浮点策略会对整个系统产生影响。
  • 当工具链配置更改时,通常需要完全重新构建。更改工具链配置通常涉及更改编译器版本、C库类型或其配置,或其他一些基本配置项,这些更改会对整个系统产生影响。
  • 当额外的包被添加到配置中时,不需要完全重新构建。builroot将检测到这个包从未被构建过,并将构建它。但是,如果这个包是一个库,可以被已经构建的包使用,那么Buildroot将不会自动重新构建这些包。或者您知道应该重新构建哪些包,并且可以手动重新构建它们,或者您应该进行完整的重新构建。例如,假设您使用ctorrent包构建了一个系统,但没有使用openss1。您的系统工作正常,但是您意识到您希望在ctorrent中支持SSL,因此您在builroot配置中启用openssl包并重新启动构建。builroot将检测到应该构建openssl,并将构建它,但它不会检测到应该重新构建ctorrent以受益于openssl以添加openssl支持。您要么必须进行完整的重新构建,要么重新构建ctorrent本身。
  • 当一个包从配置中删除时,builroot不会做任何特别的事情。它不会从目标根文件系统或工具链sysroot中删除这个包安装的文件。需要完全重新构建以摆脱此包。然而,通常您并不一定需要立即删除这个包: 您可以等到下一个空闲时间重新开始构建。
  • 当包的子选项被更改时,不会自动重新构建包。在做出这样的更改之后,通常只重新构建这个包就足够了,除非启用包子选项向包中添加了一些对已经构建的另一个包有用的特性。同样,Buildroot不跟踪何时应该重新构建包:一旦构建了包,除非显式地告诉它这样做,否则它永远不会重新构建。
  • 当对根文件系统框架进行更改时,需要进行完整的重新构建。但是,当对根文件系统进行更改时,不需要进行完整的重新构建:简单的make调用将考虑这些更改。
  • 当在FOO_DEPENDENCIES中列出的包被重新构建或删除时,包foo不会自动重新构建。例如,如果使用FOO_DEPENDENCIES = barpackage bar列在FOO_DEPENDENCIES中,并且更改了bar包的配置,则配置更改不会自动导致package foo的重新构建。在这种情况下,您可能需要重新构建构建中的任何在其依赖项中引用bar的包,或者执行完整的重新构建以确保任何bar依赖包都是最新的。

一般来说,当面临构建错误并且不确定所做的配置更改的潜在后果时,请执行完整的重新构建。如果得到相同的构建错误,那么可以确定该错误与包的部分重新构建无关,如果此错误发生在来自官方Buildroot的包中,请毫不犹豫地报告问题!随着使用Buildroot的经验的增加,你将逐渐了解何时真正需要进行完全重新构建,并且节省越来越多的时间。

执行下面的命令可以完全清除再重建:

make clean all
2.3 重新编译指定包

Buildroot用户最常见的问题之一是如何重新构建给定的包,或者如何在不重新构建所有内容的情况下删除一个包。如果不从头重新构建,则builroot不支持删除包。这是因为Buildroot不跟踪哪个包安装了output/stagingoutput/target目录中的哪些文件,或者哪个包将根据另一个包的可用性进行不同的编译。

从头开始重新构建单个包的最简单方法是删除output/build中的构建目录。然后,builroot将从头开始重新提取、重新配置、重新编译和重新安装这个包。您可以使用make <package>-dirclean命令要求builtroot执行此操作。

另一方面,如果您只想从编译步骤重新启动包的构建过程,则可以运行make <package>-rebuild。它将重新启动包的编译和安装,但不是从头开始: 它基本上是在包内重新执行makemake install,因此它只会重新构建更改过的文件。

如果希望从配置步骤重新启动包的构建过程,可以运行make <package>-reconfigure。它将重新启动包的配置、编译和安装。而<package>-rebuild意味着<package>-install<package>-reconfigure意味着<package>-rebuild这些目标,以及<package>只作用于所述包,而不触发重新创建根文件系统映像。如果需要重新创建根文件系统,还应该运行makemake all

在内部,builroot创建所谓的stamp文件来跟踪每个包完成了哪些构建步骤。它们存储在包构建目录中:

output/build/<package>-<version>/.stamp_<step-name>

上面详细介绍的命令只是操作这些stamp文件,以强制builroot重新启动包构建过程的一组特定步骤。

2.4 指定编译输出目录

默认情况下,Buildroot构建的所有内容都存储在Buildroot树的目录输出中。builroot还支持用类似于Linux内核的语法从树中构建。要使用它,在make命令行中添加O=<directory>:

make O=/tmp/build menuconfig

所有的输出文件都位于/tmp/build下。如果O路径不存在,则builroot将创建它。注意: O路径既可以是绝对路径,也可以是相对路径,但如果它作为相对路径传递,请注意它是相对于主Buildroot源目录解释的,而不是当前工作目录

当指定输出目录构建时,.config和临时文件也存储在输出目录中。这意味着只要使用唯一的输出目录,就可以安全地使用相同的源代码树并行运行多个构建。

为了方便使用,builroot在输出目录中生成一个Makefile包装器——因此在第一次运行之后,您不再需要传递O = <…>,只需运行(在输出目录中):

make <target>
2.5 设置环境变量

Buildroot中有一些预期的环境变量,它们可以被传递进Make里,并且作为环境变量,用户可以单独指定它们的值。

变量名描述
HOSTCXX编译环境本地C++编译器
HOSTCC编译环境本地C编译器
UCLIBC_CONFIG_FILE==<path/to/.config>uClibc配置文件,推荐通过.config文件配置(make menuconfig)
BUSYBOX_CONFIG_FILE=<path/to/.config>BusyBox配置文件,推荐通过.config文件配置(make menuconfig)
BR2_CCACHE_DIR指定ccache缓存文件的目录
BR2_DL_DIR指定builroot存储/检索下载文件的目录,推荐通过.config文件配置(make menuconfig)
BR2_GRAPH_ALT如果设置且非空,则在build-time图表中使用备用配色方案
BR2_GRAPH_OUT设置生成图形的文件类型,pdf(默认)或png
BR2_GRAPH_DEPS_OPTS传递额外的选项到软件包依赖图生成程序中
BR2_GRAPH_DOT_OPTS作为选项逐字传递给dot实用程序,以绘制依赖关系图
BR2_GRAPH_SIZE_OPTS传递额外的选项到build-size图表中

下面是一个使用示例:

make HOSTCXX=g++-4.3-HEAD HOSTCC=gcc-4.3-HEAD
2.6 提高文件系统镜像的存储效率

文件系统映像可能会变得非常大,这取决于选择的文件系统、软件包的数量、是否提供了可用空间等等。然而,文件系统映像中的某些位置可能只是空的(例如,一长串零),这样的文件称为稀疏文件sparse file。大多数工具都可以有效地处理稀疏文件,并且只存储或写入稀疏文件中非空的部分。例如:

  • tar接受-S选项来告诉它只存储稀疏文件的非零块:

    tar cf archive.tar -s [files…]	#将有效地将稀疏文件存储在tarball中
    tar xf archive.tar -s			#将有效存储从tarball中提取的稀疏文件
    
  • cp接受--sparse=WHEN选项,WHEN可选值包括auto/never/always这三个值之一:

    cp --sparse=always source.file dest.file # 如果source.file中有很多零,那么dest.file将是一个稀疏文件
    
2.7 查看软件包依赖关系图

Buildroot的工作之一是了解包之间的依赖关系,并确保它们按照正确的顺序构建。这些依赖关系有时可能相当复杂,对于给定的系统,通常不容易理解为什么这样或那样的包被Buildroot引入构建中。

为了帮助理解依赖关系,从而更好地理解嵌入式Linux系统中不同组件的角色,builroot能够生成依赖关系图。要生成编译的整个系统的依赖关系图,只需运行:

make graph-depends

可以在output/graphs/graph-depends.pdf中找到生成的PDF图。如果系统非常大,那么依赖关系图可能过于复杂,难以阅读。因此,可以为给定的包生成依赖关系图:

make <pkg>-graph-depends

注意,依赖关系图是使用Graphviz项目中的dot工具生成的,必须在系统上安装该工具才能使用此特性。在大多数发行版中,它作为graphviz包提供。

默认情况下,依赖关系图以PDF格式生成。但是,通过传递BR2_GRAPH_OUT环境变量,可以切换到其他输出格式,例如PNGPostScriptSVGBR2_GRAPH_DEPS_OPTS可以控制关系图输出的格式,如下:

  • --depth N/-d N,将依赖深度限制为N个级别。默认值0表示没有限制。
  • --stop-on PKG/-s PKG,停止包PKG上的图形,PKG可以是实际包名、通配符、关键字virtual(停止在虚拟包)或关键字host(停止在本地包)。PKG包仍然出现在图上,但是它的依赖项不在了。
  • --exclude PKG/-x PKG,像--stop-on一样,但也从图中省略PKG
  • --transitive/--no-transitive,绘制(或不绘制)传递依赖关系。默认情况下不绘制传递依赖项。
  • --colors R, T, H,以逗号分隔的颜色列表,用于绘制根包®,目标包(T)和本地包(H)。默认值:浅蓝色,灰色,亮灰色。

实例如下:

ubuntu->buildroot:$ BR2_GRAPH_DEPS_OPTS='--colors=red,green,cyan' make graph-depends
Getting dependency tree...
dot  -Tpdf \-o /home/ubuntu/build-root-all/buildroot/output/graphs/graph-depends.pdf \/home/ubuntu/build-root-all/buildroot/output/graphs/graph-depends.dot

下面是输出的PDF文件(buildroot编译一套toolchain):

在这里插入图片描述

2.8 查看软件包编译耗时

当系统的构建需要很长时间时,了解哪些包的构建时间最长,看看是否可以做些什么来加快构建速度,有时是有用的。为了帮助这样的构建时间分析,Buildroot收集每个包的每个步骤的构建时间,并允许从这些数据生成图形,使用如下命令即可:

make graph-build

会生成五个文件,如下:

  • build.hist-build.pdf,每个包的构建时间的直方图,按构建顺序排序。
  • build.hist-duration.pdf,每个包的构建时间的直方图,按持续时间排序(最长的优先)构建。
  • build.hist-name.pdf,每个包的构建时间的直方图,按包名排序。
  • build.pie-packages.pdf,每个包构建时间的饼状图。
  • build.pie-steps.pdf,一个饼状图,显示了包构建过程中每个步骤所花费的全局时间。
  • build.timeline.pdf,一个柱状图,按照构建顺序排布组件编译耗时,可以直观看出耗时较长的编译过程。

下面是build.hist-duration.pdf的输出,可以直观看出哪些包编译耗时较长:

在这里插入图片描述

下面是build.timeline.pdf的输出,非常直观看出编译顺序和耗时:

在这里插入图片描述

2.9 查看软件包占比图

当目标系统增长时,了解每个Buildroot包对整个根文件系统大小的贡献有时是有用的。为了帮助进行这样的分析,Buildroot收集每个包安装的文件的数据,并使用这些数据生成一个图表和CSV文件,详细说明不同包的大小贡献。使用命令如下:

make graph-size

输出如下文件:

  • output/graphs/graph-size.pdf,每个包对整个根文件系统大小的贡献的饼状图
  • output/graphs/package-size-stats.csv,一个CSV文件,给出每个包对整个根文件系统大小的大小贡献
  • output/graphs/file-size-stats. CSV,这是一个CSV文件,给出了每个已安装文件对其所属包的大小贡献,以及对整个文件系统大小的贡献。

此外,还可以设置环境变量BR2_GRAPH_SIZE_OPTS来进一步控制生成的图。可接受的选项有:

  • --size-limit X/-1 X,将把所有个人贡献低于X %的包分组到图中标记为Others的单个条目中。默认情况下,x=0.01,这意味着每个贡献小于1%的包被分组在Others下。可接受的取值范围为[0.0 ~ 1.0]。
  • --iec/--binary/--si/--decimal,使用IEC(二进制,1024的幂)或SI(十进制,1000的幂;默认)前缀。
  • --biggest-first,将包按大小递减顺序排序,而不是按大小递增顺序排序。

注意:收集的文件系统大小数据只有在完全干净地重建之后才有意义。在使用make graph-size之前,请确保运行makc clean all。要比较两个不同Buildroot编译的根文件系统大小,例如在调整配置之后或切换到另一个Buildroot版本时,可以使用size-stats-compare脚本。

它需要两个文件大小统计,csv文件(由make graph-size生成)作为输入。

ubuntu->buildroot:$ utils/size-stats-compare -h
usage: size-stats-compare [-h] [-d] [-t THRESHOLD]old-file-size-stats.csv new-file-size-stats.csv

下面是graph-size.pdf的输出:

在这里插入图片描述

3. 高级构建参数
3.1 并行构建支持

注意:本节处理的是一个非常实验性的特性,它在一些非异常情况下可以达到收支平衡。使用风险自负。

Buildroot总是能够在每个包的基础上使用并行构建:每个包都是由Buildroot使用make -jN(或非基于make的构建系统的等效调用)构建的。默认情况下,并行级别是CPUs+1,但可以使用BR2_JLEVEL配置选项进行调整。

在2020.02之前,Buildroot是以串行方式构建包的: 每个包一个接一个地构建,而包之间的构建没有并行化。截至2020.02年,Buildroot已经对顶级并行构建提供了实验性支持,通过并行构建没有依赖关系的包,可以显著节省构建时间。然而,这个功能被标记为实验性的,并且已知在某些情况下不起作用。

为了使用顶级并行构建,需要满足以下两个条件:

  • 在builroot配置中启用BR2_PER_PACKAGE_DIRECTORIES
  • 在启动Buildroot构建时使用make -jN

在内部,BR2_PER_PACKAGE_DIRECTORIES将启用一种称为**每包目录(perf-package directories)**的机制,它将具有以下效果:

  • 与所有包通用的全局目标(target)目录和全局主机(host)目录不同,将使用每个包的目标目录和主机目录,分别在$(O)/per-package/<pkg>/target/$(O)/per-package/<pkg>/host/中。这些文件夹将在<pkg>构建开始时从包依赖项的相应文件夹中填充。因此,编译器和所有其他工具只能看到和访问由<pkg>显式列出的依赖项安装的文件。
  • 在构建结束时,将填充全局目标(target)和主机(host)目录,分别位于$(O)/target$(O)/host中。这意味着在构建过程中,这些文件夹将是空的,只有在构建的最后才会填充它们。
3.2 使用在builroot之外生成的工具链

如果需要为目标设备编译自定义的程序或未打包在builroot中的其他软件,可以使用由builroot生成的工具链。默认情况下,builroot生成的工具链位于output/host/中。使用它的最简单方法是将output/host/添加到PATH环境变量中,然后使用ARCH-linux-gccARCH-linux-objdumpARCH-linux-ld等。

另外,通过运行make SDK命令,builroot还可以将所有选定包的工具链和开发文件导出为SDK。这将生成主机目录output/host/内容的tarball文件,名称如下:

output/images/<TARGET-TUPLE>_sdk-buildroot.tar.gz # 可以通过设置环境变量BR2_SDK_PREFIX来更改名字

当应用程序开发人员希望开发尚未打包为Buildroot包的应用程序时,可以将该tarball分发给应用程序开发人员。

在提取SDK tarball后,用户必须运行脚本relocate-sdk.sh(位于SDK的顶目录),以确保所有路径都使用新位置更新

或者,如果你只是想准备SDK而不生成tarball(例如,因为你将只是移动主机目录,或者将自己生成tarball),builroot也允许你只使用make prepare-sdk准备SDK而不实际生成tarball。

为了方便,通过选择BR2_PACKAGE_HOST_ENVIRONMENT_SETUP选项,可以在output/host/中安装一个environment-setup脚本。这个脚本可以从/sdk/path/environment中导出一些环境变量,这些环境变量将有助于使用Buildroot sdk交叉编译自定义项目:

  • PATH路径中将包含sdk二进制文件。
  • 标准autotools变量将用适当的值定义。
  • CONFIGURE_FLAGS将包含基本的./configure选项。

它还提供了一些有用的命令。但是请注意,一旦这个脚本被执行,环境就只会被设置为交叉编译,而不再是本机编译。

3.3 使用ccache加快编译

Ccache是一个编译器缓存。它存储每个编译过程产生的目标文件,并且能够通过使用预先存在的目标文件跳过对相同源文件(使用相同的编译器和相同的参数)的编译。当从零开始多次进行几乎相同的构建时,它可以很好地加快构建过程。

在builroot中集成了Ccache支持。你只需要在Buildoptions中启用enable compiler cache。这将自动构建ccache,并在每个主机(host)和目标(target)编译中使用它。缓存位于BR2_CCACHE_DIR配置选项定义的目录中,默认为$HOME/.buildroot-cache,此默认位置位于Buildroot输出目录之外,因此可以由单独的Buildroot构建共享。如果要删除缓存,只需删除此目录。

可以通过运行make cache-stats获取缓存的统计信息(大小、命中次数、未命中次数等)。可以按照如下方式对ccache进行更多的访问和操作:

# set cache limit size
make CCACHE_OPTIONS="--max-size=5G" ccache-options
# zero statistics counters
make CCACHE_OPTIONS="--zero-stats" ccache-options

Ccache对源文件和编译器选项进行散列处理。如果编译器选项不同,则不会使用缓存的对象文件。但是,许多编译器选项包含到暂存目录的绝对路径。因此,在不同的输出目录中构建会导致很多缓存丢失。

为了避免这个问题,builroot有使用相对路径选项(BR2_CCACHE_USE_BASEDIR)。这将把指向输出目录内的所有绝对路径重写为相对路径。因此,更改输出目录不再导致缓存丢失。相对路径的一个缺点是它们最终也是目标文件中的相对路径。因此,例如,调试器将不再找到该文件,除非您先cd到输出目录。

当使用BR2_CCACHE=y选项在builroot中启用ccache时:

  • ccache在Buildroot构建过程中使用。
  • 在Buildroot之外构建时不使用ccache,例如直接调用交叉编译器或使用SDK时。

可以使用BR2_USE_CCACHE环境变量覆盖此行为:

  • 当设置为1时,启用ccache的使用(在builroot构建期间的默认值)。
  • 当取消设置或设置为与1不同的值时,禁用ccache的使用。
3.4 重定向软件包下载目录

由builroot下载的各种tarball都存储在BR2_DL_DIR中,默认情况下是dl目录。如果想保留一个完整版本的Buildroot,它已知正在使用相关的tarball,可以复制这个目录。

这将允许使用完全相同的版本重新生成工具链和目标文件系统。如果维护多个Buildroot目录,那么共享一个下载位置可能会更好。这可以通过将BR2_DL_DIR环境变量指向一个目录来实现。如果设置了这个值,那么将覆盖builroot配置中的BR2_DL_DIR值。下面这行应该添加到<~/.bashrc>中:

export BR2_DL_DIR=<shared download location>

下载位置也可以在.config文件中设置,使用BR2_DL_DIR选项。与.config文件中的大多数选项不同,这个值被BR2_DL_DIR环境变量覆盖。

3.5 开发环境中使用

builroot的正常操作是下载一个tarball,提取它,配置,编译和安装在这个tarball中找到的软件组件。源代码在output/build/<package>-<version>中提取,这是一个临时目录: 每当使用make clean时,该目录将被完全删除,并在下一次make调用时重新创建。

即使使用Git或Subversion存储库作为包源代码的输入,builroot也会从中创建一个tarball,然后像通常使用tarball一样运行。当Buildroot主要用作集成工具来构建和集成嵌入式Linux系统的所有组件时,这种行为非常适合。

但是,如果在系统的某些组件的开发过程中使用了buildroot,那么这种行为就不是很方便了:相反,人们希望对一个包的源代码做一个小的更改,并能够使用buildrot快速重建系统。直接在output/build/<package>-<version>中进行更改不是一个合适的解决方案,因为该目录在make clean时会被删除。

因此,builroot为这个用例提供了一个特定的机制:<pkg>_OVERRIDE_SRCDIR机制。Buildroot读取一个覆盖文件,该文件允许用户告诉Buildroot某些包的源代码位置。覆盖文件的默认位置是$(CONFIG_DIR)/local.mk,由BR2_PACKAGE_OVERRIDE_FILE配置选项定义。$(CONFIG_DIR)是buildroot配置文件.config的位置,所以local.mk默认与.config文件共存,这意味着

  • 在内部构建的顶级Buildroot源目录中(即,当不使用O=时)。
  • 在外部构建的自定义目录中(即,当使用O=时)。

如果需要不同于这些默认值的位置,可以通过BR2_PACKAGE_OVERRIDE_FILE配置选项指定。在这个覆盖文件中,builroot希望找到这样的行:

<pkg1>_OVERRIDE_SRCDIR = /path/to/pkg1/sources
<pkg2>_OVERRIDE_SRCDIR = /path/to/pkg2/sources

当builroot发现对于给定的包,已经定义了<pkg>_OVERRIDE_SRCDIR时,它将不再尝试下载、解压缩和修补该包。相反,它将直接使用指定目录中可用的源代码,并且make clean不会触及该目录。这允许将builroot指向您自己的目录,这些目录可以由Git、Subversion或任何其他版本控制系统管理。

为了实现这一点,builroot将使用rsync将组件的源代码从指定的<pkg>_OVERRIDE_SRCDIR复制到output/build/<package>-custom/。此机制最好与make <pkg>-rebuildmake <pkg>-reconfigure目标结合使用。make <pkg>-rebuild all序列会将源代码从<pkg> _OVERRIDE_SRCDIR同步到output/build/<package>-custom/(多亏了rsync,只有修改过的文件被复制),并重新启动这个包的构建过程。

例如对于Linux内核软件包,开发人员可以在/home/bob/linux中更改源代码,然后运行:

make linux-rebuild all

output/images中的根文件系统映像包含更新后的Linux内核镜像。大型项目的源代码树通常包含数百或数千个文件,这些文件不是构建所需的,但会减慢使用rsync复制源代码的过程。

这可以通过定义<pkg>_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS来跳过对源树中的某些文件的同步。例如,当使用webkitgtk包时,以下命令将从本地WebKit源代码树中排除测试和树内构建:

WEBKITGTK_OVERRIDE_SRCDIR = /home/bob/WebKit
WEBKITGTK_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = \
--exclude JSTests --exclude ManualTests --exclude PerformanceTests \
--exclude WebDriverTests --exclude WebKitBuild --exclude WebKitLibraries \
--exclude WebKit.xcworkspace --exclude Websites --exclude Examples

默认情况下,builroot会跳过VCS工件(例如.git和.svn目录)的同步。有些包更喜欢在构建期间使用这些VCS目录,例如用于自动确定版本信息的精确提交引用。要以较慢的速度为代价撤销此内置过滤,请重新添加这些目录:l

LINUX_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = --include .git
c4. 附注信息
4.1 devtmpfs简介

devtmpfs是一种在Linux内核中实现的特殊类型的临时文件系统(tmpfs)。它被设计用于存储设备文件,这些设备文件代表系统中的设备,包括硬件设备(如硬盘驱动器和网络接口)以及一些软件或虚拟设备(如伪终端)。

devtmpfs的主要功能和作用包括:

  1. 设备管理devtmpfs为系统中的每个设备创建一个设备文件。这些设备文件位于/dev目录下,它们是设备驱动程序和用户空间应用程序之间的接口。应用程序可以通过读写这些设备文件来控制设备。

  2. 快速启动:在早期的Linux系统中,设备文件是由用户空间的udev系统在启动时创建的。这在某些情况下可能导致系统启动速度较慢,因为必须等待udev在/dev目录下创建所有设备文件。通过在内核中实现devtmpfs,设备文件可以在系统启动时立即可用,从而加快了系统的启动速度。

  3. 简化系统配置:在一些嵌入式系统或者容器环境中,可能没有 udev 或其他动态设备管理系统。在这种情况下,devtmpfs可以提供一个简单的方法来创建和管理设备文件。

  4. 动态设备管理:当新设备被插入或移除时,devtmpfs可以动态地创建或删除对应的设备文件。这使得系统可以在运行时适应硬件配置的变化。

需要注意的是,虽然devtmpfs在内核中创建设备文件,但是它并不负责设备的热插拔或其他更复杂的设备管理任务。这些任务通常由udev或其他用户空间的设备管理系统来完成。

4.2 mdev/udev/eudev简介

mdev, udev, 和 eudev 都是用于设备管理的工具,它们在 Linux 系统中动态地创建和管理设备节点:

  1. mdev:mdev 是 BusyBox 提供的一个轻量级的工具,主要用于在 Linux 系统中动态地创建和管理设备节点。它特别适合资源有限的系统,如嵌入式系统。
  2. udev:udev 是 Linux 系统的一部分,用于管理 /dev 目录中的设备节点。它可以动态地创建和删除设备节点,当新设备被添加到系统,或从系统中移除时,udev 会创建或删除相应的设备节点。
  3. eudev:eudev 是 udev 的一个分支,由 Gentoo 团队创建。它的目标是提供一个与 udev 兼容但对系统依赖性较小的设备管理程序,因此更易于在不同类型的 Linux 系统,包括嵌入式系统上使用。

以下是三者的一些主要功能和作用:

  1. 动态设备管理:当新设备被添加到系统(例如,USB 设备被插入)或从系统中移除时,mdev 可以动态地创建或删除相应的设备节点。

  2. 设备节点创建mdev 可以根据 /sys 文件系统中的设备信息来创建设备节点。

  3. 设备属性设置mdev 可以根据配置文件或环境变量来设置设备节点的所有者、组和权限。

  4. 事件处理:可以在设备添加或删除时执行特定的脚本或命令。

4.3 系统初始化程序简介

init 是 Unix 和 Unix-like 操作系统(如 Linux)的一个重要组成部分,它是在系统启动时由内核首先启动的进程,其进程号(PID)通常是 1。因为它是所有其他用户空间进程的父进程,所以它在系统操作中扮演着关键的角色。

以下是 init 进程的一些主要功能和作用:

  1. 系统初始化init 进程负责初始化系统,它会挂载必要的文件系统,启动必要的宁静和服务,以及执行其他初始化任务。

  2. 服务管理init 进程通常负责启动和管理系统服务。这些服务可能包括日志服务、网络服务、调度服务等。

  3. 系统运行级别管理init 进程管理系统的运行级别。例如,在 SysV init 系统中,不同的运行级别对应着不同的系统状态,如单用户模式、多用户模式、重启、关机等。

  4. 僵尸进程回收:当一个子进程终止,而其父进程没有获取其终止状态,那么它就会变成僵尸进程。init 进程负责定期收集这些僵尸进程,以防止它们占用系统资源。

  5. 系统关机和重启:当需要关闭或重启系统时,init 进程负责按照正确的顺序停止服务和卸载文件系统。

在许多现代 Linux 系统中,init 的功能由如 systemd、Upstart 这样的更现代的初始化系统来实现。这些系统提供了更强大和灵活的服务管理功能,如依赖性处理、并行启动、动态服务管理等:

  1. System V init:这是 Unix 和早期 Linux 系统中的传统初始化系统。System V init 使用一系列脚本,按照特定顺序启动各种系统服务。这些脚本通常位于 /etc/init.d/ 目录,每个运行级别有一个相关的目录(例如,/etc/rc.d//etc/rc*.d/),其中包含指向 init.d/ 目录中脚本的符号链接。虽然 System V init 的设计简单易懂,但它没有处理服务依赖关系,所有服务都必须按照固定的顺序启动,这可能限制了启动速度。
  2. Upstart:Upstart 是由 Ubuntu 开发的一个现代化的初始化系统,用来替代 System V init。Upstart 的主要优点是它可以处理服务的依赖关系,并且可以在系统运行时动态地启动和停止服务。此外,Upstart 还支持事件驱动的编程模型,这使得它可以更灵活地响应系统事件。然而,Upstart 在 2015 年被 Ubuntu 弃用,转而使用 systemd。
  3. systemd:systemd 是许多现代 Linux 发行版(如 Fedora、Debian、Ubuntu 和 CentOS)的默认初始化系统。systemd 提供了一种声明式的语法来定义服务及其依赖关系,并且可以并行地启动服务以加快启动速度。此外,systemd 还提供了许多其他的高级功能,如系统日志管理、用户登录会话管理、设备热插拔处理、网络配置等。

此外,systemd 自从被引入 Linux 系统以来,就在社区中引发了一些争议,如下:

  1. 集成度高systemd 不仅仅是一个初始化系统,它还包括了许多其他的功能,如日志管理、设备管理、网络配置、用户会话管理等。这与 Unix 的传统哲学"每个程序只做好一件事"相违背。一些用户和开发者认为,这种高度的集成导致 systemd 变得复杂和难以理解,也增加了出错的可能性。
  2. 不易替换:由于 systemd 的高度集成,很多其他的系统组件都依赖于 systemd 的特定功能。这使得在 systemd 的系统中替换 systemd 变得困难。一些用户和开发者认为,这限制了用户的选择,违反了 Linux 的开放和多样性的原则。
  3. 配置复杂:虽然 systemd 提供了一种声明式的语法来配置服务,但这种语法相较于传统的 shell 脚本更为复杂和难以理解。一些用户和开发者认为,这增加了学习和使用 systemd 的难度。
  4. 开发和决策过程:一些用户和开发者对 systemd 的开发和决策过程表示不满。他们认为 systemd 的开发团队不够接纳社区的反馈,而且对 systemd 的决策过于集权。

虽然有这些争议,但也应该认识到 systemd 也有其优点,如启动速度快、并行启动服务、处理服务依赖等,并且它已经被许多主流的 Linux 发行版采用。

4.4 getty简介

getty 是 Unix 和 Unix-like 系统(如 Linux)中的一个程序,它的主要功能是管理物理或虚拟的终端行。getty 的名字来源于 “get teletype”,它通常在系统启动时由 init 进程启动,并在特定的终端行上等待用户登录。

以下是 getty 的一些主要功能和作用:

  1. 终端行设置getty 负责设置终端行的参数,如波特率、字符大小、奇偶校验等。这在使用物理串行终端或调制解调器时特别重要。

  2. 用户登录getty 在终端上显示登录提示符,等待用户输入用户名。一旦用户输入用户名,getty 就会启动登录程序(如 login),然后让用户输入密码进行身份验证。

  3. 会话管理:一旦用户成功登录,getty 就会启动一个 shell 以开始用户的会话。当会话结束时(例如,用户登出或会话被断开),getty 会重新设置终端并等待下一个用户登录。

4.5 稀疏文件(Sparse file)

稀疏文件(Sparse file)是一种文件存储方式,用于在文件系统中有效地保存数据。它的主要特点是只保存实际有用的数据,而对于文件中的空白部分(即全零的数据块),则不进行实际的磁盘空间分配。

稀疏文件的作用:

  1. 空间效率:稀疏文件最大的优点就是它可以非常高效地使用存储空间。如果一个文件的大部分内容都是空的(也就是说,大部分的字节都是零),那么使用稀疏文件可以显著减少实际使用的磁盘空间。

  2. 时间效率:由于稀疏文件只写入实际存在的数据,因此在处理大文件时,可以显著提高读写速度。

  3. 灵活性:稀疏文件可以创建实际大小超过物理存储空间的文件,这在某些场景下非常有用,例如某些数据库操作,或者虚拟磁盘映像等。

稀疏文件的介绍:

当创建一个稀疏文件时,文件系统并不会立即分配所有的磁盘空间。相反,它只会在数据实际写入时才分配空间。如果数据块全是0,文件系统会记录这个信息,但并不会在磁盘上分配空间。因此,一个稀疏文件的大小(逻辑大小)通常会比它实际占用的磁盘空间(物理大小)大得多。

例如,如果你创建一个10GB的文件,其中9.5GB都是空白,那么这个文件的逻辑大小是10GB,但它的物理大小可能只有0.5GB。这就是稀疏文件能高效利用存储空间的原因。

在Unix-like系统(如Linux)中,可以使用dd命令创建稀疏文件,也可以使用cp --sparse=always命令将普通文件转化为稀疏文件。并且,许多文件系统,如ext3,ext4,XFS,Btrfs等都支持稀疏文件。

但是,需要注意的是,不是所有的文件系统都支持稀疏文件。在不支持稀疏文件的文件系统上,所有的零都会被实际写入,这就失去了使用稀疏文件的意义。因此,使用稀疏文件时,要确保你的文件系统支持这一特性。

4.6 Ccache介绍

ccache 是一个开源的编译缓存工具。它能大幅度地加速C/C++代码的重新编译速度。ccache 通过缓存之前编译过的源代码的对象文件,然后在源代码没有发生改变的情况下,直接使用这些缓存的对象文件,从而避免了重复的编译过程。

ccache的功能:

  1. 缓存编译结果ccache 将编译结果(对象文件)存储在缓存中。当源文件没有改变时,ccache 会直接从缓存中取出已编译的结果,而不是重新编译。这大大减少了编译时间。

  2. 自动处理ccache 可以自动处理C/C++预处理器的输出,这意味着你可以在不改变构建系统的情况下使用它。

  3. 灵活配置:你可以设置缓存的大小,当缓存满时,ccache 会自动清理最少使用的缓存项。

  4. 统计信息ccache 提供了详细的统计信息,允许你查看缓存的使用情况和效果。

ccache的作用:

  1. 提高编译速度:对于大型的C/C++项目,编译通常需要很长的时间。如果源文件没有改变,使用ccache 可以避免重复编译,大大提高编译速度。

  2. 节省资源:通过避免不必要的编译,ccache 可以节省CPU的计算资源,以及用于存储编译结果的磁盘空间。

  3. 提高开发效率ccache 的使用可以让开发者更快地进行编译-测试-修改的开发流程,从而提高开发效率。

在实际使用中,ccache 通常被设置为编译器的一个包装器(wrapper),当执行编译命令(如gccg++)时,实际上执行的是ccacheccache 会判断是否可以使用缓存的结果,如果可以,就直接使用缓存;如果不可以,就执行实际的编译命令,然后将编译结果保存到缓存中。

需要注意的是,ccache 最适合用于频繁编译的场景,如持续集成(Continuous Integration)或者频繁的源代码修改。对于只编译一次的项目,使用 ccache 的效果可能并不明显。
使用它。

相关文章:

linux之buildroot(3)配置软件包

Linux之buildroot(3)配置软件包 Author&#xff1a;Onceday Date&#xff1a;2023年11月30日 漫漫长路&#xff0c;才刚刚开始… 全系列文章请查看专栏: buildroot编译框架_Once_day的博客-CSDN博客。 参考文档&#xff1a; Buildroot - Making Embedded Linux Easymdev.t…...

学会用bash在linux写脚本 (一)

本章主要介绍如何使用bash写脚本。 了解通配符 了解变量 了解返回值和数值运算 grep的用法是“grep 关键字 file”&#xff0c;意思是从file中过滤出含有关键字的行。 例如&#xff0c;grep root /var/log/messages&#xff0c;意思是从/var/log/messages 中过滤出含有root …...

Leetcode 2949. Count Beautiful Substrings II

Leetcode 2949. Count Beautiful Substrings II 1. 解题思路2. 代码实现 Leetcode 2949. Count Beautiful Substrings II 1. 解题思路 这一题真的很丢脸&#xff0c;居然没有搞定&#xff0c;是看了大佬们的思路之后才想明白的&#xff0c;就感觉丢脸丢大了…… 这道题讲道…...

【Python系列】Python函数

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

自定义TypeHandler 将mysql返回的逗号分隔的String转换到List

sql执行如下&#xff1a; 这里我定义的接受类&#xff1a; 但是这里报了错JSON parse error: Cannot deserialize value of type java.util.ArrayList<java.lang.String>from Object value (token JsonToken.START_OBJECT); nested exception is com.fasterxml.jackson…...

Spring 高级装配详解

一、环境与profile ​ 在3.1版本中&#xff0c;Spring引入了bean profile的功能。要使用profile&#xff0c;首先要将所有不同的bean定义整理到一个或者多个pofile之中&#xff0c;再将应用部署到每个环境时&#xff0c;确保对应的profile处于激活状态。 在Java配置中&#xf…...

mapbox Marker添加自定义html

思路就是先渲染出空div使用getElementsByClassName找到点&#xff0c;之后使用insertAdjacentHTML(‘beforeend’, div) 加自定义内容。 const el document.createElement(div);// 添加一个标记el.className j_icon;const itemIcon new MapboxGl.Marker({element: el,}).set…...

Linux UUCP命令教程:如何在Linux系统中进行文件复制(附实例详解和注意事项)

Linux UUCP命令介绍 UUCP&#xff08;Unix-to-Unix Copy&#xff09;是一套允许远程执行命令和传输文件的程序。UUCP命令是该套件中的一个程序&#xff0c;它为请求文件复制操作提供了用户界面。UUCP套件还包括uux&#xff08;远程命令执行的用户界面&#xff09;、uucico&…...

【android开发-21】android中调用系统摄像头camera拍照和相册的用法详解

1&#xff0c;调用摄像头 在Android中&#xff0c;调用系统摄像头拍照需要使用Intent来启动Camera应用&#xff0c;并在应用中设置相应的权限。下面是一个简单的例子&#xff1a; // 创建一个Intent对象&#xff0c;指定要执行的动作是拍照 Intent intent new Intent(Medi…...

最新版本——Hadoop3.3.6单机版完全部署指南

大家好&#xff0c;我是独孤风&#xff0c;大数据流动的作者。 本文基于最新的 Hadoop 3.3.6 的版本编写&#xff0c;带大家通过单机版充分了解 Apache Hadoop 的使用。本文更强调实践&#xff0c;实践是大数据学习的重要环节&#xff0c;也能在实践中对该技术有更深的理解&…...

理解自我效能感:你的内在动力来源

1. 自我效能感&#xff1a;开启个人潜能的心理动力 想象一下&#xff0c;面对生活的挑战和机遇时&#xff0c;是什么内在力量驱使你去采取行动&#xff0c;或者让你犹豫不决&#xff1f;这种力量&#xff0c;与我们的心理状态紧密相关&#xff0c;其中一个关键因素就是我们的自…...

Java第二十一章

一.网络程序设计基础 1.网络协议 网络协议规定了计算机之间连接的物理、机械(网线与网卡的连接规定)、电气(有效的电平范围)等特征&#xff0c;计算机之间的相互寻址规则&#xff0c;数据发送冲突的解决方式&#xff0c;长数据如何分段传送与接收等内容.就像不同的国家有不同的…...

Redis交互速度慢,CPU占用100%,集群方案,报错等问题

Redis交互速度很慢&#xff0c;达到几十到一百毫秒一次 问题描述&#xff1a; 执行top命令发现redis占用达到100% redis交互速度慢&#xff0c;一次要几十到一百毫秒一次 解决思路 查看redis数据量&#xff0c;比如我这里达到了30万 经过本地测试&#xff0c;redis交互的速…...

wpf 系统在显示器分辨率和缩放设置为非1920*1080和100%时,SelectionChanged事件响应问题分析?

系统在显示器分辨率和缩放设置为1920*1080和100%时&#xff0c;窗口四分格能正常响应SelectionChanged事件&#xff0c;但是当缩放为125%时&#xff0c;或是分辨率大于1920*1080时四分格其中一个格子的下侧和右侧点击不响应&#xff0c;什么原因&#xff1f; 描述的问题可能由以…...

刷题记录--算法--简单

第一题 2582. 递枕头 已解答 简单 相关标签 相关企业 提示 n 个人站成一排&#xff0c;按从 1 到 n 编号。 最初&#xff0c;排在队首的第一个人拿着一个枕头。每秒钟&#xff0c;拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾&#xff0c;传递…...

条码生成器与Zint使用

文章目录 目的条形码zint支持条形码种类下载编译qt pro配置code保存条形码目的 1: 了解条形码数据理论知识 2: 了解zint第三方库相关, 如何编译引用到项目中 条形码 条形码(Barcode)一维码 和二维码(QR code)都是用于存储信息的图形化表示方式,通常应用于商品标识、库…...

C#winform上下班打卡系统Demo

C# winform上下班打卡系统Demo 系统效果如图所示 7个label控件(lblUsername、lblLoggedInEmployeeId、lab_IP、lblCheckOutTime、lblCheckInTime、lab_starttime、lab_endtime)、3个按钮、1个dataGridView控件、2个groupBox控件 C#代码实现 using System; using System.Dat…...

P1 Qt的认识及环境配置

目录 前言 01 下载Qt Creator windows下载安装包拷贝到Linux Linux直接下载 02 Linux 安装Qt 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类…...

单元测试Nunit的几种断言

Nunit提供了一些辅助函数用于确定好某个被测试函数是否正常工作。通常把这些函数称为断言 断言是单元测试最基本的组成部分。因此&#xff0c;NUnit程序库以Assert类的静态方法的形式提供了不同形式的多种断言 1. Assert.AreEqual&#xff1a;比较两个值是否相等。用于比较数…...

前端中的响应式布局与各个端适配

什么是响应式布局&#xff1f; 响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。在移动互联网高度发达的今天&#xff0c;我们在桌面浏览器上开发的网页已经无法满足在移动设备上查看的需求。传统的开发方式是PC端开发一套页面&#xff0c;手机端再开发一套页面。但是…...

2023年5个自动化EDA库推荐

EDA或探索性数据分析是一项耗时的工作&#xff0c;但是由于EDA是不可避免的&#xff0c;所以Python出现了很多自动化库来减少执行分析所需的时间。EDA的主要目标不是制作花哨的图形或创建彩色的图形&#xff0c;而是获得对数据集的理解&#xff0c;并获得对变量之间的分布和相关…...

7-1 查找书籍

给定n本书的名称和定价&#xff0c;本题要求编写程序&#xff0c;查找并输出其中定价最高和最低的书的名称和定价。 输入格式: 输入第一行给出正整数n&#xff08;<10&#xff09;&#xff0c;随后给出n本书的信息。每本书在一行中给出书名&#xff0c;即长度不超过30的字…...

【无线网络技术】——无线广域网(学习笔记)

&#x1f4d6; 前言&#xff1a;无线广域网(WWAN)是指覆盖全国或全球范围内的无线网络&#xff0c;提供更大范围内的无线接入&#xff0c;与无线个域网、无线局域网和无线城域网相比&#xff0c;它更加强调的是快速移动性。典型的无线广域网&#xff1a;蜂窝移动通信系统和卫星…...

【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、springboot分层架构、IDEA修改快捷键、vue代码风格

项目笔记为项目总结笔记,若有错误欢迎指出哟~ 【项目专栏】 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(1)spring boot项目搭建、vue项目搭建、微信小程序项目搭建 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、sp…...

NGINX相关配置

全局配置 NGINX配置信息 nginx 官方帮助文档&#xff1a;http://nginx.org/en/docs/Nginx的配置文件的组成部分&#xff1a; 主配置文件&#xff1a;/conf/nginx.conf(/nginx/conf/nginx.conf) 子配置文件: include conf.d/*.conf#事件驱动相关的配置 同步 event { worker_…...

如何将idea中导入的文件夹中的项目识别为maven项目

问题描述 大家经常遇到导入某个文件夹的时候&#xff0c;需要将某个子文件夹识别为maven项目 解决方案...

CleanMyMac4.16中文最新版本下载

当很多人还在为电脑运行缓慢、工作问题不能快速得到解决而烦恼的时候&#xff0c;我已经使用过了多款系统清理工具&#xff0c;并找到了最适合我的那一款。我的电脑是超耐用的Mac book&#xff0c;接下来给大家介绍三种在众多苹果电脑清理软件的排名较高的软件。 一、Maintena…...

谷歌正式发布最强 AI 模型 Gemini

2023年12月6日&#xff0c;谷歌公司宣布推出其被认为是规模最大、功能最强大的人工智能模型 Gemini。 Gemini将分为三个不同的套件&#xff1a;Gemini Ultra、Gemini Pro和Gemini Nano。 Gemini Ultra被认为具备最强大的能力&#xff0c;Gemini Pro则可扩展至多任务&#x…...

无人机语音中继电台 U-ATC118

简介 甚高频无线电中继通讯系统使用经过适航认证的机载电台连接数字网络传输模块&#xff0c;通过网络远程控制无缝实现无人机操作员与塔台直接语音通话。无人机操作员可以从地面控制站远程操作机载电台进行频率切换、静噪开关、PTT按钮&#xff0c;电台虚拟面板与真实面板布局…...

两种测量方式的自适应卡尔曼滤波数据融合

文章目录 测试效果代码CMakeLists.txt参考测试效果 代码 #include <iostream> #include <Eigen/Dense> #include...

.Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)

机缘 不知不觉,.NET8都已经面世,而我们一直还停留在.netframework4.5开发阶段,最近准备抽空研究一下.Net6,一是为了提高技术积累,一方面想着通过这次的学习,看有没有可能将老的FX版本替换到.Net6开发上,经过查找官方资料,对.Net6支持的系统版本做一个分享,方便大家后期…...

CopyOnWriteArraySet怎么用

简介 CopyOnWriteArraySet是一个线程安全的无序集合&#xff0c;它基于“写时复制”的思想实现。它继承自AbstractSet&#xff0c;可以将其理解成线程安全的HashSet。 CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程…...

uniapp得app云打包问题

获取appid&#xff0c;具体可以查看详情 也可以配置图标&#xff0c;获取直接生成即可 发行 打包配置 自有证书测试使用时候不需要使用 编译打包 最后找到安装包apk安装到手机 打包前&#xff0c;图片命名使用要非中文&#xff0c;否则无法打包成功会报错...

Linux bin包生成

需求背景&#xff1a; 在实际项目时我们很少把源码用个tar给到客户&#xff0c;这样显得很不专业&#xff0c;且有的时候我们提供补丁&#xff0c;那么这个时候我们提供一个补丁的bin包可以直接安装运行就显得很高大上了。 物料准备 准备一台liunx&#xff0c;虚拟机亦可&am…...

Java多人聊天

服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…...

自动驾驶:传感器初始标定

手眼标定 机器人手眼标定AxxB&#xff08;eye to hand和eye in hand&#xff09;及平面九点法标定 Ax xB问题求解&#xff0c;旋转和平移分步求解法 手眼标定AXXB求解方法&#xff08;文献总结&#xff09; 基于靶的方法 相机标定 (1) ApriTag (2) 棋盘格&#xff1a;cv::f…...

如何将 MySQL 数据库转换为 SQL Server

本文解释了为什么组织希望将其 MySQL 数据库转换为 Microsoft SQL 数据库。本文接着详细介绍了尝试转换之前需要记住的事项以及所涉及的方法。专业的数据库转换器工具将帮助您快速将 MySQL 数据库记录转换为 MS SQL Server。 在继续之前&#xff0c;我们先讨论一下 MySQL 到 M…...

【开源】基于Vue+SpringBoot的河南软件客服系统

文末获取源码&#xff0c;项目编号&#xff1a; S 067 。 \color{red}{文末获取源码&#xff0c;项目编号&#xff1a;S067。} 文末获取源码&#xff0c;项目编号&#xff1a;S067。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、…...

《算法面试宝典》--深度学习常见问题汇总

第三章 深度学习基础 3.1 基本概念 3.1.1 神经网络组成? 神经网络类型众多,其中最为重要的是多层感知机。为了详细地描述神经网络,我们先从最简单的神经网络说起。 感知机 多层感知机中的特征神经元模型称为感知机,由Frank Rosenblatt于1957年发明。 其中 x 1 x_1 x...

【计算机网络实验】实验三 IP网络规划与路由设计(头歌)

目录 一、知识点 二、实验任务 三、头歌测试 一、知识点 IP子网掩码的两种表示方法 32位IP子网掩码&#xff0c;特点是从高位开始连续都是1&#xff0c;后面是连续的0&#xff0c;它有以下两种表示方法&#xff1a; 传统表示法&#xff0c;如&#xff1a;255.255.255.0IP前…...

CodeBlocks添加头文件,解决fatal error: ui.h No such file or directory

问题描述 在使用codeblocks工具进行LVGL仿真过程中报错&#xff0c;找不到头文件 原因分析&#xff1a; 没有将头文件加入编辑器搜索的目录中&#xff0c;编译时找不到头文件。 解决方案&#xff1a; 将要包含的头文件的目录加进去就可以了...

鸿蒙开发:UIAbility组件与UI的数据同步-使用EventHub进行数据通信【鸿蒙专栏-21】

文章目录 ArkTS应用模型中UIAbility组件与UI的数据同步使用EventHub进行数据通信使用globalThis进行数据同步1. UIAbility和Page之间使用globalThis2. UIAbility和UIAbility之间使用globalThis3. 使用globalThis的注意事项4. 使用globalThis的注意事项同名对象覆盖导致问题的场…...

云架构的思考3--云上开发

目录 1 DevOps--简单灵活性高2 服务化&#xff08;微服务&#xff09;--弹性&#xff08;可扩展&#xff09;、按需自主服务3 无状态&#xff08;Serverless&#xff09;--弹性&#xff08;可扩展&#xff09;4 日志--安全5 配置中心--安全6 设计模式6.1 使用“适配器模式”调用…...

vue3日常知识点学习归纳

1&#xff0c;父子组件传递&#xff1a; 父组件传递参数 <template><div><!-- 子组件 参数&#xff1a;num 、nums --><child :num"nums.num" :doubleNum"nums.doubleNum" increase"handleIncrease"></child>&l…...

策略模式终极解决方案之策略机

我们在开发时经常会遇到一堆的if else …, 或者switch, 比如我们常见的全局异常处理等, 像类似这种很多if else 或者多场景模式下, 策略模式是非常受欢迎的一种设计模式, 然而, 一个好的策略模式却不是那么容易写出来. 我在工作中也因为写烦了switch,if else 觉得很不优雅, 因…...

linux 常用指令目录大纲

Linux下的Signal信号处理及详解&#xff0c;test ok-CSDN博客 Linux下怎样判断一个binary是否可以debug//test ok_感知算法工程师的博客-CSDN博客 linux file命令的用法//test ok-CSDN博客 linux下生成core dump方法与gdb解析core dump文件//test ok-CSDN博客 linux readel…...

webpack该如何打包

1.我们先创建一个空的大文件夹 2.打开该文件夹的终端 输入npm init -y 2.1.打开该文件夹的终端 2.2在该终端运行 npm init -y 3.安装webpack 3.1打开webpack网址 点击“中文文档” 3.2点击“指南”在点击“起步” 3.3复制基本安装图片画线的代码 4.在一开始的文件夹下在创建一…...

【STM32】TIM定时器输入捕获

1 输入捕获 1.1 输入捕获简介 IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff08;上升沿/下降沿&#xff09;&#xff0c;当前CNT的值将被锁存到CCR中&#xff08;把CNT的值读出来&#xff0c;写入到…...

webrtc 设置不获取鼠标 启用回声消除

数 getDisplayMedia()(属于 navigator.mediaDevices 的一部分)与 getUserMedia() 类似,用于打开显示内容(或部分内容,如窗口)。返回的 MediaStream 与使用 getUserMedia() 时相同。 显示鼠标与否 getDisplayMedia() 的约束条件与常规视频或音频输入资源的限制不同。 {…...

JVM虚拟机:如何查看JVM初始和最终的参数?

本文重点 在前面的课程中&#xff0c;我们学习了如何查看当前程序所处于的xx参数&#xff0c;本文再介绍一种如何参看JVM的xx参数&#xff1f; 查看JVM的所有初始化参数 方式一&#xff1a;java -XX:PrintFlagsInitial 方式二&#xff1a;java -XX:PrintFlagsInitial -versio…...