0%

macOS交叉编译Linux避坑指南

elf.h: No such file or directory

现象

1
scripts/sorttable.c:27:10: fatal error:elf.h: No such file or directory

macOS中并未包含elf.h,可以在 github.com/bminor/glibc/blob/master/elf/elf.h 获取,建议将其放到/usr/local/include目录下,编译时会自动搜索此路径,如果依旧提示找不到elf.h,可以使用使用HOSTCFLAGS强制指定。

解决方案

1
2
3
4
5
# 下载elf.h头到/usr/local/include
curl https://raw.githubusercontent.com/bminor/glibc/master/elf/elf.h > /usr/local/include/elf.h

# 编译时指定搜索路径
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- HOSTCFLAGS=“-I/usr/local/include”

stat: illegal option – c

现象

1
2
3
4
5
6
7
8
9
10
  CC      init/version.o
AR init/built-in.o
AR built-in.o
LD vmlinux.o
MODPOST vmlinux.o
KSYM .tmp_kallsyms1.o
KSYM .tmp_kallsyms2.o

stat: illegal option -- c
usage: stat [-FlLnqrsx] [-f format] [-t timefmt] [file ...]

该问题在Linux-4.16及以前的版本中必然出现,后续版本已得到修复,详见提交:kbuild: Use ls(1) instead of stat(1) to obtain file size

解决方案

下载file-size.sh到内核的scripts目录下,并将源码中有关stat -c "%s"替换为$(CONFIG_SHELL) $(srctree)/scripts/file-size.sh

1
2
3
4
5
6
7
cd your_kernel_src

# 下载file-size.sh到内核源码的scripts目录下
curl https://raw.githubusercontent.com/torvalds/linux/a670b0b4aed129dc11b465c1c330bfe9202023e5/scripts/file-size.sh > scripts/file-size.sh

# 将内核源码scripts/link-vmlinux.sh中有关"stat -c %s"的命令替换为file-size.sh
sed -i '' 's/stat -c "%s"/${CONFIG_SHELL} "${srctree}\/scripts\/file-size.sh"/g' scripts/link-vmlinux.sh

某些环境下可能无法下载,此时请手动创建此脚本并增加可执行权限,file-size.sh内容如下:

1
2
3
4
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -- $(ls -dn "$1")
printf '%s\n' "$5"

‘openssl/bio.h’ file not found

现象

1
2
3
4
5
6
  HOSTCC  scripts/sorttable
HOSTCC scripts/asn1_compiler
HOSTCC scripts/extract-cert
../scripts/extract-cert.c:21:10: fatal error: 'openssl/bio.h' file not found
#include <openssl/bio.h>
^~~~~~~~~~~~~~~

macOS自带的openssl并没有相关的头文件所致。

解决方案

先通过homebrew安装,编译内核时再使用HOSTCFLAGSHOSTLDFLAGS指定库所在路径即可。

1
2
3
4
5
# 安装openssl
brew install openssl

# 内核编译时指定openssl所在路径
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- HOSTCFLAGS="-I/opt/homebrew/opt/openssl/include" HOSTLDFLAGS="-L/opt/homebrew/opt/openssl/lib"

typedef redefinition with different types ‘struct uuid_t’ vs ‘__darwin_uuid_t’

现象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  HOSTCC  scripts/mod/modpost.o
CC scripts/mod/devicetable-offsets.s
UPD scripts/mod/devicetable-offsets.h
HOSTCC scripts/mod/file2alias.o
../scripts/mod/file2alias.c:47:3: error: typedef redefinition with different types ('struct uuid_t' vs '__darwin_uuid_t' (aka 'unsigned char [16]'))
} uuid_t;
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_uuid_t.h:31:25: note: previous definition is here
typedef __darwin_uuid_t uuid_t;
^
../scripts/mod/file2alias.c:1329:42: error: array initializer must be an initializer list or string literal
DEF_FIELD(symval, tee_client_device_id, uuid);

...

../scripts/mod/file2alias.c:1335:7: error: member reference base type 'typeof (((struct tee_client_device_id *)0)->uuid)' (aka 'unsigned char [16]') is not a structure or union
uuid.b[15]);
~~~~^~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h:47:56: note: expanded from macro 'sprintf'
__builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
^~~~~~~~~~~
18 errors generated.

从错误提示上看,是由于macOS环境已经定义了uuid_t从而引发了重复定义的错误。内核自5.1版本开始支持基于TEE的总线驱动框架,通过UUID来进行设备和驱动的匹配,详见提交:tee: add bus driver framework for TEE based devices

解决方案

要解决此问题无非就是将内核源码中的uuid_t换个名字即可,不过一个一个查找替换太麻烦,建议使用宏的方式。(PS:该问题在openwrt中已有相关解决,详见提交:kernel: 5.4 fix build on darwin

your_kernel_src/scripts/mod/file2alias.c:45

1
2
3
4
5
6
7
8
9
10
11
12
13
/* backwards compatibility, don't use in new code */
typedef struct {
__u8 b[16];
} uuid_le;

// 在uuid_t结构体定义之前通过宏定义为其换个壳
#ifdef __APPLE__
#define uuid_t compat_uuid_t
#endif

typedef struct {
__u8 b[16];
} uuid_t;

Absolute addressing not allowed in arm64 code but used in ‘_devtable_ptr377’ referencing ‘_devtable377’

现象

1
2
3
4
5
  HOSTCC  scripts/dtc/dtc-parser.tab.o
HOSTCC scripts/kallsyms
HOSTLD scripts/mod/modpost
ld: Absolute addressing not allowed in arm64 code but used in '_devtable_ptr377' referencing '_devtable377'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

此问题主要在arm64架构的macOS、内核为4.20及以前的环境中出现,主要源自scripts/mod/file2alias.c中的ADD_TO_DEVTABLE宏定义导致程序链接时异常,好在有位大神觉得这种实现方式不够优雅,直接通过简单粗暴的查表把这些宏给干掉了。详见提交:modpost: file2alias: go back to simple devtable lookup

PS:其实这个问题在之前的提交dd2a3ac专门针对macOS环境下交叉编译出错进行修复,不过当时应该只能针对Intel架构的Mac进行测试。

解决方案

解决该问题要修改的代码比较多,建议分别下载file2alias.cdevicetable-offsets.c至scripts/mod目录,和mod_devicetable.h至include/linux目录下覆盖原文件。

注意:上述链接仅为内核5.0版本的代码,也可自行下载最新版本,后果自负。

1
2
3
4
5
6
7
8
9
10
cd your_kernel_src

# 下载并覆盖scripts/mod/file2alias.c
curl https://raw.githubusercontent.com/torvalds/linux/ec91e78d378cc5d4b43805a1227d8e04e5dfa17d/scripts/mod/file2alias.c > scripts/mod/file2alias.c

# 下载并覆盖scripts/mod/devicetable-offsets.c
curl https://raw.githubusercontent.com/torvalds/linux/ec91e78d378cc5d4b43805a1227d8e04e5dfa17d/scripts/mod/devicetable-offsets.c > scripts/mod/devicetable-offsets.c

# 下载并覆盖include/linux/mod_devicetable.h
curl https://raw.githubusercontent.com/torvalds/linux/ec91e78d378cc5d4b43805a1227d8e04e5dfa17d/include/linux/mod_devicetable.h > include/linux/mod_devicetable.h
小小鼓励,大大心意!