Closed JackPanda8 closed 3 years ago
/cc @dcharkes
Hi @JackPanda8,
Does FFI support iOS static library?
Yes, following the steps from the documentation locally works for me.
Please take a look at https://github.com/flutter/flutter/issues/62666#issuecomment-668377567
And please double check that Xcode statically links the C code:
On iOS, you need to tell Xcode to statically link the file:
In Xcode, open Runner.xcworkspace. Add the C/C++/Objective-C/Swift source files to the Xcode project.
https://flutter.dev/docs/development/platform-integration/c-interop#step-2-add-cc-sources
If the problem still persists, please provide a minimal reproduction.
Header and universal static library are added
Strip style set to non-global
Even added the attribute about visibility
It's not working even debug build on simulator
Even the iOS swift app delegate can see and run it without problem
the universal static library support all the cpu
even create a test c file
added pseudo code that internally call the library function
The number "3" is successfully printed in the console so the FPDF_DestroyLibrary symbol is definetly not stripped.
But still dart can't see it...
Here are the necessary files need to to replicate https://drive.google.com/file/d/1tpI_StOh7ffPHjVapJJ34dMg2tJka45E/view?usp=sharing
Any update or comment?
Hi @bitsydarel, I have not yet had time to look into this.
The last time I tried to do static linking for iOS and MacOS I ran into similar problems. I ended up using dynamic libraries instead.
Does using dynamic libraries work for you in the mean time? (Until I have time to dig into this.)
Hi @dcharkes not really as those libraries are provided to us, and I have not seen usecase of creating fat library as dynamic libraries (for simulator and device).
@dcharkes Does it have to do with how dart lookup for library ? Is there anyway I could help to speed up the résolution of this issue ? As it’s one of our blocker in an ongoing project.
Here are the necessary files need to to replicate https://drive.google.com/file/d/1tpI_StOh7ffPHjVapJJ34dMg2tJka45E/view?usp=sharing
I don't have access to this.
Could you upload it is a GitHub repository instead?
The last time I tried to do static linking for iOS and MacOS I ran into similar problems. I ended up using dynamic libraries instead.
I have succeeded in looking up symbols of a statically linked library by creating the podspec of the framework as the following.
flutter create --platforms=android,ios,macos,windows,linux --template=plugin mylib_staticlib
Modify mylib_staticlib/macos/mylib_staticlib.podspec
(for Flutter desktop MacOS):
Pod::Spec.new do |s|
s.name = 'mylib_staticlib'
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 'FlutterMacOS'
s.platform = :osx, '10.11'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
s.vendored_libraries = 'Frameworks/libmylib_staticlib.a'
s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libmylib_staticlib.a" }
s.swift_version = '5.0'
end
And copy the static library in to mylib_staticlib/macos/Frameworks
.
For iOS, a similar approach.
mylib_staticlib/ios/mylib_staticlib.podspec
:
Pod::Spec.new do |s|
s.name = 'mylib_staticlib'
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.vendored_libraries = 'Frameworks/libmylib_staticlib.a'
s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libmylib_staticlib.a" }
s.swift_version = '5.0'
end
And the fat static library (arm64 for device and x64 for simulator) in mylib_staticlib/ios/Frameworks/libmylib_staticlib.a
.
So the 2 important lines in the podspec:
s.vendored_libraries = 'Frameworks/libmylib_staticlib.a'
s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libmylib_staticlib.a" }
The first statically links the static library, and the second line is the correct invocation to tell the linker to not strip the symbols.
Here's the repository with the necessary files https://github.com/bitsydarel/dart_ffi_static_link_issue
@dcharkes Would be nice to have this test on iOS and on template=app
To troubleshoot your problem, we need a complete flutter project, not just the static libraries and header files.
Create a new one with flutter create --platforms=android,ios,macos,windows,linux --template=plugin <insert-name>
, copy the static library in to the flutter plugin, modify the podspec, and try to lookup the symbol in a simple flutter app causing the error.
@dcharkes Would be nice to have this test on iOS and on template=app
You are always going to need a template=plugin
approach here, both for static libraries, dynamic libraries and source code. (Longer explanation: the plugin
creates all the necessary build configuration for including native code.)
@dcharkes So basically meaning adding it in an application directly won't do ? is there a reason for the why the app can't create those build configuration and if possible what are those build configuration ?
One could possibly. I am not familiar with the how the Flutter app/plugin builds are setup to tell you how. A good starting point for reverse engineering that would be to take a look at what files are generated when doing flutter create --template=plugin
. And otherwise ask a question on the Flutter issue tracker.
Any specific reason why you don't want to have a Flutter app + Flutter plugin right next to it in the same repository? And then have a ../myplugin
dependency in your pubspec.yaml
?
@dcharkes project pushed, also added the lookup functions and on the podspec file also added the required setup as suggested. But still not working on iOS
`[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, FPDF_DestroyLibrary): symbol not found)
Your reproduction doesn't work here. The static library is missing symbols. Did you mean to include a static library with the standard c/c++ libs as well?
Xcode's output:
↳
Undefined symbols for architecture arm64:
"std::__1::basic_streambuf<char, std::__1::char_traits<char> >::setbuf(char*, long)", referenced from:
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cpdf_streamparser.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cfdf_document.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cpdf_syntax_parser.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(fpdf_parser_decode.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cpdf_generateap.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cfx_fontmapper.o)
vtable for std::__1::basic_stringbuf<char, std::__1::char_traits<char>, std::__1::allocator<char> > in libpdfium.a(cpdfsdk_appstream.o)
...
@dcharkes if you check the android pdfium folder, you will see other libraries that the library would need
@dcharkes if you check the android pdfium folder, you will see other libraries that the library would need
https://github.com/bitsydarel/dart_ffi_static_link_issue/tree/main/pdfium/android
Those are all shared libraries, not static libraries, and not compiled in a way MacOS/iOS can understand them.
Please provide a working reproduction.
Hi @bitsydarel,
This is simple. Add on "OTHER_LDFLAGS" the link to "c++" as i showed before in xcode sample.
File: dart_ffii_static_link_issue.podspec
s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libpdfium.a -lc++" }
Hi @paulo-coutinho compilation now's working but it's still can't find the symbol `[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, FPDF_DestroyLibrary): symbol not found)
`
@dcharkes Now the sample is reproducible, i pushed the changes so you could check if it's dart that can't load the symbols.
Thank you guys for the help!
How do you testing it?
When you run the app if you check the console you should see logs about about the running app.
Hi,
Im investigating the generated binary from the Runner app and Xcode don't link with it:
nm /Users/paulo/Library/Developer/Xcode/DerivedData/Runner-aaxqkqpcwbuqojfckhanjbwlqrbu/Build/Products/Debug-iphoneos/Runner.app/Runner| grep FPDF
[nothing]
And i make the same thing with that my sample using the same library and it is linked correctly:
nm /Users/paulo/Library/Developer/Xcode/DerivedData/PDFiumTest-floybqwuisyrxufsdrwjfipgjiwy/Build/Products/Debug-iphoneos/PDFiumTest.app/PDFiumTest | grep FPDF
0000000100069874 t _FPDFPage_GetCropBox
000000010006978c t _FPDFPage_GetMediaBox
0000000100069318 t _FPDFText_CountChars
0000000100069550 t _FPDFText_CountRects
00000001000695cc t _FPDFText_GetBoundedText
0000000100069358 t _FPDFText_GetCharBox
00000001000693f8 t _FPDFText_GetCharIndexAtPos
0000000100069328 t _FPDFText_GetFontSize
000000010006955c t _FPDFText_GetRect
0000000100069440 t _FPDFText_GetText
0000000100069278 t _FPDFText_LoadPage
000000010006a5b8 t _FPDF_CloseDocument
000000010006a4e0 t _FPDF_ClosePage
000000010006a45c t _FPDF_GetPageBoundingBox
000000010006a2d8 t _FPDF_GetPageCount
000000010006a14c t _FPDF_InitLibraryWithConfig
000000010006a1c4 t _FPDF_LoadDocument
000000010006a310 t _FPDF_LoadPage
000000010006898c t __Z20CPDFPageFromFPDFPageP13fpdf_page_t__
0000000100068980 t __Z20FPDFPageFromIPDFPageP9IPDF_Page
000000010006897c t __Z20IPDFPageFromFPDFPageP13fpdf_page_t__
0000000100068984 t __Z28CPDFDocumentFromFPDFDocumentP17fpdf_document_t__
0000000100068988 t __Z28FPDFDocumentFromCPDFDocumentP13CPDF_Document
The library is not the problem, but the link process.
You can use any library name in podspec that it don't will generate error and will open the app:
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.vendored_libraries = 'libpdfiumXYZ.a'
s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-lc++ -lz" }
So you problem is masked.
If your sample was using podspec, how would you link the library ?
It is easy. I made it work here:
https://github.com/paulo-coutinho/pdfium-test/pull/1
You need:
cd ios
pod install
open PDFiumTest.xcworkspace
@dcharkes any update because the suggested changes by @paulo-coutinho does actually make the code compile and also make it available in swift or objective c code.
But dart can't see it...
Latest configuration: `s.source_files = 'Classes/*/' s.dependency 'Flutter' s.platform = :ios, '9.0'
s.libraries = ["c++", "z"]
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.vendored_libraries = 'Frameworks/libpdfium.a' s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libpdfium.a" } s.swift_version = '5.0'`
Hi @bitsydarel,
I am also struggling with the exact same issue, for PDFium too! Did you make any progress since your last message? I'll post here if I find a solution.
Jean-Marie
hi, @jmgeffroy
Waiting on @dcharkes, because it’s seems to be a dart ffi issue as swift and obj can see and use the library.
Hi @bitsydarel, Thanks a lot for your lightning-fast reply! OK, so I'll eagerly await, too ;-)
@bitsydarel I am able to look up symbols fine on iOS/MacOS with a small static library built by CMake using the podspec from https://github.com/dart-lang/sdk/issues/44328#issuecomment-855682903.
I presume either the static library is built in a different way, or your project setup is not the same. I haven't found the time to dig into your repo.
I'll see if I can upload my working repro somewhere so you can work from there.
@dcharkes strangely we tried with other libraries that have dependency with other c/c++ libraries and combined the libraries using lipo.
Dart can’t see the symbols but rust and swift can, is there something different in how dart look for symbols for static libraries ?
Dart just uses dlsym
on iOS and MacOS, try using dlsym from C or Rust to see if you can see the symbols while trying to dynamically link rather than statically link.
Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away! Thanks for your contribution.
any solution?
as the official doc : Symbols from a statically linked library can be loaded using DynamicLibrary.executable or DynamicLibrary.process.
but i got the error: Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, pause_all_task): symbol not found)
-------------here is my code--------------------------------