Search code examples
androidccmakeopenssl

How to add external library to C/C++ JNI project via CMake


I have an Android-C library project that I am working on in Android Studio. I need to add external libraries like C directly to my project (not via Android Studio Gradle Dependency).

I have installed OpenSSL 3 via homebrew and set OPENSSL_ROOT_DIR in my .zprofile. However, when I attempt to build the project, I'm faced with the following errors


C++ build system [configure] failed while executing:
    /opt/homebrew/bin/cmake \
      -H/Users/mba/AndroidStudioProjects/MyApplication/app/src/main/cpp \
      -DCMAKE_SYSTEM_NAME=Android \
      -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
      -DCMAKE_SYSTEM_VERSION=24 \
      -DANDROID_PLATFORM=android-24 \
      -DANDROID_ABI=arm64-v8a \
      -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
      -DANDROID_NDK=/Users/mba/Library/Android/sdk/ndk/25.1.8937393 \
      -DCMAKE_ANDROID_NDK=/Users/mba/Library/Android/sdk/ndk/25.1.8937393 \
      -DCMAKE_TOOLCHAIN_FILE=/Users/mba/Library/Android/sdk/ndk/25.1.8937393/build/cmake/android.toolchain.cmake \
      -DCMAKE_MAKE_PROGRAM=/Users/mba/Library/Android/sdk/cmake/3.22.1/bin/ninja \
      -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/Users/mba/AndroidStudioProjects/MyApplication/app/build/intermediates/cxx/Debug/444d406q/obj/arm64-v8a \
      -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/Users/mba/AndroidStudioProjects/MyApplication/app/build/intermediates/cxx/Debug/444d406q/obj/arm64-v8a \
      -DCMAKE_BUILD_TYPE=Debug \
      -DCMAKE_FIND_ROOT_PATH=/Users/mba/AndroidStudioProjects/MyApplication/app/.cxx/Debug/444d406q/prefab/arm64-v8a/prefab \
      -B/Users/mba/AndroidStudioProjects/MyApplication/app/.cxx/Debug/444d406q/arm64-v8a \
      -GNinja \
      -DANDROID_STL=c++_shared
  from /Users/mba/AndroidStudioProjects/MyApplication/app
CMake Error at /opt/homebrew/Cellar/cmake/3.29.2/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the
  system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY
  OPENSSL_INCLUDE_DIR)

My CMakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.

# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)

project("nfcNative")

find_package(OpenSSL REQUIRED)
message(STATUS "OPENSSL_LIBRARIES:${OPENSSL_LIBRARIES}")

add_library(${CMAKE_PROJECT_NAME} SHARED
        nfcNative.c
        commands.c
        rsa.c
        )

include_directories(src/main/cpp/include/ ${OPENSSL_INCLUDE_DIRS})
target_link_libraries(${CMAKE_PROJECT_NAME}
        android
        log
        OpenSSL::Crypto
        OpenSSL::Ssl
        )

I set OPENSSL_ROOT_DIR in the following locations and the compiler still can't find it

enter image description here

Also, I am able to find package added via Android studio dependency with

find_package(openssl REQUIRED CONFIG)

however, the provided package (com.android.ndk.thirdparty:openssl:1.1.1q-beta-1 is only version 1.1.1 and my project requires the more recent versions 3.x


Solution

  • If you are like me and you are using Android Studio and NDK, then you are probably still stuck and unsure with how to use the prebuilt jniLibs.

    Here's my approach:

    1. Add an android library to your dependencies in your app's build.gradle file

    `dependencies { ///Other dependencies

    //Libraries for C/C++
    implementation("com.github.brunotl.ndk.thirdparty:openssl:3.2.1-beta-4")
    implementation("com.github.brunotl.ndk.thirdparty:curl:7.85.0-beta-4")
    

    }`

    1. Modify the android section of your app's build.gradle to build using CMake.

    `android { namespace = "com.native.example" compileSdk = 34

    defaultConfig {
        applicationId = "com.native.example"
        minSdk = 28
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    
        externalNativeBuild {
            cmake {
                arguments += "-DANDROID_STL=c++_shared"
            }
        }
    }
    
    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            isDebuggable = true
            isJniDebuggable = true
            isRenderscriptDebuggable = true
            signingConfig = signingConfigs.getByName("debug")
        }
        getByName("debug") {
            isDebuggable = true
            isJniDebuggable = true
            isRenderscriptDebuggable = true
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    externalNativeBuild {
        cmake {
            path = file("src/main/cpp/CMakeLists.txt")
            version = "3.22.1"
        }
    }
    buildFeatures {
        viewBinding = true
    }
    buildFeatures {
        prefab = true
    }
    

    } `

    1. Modify your CMakeLists.txt to find and link these libraries

      `cmake_minimum_required(VERSION 3.22.1)

      project("nfcNative")

      find_package(openssl REQUIRED CONFIG) find_package(curl REQUIRED CONFIG) message(STATUS "OPENSSL_LIBRARIES:${OPENSSL_LIBRARIES}") message(STATUS "CURL_LIBRARIES:${CURL_LIBRARIES}")

      add_library(${CMAKE_PROJECT_NAME} SHARED # List C/C++ source files with relative paths to this CMakeLists.txt. ... )

      include_directories(src/main/cpp/include/ ${OPENSSL_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} )

      target_link_libraries(${CMAKE_PROJECT_NAME} curl::curl openssl::crypto openssl::ssl android log )`