iOS Question [SOLVED] Static lib using external framework

JordiCP

Well-Known Member
Licensed User
I have been searching related threads but there aren't many and I couldn't find a clue that was useful for my problem.
My goal is to be able to use some OpenCV functionality from inline ObjC. For this, I am trying to build a static lib that uses the opencv framework, and define a class with some methods that use this framework

For this, first I made a very simple static library with XCode: created it, copy .h and .a files it to my local Mac, and then call its functions with inline Objective-C in my B4i app --> until here, everything works.

Now, the complicated part, where I am stuck. What I have tried is:
  • Add OpenCV to the XCode project using cocoaPods (didn't succeed adding the framework, so I tried this approach and worked ok in XCode).
  • Then I add a couple of functions in the class (interface + implementacion) that use OpenCV, adding the needed headers --> the lib is compiled without errors.
  • Then I add the files to my local Mac Libs folder and do the same as before: try to call a method that uses a simple OpenCV function --> a lot of errors appear:
B4X:
...

Undefined symbols for architecture arm64:
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::at(unsigned long) const", referenced from:
      google::protobuf::io::Tokenizer::IsIdentifier(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in opencv2(tokenizer.o)
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::find(char const*, unsigned long, unsigned long) const", referenced from:
      google::protobuf::GlobalReplaceSubstring(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) in opencv2(strutil.o)
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::find(char, unsigned long) const", referenced from:
      cv::ocl::Device::Impl::Impl(void*) in opencv2(ocl.o)
      _cvOpenFileStorage in opencv2(persistence_c.o)
      google::protobuf::DescriptorBuilder::LookupSymbolNoPlaceholder(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::DescriptorBuilder::ResolveMode, bool) in opencv2(descriptor.o)
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::rfind(char, unsigned long) const", referenced from:
      _cvOpenFileStorage in opencv2(persistence_c.o)
      google::protobuf::DescriptorPool::IsSubSymbolOfBuiltType(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const in opencv2(descriptor.o)
      google::protobuf::DescriptorBuilder::LookupSymbolNoPlaceholder(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::DescriptorBuilder::ResolveMode, bool) in opencv2(descriptor.o)
      google::protobuf::DescriptorPool::NewPlaceholderWithMutexHeld(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::DescriptorPool::PlaceholderType) const in opencv2(descriptor.o)
      google::protobuf::DescriptorBuilder::AddSymbol(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, void const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::Message const&, google::protobuf::Symbol) in opencv2(descriptor.o)
      google::protobuf::DescriptorBuilder::AddPackage(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, google::protobuf::Message const&, google::protobuf::FileDescriptor const*) in opencv2(descriptor.o)
      google::protobuf::FieldDescriptor::InternalTypeOnceInit() const in opencv2(descriptor.o)
      ...
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::compare(unsigned long, unsigned long, char const*, unsigned long) const", referenced from:
      cv::dnn::experimental_dnn_v4::(anonymous namespace)::TFImporter::populateNet(cv::dnn::experimental_dnn_v4::Net) in opencv2(tf_importer.o)
      cv::dnn::experimental_dnn_v4::(anonymous namespace)::addConstNodes(tensorflow::GraphDef&, std::__1::map<cv::String, int, std::__1::less<cv::String>, std::__1::allocator<std::__1::pair<cv::String const, int> > >&, std::__1::set<cv::String, std::__1::less<cv::String>, std::__1::allocator<cv::String> >&) in opencv2(tf_importer.o)
      cv::dnn::NetNeedsUpgrade(opencv_caffe::NetParameter const&) in opencv2(caffe_io.o)
      cv::dnn::NetNeedsBatchNormUpgrade(opencv_caffe::NetParameter const&) in opencv2(caffe_io.o)
      cv::dnn::UpgradeV0PaddingLayers(opencv_caffe::NetParameter const&, opencv_caffe::NetParameter*) in opencv2(caffe_io.o)
      cv::dnn::UpgradeV0LayerParameter(opencv_caffe::V1LayerParameter const&, opencv_caffe::V1LayerParameter*) in opencv2(caffe_io.o)
      cv::dnn::UpgradeV0LayerType(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in opencv2(caffe_io.o)
      ...
  "std::__1::__vector_base_common<true>::__throw_length_error() const", referenced from:
      void std::__1::vector<int, std::__1::allocator<int> >::__push_back_slow_path<int const>(int const&) in opencv2(system.o)
      void std::__1::vector<void*, std::__1::allocator<void*> >::__push_back_slow_path<void* const>(void* const&) in opencv2(system.o)
      void std::__1::vector<cv::ThreadData*, std::__1::allocator<cv::ThreadData*> >::__push_back_slow_path<cv::ThreadData* const>(cv::ThreadData* const&) in opencv2(system.o)
      std::__1::vector<void*, std::__1::allocator<void*> >::__append(unsigned long, void* const&) in opencv2(system.o)
      void std::__1::vector<int, std::__1::allocator<int> >::__push_back_slow_path<int const>(int const&) in opencv2(tf_importer.o)
      std::__1::vector<int, std::__1::allocator<int> >::__append(unsigned long) in opencv2(tf_importer.o)
      std::__1::vector<int, std::__1::allocator<int> >::__append(unsigned long, int const&) in opencv2(tf_importer.o)

.....(a lot more, similar to these)

Has someone gone through the same process? Should I abandon the cocoa Pods way and go back to the framework, or it is not related? Perhaps my approach is totally wrong and there are simpler ways to get it.

Thanks in advance!
 

JanPRO

Well-Known Member
Licensed User
Hi,

My goal is to be able to use some OpenCV functionality from inline ObjC. For this, I am trying to build a static lib that uses the opencv framework, and define a class with some methods that use this framework
First of all, if you create your own custom library in Xcode, why do you want to use inline ObjC code? Instead of this, convert your main header file to a xml (with the attached tool here) and use your library directly in B4i.

Should I abandon the cocoa Pods way and go back to the framework, or it is not related?
Cocoa pods should be fine, however from my experience I recommend you to use frameworks, because they are easier to add and your project is more tidied up. I have sucessfully used the OpenCV framework in custom libraries in the past.

a lot of errors appear:
Your library doesn't contain the required arm64 architecture for iPhones, probably you have compiled your library with the simulator sdk. Change your build device to "Generic iOS Device". If you want to create a library which runs on iPhone & simulator then you need to create a fat library with the lipo tool.

In B4i you have also the possibility to use the OpenCV framework directly with inline Objc code, add a reference to the framework with the #AdditionalLib tag.

Jan
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
...a lot of information here, thanks!

I must be doing something really wrong. Before I was building the lib for a connected iPhone5S. Now I have just built the lib again for a generic iOS device, done the same process and the problem persists.

Then I have removed my lib, and just referenced the opencv2.framework with #AdditionalLib , and the same sort of errors appear

B4X:
(...)
Undefined symbols for architecture arm64:
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::find(char, unsigned long) const", referenced from:
      cv::ocl::Device::Impl::Impl(void*) in opencv2(ocl.o)
      _cvOpenFileStorage in opencv2(persistence_c.o)
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::rfind(char, unsigned long) const", referenced from:
      _cvOpenFileStorage in opencv2(persistence_c.o)
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::compare(unsigned long, unsigned long, char const*, unsigned long) const", referenced from:
      base64::Base64Writer::check_dt(char const*) in opencv2(persistence_base64.o)
  "std::__1::__vector_base_common<true>::__throw_length_error() const", referenced from:
(...)

I'm starting to think that perhaps my opencv2.framework file is not correct, will do some more tests in this direction
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
no way :mad:. An empty project referencing opencv framework (3.4.1) throws all those errors

Just for curiosity, which opencv framework did you use? Was the framework out-of-the-box or you built it yourself?


-- EDIT --

Finally I could solve it with the latest framework and the hint given here :)
 
Last edited:
Upvote 0
Top