[交叉]编译Linux内核时缺少OpenSSL库

May. 13, 2024

编译内核时提示<openssl/bio.h>缺失,原因是编译的机器上没有安装libssl库。

网上查了一下基本都需要用apt之类的安装libssl,但是我是在公用的机器上编译的,并不太方便直接安装。

于是下载编译了openssl源码,然后尝试在编译内核时把头文件和编译好的库添加进去,但是依然会报错。

实际上,用到openssl的是scripts下的extract-cert.c, 这个文件是用本地的GCC编译的,并不是内核的一部分, 所以make时直接传递的CFLAGS等参数是不会作用到这个文件的编译的。

研究了一下暂时没找到怎么在编译内核时给这个文件指定CFLAGS。 所以直接修改了scripts下的Makefile。

# SPDX-License-Identifier: GPL-2.0
###
# scripts contains sources for various helper programs used throughout
# the kernel for the build process.

# 修改的部分
OPENSSL_INSTALL=<.....>/openssl-build/      # 编译好的openssl
OPENSSL_LDFLAG=-L$(OPENSSL_INSTALL)lib      # openssl的库文件
OPENSSL_CFLAG=-I$(OPENSSL_INSTALL)include   # openssl的头文件

CRYPTO_LIBS = $(shell pkg-config --libs libcrypto 2> /dev/null || echo $(OPENSSL_LDFLAG) -lcrypto)      # 把编译好的openssl库加进来
CRYPTO_CFLAGS = $(OPENSSL_CFLAG) $(shell pkg-config --cflags libcrypto 2> /dev/null)    # 添加openssl的头文件


hostprogs-always-$(CONFIG_BUILD_BIN2C)			+= bin2c
hostprogs-always-$(CONFIG_KALLSYMS)			+= kallsyms
hostprogs-always-$(BUILD_C_RECORDMCOUNT)		+= recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT)		+= sorttable
hostprogs-always-$(CONFIG_ASN1)				+= asn1_compiler
hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT)		+= sign-file
hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING)	+= extract-cert
hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)	+= insert-sys-cert
hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST)	+= extract-cert

HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
HOSTCFLAGS_sign-file.o = $(CRYPTO_CFLAGS)
HOSTLDLIBS_sign-file = $(CRYPTO_LIBS)
HOSTCFLAGS_extract-cert.o = $(CRYPTO_CFLAGS)
HOSTLDLIBS_extract-cert = $(CRYPTO_LIBS)

ifdef CONFIG_UNWINDER_ORC
ifeq ($(ARCH),x86_64)
ARCH := x86
endif
HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
HOSTLDLIBS_sorttable = -lpthread
endif

# The following programs are only built on demand
hostprogs += unifdef

# The module linker script is preprocessed on demand
targets += module.lds

subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-$(CONFIG_SECURITY_SELINUX) += selinux

# Let clean descend into subdirs
subdir-	+= basic dtc gdb kconfig mod

之后正常执行内核编译步骤即可。

附openssl编译步骤:

# 下载openssl源码

./config --prefix=<.....>/openssl-build/       # 指定安装位置
make CC=x86_64-conda-linux-gnu-gcc  -j         # 编译,公用的机器gcc版本太低,所以使用的是conda安装的gcc
make install    # 编译安装

补充

以上编译的是5.9的内核。其他版本的Makefile会有区别,不过方法是一样的。

如果是新的内核,还需要涉及到其他地方。原来的scripts/Makefile里仍然需要修改,只是要编译的文件变成了sign-file

HOSTCFLAGS_sign-file.o = $(OPENSSL_CFLAG) # $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo $(OPENSSL_LDFLAG) -lcrypto)

而extract-cert.c在/certs里,这个目录里的Makefile也需要修改。

HOSTCFLAGS_extract-cert.o :=  $(OPENSSL_CFLAG) # $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
HOSTLDLIBS_extract-cert :=  -L$(OPENSSL_INSTALL)lib -lcrypto # $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo $(OPENSSL_LDFLAG) -lcrypto)

但是make时还会报错,

certs/extract-cert: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory

因为是用非系统库目录下的.so库文件编译的,所以编译好的extract-cert运行时还是会找不到动态链接库libcrypto.so。找到certs/Makefile里的cmd_extract_certs, 用环境变量LD_LIBRARY_PATH来给它添加运行时的用到的动态链接库。

EXPORT_LD_LIBRARY_PATH=env "LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(OPENSSL_INSTALL)lib"

quiet_cmd_extract_certs  = CERT    $@
      cmd_extract_certs  =$(EXPORT_LD_LIBRARY_PATH) $(obj)/extract-cert "$(extract-cert-in)" $@
extract-cert-in = $(filter-out $(obj)/extract-cert, $(real-prereqs))

这样应该能正常编译整个内核了。

总结

主要是问题来自内核编译之前需要先编译scripts/里的一些工具,它们和内核本身是没有关系的。本来编译它们时额外指定头文件和库很简单,只是在Linux本来就很复杂的Makefile工程里解决起来比较麻烦。