pezcode / open3d-core-android

Cross-compiling and using the core Open3D library on Android
19 stars 14 forks source link

C/C++: ld: error: undefined symbol: open3d::io::CreateImageFromFile(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&) #9

Open vittoema96 opened 1 year ago

vittoema96 commented 1 year ago

Whenever i try to call CreateImageFromFile (or any other method from this library that receives an std:string as an argument), during compilation i get hit with the following error:

C/C++: ld: error: undefined symbol: open3d::io::CreateImageFromFile(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&) I understand that it may be a compilation/ndk problem, but not much more than that.

Here I'll explain how i compiled the project and setup the Android Studio environment:

I am trying to build on Windows 10 I have version 3.14 of CMake installed

I have cloned the project with git clone https://github.com/InstytutXR/open3d-core-android. I have edited the CMakeLists.txt file to download version 0.9.0 instead of 0.10.0 (keeping 0.10 did not work) Inside the downloaded project folder, I have run the commands:

mkdir build & cd build
cmake -G Ninja -DANDROID_NDK=C:\Users\vittorio.veloccia\AppData\Local\Android\Sdk\ndk\20.1.5948944 -DCMAKE_INSTALL_PREFIX=../install .. && cmake --build .

This part correclty builds (aka no errors thrown)

Now i created an Android Studio Native C++ project.

My app's gradle.build file looks like this:

plugins {
    id 'com.android.application'
}

android {
    namespace 'com.example.testo3d'
    compileSdk 33
    ndkVersion "20.1.5948944"

    defaultConfig {
        applicationId "com.example.testo3d"
        minSdk 24
        targetSdk 33
        versionCode 1
        versionName "1.0"

        externalNativeBuild {
            cmake {
                version '3.22.1'
                arguments "-DOPEN3D_PATH=C:\\Development\\open3d-core-android\\install"
            }
        }
        ndk {
            abiFilters = []
            abiFilters.addAll(ABI_FILTERS.split(';').collect{it as String})
        }
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.22.1'
        }
    }
    buildFeatures {
        viewBinding true
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

In gradle.properties I have set the following property ABI_FILTERS=armeabi-v7a;arm64-v8a (these 2 are the only ones i have compiled)

My CMakeLists.txt file (inside Android Studio's cpp folder) looks like this:

cmake_minimum_required(VERSION 3.22.1)

project("testo3d")

set(SOURCE_FILES native-lib.cpp)

add_library( ${PROJECT_NAME} SHARED ${SOURCE_FILES})

find_library(log-lib log)

if(NOT OPEN3D_PATH)
    message(FATAL_ERROR "Open3D path not specified")
endif()

set(open3d-abi-path ${OPEN3D_PATH}/open3d-${ANDROID_ABI})

find_package(Open3D 0.9.0 # exact match required (major, minor, patch)
        REQUIRED
        PATHS ${open3d-abi-path}
        # don't look anywhere except in the path(s) we specify
        NO_DEFAULT_PATH
        # ignore the NDK CMAKE_FIND_ROOT_PATH, otherwise all search paths get prefixed with it
        NO_CMAKE_FIND_ROOT_PATH)

find_library(open3d-lib
        Open3D
        PATHS ${Open3D_LIBRARY_DIRS}
        NO_DEFAULT_PATH
        NO_CMAKE_FIND_ROOT_PATH)

file(COPY ${open3d-lib} DESTINATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI})

# Open3D gives us non-existing directories
# CMake doesn't allow adding those as interface include directories
foreach(dir ${Open3D_INCLUDE_DIRS})
    if(NOT EXISTS ${dir})
        list(REMOVE_ITEM Open3D_INCLUDE_DIRS ${dir})
    endif()
endforeach()

add_library(Open3D SHARED IMPORTED)
set_target_properties(Open3D PROPERTIES
        IMPORTED_LOCATION ${open3d-lib})
set_property(TARGET Open3D APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Open3D_INCLUDE_DIRS})

target_link_libraries(# Specifies the target library.
        ${PROJECT_NAME} PRIVATE
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}

        Open3D)

Lastly, my native-lib.cpp file (inside Android Studio's cpp folder) looks like this:

#include <jni.h>
#include "string"
#include "Open3D/Geometry/RGBDImage.h"
#include "Open3D/IO/ClassIO/ImageIO.h"

using namespace open3d::geometry;

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_o3dnative_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string path = "/emulated/storagew/0/Android/data/com.example.testo3d/files/image.jpg";
    Image colImg = *open3d::io::CreateImageFromFile(path);
    return env->NewStringUTF(path.c_str());
}

Can anyone help me out on understanding what that error might mean and how to resolve it?

IShiraiKurokoI commented 3 months ago

I also encountered this problem, and I know why. I used IDA to reversely view the symbol tables of all compiled functions, and found that open3d::io does not exist. Then I found this sentence in the readme: "in this fork IO module is removed since some external libraries are hard to compile (turbojpeg).". The IO code is also commented out in the patch file, so of course IO cannot be used.