Vygintas B
Vygintas B

Reputation: 1694

FreeType2 Cross-compiling for Android

I was able to compile Freetype2 library for arm, arm64, x86, x86_64 architectures. These are steps I done to compile it.

  1. Created standalone toolchains for architectures mentioned above. make_standalone_toolchain.py \ --arch arm64 \ --api 26 \ --stl=libc++ \ --install-dir=my-arm64-toolchain
  2. Set some envirement variables

    export PATH=$PATH:`pwd`/my-toolchain/bin
    target_host=aarch64-linux-android
    export AR=$target_host-ar
    export AS=$target_host-as
    export CC=$target_host-gcc
    export CXX=$target_host-g++
    export LD=$target_host-ld
    export STRIP=$target_host-strip
    export CFLAGS="-fPIE -fPIC"
    export LDFLAGS="-pie"
    
  3. Configure freetype for compilation

./configure --host=aarch64-linux-android --prefix=/home/freetype-arm64 --without-zlib --without-harfbuzz --with-png=no

  1. And finally make && install

Compilation was successfull and I was able to get Static freetype library.

I added library to my android studio libs folder. This is folder structure for library:

libs---freetype
    |---${ANDROID_ABI}
         |---include
             |---freetype2
                 |---freetype
                     ---|Bunch of header files
                 |---ftbuild.h
         |---lib
             |---libfreetype.a

This is my CMakeLists.txt:

cmake_minimum_required(VERSION 3.4.1)

add_definitions("-DGLM_FORCE_SIZE_T_LENGTH -DGLM_FORCE_RADIANS")

add_subdirectory(src/main/cpp/glm)

add_library(freetype STATIC IMPORTED)
set_target_properties(freetype PROPERTIES IMPORTED_LOCATION${PROJECT_SOURCE_DIR}/libs/freetype/${ANDROID_ABI}/lib/libfreetype.a)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall")
add_library(native-lib SHARED
        src/main/cpp/native-lib.cpp
        src/main/cpp/graph.cpp
        src/main/cpp/text.cpp
        src/main/cpp/graphDataWorker.cpp
        )
target_include_directories(native-lib PRIVATE ${PROJECT_SOURCE_DIR}/libs/freetype/${ANDROID_ABI}/include/freetype2)                       

target_link_libraries(native-lib
                  android
                  freetype
                  GLESv2
                  EGL
                  glm
                  atomic
                  log
                  OpenSLES
                  )

The problem is that I can use library inside my code and android studio is not giving me any errors, but then i try to run application it gives me this error:

linker command failed with exit code 1 (use -v to see invocation)

PS: I Can't see freetype headers in android studio file tree aswell, but can see other libraries.

Question: Am I importing library in a wrong way or this is cross-compilation issue and if so how to do it properly? I done a lot of research on this issue and was unable to find a solution Any help will be appreciated.

Upvotes: 3

Views: 3096

Answers (1)

piwi
piwi

Reputation: 5346

Unless you mixed paths when installing your build of FreeType2, it seems that the compilation of the library is incorrect, since the linker complains about the library being for x86_64 architecture.

On Linux, usually you can check the architecture the library is built for with command file. Another way to check the architecture is to use the objdump tool that is shipped with Android NDK (if I remember correctly it is generated with a toolchain as well). Its name follows the same pattern than the compiler/linker/... tools, $target_host-objdump.

I would recommend to compile FreeType2 using CMake instead of autotools, at least in my case I successfully did it that way.


Here is a sample of CMake configuration I wrote to cross-compile FreeType2 for Android. It is a little complex because it is part of a project where I build several libraries.

The idea is that my CMake configuration uses ExternalProject to download and compile Freetype. My top-level CMakeLists.txt contains:

# CMakeLists.txt
set(DEVENV_CMAKE_ARGS
  -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
  -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
  -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
  -DCMAKE_C_FLAGS=${CMAKE_CXX_FLAGS}
  -DCMAKE_C_FLAGS_${BUILD_TYPE}=${CMAKE_C_FLAGS_${BUILD_TYPE}}
  -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
  -DCMAKE_CXX_FLAGS_${BUILD_TYPE}=${CMAKE_CXX_FLAGS_${BUILD_TYPE}}
  -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
  -DCMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}
)
if(BUILD_SHARED_LIBS)
  list(APPEND DEVENV_CMAKE_ARGS -DBUILD_STATIC_LIBS=OFF -DLIBTYPE=SHARED)
else()
  list(APPEND DEVENV_CMAKE_ARGS -DBUILD_STATIC_LIBS=ON -DLIBTYPE=STATIC)
endif()
if(DEFINED ANDROID_TOOLCHAIN_DIR)
  get_filename_component(_toolchain_dir ${ANDROID_TOOLCHAIN_DIR} ABSOLUTE)
  list(APPEND DEVENV_CMAKE_ARGS -DANDROID_TOOLCHAIN_DIR=${_toolchain_dir})
endif()
if(DEFINED CMAKE_ANDROID_ARCH_ABI)
  list(APPEND DEVENV_CMAKE_ARGS -DCMAKE_ANDROID_ARCH_ABI=${CMAKE_ANDROID_ARCH_ABI})
endif()

if(CMAKE_TOOLCHAIN_FILE)
  get_filename_component(_toolchain_file ${CMAKE_TOOLCHAIN_FILE} ABSOLUTE)
  list(APPEND DEVENV_CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${_toolchain_file})
endif()

add_subdirectory(freetype)

So the variable DEVENV_CMAKE_ARGS contains appropriate CMake arguments for cross-compiling that reflect my current CMake configuration. Under directory freetype, the CMakeLists.txt contains:

# freetype/CMakeLists.txt
project(freetype)

include(ExternalProject)

if(NOT FREETYPE_GIT_REPOSITORY)
  set(FREETYPE_GIT_REPOSITORY "https://git.savannah.gnu.org/git/freetype/freetype2.git")
endif()

set(FREETYPE_GIT_REPOSITORY "${FREETYPE_GIT_REPOSITORY}"
  CACHE STRING "Git repository for library Freetype."
)

if(NOT FREETYPE_GIT_TAG)
  set(FREETYPE_GIT_TAG "VER-2-9")
endif()

set(FREETYPE_GIT_TAG "${FREETYPE_GIT_TAG}"
  CACHE STRING "Tag or branch of Git repository to build."
)

message(STATUS "Freetype Git repository: ${FREETYPE_GIT_REPOSITORY}")
message(STATUS "Freetype Git tag: ${FREETYPE_GIT_TAG}")

externalproject_add(freetype
  GIT_REPOSITORY "${FREETYPE_GIT_REPOSITORY}"
  GIT_TAG "${FREETYPE_GIT_TAG}"
  SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/freetype/src"
  BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/freetype/build"
  CMAKE_ARGS ${DEVENV_CMAKE_ARGS}
)

Basically this CMakeLists.txt uses ExternalProject to download and compile FreeType2 in the build directory.

And I use a toolchain file for Android:

# android.cmake
set(CMAKE_SYSTEM_NAME "Android")
set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN ${ANDROID_TOOLCHAIN_DIR})

Sorry if it is overly complex; it comes from a project where I was playing with cross-compiling for Android. I hope it helps anyway.

Upvotes: 4

Related Questions