Linux 下交叉编译 ARM64-linux 版本 GDAL-3.2.0

Linux 下交叉编译 ARM64-linux 版本 GDAL-3.2.0

1、下载安装编译环境

这里的主机环境是 linux x86_64 ,具体哪个版本不重要,安装相关工具的时候使用对应版本的命令即可(可参考:GEOS/GDAL 交叉编译ARM64-linux版本)。

我这里下载的是 gcc-arm-8.3 版本的交叉编译工具链下载网站,命令如下:

# 1、下载安装编译器
axel https://developer.arm.com/-/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz?revision=2e88a73f-d233-4f96-b1f4-d8b36e9bb0b9&la=en&hash=167687FADA00B73D20EED2A67D0939A197504ACD
# 解压到 /opt 目录下
tar -xJvf gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz -C /opt/

还需要安装cmakemakeautomakeautoconflibtoolzipsqlite等软件,具体安装方法根据 Linux 发行版本确定,这里不再赘述。

备注:ARM64 都是带 fpu 的,所以不需要区分-mfloat-abi的设置。

2、使用 VCPKG 编译一些基础的依赖库

下载安装 vcpkg 的命令如下:

# 下载 vcpkg
git clone https://github.com/microsoft/vcpkg.git
# 编译出 vcpkg 工具
cd vckpg
./bootstrap-vcpkg.sh

编译 sqlite3curlgeos 等第三方库的 ARM64-linux 版本:

# 导入 gcc-arm 工具链的路径到 PATH
export PATH=${PATH}:/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin
# 下载和编译第三方库
./vcpkg install sqlite3:arm64-linux    # 当前版本 3.33.0
./vcpkg install zstd:arm64-linux       # 当前版本 1.4.5
./vcpkg install liblzma:arm64-linux    # 当前版本 5.2.5
./vcpkg install tiff:arm64-linux       # 当前版本 4.1.0
./vcpkg install curl:arm64-linux       # 当前版本 7.73.0
./vcpkg install hdf5:arm64-linux
./vcpkg install libwebp:arm64-linux    # 当前版本 1.1.0
./vcpkg install openjpeg:arm64-linux   # 当前版本 2.3.1
./vcpkg install geos:arm64-linux       # 当前版本 3.8.1

libgeos 3.8与之前的版本略有差异,也可以选择自己编译。自己编译要注意是否使用 -DGEOS_INLINE=1 条件,对编译出的库的影响。
hdf5 编译失败可以参考 https://www.cnblogs.com/oloroso/p/14606052.html

3、交叉编译 PROJ-7.2.0

之所以不使用 vcpkg 来编译 proj4 库,是因为当前 vcpkg 内的版本比较低,就自己编译了。

编译过程命令记录如下:

# 下载源码包
axel https://github.com/OSGeo/PROJ/releases/download/7.2.0/proj-7.2.0.tar.gz
# 解压并进入目录
tar -xzf proj-7.2.0.tar.gz && cd proj-7.2.0

# 使用 cmake 命令生成 Makefile
# CMAKE_INCLUDE_PATH、CMAKE_LIBRARY_PATH 指向上一步编译第三方库的输出目录
PATH=${PATH}:/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin \
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
-DCMAKE_FIND_ROOT_PATH=/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu \
-DCMAKE_INCLUDE_PATH=/home/test/code/vcpkg/installed/arm64-linux/include \
-DCMAKE_LIBRARY_PATH=/home/test/code/vcpkg/installed/arm64-linux/lib \
-DCMAKE_C_FLAGS=-fPIC -DCMAKE_CXX_FLAGS=-fPIC \
-DCMAKE_CXX_STANDARD=11 -DCMAKE_INSTALL_PREFIX="./output" \
-DPROJ_TESTS=OFF -DBUILD_GMOCK=OFF \
-DBUILD_LIBPROJ_SHARED=OFF -Dgtest_force_shared_crt=OFF \
-DBUILD_PROJSYNC=OFF -DBUILD_PROJINFO=OFF -DBUILD_CCT=OFF \
-DBUILD_CS2CS=OFF -DBUILD_GEOD=OFF -DBUILD_GIE=OFF -DBUILD_PROJ=OFF
# 上面一堆 -DBUILD_XXX=OFF 关闭相应的构建,是因为前面编译的第三方库都是静态库
# 这里要用的话某些库的依赖(比如libcurl依赖的openssl)需要手动修改 CMakeLists.txt 去引入
# 所以干脆不要了,编译 proj 本来也只是给编译 gdal 使用的。

# 编译并输出编译结果到 output 目录
make && make install

编译之后,可以拷贝到 vcpkg 的安装目录下,后面编译 GDAL 的时候,方便第三方库路径的指定。

CMAKE 编译工具链指定

上面使用了直接指定 CMAKE_CXX_COMPILER 等相关变量的方式,需要指定的变量比较多。

推荐通过创建一个 gcc_arm_toolchain.cmake 文件,然后使用 -DCMAKE_TOOLCHAIN_FILE=gcc_arm_toolchain.cmake 选项的方式来指定编译器等相关设置。

gcc_arm_toolchain.cmake 文件内容

# 指定目标系统
SET(CMAKE_SYSTEM_NAME Linux)

# 指定编译器
SET(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
SET(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

# 指定搜索的根路径
SET(CMAKE_FIND_ROOT_PATH /opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # 使用本机程序
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)  # 仅使用 FIND_ROOT 下的库
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)  # 仅使用 FIND_ROOT 下的头文件

4、交叉编译 GDAL-3.2.0

先下载并解压源代码

axel https://github.com/OSGeo/gdal/releases/download/v3.2.0/gdal-3.2.0.tar.gz
tar -xzf gdal-3.2.0.tar.gz

然后参考 linux下编译GDAL3.x > configure 完成,输出 geos 等为 no 修改 configure 文件。

大概修改如下:

  • 搜索 CURL_SETTING= 找到 CURL 库检查这一段的结尾,添加

    CURL_SETTING=yes
    CURL_INC=
    CURL_LIB="-lcurl -lssl -lcrypt $LIBS"

  • 回到第一行,搜索 checking for sqlite3_open

    找到后将上面一行 LIBS="" 注释掉

    (因为会出有很多个,只修改这一个即可)

  • 搜索 LIBLZMA_SETTING= 修改等于号后面部分

    LIBLZMA_SETTING="yes"

  • 搜索 HAVE_OPENJPEG=no 找到 OPENJPEG 库检查这一段的结尾,添加

    HAVE_OPENJPEG="yes"

    OPENJPEG_LIBS="-lopenjp2 ${LIBS}"

    OPT_GDAL_FORMATS="openjpeg $OPT_GDAL_FORMATS"

  • 搜索 HAVE_GEOS= 找到 GEOS 库检查这一段的结尾,添加

    HAVE_GEOS="yes"

    HAVE_GEOS_RESULT="yes"

    GEOS_LIBS="-lgeos -lgeos_c ${LIBS}"

然后执行 configure 脚本,生成 Makefile 文件。

# 注意这里的环境变量设置
PATH=${PATH}:/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin \
CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \
CFLAGS=-I/home/test/code/vcpkg/installed/arm64-linux/include \
CXXFLAGS=-I/home/test/code/vcpkg/installed/arm64-linux/include \
LDFLAGS=-L/home/test/code/vcpkg/installed/arm64-linux/lib \
LIBS="-lpthread -dl"  LT_SYS_LIBRAR_PATH=./lib \
./configure --prefix=/home/test/code/gdal_output --host=aarch64-linux \
--with-sqlite3=/home/test/code/vcpkg/installed/arm64-linux  \
--with-rename-internal-libtiff-symbols=yes \
--with-rename-internal-shapelib-symbols=yes \
-with-curl=/home/test/code/vcpkg/installed/arm64-linux \
-with-proj=/home/test/code/vcpkg/installed/arm64-linux \
-with-proj-extra-lib-for-test="-lcurl -ltiff -lssl -lcrypto -ljpeg -llzma -lz" \
--with-zstd=/home/test/code/vcpkg/installed/arm64-linux \
--with-geotiff=internal \
--with-jpeg=/home/test/code/vcpkg/installed/arm64-linux \
--with-openjpeg=yes --with-liblzma=yes \
-with-webp=/home/test/code/vcpkg/installed/arm64-linux \
-with-geos=/home/test/code/vcpkg/installed/arm64-linux

最后进行编译

PATH=${PATH}:/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin make

4、遇到的错误及解决办法

基本上都可以按照 linux下编译GDAL3.x(集成Proj和Geos等) 里面对错误的解决办法进行解决。

这里修改后的 LIBS 变量内容如下:

OTHER_LIB_PATH="/home/test/code/vcpkg/installed/arm64-linux/lib"
LIBS	=	${OTHER_LIB_PATH}/libwebp.a \
			${OTHER_LIB_PATH}/libwebpdecoder.a \
			 ${OTHER_LIB_PATH}/libwebpdemux.a \
			 ${OTHER_LIB_PATH}/libwebpmux.a \
			 ${OTHER_LIB_PATH}/libopenjp2.a \
			 ${OTHER_LIB_PATH}/libturbojpeg.a \
			 ${OTHER_LIB_PATH}/libzstd.a \
			 ${OTHER_LIB_PATH}/libproj.a \
			 ${OTHER_LIB_PATH}/libcurl.a \
			 ${OTHER_LIB_PATH}/libtiff.a \
			 ${OTHER_LIB_PATH}/libssl.a \
			 ${OTHER_LIB_PATH}/libcrypto.a \
			 ${OTHER_LIB_PATH}/libjpeg.a \
			 ${OTHER_LIB_PATH}/libszip.a \
			 ${OTHER_LIB_PATH}/libsqlite3.a \
			 ${OTHER_LIB_PATH}/libgeos_c.a \
			 ${OTHER_LIB_PATH}/libgeos.a \
			 ${OTHER_LIB_PATH}/liblzma.a \
			 ${OTHER_LIB_PATH}/libz.a \
			$(KAK_LIBS) $(DWG_LIBS) $(CURL_LIB) \
			$(MRSID_LIBS) $(MRSID_LIDAR_LIBS) $(ECW_LIBS) $(INGRES_LIB) \
			$(PCIDSK_LIB) $(RASDAMAN_LIB) $(SOSI_LIB) \
			$(OPENCL_LIB) $(JVM_LIB) $(LIBICONV) $(FGDB_LIB) $(LIBXML2_LIB) $(MONGODB_LIB) \
			$(MONGOCXXV3_LIBS) $(JNI_LIB) $(HDFS_LIB) \
			-lpthread -lm -lrt -ldl \

找不到 png_riffle_palette_neon 等相关定义的问题

报错的内容如下:

/bin/sh /home/test/code/gdal-3.2.0/gdal/libtool --mode=link --silent aarch64-linux-gnu-g++ -L/home/test/code/vcpkg/installed/arm64-linux/lib gdalinfo_bin.lo  /home/test/code/gdal-3.2.0/gdal/libgdal.la  -o gdalinfo
/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/8.3.0/../../../../aarch64-linux-gnu/bin/ld: /home/test/code/gdal-3.2.0/gdal/.libs/libgdal.so: undefined reference to `png_riffle_palette_neon'
/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/8.3.0/../../../../aarch64-linux-gnu/bin/ld: /home/test/code/gdal-3.2.0/gdal/.libs/libgdal.so: undefined reference to `png_do_expand_palette_rgb8_neon'
/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/8.3.0/../../../../aarch64-linux-gnu/bin/ld: /home/test/code/gdal-3.2.0/gdal/.libs/libgdal.so: undefined reference to `png_init_filter_functions_neon'
/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/8.3.0/../../../../aarch64-linux-gnu/bin/ld: /home/test/code/gdal-3.2.0/gdal/.libs/libgdal.so: undefined reference to `png_do_expand_palette_rgba8_neon'

查看编译好的 .libs/libgdal.so 的导出函数

objdump -T .libs/libgdal.so|grep png_
0000000000000000      D  *UND*	0000000000000000              png_riffle_palette_neon
0000000000000000      D  *UND*	0000000000000000              png_do_expand_palette_rgb8_neon
0000000000000000      D  *UND*	0000000000000000              png_init_filter_functions_neon
0000000000000000      D  *UND*	0000000000000000              png_do_expand_palette_rgba8_neon
000000000168d064 g    DF .text	000000000000005c  Base        png_push_restore_buffer
000000000168b9ec g    DF .text	0000000000000068  Base        png_malloc_base
....

果然这里几个函数没有定义,找到这几个函数所在的文件

grep png_riffle_palette_neon -R frmts/png/libpng/*  
frmts/png/libpng/pngpriv.h:                      png_riffle_palette_neon,
frmts/png/libpng/pngrtran.c:               png_riffle_palette_neon(png_ptr);

查看 frmts/png/libpng/pngpriv.h 文件,找到这个函数的声明,可知这是一个内部函数,并且只有在 PNG_ARM_NEON_IMPLEMENTATION1 的时候才存在。这个函数本身没有定义,只是在 pngrtran.c 文件里面调用了一次。

// frmts/png/libpng/pngpriv.h
2120 #if PNG_ARM_NEON_IMPLEMENTATION == 1
2121 PNG_INTERNAL_FUNCTION(void,
2122                       png_riffle_palette_neon,
2123                       (png_structrp),
2124                       PNG_EMPTY);

// frmts/png/libpng/pngrtran.c
4774 #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
4775          if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8))
4776          {
4777             if (png_ptr->riffled_palette == NULL)
4778             {
4779                /* Initialize the accelerated palette expansion. */
4780                png_ptr->riffled_palette =
4781                    (png_bytep)png_malloc(png_ptr, 256 * 4);
4782                png_riffle_palette_neon(png_ptr);
4783             }
4784          }
4785 #endif

通过查看相关的宏定义可知,只有在 PNG_ARM_NEON_IMPLEMENTATION 定义了,且值为 1 的时候,这些函数才会被调用。找到frmts/png/libpng/pngpriv.h 文件中对 PNG_ARM_NEON_IMPLEMENTATION 的定义相关语句,可以知道在没有设置 PNG_ARM_NEON_OPT 宏的时候,会去根据进行相关设置。

所以这里的解决办法也很简单,直接在这里顶上加上一行 #define PNG_ARM_NEON_OPT 0 即可。

#ifndef PNG_ARM_NEON_OPT
   /* ARM NEON optimizations are being controlled by the compiler settings,
    * typically the target FPU.  If the FPU has been set to NEON (-mfpu=neon
    * with GCC) then the compiler will define __ARM_NEON__ and we can rely
    * unconditionally on NEON instructions not crashing, otherwise we must
    * disable use of NEON instructions.
    *
    * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they
    * can only be turned on automatically if that is supported too.  If
    * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail
    * to compile with an appropriate #error if ALIGNED_MEMORY has been turned
    * off.
    *
    * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated
    * __ARM_NEON__, so we check both variants.
    *
    * To disable ARM_NEON optimizations entirely, and skip compiling the
    * associated assembler code, pass --enable-arm-neon=no to configure
    * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS.
    */
#  if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \
   defined(PNG_ALIGNED_MEMORY_SUPPORTED)
#     define PNG_ARM_NEON_OPT 2
#  else
#     define PNG_ARM_NEON_OPT 0
#  endif
#endif
posted @ 2020-11-17 17:19  乌合之众  阅读(5258)  评论(2编辑  收藏  举报
clear