0

I have a simple C++ function compiled into a dylib file that I'm trying to run on an Android phone. The function is super simple, it just adds to numbers and returns the result. However, I keep getting this error: Another exception was thrown: Invalid argument(s): Failed to load dynamic library 'libadd.dylib': dlopen failed: library "libadd.dylib" not found .

I'm really not sure what I'm doing wrong. I've done the following steps: My Dart implementation:

import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;

import 'package:path/path.dart' as path;

typedef C_ADD = ffi.Int Function(
    ffi.Int a, ffi.Int b); // FFI signature of C function
typedef ADD = int Function(int a, int b);

void linkAndCallFunction() {
  var libraryPath = path.join(Directory.current.path, "libadd.dylib");
  final dylib = ffi.DynamicLibrary.open(libraryPath);

  final ADD add = dylib.lookup<ffi.NativeFunction<C_ADD>>("add").asFunction();
  final result = add(40, 2);
  print(result);
}

I've added these to the build.gradle files: build.gradle:

buildscript{
    ext{
        ndkVersion = "25.1.8937393"
    }
    ...

and app/build.gradle:

android {
    ndkVersion rootProject.ext.ndkVersion
    externalNativeBuild {
        cmake {
            path "../../lib/CMakeLists.txt"
        }
    }

This is my CMakeLists.txt file:

cmake_minimum_required(VERSION 3.10.2)
project(add LANGUAGES CXX C)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")

add_library(add SHARED ./add.cpp)

and my file structure of the project looks like this:

   lib/
      - add.cpp
      - add.o
      - CMakeLists.txt
      - libadd.dylib
      - main.dart

it also may be worth mentioning that in order to compile add.cpp into a dylib I ran the following commands:

g++ -c add.cpp
ar rvs libadd.dylib add.o

and if you're wondering, add.cpp looks like this:

#define EXPORT extern "C" __attribute__((visibility("default")))
__attribute__((used))

EXPORT
int add(int a, int b){
    return a + b;
}

Where is this error coming from? am I compiling to a dylib incorrectly?

Zachary Haslam
  • 103
  • 1
  • 12
  • You have a cmake file (implies Android) but you are trying to load a dylib (which implies macos). You've tagged the question android - so why a dylib? Why are you manually invoking g++? Can you explain more what you are doing - target os, flutter or pure dart? – Richard Heap Jan 07 '23 at 02:23
  • https://www.youtube.com/watch?v=X8JD8hHkBMc – Richard Heap Jan 07 '23 at 02:33
  • @RichardHeap I'm trying to write a couple of c++ functions for the backend of a project I'm working on, the frontend will be in Flutter. I'm realizing now that I need to run `cmake .` and `make` before I run the program, but since I'm using Mac those commands actually create a .dylib file, and when I run the program on a connected Android phone it still doesn't work. I want a static library instead that will be shipped with the app instead of compiling it at runtime. How would I even compile it to work on the Android phone? Also, do I have to initialize the flutter project as a plugin first? – Zachary Haslam Jan 08 '23 at 18:14
  • I'd always do flutter ffi work in a plugin then depend the main project on the plugin. Nothing gets compiled at runtime - it gets compiled at build time - when you do flutter run or launch the debugger. Just because you are building *on* a mac, doesn't mean you should be compiling *for* the mac - you need to be compiling for android. Follow the steps in the video linked above. – Richard Heap Jan 08 '23 at 20:08

1 Answers1

0

The answer to this problem was relatively simple, it just stemmed from my lack of knowledge on how Android actually compiles to a static library. Hopefully it helps someone else who is trying to understand how to setup external C++ code in a flutter program.

The static library is generated automatically and is set up in CMakeLists.txt.

Firstly, I moved all the C++ files into the android folder. Then, I set up CMakeLists.txt like this:

cmake_minimum_required(VERSION 3.10.2)

add_library( add  // library name, will create libadd.so

            SHARED

            add.cpp

)

The problem before was that I was trying to manually compile the file myself, when I should have been letting CMakeLists do it instead. According to the android documentation:

"The convention CMake uses to name the file of your library is as follows:

liblibrary-name.so

For example, if you specify "native-lib" as the name of your shared library in the build script, CMake creates a file named libnative-lib.so. " https://developer.android.com/studio/projects/configure-cmake

So when I run the program, the static library is created automatically and placed in the correct place. Then, the Dart FFI can find it with the DynamicLibrary.open() function. In this case, CMakeLists will generate a file called libadd.so, and I can callDynamicLibrary.open('libadd.so') and the program works.

Zachary Haslam
  • 103
  • 1
  • 12