Skip to content
This repository has been archived by the owner on Jan 17, 2024. It is now read-only.

Problem adding C dynamic library to existing flutter application. #109

Closed
ghost opened this issue Jun 15, 2021 · 4 comments
Closed

Problem adding C dynamic library to existing flutter application. #109

ghost opened this issue Jun 15, 2021 · 4 comments

Comments

@ghost
Copy link

ghost commented Jun 15, 2021

Hello!
I've ran into problem trying to add my own small c library to existing flutter application.
Here is error message:

[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Invalid argument(s): Failed to load dynamic library 'lib.a': dlopen(lib.a, 0x0001): dlopen(): file not found: lib.a

Library is working fine, when I call it directly from dart code on local machine, but when I try to add it to existing flutter project on iOS emulator or iOS device, it throws an error.

Here is 'C interop' official documentation:

On iOS, you need to tell Xcode to statically link the file:

In Xcode, open Runner.xcworkspace.
1 - Add the C/C++/Objective-C/Swift source files to the Xcode project.
2 - On Android, you need to create a CMakeLists.txt file to define how the sources should be compiled and point Gradle to it. From the root of your project directory, use the following instructions

Asking to make this step clear:

1 - Add the C/C++/Objective-C/Swift source files to the Xcode project.

How to properly add source files to existing project in Xcode? (I have 2 files lib.a and lib.h, which I want to add)

I was trying to create a plugin and modify .podspec file in different ways, but it doesn't really help. Dart still throwing that error:

[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Invalid argument(s): Failed to load dynamic library 'lib.a': dlopen(lib.a, 0x0001): dlopen(): file not found: lib.a

Here is how my iOS folder structure (in plugin directory):
Снимок экрана 2021-06-15 в 12 50 16

Here is full crypto_export.podspec file:

#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint crypto_export.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
  s.name             = 'crypto_export'
  s.version          = '0.0.1'
  s.summary          = 'A new flutter plugin project.'
  s.description      = <<-DESC
A new flutter plugin project.
                       DESC
  s.homepage         = 'http://example.com'
  s.license          = { :file => '../LICENSE' }
  s.author           = { 'Your Company' => 'email@example.com' }
  s.source           = { :path => '.' }
  s.source_files = 'Classes/**/*'
  s.dependency 'Flutter'
  s.platform = :ios, '8.0'

  # Flutter.framework does not contain a i386 slice.
  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
  s.swift_version = '5.0'
end

I was trying to call my lib.a with following lines:

final DynamicLibrary dynamicGoLibrary = DynamicLibrary.open('lib.a');
final DynamicLibrary dynamicGoLibrary = DynamicLibrary.open('Classes/lib.a');

,it doesn't help.

How do I transfer my lib.a and lib.h files from plugin folder to iOS application and how do I open them with dart FFI?

Here is link to my GitHub plugin page. All C sources are there, including my c library (simple export of some cryptography functions).

I also tried to modify .podspec file adding those lines:

  s.preserve_paths = 'lib.a'
  s.vendored_frameworks = 'lib.a'

And changing this line:

  s.source_files = './*'

But I still get the same error message, error says, dart can't find a file called lib.a. How do I add this file to flutter application on real device?

@dcharkes
Copy link
Contributor

With static libraries you need to tell the Xcode linker to not strip the symbols.

  s.vendored_libraries = 'Frameworks/libmylib_staticlib.a'
  s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libmylib_staticlib.a" }

The .a static library must live in the Frameworks folder.

Static libraries are linked in to the executable, so you don't DynamicLibrary.open them. Instead, you look them up in the executable itself DynamicLibrary.executable().

@ghost
Copy link
Author

ghost commented Jun 15, 2021

Thanks a lot for your response!
You just can not imagine what a saver you are!

I made those changes:

  1. Added those lines to .podspec file:
  s.vendored_libraries = 'Frameworks/lib.a'
  s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/lib.a" }
  1. Added files in Xcode to Pods/Frameworks

Снимок экрана 2021-06-15 в 18 04 43


If I launch application using those lines:

final DynamicLibrary dynamicGoLibrary = DynamicLibrary.open('lib.a');

or

final DynamicLibrary dynamicGoLibrary = DynamicLibrary.open('Frameworks/lib.a');

I get following exception:

ArgumentError (Invalid argument(s): Failed to load dynamic library 'lib.a': dlopen(lib.a, 1): image not found)

If I try to launch it using .executable() like that:

final DynamicLibrary dynamicGoLibrary = DynamicLibrary.executable();

I get following error:

ArgumentError (Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, Keys): symbol not found))

This library was build from cgo using c-shared mod. When I try to call it from dart using dart:ffi on local machine it works fine. But I can't access it from any flutter application (iOS/macos).

@dcharkes
Copy link
Contributor

Because of the way Flutter plugins are set up (they generate a ton of boilerplate files from a templating system for every target platform), it is not recommended to try to create this boilerplate in an existing application.

Instead, create a Flutter FFI plugin and the application in the same Git repo.

Here is a PR adding FFI plugins to Flutter. (Instructions to on how to run it in the PR for if you want to use this before its merged.)

For using Golang, please make sure that an example with C code works before using Go. That way we ensure the issue is in the Go setup rather than in the rest of the setup.

Feel free to open a new issue w.r.t. Go. (Closing this one as its title is asking for an unsupported use case.)

@Sakari369
Copy link

Would be really useful having some sort of guide how to do this on macOS and iOS properly, having to write a CocoaPods file is just a world of pain if you don't have any idea how to do it, even the linter will fail with C++ headers if you don't know the magic --skip-import-validation flag which I found no reference anywhere.

I might write a blog post about this, got pretty pissed while trying to do this, luckily I found this issue and your response @dcharkes ! 🙏

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

2 participants