I have this C function in meaning_of_life.c
:
#define FFI_PLUGIN_EXPORT
FFI_PLUGIN_EXPORT int getMeaningOfLife(){
return 42;
}
I tried to compile it to a shared library (.so
) using alot of ways but I keep getting errors when I try to use it on android like incompatible target
and file in wrong format
. Can you tell me the right way to do it?
add_library(meaningoflife SHARED IMPORTED )
set_target_properties(meaningoflife
PROPERTIES
IMPORTED_LOCATION
/home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so
)
target_link_libraries(my_plugin meaningoflife)
.so
shared library from the plugin, first I tried the method on this page (using the NDK compilers and toolchain):cd /home/haidar/dev_haidar/c++/meaning_of_life/Src
comp=/home/haidar/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin
$comp/aarch64-linux-android26-clang -fPIC meaning_of_life.c -o libLife.so -shared // also tried with other compilers as armv7a-linux-androideabi26-clang
The library is generated, but when I use it, I get one of the errors mentioned above (depending on the compiler used to create it), for example, here is some part of the error:
[ ] FAILURE: Build failed with an exception.
[ ] * What went wrong:
[ ] Execution failed for task ':image_magick_ffi:buildCMakeDebug[armeabi-v7a]'.
[ ] > Build command failed.
[ ] Error while executing process /home/haidar/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a image_magick_ffi}
[ ] ninja: Entering directory `/home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a'
[ ] [1/1] Linking C shared library /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
[ ] FAILED: /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
[ ] : && /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --gcc-toolchain=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libimage_magick_ffi.so -o /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so CMakeFiles/image_magick_ffi.dir/image_magick_ffi.c.o /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so -latomic -lm && :
[ ] /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so: incompatible target
[ ] clang: error: linker command failed with exit code 1 (use -v to see invocation)
[ ] ninja: build stopped: subcommand failed.
[ ] * Try:
[ ] > Run with --debug option to get more log output.
[ ] > Run with --scan to get full insights.
[ ] * Exception is:
[ ] org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':image_magick_ffi:buildCMakeDebug[armeabi-v7a]'.
[ ] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:147)
[ ] at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
[ ] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:145)
[ ] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
[ ] at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
[ ] at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
[ ] at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
[ ] at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
[ ] at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
[ ] at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
[ ] at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
[ ] at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
[ ] at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
[ ] at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
[ ] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[ ] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[ ] at java.base/java.lang.Thread.run(Thread.java:829)
[ ] Caused by: org.gradle.internal.UncheckedException: Build command failed.
[ ] Error while executing process /home/haidar/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a image_magick_ffi}
[ ] ninja: Entering directory `/home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a'
[ ] [1/1] Linking C shared library /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
[ ] FAILED: /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
[ ] : && /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --gcc-toolchain=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libimage_magick_ffi.so -o /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so CMakeFiles/image_magick_ffi.dir/image_magick_ffi.c.o /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so -latomic -lm && :
[ ] /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so: incompatible target
[ ] clang: error: linker command failed with exit code 1 (use -v to see invocation)
[ ] ninja: build stopped: subcommand failed.
[ ] at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:68)
[ ] at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:41)
[ ] at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:107)
[ ] at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
[ ] at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
[ ] at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:242)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
[ ] at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:227)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:210)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:193)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:171)
[ ] at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
[ ] at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
[ ] at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
[ ] at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
[ ] at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
[ ] at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
[ ] at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
[ ] at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
[ ] at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
[ ] at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
[ ] at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
[ ] at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
[ ] at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
[ ] at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
[ ] at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
[ ] at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
[ ] at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:61)
[ ] at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:42)
[ ] at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
[ ] at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
[ ] at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:180)
[ ] at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
[ ] at org.gradle.internal.Either$Right.fold(Either.java:175)
[ ] at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
[ ] at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
[ ] at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
[ ] at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
[ ] at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
[ ] at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
[ ] at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
[ ] at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
[ ] at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
[ ] at java.base/java.util.Optional.orElseGet(Optional.java:369)
[ ] at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
[ ] at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
[ ] at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
[ ] at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
[ ] at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
[ ] at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
[ ] at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
[ ] at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
[ ] at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
[ ] at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
[ ] at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
[ ] at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
[ ] at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:249)
[ ] at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:86)
[ ] at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:54)
[ ] at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
[ ] at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
[ ] at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
[ ] at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
[ ] at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
[ ] at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
[ ] at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:287)
[ ] at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
[ ] at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
[ ] at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
[ ] at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
[ ] at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
[ ] at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
[ ] at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
[ ] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:144)
[ ] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
[ ] at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
[ ] at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
[ ] at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
[ ] at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
[ ] at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
[ ] at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
[ ] at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
[ ] at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
[ ] at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
[ ] at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
[ ] at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
[ ] at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
[ ] at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
[ ] at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
[ ] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[ ] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[ ] at java.base/java.lang.Thread.run(Thread.java:829)
[ ] Caused by: Build command failed.
...
.so
shared library from the plugin, This time I tried the method on the official android docs page, I used this command which generated a json file with another command to compile the C file above, but I don't understand how to create the shared library in this case (the template of the command is from the same page):cmake -H/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_FIND_ROOT_PATH=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/haidar/Android/Sdk/ndk/25.1.8937393/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NDK=/home/haidar/Android/Sdk/ndk/25.1.8937393 -DANDROID_PLATFORM=android-23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=/home/haidar/Android/Sdk/ndk/25.1.8937393 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_MAKE_PROGRAM=/home/haidar/Android/Sdk/cmake/3.22.1/bin/ninja -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=26 -B/home/haidar/dev_haidar/c++/meaning_of_life -GNinja
Note: The device I tried to run the flutter app (that uses the plugin, that uses the .so
library) on is a Huawei p10 lite, which has a CPU that supports arm63-v8a, armeabi-v7a, armeabi.
Listing the steps to solve this or tips would be much appreciated. Thanks.
I found this shell script on github (which is very similar to what I did in step 6 above), I tweaked it to fit my paths and it successfully generated the .so
files for each architecture. I created a pure android app and called it from the app and everything worked fine.
add_library(getnumber SHARED IMPORTED)
set_target_properties(getnumber PROPERTIES IMPORTED_LOCATION
/home/haidar/dev_haidar/c++/getnumber/Src/prebuilt/release/arm64-v8a/libgetnumber.so
)
target_link_libraries(imagemagicknativeapp getnumber)
and everything worked fine.
When I depended on it in the flutter plugin in the exact same way
add_library(getnumber SHARED IMPORTED )
set_target_properties(getnumber
PROPERTIES
IMPORTED_LOCATION
/home/haidar/dev_haidar/flutter/image_magick_ffi/src/Dependencies/ImageMagick/lib/android/arm64-v8a/libgetnumber.so
)
target_link_libraries(image_magick_ffi getnumber)
I still get an error
ld: error: /home/haidar/dev_haidar/flutter/image_magick_ffi/src/Dependencies/ImageMagick/lib/android/arm64-v8a/libgetnumber.so is incompatible with armelf_linux_eabi
I know the problem is related to the compilation/linking target being different than the actual target (my phone), but how can I tell flutter to change this behavior?
Thanks to Piero5W11 from FlutterDev on discord, I was able to solve this particular problem.
The solution is to remove the part related to adding the library from CMake (don't add the library from CMake, we will add it from somewhere else), so remove this part:
add_library(getnumber SHARED IMPORTED)
set_target_properties(getnumber PROPERTIES IMPORTED_LOCATION
/home/haidar/dev_haidar/c++/getnumber/Src/prebuilt/release/arm64-v8a/libgetnumber.so
)
target_link_libraries(imagemagicknativeapp getnumber)
from CMakeLists.txt
,
and instead, copy the shared library to {PLUGIN_PROJECT_ROOT}/android/src/main/jniLibs/{ABI_VERSION}/libgetnumber.so
(replace the wildcards)
Just do this and do zero other configuration in the CMakeLists or gradle files.
As for the dart side, this library will be bundled with the app as any other library so you can load it by its name getnumber
using the dart dynamic loader, and then use it to lookup symbols in it.
This is how my plugin's project structure looks like now:
and you can how see the generated apk contains the library just bcz it was put in jniLibs:
Note: I generated libgetnumber
using the script from the link in the question, it is perfect for creating ABIs for all targets, just tweak it to fit your paths.
To add the shared libraries through CMakeLists.txt
of the flutter ffi plugin:
jniLibs
folder (source)CMakeLists.txt
, in ${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/ImageMagick/lib/android/${ANDROID_ABI}/libc++_shared.so
(put your own paths instead)android/build.gradle
in the plugin: ndk {
abiFilters "arm64-v8a" // put only the architectures that your lib is targeting
}
note: if you have .so
versions for all ABIs, then you will not need this step.
.so
files as libraries in CMake and link them to your flutter plugin library:CMakeLists.txt
:
project(my_ffi_library VERSION 0.0.1 LANGUAGES C)
add_library(my_ffi_library SHARED
"myclass.c"
)
...
# Add your library
add_library(my-lib SHARED IMPORTED)
set_target_properties(
my-lib
PROPERTIES IMPORTED_LOCATION
path/to/your/lib.so
)
# Link your library to the flutter plugin library
target_link_libraries(my_ffi_library my-lib)