5

Make error when cross compiling protobuf for ARM

compiled script:

  1 #!/bin/sh
  2 
  3 export PREFIX=$HOME/soft/protobuf_arm/
  4 CLANG_TOOLCHAIN=$HOME/soft/arm-29-toolchain-clang
  5 export PATH=$CLANG_TOOLCHAIN/bin:$PATH
  6 export SYSROOT=$CLANG_TOOLCHAIN/sysroot
  7 export CC="armv7a-linux-androideabi29-clang --sysroot $SYSROOT"
  8 export CXX="armv7a-linux-androideabi29-clang++ --sysroot $SYSROOT"
  9 
 10 cd $HOME/github/c++/protobuf
 11 make clean
 12 ./autogen.sh
 13 ./configure --prefix=$PREFIX \
 14 --host=armv7a-linux-androideabi29 \
 15 --with-sysroot="${SYSROOT}" \
 16 --enable-shared \
 17 --enable-cross-compile \
 18 --with-protoc=$HOME/soft/protobuf_linux/protoc \
 19 CFLAGS="-march=armv7-a -D__ANDROID_API__=29" \
 20 CXXFLAGS="-frtti -fexceptions -march=armv7-a -D__ANDROID_API__=29" \
 21 LIBS="-llog -lz -lc++_static"
 22 make -j 12
 23 make install

There is no error in configure, error in make:

In file included from google/protobuf/compiler/csharp/csharp_source_generator_base.cc:39:
./google/protobuf/compiler/csharp/csharp_source_generator_base.h:62:25: warning: private field 'descriptor_' is not used [-Wunused-private-field]
  const FileDescriptor* descriptor_;
                        ^
1 warning generated.
  CXXLD    libprotoc.la
clang90++: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument]
clang90++: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument]
  CXXLD    protoc
./.libs/libprotoc.so: error: undefined reference to 'descriptor_table_google_2fprotobuf_2fdescriptor_2eproto'
./.libs/libprotoc.so: error: undefined reference to 'scc_info_FileDescriptorProto_google_2fprotobuf_2fdescriptor_2eproto'
clang90++: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [Makefile:3883: protoc] Error 1
make[2]: Leaving directory '/home/sen/github/c++/protobuf/src'
make[1]: *** [Makefile:1866: all-recursive] Error 1
make[1]: Leaving directory '/home/sen/github/c++/protobuf'
make: *** [Makefile:1773: all] Error 2

Environment

Linux x 5.6.15-arch1-1
GNU Make 4.3
NDK (Side by side) 21.1.6352462
protobuf v3.13.0

What is interesting is that although an error was reported, library files such as .so were obtained under protobuf/src/.libs.

senlinmu
  • 141
  • 2
  • 11

2 Answers2

2

Short answer

This is may be a bit involved, but it could be as simple as:

  • add -fuse-ld=bfd to CFLAGS
  • add -fuse-ld=bfd to CXXFLAGS

If doing that doesn't fix the problem, then you may need to also:

  • after ./autogen.sh but before ./configure patch ltmain.sh to allow use of -fuse-ld=bfd (patch file below)

Patch file (ltmain.sh.patch):

--- a/ltmain.sh 2015-02-16 04:15:37.000000000 +1100
+++ b/ltmain.sh 2021-05-23 18:18:46.000000000 +1000
@@ -7273,9 +7273,11 @@
       # --sysroot=*          for sysroot support
       # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
       # -stdlib=*            select c++ std lib with clang
+      # -fuse-ld=*           Linker select flags for GCC
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+      -fuse-ld=*)
         func_quote_for_eval "$arg"
    arg=$func_quote_for_eval_result
         func_append compile_command " $arg"

Patch command:

patch -p1 < path/to/ltmain.sh.patch

Long answer

The issue is due to the symbols being exported weakly from in src/.libs/libprotobuf.so which goes against the mapping configuration provided in src/libprotobuf.map. This configuration specifies that all symbols that match the pattern *google* should be exported strongly (and thus are available for linking into protoc) whereas all others should be hidden.

However, there is a bug in the default linker (GOLD) that is used when running armv7a-linux-androideabi29-clang++, which ignores any mapping directive inside the extern "C++" block. Within the NDK there are three linkers provided:

  • ld
  • ld.bfd
  • ld.gold

The BFD linker does not have the same issue, so the path forward is to configure armv7a-linux-androideabi29-clang++ to use the BFD linker, and that is what the -fuse-ld=bfd option does.

Unfortunately, this may not quite so straightforward, as the protobuf source is built using libtool and the latest released version does not recognise the -fuse-ld argument. Thus, if your distro version of libtool hasn't applied the patch to their packaged version, we need to apply a change to allow it to do so (partially taken from a development commit). The least invasive way to do this is to wait until the necessary file (ltmain.sh) has been copied into the source as part of the ./autogen.sh command, and then patch it so that when that file is processed (as part of the ./configure command) the change propagates into the created libtool file.

What about aarch64-linux-android29?

When building with aarch64-linux-android29-clang++, the default linker has been changed to the BFD linker, so for a codebase like protobuf this issue just won't occur. Using the same patch above, you can replicate the issue using -fuse-ld=gold.

msbit
  • 4,152
  • 2
  • 9
  • 22
1

I'm getting this error too when compiling on Linux (debian 4.19.0-16-amd64) for armv7a-linux-androideabi

As you said, it's "ok" cause the libs are created in src/.libs and they seem to work fine (at least libprotobuf.so)

I didn't have the issue using an old version of the ndk-r21 (Pkg.Revision = 21.0.6113669) I updated recently to the latest ndk-r21e (21.4.7075529) where I've discovered is the issue...

PS: this is not happening for aarch64-linux-android Here is a link on Qt forum on the topic.

For those interested, here is my compile script to build the x86_64 version and both Android 32 and 64 bits.

Matthieu
  • 121
  • 7