基于 IPQ807x 编译 QSDK

接上一篇 下载安装基于 openwrt 的 QSDK, 这一篇来讲下编译 QSDK 的步骤以及遇到的问题及其处理方法。

正常步骤,是下面这样的,根据设备类型选择 config 文件,生成 .config, 然后完整编译。

cp qca/configs/qsdk/ipq_open.config .config
echo  CONFIG_TARGET_ipq_ipq807x_64=y  >> .config
echo CONFIG_TARGET_ipq_ipq807x_64_QSDK_Open=y  >> .config

make package/symlinks
make defconfig
make V=s

make V=s 之前的指令都能正常通过,但是编译过程中就可能出现各种情况,比如缺少编译工具等。

依赖工具

每个人的编译环境可能都不一样,所以缺少的依赖也不同,这里给出我的环境(ubuntu 20.04)缺少的工具

  • ocaml-nox: Objective Caml compiler for GUI of make menuconfig
  • zlib1g-dev: for zlib
  • libssl-dev: for openssl
  • subversion: for svn

安装如下:

sudo apt install ocaml-nox
sudo apt install zlib1g-dev
sudo apt install libssl-dev
sudo apt install subversion

编译错误

m4

在编译过程中,m4 编译失败,报错信息如下:

gcc  -I.   -I/home/litreily/qsdk/qsdk/staging_dir/host/include -I/home/litreily/qsdk/qsdk/staging_dir/host/usr/include  -O2 -I/home/litreily/qsdk/qsdk/staging_dir/host/include -I/home/litreily/qsdk/qsdk/staging_dir/host/usr/include -MT freadahead.o -MD -MP -MF $depbase.Tpo -c -o freadahead.o freadahead.c &&\
mv -f $depbase.Tpo $depbase.Po
freadahead.c: In function 'freadahead':
freadahead.c:91:3: error: #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread, ungetc on your system, then report this to bug-gnulib."
   91 |  #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread, ungetc on your system, then report this to bug-gnulib."
      |   ^~~~~
make[6]: *** [Makefile:1837: freadahead.o] Error 1
make[6]: Leaving directory '/home/litreily/qsdk/qsdk/build_dir/host/m4-1.4.17/lib'
make[5]: *** [Makefile:1602: all] Error 2

关键信息是 #error "Please port gnulib freadahead.c to your platform".

解决方案是打补丁,参考 glibc update breaks buildroot 给出的方案,从 GitHub 寻找到了 patch.

GitHub 上下载指定 commit 对应的 patch 时,只需要在 commit url 后面添加 .patch 后缀即可。

下载后放到目录 tools/m4/patches/. 然后重新执行 make V=s, 或者 make tools/m4/compile V=s, 你会发现,之前的错误信息不见了,但是会出现其它错误,指示我们新加入的 patch 添加失败。这是为什么呢?因为 GitHub 的 patch 对应的 m4 的版本和 QSDK 中的不一样,所以需要对patch稍加修改,把不存在的文件部分删除即可。

裁剪后的 patch 如下:

diff --git a/lib/fflush.c b/lib/fflush.c
index 983ade0ff..a6edfa105 100644
--- a/lib/fflush.c
+++ b/lib/fflush.c
@@ -33,7 +33,7 @@
 #undef fflush


-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */

 /* Clear the stream's ungetc buffer, preserving the value of ftello (fp).  */
 static void
@@ -72,7 +72,7 @@ clear_ungetc_buffer (FILE *fp)

 #endif

-#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)
+#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)

 # if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT
 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
@@ -148,7 +148,7 @@ rpl_fflush (FILE *stream)
   if (stream == NULL || ! freading (stream))
     return fflush (stream);

-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */

   clear_ungetc_buffer_preserving_position (stream);

diff --git a/lib/fpurge.c b/lib/fpurge.c
index b1d417c7a..3aedcc373 100644
--- a/lib/fpurge.c
+++ b/lib/fpurge.c
@@ -62,7 +62,7 @@ fpurge (FILE *fp)
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   fp->_IO_read_end = fp->_IO_read_ptr;
   fp->_IO_write_ptr = fp->_IO_write_base;
   /* Avoid memory leak when there is an active ungetc buffer.  */
diff --git a/lib/freadahead.c b/lib/freadahead.c
index c2ecb5b28..23ec76ee5 100644
--- a/lib/freadahead.c
+++ b/lib/freadahead.c
@@ -30,7 +30,7 @@ extern size_t __sreadahead (FILE *);
 size_t
 freadahead (FILE *fp)
 {
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   if (fp->_IO_write_ptr > fp->_IO_write_base)
     return 0;
   return (fp->_IO_read_end - fp->_IO_read_ptr)
diff --git a/lib/freading.c b/lib/freading.c
index 73c28acdd..c24d0c88a 100644
--- a/lib/freading.c
+++ b/lib/freading.c
@@ -31,7 +31,7 @@ freading (FILE *fp)
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   return ((fp->_flags & _IO_NO_WRITES) != 0
           || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0
               && fp->_IO_read_base != NULL));
diff --git a/lib/fseeko.c b/lib/fseeko.c
index 0101ab55f..193f4e8ce 100644
--- a/lib/fseeko.c
+++ b/lib/fseeko.c
@@ -47,7 +47,7 @@ fseeko (FILE *fp, off_t offset, int whence)
 #endif

   /* These tests are based on fpurge.c.  */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   if (fp->_IO_read_end == fp->_IO_read_ptr
       && fp->_IO_write_ptr == fp->_IO_write_base
       && fp->_IO_save_base == NULL)
@@ -123,7 +123,7 @@ fseeko (FILE *fp, off_t offset, int whence)
           return -1;
         }
 
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
       fp->_flags &= ~_IO_EOF_SEEN;
       fp->_offset = pos;
 #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
--- a/lib/stdio-impl.h
+++ b/lib/stdio-impl.h
@@ -18,6 +18,12 @@
    the same implementation of stdio extension API, except that some fields
    have different naming conventions, or their access requires some casts.  */ 
  
+/* Glibc 2.28 made _IO_IN_BACKUP private.  For now, work around this
+   problem by defining it ourselves.  FIXME: Do not rely on glibc
+   internals.  */
+#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN
+# define _IO_IN_BACKUP 0x100
+#endif
  
 /* BSD stdio derived implementations.  */
 

这个 patch 最主要的修改就是将 _IO_ftrylockfile 改成了 _IO_EOF_SEEN, 具体原因没有深究,有知道的可以留言分享下~

ok, 将这个patch加入后,m4 就能正常编译过去了。接着 make V=s 编译整个项目吧。

make-ext4fs

make-ext4fs 编译失败的信息如下:

cc -o make_ext4fs allocate.o canned_fs_config.o contents.o crc16.o ext4fixup.o ext4_sb.o ext4_utils.o extent.o indirect.o make_ext4fs_main.o make_ext4fs.o sha1.o uuid.o wipe.o libsparse/libsparse.a -lz
/usr/bin/ld: contents.o: in function `make_special':
contents.c:(.text+0xbf7): undefined reference to `major'
/usr/bin/ld: contents.c:(.text+0xc17): undefined reference to `minor'
collect2: error: ld returned 1 exit status
make[3]: *** [Makefile:24: make_ext4fs] Error 1

参考 github issue 可知,这是缺少头文件 <sys/sysmacros.h> 导致的。

加如 patch 0001-fix-undefined-reference-major-minor.patch,放到目录 tools/make-ext4fs/patches/

--- a/contents.c        2021-02-07 15:37:31.463251930 +0800
+++ b/contents.c        2021-02-07 15:37:03.022743240 +0800
@@ -15,6 +15,7 @@
  */
 
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <string.h>
 #include <stdio.h>
 

make tools/make-ext4fs/{clean,compile} V=s 编译成功!

e2fsprogs

e2fsprogs 的编译错误与 make-ext4fs 类似,其错误信息如下:

/usr/bin/ld: ../lib/libblkid.a(devname.o): in function `probe_all':
devname.c:(.text+0x888): undefined reference to `makedev'
/usr/bin/ld: devname.c:(.text+0xb7e): undefined reference to `makedev'
/usr/bin/ld: devname.c:(.text+0xc5b): undefined reference to `makedev'
collect2: error: ld returned 1 exit status
make[6]: *** [Makefile:391: e2fsck] Error 1
make[6]: Leaving directory '/home/litreily/qsdk/qsdk/build_dir/host/e2fsprogs-1.42.8/e2fsck'
make[5]: *** [Makefile:355: all-progs-recursive] Error 1

makedev 也属于头文件 <sys/sysmacros.h>, 添加 patch 到目录 tools/e2fsprogs/patches

--- a/lib/blkid/devname.c 2021-02-07 16:04:24.190214251 +0800
+++ b/lib/blkid/devname.c 2021-02-07 16:03:53.869128549 +0800
@@ -37,6 +37,7 @@
 #include <sys/mkdev.h>
 #endif
 #include <time.h>
+#include <sys/sysmacros.h>
 
 #include "blkidP.h"

make tools/e2fsprogs/{clean,compile} V=s 编译成功!

mtd-utils

make-ext4fs, e2fsprogs 类似,也是缺少 sysmacros.h

/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.o: in function `write_special_file':
/home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:944: undefined reference to `major'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:944: undefined reference to `minor'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.o: in function `recursive_populate_directory':
/home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:1273: undefined reference to `minor'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:1273: undefined reference to `major'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:1263: undefined reference to `minor'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:1263: undefined reference to `major'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.o: in function `interpret_table_entry':
/home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:467: undefined reference to `makedev'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:503: undefined reference to `makedev'
/usr/bin/ld: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2.c:510: undefined reference to `makedev'
collect2: error: ld returned 1 exit status
make[4]: *** [common.mk:71: /home/litreily/qsdk/qsdk/build_dir/host/mtd-utils-1.5.1/mkfs.jffs2] Error 1

添加 patch 到目录 tools/mtd-utils/patches.

--- a/include/common.h  2021-02-07 16:25:50.643801767 +0800
+++ b/include/common.h  2021-02-07 16:25:41.139803836 +0800
@@ -19,6 +19,7 @@
 #ifndef __MTD_UTILS_COMMON_H__
 #define __MTD_UTILS_COMMON_H__
 
+#include <sys/sysmacros.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>

make tools/mtd-utils/{clean,compile} V=s 编译成功!

这里注意下,如果在 mkfs.jffs2.c 中添加这个头文件的话,还会有其它文件报错,也是缺少头文件,所以方便起见,将该头文件放入共有的共用的 common.h

u-boot

u-boot 编译失败。

/home/litreily/qsdk/qsdk/build_dir/host/u-boot-2014.10/lib/rsa/rsa-sign.c: In function 'rsa_get_exponent':
/home/litreily/qsdk/qsdk/build_dir/host/u-boot-2014.10/lib/rsa/rsa-sign.c:279:21: error: dereferencing pointer to incomplete type 'RSA' {aka 'struct rsa_st'}
  279 |  if (BN_num_bits(key->e) > 64)
      |                     ^~
make[5]: *** [scripts/Makefile.host:134: tools/lib/rsa/rsa-sign.o] Error 1

根据 github issue 讨论,这是需要安装 libssl1.0-dev, 但是之前安装的是默认的 libssl1.1, 所以需要重新安装 1.0 版本。

但是 ubuntu 默认源并不包含 1.0 版本,参考 github - cannot install on Debian stable (libssl1.0-dev), 需要手动修改:

sudo echo "deb http://security.ubuntu.com/ubuntu bionic-security main" >> /etc/apt/sources.list
sudo apt update
sudo apt-cache policy libssl1.0-dev
sudo apt install libssl1.0-dev

安装成功后,重新编译就正常了。

findutils

编译错误与 m4 一致。

freadahead.c: In function 'freadahead':
freadahead.c:64:3: error: #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread on your system, then report this to bug-gnulib."
   64 |  #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread on your system, then report this to bug-gnulib."
      |   ^~~~~
make[8]: *** [Makefile:890: freadahead.o] Error 1

需要注意的是,虽然报错信息一样,但 patch 却和 m4 并不通用,因为其所用的 gnulib 库版本不一致。这种情况下,有两种选择

  1. 单独 fix 编译错误
  2. 升级 findutils, 4.4.2 -> 4.6.0

为了保持版本不变,选择第一种方式,先看下报错 log 对应 code:

size_t
freadahead (FILE *fp)
{
#if defined _IO_ferror_unlocked     /* GNU libc, BeOS */
  if (fp->_IO_write_ptr > fp->_IO_write_base)
    return 0;
  return fp->_IO_read_end - fp->_IO_read_ptr;
#elif defined __sferror             /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
  if ((fp->_flags & __SWR) != 0 || fp->_r < 0)
    return 0;
  return fp->_r;
#elif defined _IOERR                /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */
# if defined __sun && defined _LP64 /* Solaris/{SPARC,AMD64} 64-bit */
#  define fp_ ((struct { unsigned char *_ptr; \
                         unsigned char *_base; \
                         unsigned char *_end; \
                         long _cnt; \
                         int _file; \
                         unsigned int _flag; \
                       } *) fp)
  if ((fp_->_flag & _IOWRT) != 0)
    return 0;
  return fp_->_cnt;
# else
  if ((fp->_flag & _IOWRT) != 0)
    return 0;
  return fp->_cnt;
# endif
#elif defined __UCLIBC__            /* uClibc */
# ifdef __STDIO_BUFFERS
  if (fp->__modeflags & __FLAG_WRITING)
    return 0;
  return fp->__bufread - fp->__bufpos;
# else
  return 0;
# endif
#elif defined __QNX__               /* QNX */
  if ((fp->_Mode & 0x2000 /* _MWRITE */) != 0)
    return 0;
  /* fp->_Buf <= fp->_Next <= fp->_Rend */
  return fp->_Rend - fp->_Next;
#else
 #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread on your system, then report this to bug-gnulib."
#endif
}

可以看出报错的原因是某些宏定义没有定义。与此类似的文件有:

  • fseeko.c
  • fpurge.c
  • freading.c
  • freadahead.c

统一处理下,把最后的 #else 分支内容注释掉,然后添加相应的 return 0.

--- a/gnulib/lib/freadahead.c   2021-02-08 09:11:12.009710455 +0800                                                                                           
+++ b/gnulib/lib/freadahead.c   2021-02-08 09:06:20.140641585 +0800                                                                                           
@@ -61,6 +61,7 @@                                                                                                                                             
   /* fp->_Buf <= fp->_Next <= fp->_Rend */                                                                                                                   
   return fp->_Rend - fp->_Next;                                                                                                                              
 #else
- #error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread on your system, then report this to bug-gnulib."
+ //#error "Please port gnulib freadahead.c to your platform! Look at the definition of fflush, fread on your system, then report this to bug-gnulib."
+ return 0;
 #endif
 }
--- a/gnulib/lib/freading.c     2021-02-08 09:11:12.009710455 +0800
+++ b/gnulib/lib/freading.c     2021-02-08 09:06:20.140641585 +0800
@@ -43,7 +43,8 @@
   return ((fp->_Mode & 0x2 /* _MOPENW */) == 0
          || (fp->_Mode & 0x1000 /* _MREAD */) != 0);
 #else
- #error "Please port gnulib freading.c to your platform!"
+ //#error "Please port gnulib freading.c to your platform!"
+ return 0;
 #endif
 }
  
--- a/gnulib/lib/fpurge.c       2021-02-08 09:11:12.009710455 +0800
+++ b/gnulib/lib/fpurge.c       2021-02-08 09:06:20.140641585 +0800
@@ -114,7 +114,8 @@
     fp->_Rend = fp->_Next;
   return 0;
 # else
- #error "Please port gnulib fpurge.c to your platform! Look at the definitions of fflush, setvbuf and ungetc on your system, then report this to bug-gnulib."
+ //#error "Please port gnulib fpurge.c to your platform! Look at the definitions of fflush, setvbuf and ungetc on your system, then report this to bug-gnulib."
+ return 0;
 # endif
  
 #endif
--- a/gnulib/lib/fseeko.c       2021-02-08 09:11:12.009710455 +0800
+++ b/gnulib/lib/fseeko.c       2021-02-08 09:06:20.140641585 +0800
@@ -95,7 +95,7 @@
       && fp->_Rback == fp->_Back + sizeof (fp->_Back)
       && fp->_Rsave == NULL)
 #else
-  #error "Please port gnulib fseeko.c to your platform! Look at the code in fpurge.c, then report this to bug-gnulib."
+  //#error "Please port gnulib fseeko.c to your platform! Look at the code in fpurge.c, then report this to bug-gnulib."
 #endif
     {
       off_t pos = lseek (fileno (fp), offset, whence);

make tools/findutils/{clean,compile} V=s 编译成功!

squashfs4

squashfs4 的错误信息与 make-ext4fs 等类似,也是缺少头文件 <sys/sysmacros.h>.

mksquashfs.c: In function 'create_inode':
mksquashfs.c:1372:24: error: called object 'major' is not a function or function pointer
 1372 |   unsigned int major = major(buf->st_rdev);
      |                        ^~~~~

把头文件加上就好了。

--- a/squashfs-tools/mksquashfs.c       2021-02-08 10:08:42.135709202 +0800
+++ b/squashfs-tools/mksquashfs.c       2021-02-08 10:09:03.263649419 +0800
@@ -52,6 +52,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/wait.h>
+#include <sys/sysmacros.h>
 
 #ifndef linux
 #ifndef __CYGWIN__
--- a/squashfs-tools/unsquashfs.c       2021-02-08 10:08:48.335691509 +0800
+++ b/squashfs-tools/unsquashfs.c       2021-02-08 10:09:24.919589603 +0800
@@ -30,6 +30,7 @@
 #include "xattr.h"
 
 #include <sys/types.h>
+#include <sys/sysmacros.h>
 
 struct cache *fragment_cache, *data_cache;
 struct queue *to_reader, *to_deflate, *to_writer, *from_writer;

make tools/squashfs4/{clean,compile} V=s 编译成功!

coccinelle

coccinelle 依赖 ocaml, 而且版本不一样会编译出错,当前 QSDK 所用的ocaml版本较低,为 4.02.3, 但是本机默认安装的却是 4.08.1, 所以需要重新降级安装,参考 这里 给出的解决方案。

# install opam
sudo add-apt-repository ppa:avsm/ppa # 或许可以省略
sudo apt update
sudo apt install opam

# environment setup
opam init
eval `opam env`
# install given version of the compiler
opam switch create 4.02.3
eval `opam env`
# check you got what you want
which ocaml
ocaml -version

然后重新编译 coccinelle, 发现会提示找不到 ocamlfind ,这时再用刚刚安装的 opam 安装一下就好了。

opam install ocamlfind

下载和使用 opam 过程中会通过 curl 指令从网络下载数据,所以可能比较慢,需要耐心等待。

之后重新编译 coccinelle 就成功啦。

bazel

Bazel 依赖一些第三方库,比如 grpc.git ,由于 Glibc 版本原因,grpc 定义的 gettid 函数与库函数产生了冲突。

Execution platform: @bazel_tools//platforms:host_platform
third_party/grpc/src/core/support/log_linux.c:57:13: error: conflicting types for 'gettid'
   57 | static long gettid(void) { return syscall(__NR_gettid); }
      |             ^~~~~~
In file included from /usr/include/unistd.h:1170,
                 from third_party/grpc/src/core/support/log_linux.c:55:
/usr/include/x86_64-linux-gnu/bits/unistd_ext.h:34:16: note: previous declaration of 'gettid' was here
   34 | extern __pid_t gettid (void) __THROW;
      |                ^~~~~~
Target //src:bazel_nojdk failed to build
INFO: Elapsed time: 43.689s, Critical Path: 0.74s
INFO: 22 processes: 22 local.
FAILED: Build did NOT complete successfully

参考 grpc 官方 fix solution , 需要将 log_linux.c 中的 gettid 改为 sys_gettid.

diff --git a/tools/bazel/Makefile b/tools/bazel/Makefile
index 971270fadb33..74ba38be40d0 100644
--- a/tools/bazel/Makefile
+++ b/tools/bazel/Makefile
@@ -14,6 +14,7 @@ include $(INCLUDE_DIR)/host-build.mk
 
 export JAVA_HOME=$(STAGING_DIR_HOST)/bin/openjdk-1.8-native
 define Host/Compile
+       sed -i 's/gettid/sys_gettid/'  $(HOST_BUILD_DIR)/../third_party/grpc/src/core/support/log_linux.c
        $(HOST_BUILD_DIR)/../compile.sh
 endef

这里需要说明的是,为什么这里不在 tools/bazel/patches 添加补丁,而是在 Makefile 里直接修改文件。这是因为 bazel 本身包含大量的第三方库,这些库的所在目录与 bazel 本身编译目录并不相同。

# bazel 编译目录
build_dir/host/bazel-0.23.2-dist/bazel-0.23.2/

# third parth
build_dir/host/bazel-0.23.2-dist/third_party/

我尝试在 patches 添加补丁,并以相对路径 ../third_party 访问第三方库,但是在 apply patch 的时候会报错,提示找不到文件,我猜测应该是补丁文件不支持相对路径。尝试多次无果,最终决定通过修改 Makefile 实现对第三方库文件的修改。事实证明,以上修改完美解决了问题。

小结

纵观以上所有的编译问题,大致分为以下几类:

  1. 缺少宏定义
    1. m4: _IO_ftrylockfile -> _IO_EOF_SEEN
    2. findutils
  2. 缺少头文件 <sys/sysmacros.h>
    1. make-ext4fs
    2. e2fsprogs
    3. mtd-utils
    4. squashfs4
  3. 依赖工具版本不兼容
    1. u-boot: 依赖 libssl1.0-dev
    2. coccinelle: 依赖 ocaml 4.02.3
  4. 第三方库冲突
    1. bazel: 依赖的 grpc 定义的函数 gettid 与 GLIBC 库函数冲突

实际上大部分问题还是与编译环境有关,编译环境是 Ubuntu 20.04, 所用的工具版本较新,与 QSDK 所需的旧版本不完全兼容,所以导致了各种编译错误。这时候感觉使用 docker 搭建编译环境或许更方便。

注意事项

为了方便编译过程的正常进行,可以修改某些文件或者添加脚本简化编译过程。

修改 distclean

有时候我们会使用 make distclean 清除整个编译信息,但是这个指令会将 dl 中的下载数据和 .config 文件一同删除,这是我们不希望的。所以可以修改 distclean 对应的指令。这个指令在 include/toplevel.mk. 修改如下:

diff --git a/include/toplevel.mk b/include/toplevel.mk
index 3738dbb89eec..508e67e3384f 100644
--- a/include/toplevel.mk
+++ b/include/toplevel.mk
@@ -222,7 +222,7 @@ docs/clean: FORCE
        @$(_SINGLE)$(SUBMAKE) -C docs clean
 
 distclean: clean_kernel
-       rm -rf tmp build_dir staging_dir dl .config* feeds package/feeds package/openwrt-packages bin
+       rm -rf tmp build_dir staging_dir feeds package/feeds package/openwrt-packages bin
        @$(_SINGLE)$(SUBMAKE) -C scripts/config clean
 
 ifeq ($(findstring v,$(DEBUG)),)

添加 build.sh

为了方便编译,可以在 scripts 目录添加脚本 build.sh

#!/bin/bash
cp qca/configs/qsdk/ipq_open.config .config
echo CONFIG_TARGET_ipq_ipq807x_64=y >> .config
echo CONFIG_TARGET_ipq_ipq807x_64_QSDK_Open=y >> .config

make package/symlinks
make defconfig
make V=s

将编译相关的指令都放一起,然后执行 scripts/build.sh 就好了。

参考