Issues Linking ObjC Library using Xamarin - ios

I've been working on binding my first ObjC library (SVGKit) for the past few days. I've got it all building and compiling but I'm unable to get it running when referenced by another project.
My code for the binding can be found here: https://github.com/jamesmundy/SVGKit.Xamarin
When run, the following error is displayed:
Could not create an native instance of the type
'SVGKitBindings.SVGKImageView': the native class hasn't been loaded.
It is possible to ignore this condition by setting
ObjCRuntime.Class.ThrowOnInitFailure to false.
I've checked the static library I'm using and it supports the following platforms:
Architectures in the fat file: libSVGKit-iOS.1.2.0.a are: armv7 i386
x86_64 arm64
I believe this is all I need.
My linker file is as follows:
[assembly: LinkWith ("libSVGKit-iOS.1.2.0.a", LinkTarget.ArmV7 |
LinkTarget.Simulator, SmartLink = true, ForceLoad = true)]
Do I have to configure the project that I'm using this binding in differently? Any help getting the native library to load is much appreciated.
Update 1: Thanks to a suggestion I tried editing the Linker file to support the same platforms as the static library, unfortunately it didn't solve the problem. The file is now as follows:
[assembly: LinkWith ("libSVGKit-iOS.1.2.0.a", LinkTarget.ArmV7 |
LinkTarget.Simulator | LinkTarget.Arm64 | LinkTarget.Simulator64,
SmartLink = true, ForceLoad = true)]
I also tried the code on all the emulators, but still had no luck unfortunately.

[assembly: LinkWith ("libSVGKit-iOS.1.2.0.a", LinkTarget.ArmV7 | LinkTarget.Simulator, SmartLink = true, ForceLoad = true)]
That might not be your (only) issue but it's not correct. Your LinkTarget should be matching the architecture supported by the static library. IOW you are missing Arm64 and Simulator64.
Also try to execute your application on different simulators (32 bits, like iPhone 4S, and 64bits like iPhone 5S) or devices (again 32 vs 64 bits). That will tell you if it's a general or architecture-specific issue (and you should update your question with those extra bits of information).

I was able to solve this problem after having identified a few issues with my code and the project.
The Linker.cs file was not actually building with the project. Although it was in the solution it wasn't being compiled and therefore the important information it contained to link the libraries together was missing.
SVGKit uses several framework. I was not referencing these in the linker file and there were some other linkerflags needed. When I had solved this issue the file looked like this:
[assembly: LinkWith ("libSVGKit-iOS.1.2.0.a", LinkTarget.ArmV7 |
LinkTarget.Simulator | LinkTarget.Arm64 | LinkTarget.Simulator64,
SmartLink = true, Frameworks="QuartzCore CoreText CoreGraphics
CoreImage UIKit", LinkerFlags="-lxml2 -ObjC", ForceLoad = true)]

Related

Xamarin.iOS is not seeing reference to iOS binding library

I have created new Cocoa Touch Static Library in XCode.
I have written code in: StaticLibrary.m:
#import "StaticLibrary.h"
#implementation StaticLibrary
- (int)addX:(int)x toY:(int)y
{
int sum = x + y;
return sum;
}
#end
I have build project in Release-iphoneos and Release-iphonesimulator, then use terminal:
lipo -create Release-iphoneos/StaticLibrary.a Release-iphonesimulator/StaticLibrary.a -output StaticLibraryFat.a
Now I have fat library "StaticLibraryFat.a". Then I create new iOS Binding Library (Xamarin), click PPM -> Add Existing item -> StaticLibraryFat.a. So the file was added and the new libStaticLibraryFinal.linkwith.cs was created. Code inside:
using System;
using ObjCRuntime;
[assembly: LinkWith ("libStaticLibraryFinal.a", LinkTarget.Simulator, ForceLoad = true)]
I go to Mac, open terminal and use Objective Sharpie:
sharpie bind --output=StaticLibrary --namespace=StaticLibrary ~/Desktop/StaticLibrary/StaticLibrary/*.h --sdk=iphoneos12.1 -scope ~/Desktop/StaticLibrary
Now I copy content of ApiDefinitions.cs into iOS Binding Library (Xamarin) - to ApiDefinitions.cs in project.
ApiDefinition.cs
namespace NativeLibrary
{
[BaseType(typeof(NSObject))]
interface StaticLibrary
{
[Export("addX:toY:")]
int AddX(int x, int y);
}
}
I build iOS Binding Library (Xamarin). In folder bin -> Debug there is NativeLibrary.dll.
I create new iOS App (Xamarin). PPM -> Add Reference -> Project -> Solution -> iOS Binding Library (Xamarin).
In ViewController.cs I write:
using NativeLibrary
and
NativeLibrary.AddX(1, 2);
but there is an error
"Using directive is unnecessary. The type or namespace name "Native
Library" could not be found (are you missing a using directive or an
assembly reference?)
What am I doing wrong?
When I add reference to iOS Class library then the reference is working perfectly. Why reference to iOS Binding Library is not working?
Ok, I have solved it. There was a problem with different namespaces, so Visual Studio can not connect everything. Namespace at ApiDefinition.cs and Structs.cs must be the same as name of iOSBindingLibrary. The generated .dll file has name "NativeLibrary.dll" and I change it to namespace.dll, then at iOS application I add reference to this dll. then using directive (using "namespace"). In class I write name of XCode's library and create new object. Everything is working perfectly.
This is Crazy, but in my case,
just create the ios binding project in a different solution and add the binding project DLL directly in the ios project. it will work fine.

Why dulplicate symbol errors do not occur when linking both libsqlite3.dylib and libsqlcipher.a?

I'm integrating sqlcipher into an iOS project according to this tutorial: https://www.zetetic.net/sqlcipher/ios-tutorial/
There is a hot tip which says:If libsqlite3.dylib or another SQLite framework is listed in your Link Binary With Libraries list be sure to remove it, or you'll see duplicate symbol errors.
But I tried to add both libsqlite3.tbd(no dylib in xcode 7) and libsqlcipher.a to Link Binary With Libraries, the dulplicate symbol error do not occur! Why?
And I notice if I click the #import <sqlite3.h> line, xcode show the sqlite3.h file in xcode's lib folder, not the one in sqlcipher.
However, sqlcipher does work, the database is really encrypted.
libsqlite3.tbd is just a text file that defines platform architectures supported by the library, target platforms, dylib installation path and exported symbols. Using a .tbd file, you decrease the your bundled application size as the library binary is already included on the platform device so it does not need to be linked into your application image.
libsqlite3.tbd looks like this:
---
archs: [ armv7, armv7s, arm64 ]
platform: ios
install-name: /usr/lib/libsqlite3.dylib
current-version: 216.4
compatibility-version: 9.0
exports:
- archs: [ armv7, armv7s, arm64 ]
symbols: [ __sqlite3_lockstate, __sqlite3_purgeEligiblePagerCacheMemory,
__sqlite3_system_busy_handler, __sqlite_auto_profile,
__sqlite_auto_profile_syslog, __sqlite_auto_trace,
__sqlite_auto_trace_syslog, _sqlite3OsShmHasMultipleLinks,
_sqlite3OsShmRenamedWhileOpen, _sqlite3OsShmWasTruncated,
_sqlite3OsShmWasUnlinkedWhileOpen, _sqlite3VersionNumber,
_sqlite3VersionString, _sqlite3_aggregate_context,
_sqlite3_aggregate_count, _sqlite3_auto_extension,
_sqlite3_backup_finish, _sqlite3_backup_init, _sqlite3_backup_pagecount,
_sqlite3_backup_remaining, _sqlite3_backup_step,
_sqlite3_bind_blob, _sqlite3_bind_blob64, _sqlite3_bind_double,
_sqlite3_bind_int, _sqlite3_bind_int64, _sqlite3_bind_null,
_sqlite3_bind_parameter_count, _sqlite3_bind_parameter_index,
_sqlite3_bind_parameter_name, _sqlite3_bind_text,
_sqlite3_bind_text16, _sqlite3_bind_text64, _sqlite3_bind_value,
_sqlite3_bind_zeroblob, _sqlite3_blob_bytes, _sqlite3_blob_close,
_sqlite3_blob_open, _sqlite3_blob_read, _sqlite3_blob_reopen,
_sqlite3_blob_write, _sqlite3_busy_handler, _sqlite3_busy_timeout,
_sqlite3_cancel_auto_extension, _sqlite3_changes,
_sqlite3_clear_bindings, _sqlite3_close, _sqlite3_close_v2,
_sqlite3_collation_needed, _sqlite3_collation_needed16,
_sqlite3_column_blob, _sqlite3_column_bytes, _sqlite3_column_bytes16,
_sqlite3_column_count, _sqlite3_column_decltype,
_sqlite3_column_decltype16, _sqlite3_column_double,
_sqlite3_column_int, _sqlite3_column_int64, _sqlite3_column_name,
_sqlite3_column_name16, _sqlite3_column_text, _sqlite3_column_text16,
_sqlite3_column_type, _sqlite3_column_value, _sqlite3_commit_hook,
_sqlite3_compileoption_get, _sqlite3_compileoption_used,
_sqlite3_complete, _sqlite3_complete16, _sqlite3_config,
_sqlite3_context_db_handle, _sqlite3_create_collation,
_sqlite3_create_collation16, _sqlite3_create_collation_v2,
_sqlite3_create_function, _sqlite3_create_function16,
_sqlite3_create_function_v2, _sqlite3_create_module,
_sqlite3_create_module_v2, _sqlite3_data_count,
_sqlite3_data_directory, _sqlite3_db_config, _sqlite3_db_filename,
_sqlite3_db_handle, _sqlite3_db_mutex, _sqlite3_db_readonly,
_sqlite3_db_release_memory, _sqlite3_db_status,
_sqlite3_declare_vtab, _sqlite3_enable_shared_cache,
_sqlite3_errcode, _sqlite3_errmsg, _sqlite3_errmsg16,
_sqlite3_errstr, _sqlite3_exec, _sqlite3_expired,
_sqlite3_extended_errcode, _sqlite3_extended_result_codes,
_sqlite3_file_control, _sqlite3_finalize, _sqlite3_free,
_sqlite3_free_table, _sqlite3_get_autocommit, _sqlite3_get_auxdata,
_sqlite3_get_table, _sqlite3_global_recover, _sqlite3_initialize,
_sqlite3_intarray_bind, _sqlite3_intarray_create,
_sqlite3_interrupt, _sqlite3_last_insert_rowid,
_sqlite3_libversion, _sqlite3_libversion_number,
_sqlite3_limit, _sqlite3_log, _sqlite3_malloc, _sqlite3_malloc64,
_sqlite3_memory_alarm, _sqlite3_memory_highwater,
_sqlite3_memory_used, _sqlite3_mprintf, _sqlite3_msize,
_sqlite3_mutex_alloc, _sqlite3_mutex_enter, _sqlite3_mutex_free,
_sqlite3_mutex_leave, _sqlite3_mutex_try, _sqlite3_next_stmt,
_sqlite3_open, _sqlite3_open16, _sqlite3_open_v2,
_sqlite3_os_end, _sqlite3_os_init, _sqlite3_overload_function,
_sqlite3_prepare, _sqlite3_prepare16, _sqlite3_prepare16_v2,
_sqlite3_prepare_v2, _sqlite3_profile, _sqlite3_progress_handler,
_sqlite3_randomness, _sqlite3_realloc, _sqlite3_realloc64,
_sqlite3_release_memory, _sqlite3_reset, _sqlite3_reset_auto_extension,
_sqlite3_result_blob, _sqlite3_result_blob64, _sqlite3_result_double,
_sqlite3_result_error, _sqlite3_result_error16,
_sqlite3_result_error_code, _sqlite3_result_error_nomem,
_sqlite3_result_error_toobig, _sqlite3_result_int,
_sqlite3_result_int64, _sqlite3_result_null, _sqlite3_result_text,
_sqlite3_result_text16, _sqlite3_result_text16be,
_sqlite3_result_text16le, _sqlite3_result_text64,
_sqlite3_result_value, _sqlite3_result_zeroblob,
_sqlite3_rollback_hook, _sqlite3_rtree_geometry_callback,
_sqlite3_rtree_query_callback, _sqlite3_set_authorizer,
_sqlite3_set_auxdata, _sqlite3_shutdown, _sqlite3_sleep,
_sqlite3_snprintf, _sqlite3_soft_heap_limit, _sqlite3_soft_heap_limit64,
_sqlite3_sourceid, _sqlite3_sql, _sqlite3_status,
_sqlite3_status64, _sqlite3_step, _sqlite3_stmt_busy,
_sqlite3_stmt_readonly, _sqlite3_stmt_status, _sqlite3_strglob,
_sqlite3_stricmp, _sqlite3_strnicmp, _sqlite3_table_column_metadata,
_sqlite3_temp_directory, _sqlite3_test_control,
_sqlite3_thread_cleanup, _sqlite3_threadsafe, _sqlite3_total_changes,
_sqlite3_trace, _sqlite3_transfer_bindings, _sqlite3_update_hook,
_sqlite3_uri_boolean, _sqlite3_uri_int64, _sqlite3_uri_parameter,
_sqlite3_user_data, _sqlite3_value_blob, _sqlite3_value_bytes,
_sqlite3_value_bytes16, _sqlite3_value_double, _sqlite3_value_int,
_sqlite3_value_int64, _sqlite3_value_numeric_type,
_sqlite3_value_text, _sqlite3_value_text16, _sqlite3_value_text16be,
_sqlite3_value_text16le, _sqlite3_value_type, _sqlite3_version,
_sqlite3_vfs_find, _sqlite3_vfs_register, _sqlite3_vfs_unregister,
_sqlite3_vmprintf, _sqlite3_vsnprintf, _sqlite3_vtab_config,
_sqlite3_vtab_on_conflict, _sqlite3_wal_autocheckpoint,
_sqlite3_wal_checkpoint, _sqlite3_wal_checkpoint_v2,
_sqlite3_wal_hook ]
...
You do not receive a duplicate symbol linker error because you are only including a single binary library, libsqlcipher.a. You need to remove the libsqlite3.tbd reference and include libsqlcipher.a if you wish to use SQLCipher within your iOS application.
I encounted the same problem, if you do not remove the libsqlite3.0.tbd, the encryption will depend on the ios system, on iOS 13 and later, it will be encrypted using system algorithm, on iOS 12 and earier , the db wont be encrypted.
You did not receive duplicate symbols error, cause the system sqlite is a dynamic library.

How to support different architectures on a podspec?

In my company we are using some 3rd party static library that comes with a "wrapper" class and I want to create a pod for it. We have two versions of the static library, for simulator and device. The folder with the files that I want to include in the pod looks like this:
Engine
|
|- libEngine.a
|
|- libEngine-Simulator.a
|
|- Engine.h
|
|- EngineWrapper.h
|
|- EngineWrapper.mm
|
|- SomeOtherFile.bin
Now, since:
The library only supports armv7
EngineWrapper.mm is not using ARC
there is a requirement to set CLANG_CXX_LIBRARY to libstdc++ and
SomeOtherFile.bin needs to be "seen" by Engine.h,
the related part of my podspec looks like that:
s.requires_arc = false
s.source_files = 'Classes/ios/Engine'
s.preserve_path = 'Classes/ios/Engine/SomeOtherFile.bin', 'Classes/ios/Engine/libEngine-Simulator.a', 'Classes/ios/Engine/libEngine.a'
s.vendored_libraries = 'Classes/ios/Engine/libEngine-Simulator.a', 'Classes/ios/Engine/libEngine.a'
s.xcconfig = { 'CLANG_CXX_LIBRARY' => 'libstdc++', 'VALID_ARCHS' => 'armv7' }
This is just one of the hundreds of combinations/different settings I tried. I can provide more examples if you want. However, no matter what I try, I get the following error when trying to build:
Undefined symbols for architecture armv7
I tried to go through all the settings in Pods.xcodeproj but I can't see something suspicious there (but at the same time I am not familiar with the way Cocoapods works in detail).
Among others, I tried to:
keep a flat folder hierarchy (instead of the Classes/ios/Engine path)
use libraries instead of vendored_libraries
remove one of the static libraries
create a fat binary instead of having the two ones
zip all the files together (in the same way TestFlight does it in their podspec)
remove the VALID_ARCHS setting
and I also saw several different podspec examples using static libraries, but without any luck..
I am using Cocoapods ver 0.32.1.
If you have any idea of what could be wrong, please let me know before I lose my sanity. Thanks!

CMake FIND_LIBRARY vars are set to -NOTFOUND when finding Mac OS X Frameworks

I'm trying to add Mac OS X framework usage to my program, which includes some files with Objective-c++ code.
It DOES work with SET (CMAKE_EXE_LINKER_FLAGS "-framework CoreMedia -framework ... "), but i don't really like this way and it seems just wrong.
That's the CMake part of actual adding, but it doesn't work and i dont really know what i'm missing :( I tried using the
link_directories("${CMAKE_OSX_SYSROOT}/System/Library/Frameworks")
include_directories("${CMAKE_OSX_SYSROOT}/System/Library/Frameworks")
but it didn't help at all. So here's the code:
add_executable(myprogram src/myprogram.cpp)
FIND_LIBRARY(COREMEDIA_LIB NAMES CoreMedia)
FIND_LIBRARY(COREVIDEO_LIB NAMES CoreVideo)
FIND_LIBRARY(FOUNDATION_LIB NAMES Foundation)
FIND_LIBRARY(AVFOUNDATION_LIB NAMES AVFoundation)
target_link_libraries(myprogram ${COREMEDIA_LIB})
target_link_libraries(myprogram ${COREVIDEO_LIB})
target_link_libraries(myprogram ${FOUNDATION_LIB})
target_link_libraries(myprogram ${AVFOUNDATION_LIB})
It produces the cmake errors:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
AVFOUNDATION_LIB
linked by target "myprogram" in directory <some directory containing app>
<... other 3 are here aswell ...>
Ok, got it. I need to specify PATHS variable to ${CMAKE_OSX_SYSROOT}/System/Library. I don't know why but it can't find it in this folder automatically, thought it's a standard folder though...
so call like this:
for example, when i link AVFoundation framework:
add_executable(myprogram)
find_library(SOME_VAR
NAMES AVFoundation
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
PATH_SUFFIXES Frameworks
NO_DEFAULT_PATH)
and then
target_link_libraries(myprogram "${SOME_VAR}/AVFoundation")
Hope it will help someone.
This is working for me:
IF (APPLE)
find_library(COREMIDI_LIBRARY CoreMIDI)
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
target_link_libraries(myprogram ${COREFOUNDATION_LIBRARY} ${COREMIDI_LIBRARY})
ENDIF (APPLE)

Help in using OpenCV - Errors of type: identifier not found

Am a beginner to OpenCV and have gone so far as to work out the hello world samples, inverting, color conversion(RGB->greyscale ) etc programs working.
However i am stuck at the Programs that use cvCanny, cvPyr and other such feature detectors.Would really be thankful if the tiny prblem was sorted out .
I get the Error: error C3861: 'cvPyrDown': identifier not found
error C3861: 'cvCanny': identifier not found
I've included the imgproc and features2d headers yet the problem persists.
What am I missing out ?
Do you have your "Additional input directories" property set correctly?
Mine, configured by cmake, looks like this:
C:/OpenCV-2.2.0/release
C:/OpenCV-2.2.0/include
C:/OpenCV-2.2.0/include/opencv
C:/OpenCV-2.2.0/modules/core/include
C:/OpenCV-2.2.0/modules/imgproc/include
C:/OpenCV-2.2.0/modules/features2d/include
C:/OpenCV-2.2.0/modules/gpu/include
C:/OpenCV-2.2.0/modules/calib3d/include
C:/OpenCV-2.2.0/modules/objdetect/include
C:/OpenCV-2.2.0/modules/video/include
C:/OpenCV-2.2.0/modules/highgui/include
C:/OpenCV-2.2.0/modules/ml/include
C:/OpenCV-2.2.0/modules/legacy/include
C:/OpenCV-2.2.0/modules/contrib/include
C:/OpenCV-2.2.0/modules/flann/include
Btw. CMake is a nice tool if you are dealing with libraries that contains many include files, line OpenCV.
You can also check two other things:
After compiling OpenCV2.2 from sources, did you built "INSTALL" project in the OpenCV VS solution?
If you are using c++ headers, you might prefer c++ version of those functions,
in the cv namespace:
cv::Canny(...)
That sounds like a link error rather than any problems with include. Are you sure you are linking with cv.lib?
You need to add the $(OPENCV_ROOT)/lib directory to the linker path so it knows where to search for the files.
From the description, I assume you're using Visual Studio? If so, you have two options for doing so.
Add it to this project under Project -> Properties -> Linker -> General -> Additional Library Directories.
Add it for all projects: Tools -> Options -> Projects and Solutions -> VC++ Directories -> Library files. And then add folders there.

Resources