Search code examples
androidandroid-ndkvtkndk-build

Linking VTK with ndk-build on NDK r17c results with 'undefined references' errors


I had built VTK on Linux with Android NDK r17c and the result was 54 static (.a) libraries of total 600+ MB. Now, I had imported these librarires to my AndroidStudio 3.3 project and I would like to use the built libraries in my native code. In Android Studio I am using the same version of the NDK (r17c).

In AndroidStudio I had created new module for using the VTK and inside that module I am using ndk-build for building the library. The structure of the module is:

...
|--jni/
|--|--include/
|--|--|--vtkAbstractArray.h
|--|--|--vtkAbstractCellLinks.h
|--|--|-- ...
|--|--lib/
|--|--|--arm64-v8a/
|--|--|--|--libvtkCommonColor-8.9.0.a
|--|--|--|--libvtkCommonComputationalGeometry-8.9.0.a
|--|--|--|--...
|--|--Application.mk
|--|--Android.mk
|--|--vtk-lib.cpp

I am using the VTK library in my vtk-lib.cpp file (which I am accessing from Java code).

In order just to get this to work, I wasn't building the library for all of the supported android architectures (but only for my arm64-v8a device), so I defined an Application.mk file like this:

APP_STL := c++_static
API_ABI := arm64-v8a

In my Android.mk file, I had defined 54 modules with PREBUILT_STATIC_LIBRARY (one for each of the 54 built .a files). In the end, I am building a BUILD_SHARED_LIBRARY with vtk-lib.cpp file to be accessible from Java:

LOCAL_PATH := $(call my-dir)

#prepare vtk-common-color
include $(CLEAR_VARS)
LOCAL_MODULE := vtk-common-color
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libvtkCommonColor-8.90.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

#...53 more modules for every .a static library

include $(CLEAR_VARS)
LOCAL_SRC_FILES  := vtk-lib.cpp
LOCAL_MODULE     := vtk-lib
LOCAL_STATIC_LIBRARIES := vtk-common-color ... # 53 more module names
LOCAL_CPP_FEATURES := rtti exceptions
LOCAL_CPPFLAGS += --std=c++11
include $(BUILD_SHARED_LIBRARY)

When I try to build the application a get a bunch of the errors regarding the undefined reference as shown below:

Build command failed.
Error while executing process [some path]\Android\sdk\ndk-bundle\ndk- 
build.cmd with arguments {NDK_PROJECT_PATH=null 
APP_BUILD_SCRIPT=[some path]\src\main\jni\Android.mk NDK_APPLICATION_MK= 
[some path]\src\main\jni\Application.mk APP_ABI=arm64-v8a 
NDK_ALL_ABIS=arm64-v8a NDK_DEBUG=1 APP_PLATFORM=android-23 
NDK_OUT=[some path]/build/intermediates/ndkBuild/debug/obj 
NDK_LIBS_OUT=[some path]\build\intermediates\ndkBuild\debug\lib [some 
path]build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/libvtk-lib.so}

[arm64-v8a] Compile++      : vtk-lib <= vtk-lib.cpp
[arm64-v8a] SharedLibrary  : libvtk-lib.so
[some path]/src/main/jni/lib/arm64-v8a/libvtkFiltersSources- 
8.90.a(vtkConeSource.cxx.o): In function `vtkConeSource::New()':
[some path ON LINUX]/VTK/Filters/Sources/vtkConeSource.cxx:30: undefined 
reference to `vtkObjectBase::InitializeObjectBase()'
[some path]/src/main/jni/lib/arm64-v8a/libvtkFiltersSources- 
8.90.a(vtkConeSource.cxx.o): In function 
`vtkConeSource::vtkConeSource(int)':
[some path ON LINUX]/VTK/Filters/Sources/vtkConeSource.cxx:35: undefined 
reference to `vtkPolyDataAlgorithm::vtkPolyDataAlgorithm()'

#etc etc many more errors

I had came across this github thread so I had tried using the LOCAL_WHOLE_STATIC_LIBRARIES instead of LOCAL_STATIC_LIBRARIES, different versions of LOCAL_LDLIBS and LOCAL_LDFLAGS but still no luck.

Any help?


Solution

  • I ended up using CMake insted of ndk-build.

    I needed to add this code to my module's build.gradle:

    android {
        ...
    
        defaultConfig {
            ...
    
            externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11"
                    arguments "-DANDROID_CPP_FEATURES=rtti exceptions",
                            "-DANDROID_STL=gnustl_shared"
                    abiFilters 'arm64-v8a'
                }
            }
        }
    
        ...
    
        externalNativeBuild {
            cmake {
                path "src/main/jni/CMakeLists.txt"
            }
        }
    }
    

    And, my CMakeLists.txt looks like this:

    cmake_minimum_required(VERSION 3.4.1)
    
    set(LIB_DIR ${PROJECT_SOURCE_DIR}/lib/${ANDROID_ABI})
    
    add_library(vtk-common-color STATIC IMPORTED)
    set_target_properties(vtk-common-color
        PROPERTIES IMPORTED_LOCATION
        ${LIB_DIR}/libvtkCommonColor-8.90.a)
    
    #53 more libraries
    
    add_library( vtk-lib SHARED ${PROJECT_SOURCE_DIR}/vtk-lib.cpp)
    
    target_include_directories(vtk-lib PRIVATE ${PROJECT_SOURCE_DIR}/include)
    
    target_link_libraries(
        vtk-lib
        -Wl,--start-group -L ${TARGET_OUT}
        vtk-common-color
        #53 more libraries names
        -Wl,--end-group
    )