HOW TO sqlite3_load_extension from within Objective-c [error: dlopen(...) image not found] - objective-c

I am trying to load an extension to sqlite3 for use within iPhone application objective-c code. I successfully compiled the c file of new functions into a dylib named libsqlitefunctions.dylib. Here is where I am a bit lost. I call sqlite3_load_extension as follows:
char *error = sqlite3_malloc(MAX_SQLITE_ERROR_MESSAGE_SIZE);
const char *library = [#"libsqlitefunctions.dylib" UTF8String];
if (sqlite3_load_extension(database, library, 0, &error) != SQLITE_OK) {
message = [NSString stringWithFormat:#"%s", error];
}
sqlite3_free(error);
No matter what I do, I get the error: dlopen(libsqlitefunctions.dylib, 10): image not found
I tried:
indicating the fully qualified path to the dylib
indicating a relative path
not indicating a path (as shown above)
adding the dylib as a framework
adding the .c file to my project and compiling it into a .o file and then trying to load it
Please note that this is not an entry point problem, since I pass 0 as that arg. This will force the dylib to load by calling an init function defined in the dylib. I do not even get to that point.
I am pretty much a newbie compared to the rest of you guys and feel that I am probably lacking an understanding of how libraries are loaded.
I would really appreciate any ideas since the ability to make use of the functions in this library is important to the functionality of my app. Thank you all in advance.

OK, I took your advice and simply added my new functionality to the sqlite3.c file I had in my project. It compiled and linked statically and works fine. Thank you for the idea. I still would like to know what was preventing me from loading an extension, but am pleased with having learned other things in solving the problem - PLUS I met my deadline. Thank you again.

After days of search I finally found a solution !
1) once your sqlite_extension.h and sqlite_extension.c files moved into your sqlite_extension folder
2) cd to that sqlite_extension folder
3) compile your code using :
gcc -g -fPIC -std=gnu99 -current_version 1.0 -compatibility_version 1.0 -dynamiclib -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk sqlite_extension.c -o sqlite_extension.dylib
You might need to change the SDK path for something like ../iPhoneOSN.M.sdk where N.M indicate the last available version of iOS, have a look to the folder "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/" to find an existing path
4) You can check the resulting file using :
file /path/to/your/sqlite_extension.dylib
which should return something like :
/./././sqlite_extension.dylib (for architecture armv7): Mach-O dynamically linked shared library arm
/./././sqlite_extension.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library
or using the more detailed :
otool -l sqlite_extension.dylib
5) Now your library needs to be code-signed with the same identity as your embedding app you can do this using :
codesign -fs "your_apple_identity" sqlite_extension.dylib
your_apple_identity can be in the form "your_name: your_apple_login_email#address.xxx"
The best way to make sure is to copy the one from your embedded app executable compiled and running on your device with Xcode or the archive on your computer using :
codesign --display --verbose=4 ~/Library/Developer/Xcode/Archives/2016-09-25/YourApp\ 25-09-2016\ 12.00.xcarchive/Products/Applications/YourApp.app/YourApp
The string to use in place of "your_apple_identity" is the one found after the first occurence of Authority=
6) Once your library code-signed, you can check that you get similar signing information as your App using the same command :
codesign --display --verbose=4 sqlite_extension.dylib
7) Your Library is now ready to be embedded in your app, all you need is to make sure Xcode refreshes your library file if you had try a previous file with the same name. To do so you can remove the former file, compile and run on your device, put back the new file making sure it is in the "Copy Bundle ressources" not the "Link Binary With Librairies" of the Build Phases tab of your app
Your extension should then load without error when your app requests SQLite to use it
iOS 9.3.5
Xcode 8.0
SQLite 3.9.2

I'm not 100% sure this is explicitly disallowed, but another type of dynamic loading -- frameworks -- isn't supported on the iPhone. You may need to compile and link the library statically, rather than dynamically.

i know topic is old . but googling brought me here. and for anyone that has this problem and end up here :
you must first call
sqlite3_enable_load_extension(db, 1);

I know that I am answering late but I faced the same problem and found how to load an extension.
Once you have the source file X.c, compile a shared library(In Linux machine) using
gcc -g -fPIC -shared X.c -o X.so
Where X.c is the extension in use
Then enable loading extension in C interface to SQLite using
sqlite3_enable_load_extension(db,1);
Then load the extension using
sqlite3_load_extension(db,"/path/of/extension/X.so","sqlite3_X_init",0);
Thats it, extension will be loaded now.

Related

Invalid Swift Support / The SwiftSupport folder is empty

Environment: Xcode 7 GM
I uploaded iOS app successfully using Xcode without error. This app is written in Objective-C and Swift.
However, immediately after successful upload, I got this email from Apple stating this error:
Invalid Swift Support - We have discovered one or more issues with your recent delivery for XXXXX(my app name). To process your delivery, the following issues must be corrected:
Invalid Swift Support - The SwiftSupport folder is empty. Rebuild your app using the current public (GM) version of Xcode and resubmit it.
Once these issues have been corrected, you can then redeliver the corrected binary.
Anybody has a solution against this issue?
I have already confirmed below issues.
"SwiftSupport/iphoneos/" libraries in archives(.xcarchive file) is equaly to "Products/Applications/myApp.ipa/Frameworks/"
My "Valid Architectures" setting is "$(ARCHS_STANDARD)" displaying "armv7k".
Provisioning profile is set to Dev and Release which has been created in iTunes connect, respectively.
And, in my "Edit scheme", Test target is unchecked at Archive.
important note: this only works for projects that do not use swift, see comment below
I just met the same issue and resolved it by making the following change -
If you used to have Swift files in your project but then removed them, you only need to set "Embedded Content Contains Swift Code" to NO in Build Options.
when try to export after "Xcode->Product->Archive"
you should choose "save for ios app store deployment" option
The same problem confused me a couple of days,
the above setting can solve this problem.
no matter "embedded content contains swift code" is yes or no.
There are many conflicting answers on this page.. what worked for me was the one mentioned here, which is simply select a save for iOS app store deployment option (I'm actually not interested in an app store release.. I want to simply push a release for testflight internal testing)..
that being said, I have a way to verify that your ipa will be approved or not before submitting it:
drag the .ipa file into a new folder (call it analysis)
right click the ipa file and rename it to .zip (confirm the dialog to use .zip)
double click the zip file
here if you get a folder (with the same name as the .ipa file) that has the following subfolders in it:
payload
swiftSupport
Symbols
then you are good to go, however if you only see the Payload folder within.. then you gotta try again
also a couple of pointers
I've tried setting "Embedded Content Contains Swift Code" to NO, it worked just once then stopped working after that
I've ensured that I had no cocoapod errors.. that didn't help either
I've tried manually adding the SwiftSupport folder inside the archive as suggested here.. but then i got all sorts of side effects.. didn't work
conclusion
I think this is due to some bug with xcode (writing this with Xcode 8.0 build (8A218a).. so keep on trying your luck until it works.. just don't expect some solid explanation for it
Five Step Solution:
Go to build settings and make flag Embedded Content Contains Swift Code -> YES, if your code contains partial swift code or entirely made in Swift
Archive your build using Xcode->Product->Archive
Export the Archive Build you will suddenly see the difference build size will be 40+ MBs this is because XCode has added SwiftSupport folder which was missing
Now upload this build using Application loader
If this does not work check that if you have multiple XCode on your system goto
Xcode->Preferences->Location->Command Lines Tools has the same latest or the same Xcode from drop down selected on which you have done the coding & vola it's done.
This is slightly a drawback as swift carries the baggage and has to be compatible with earlier version and Objective C code.
My many hours were wasted hope you will find this helpful ;)
This error can happen if you use xcodebuild to export the IPA without specifying the -exportOptionsPlist option
See xcodebuild -help for the available keys, but you probably want a plist with at least the method key set to "app-store", like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
</dict>
</plist>
I spent almost an entire day on this issue, none of the above solutions worked. I got rid of this error by lowering my target tvOS back to 11 from 13; where it was originally. That restored the SwiftSupport folder. The question that remains to be answered is whether this is due to our Provision not allowing us to target tvOS 13 - or somehow the Apple Store folks not being aligned with the xCode folks because the app created by targeting tvOS 13 is 14mb and tvOS 11 is 44mb and different app folder structure.
I received this same email after uploading an .ipa file to App Store Connect through the Transporter app. The following is where I went wrong: I distributed the app using ad hoc.
The following steps are the solution for my error:
Archive app
Distribute on TestFlight and the App Store
Export
Open ExportOptions.plist in the newly created folder from the export.
Make sure the method property has the value app-store if you are uploading to App Store Connect/TestFlight like me.
Drag and drop the exported .ipa file to Transporter.
Deliver your app to upload it.
And that's it!
I grappled with this for several hours and here is what worked for me.
In the Archive, Xcode did not copy swift libs into SwiftSupport/iphoneos even though my project had "Embedded Content Contains Swift Code" set to yes for all targets. Nor did it copy swift libs into "AppName.app/Frameworks". So I had to do that manually in the Archive before submitting:
copy "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/lib*" to "Archive_folder/Products/Applications/AppName.app/Frameworks" and "SwiftSupport/iphoneos"
If your app also has a watch app
copy
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/watchos" into "Archive_folder/SwiftSupport/watchos" and "Archive_folder/Products/Applications/AppName.app/Watch/AppName WatchKit App.app/Frameworks"
Then submit the app.
App Store build submission Issue:
Invalid Swift Support - The SwiftSupport folder is missing. Rebuild your app using the current public (GM) version of Xcode and resubmit it.
Solution:
In most cases we found this issue due to submitting application via App Loader and our usual practice to make ipa as Organizer > App Archive > Show In Finder > Show Package Content > Products > Applications> OurProjectName.app in copying this app to Payload folder and zip it and making ipa file to submit on App Store using App Loader. That is work fine for submitting only objective c files contained projects.
But there is some changes if your project contains any swift classes and usage of it. If your project contains swift classes with Objective C project, IPA content structure changed slightly different as attached screenshot.
To fix this issue, submit app directly from Xcode [ OR ] if you want to submit application via App Loader than first Export ipa using Export option from Xcode organizer and submit those ipa file to app store via App Loader.
See the reference screenshot as below:
Hurrey!!! Your issue will be fixed :) :) :)
My problem was that I was using an adhoc profile to submit to TestFlight (has to be a distribution provisioning profile). Great error messages Apple!
This happened to me after I changed project settings.
Go to "File" > "Project Settings..." (or in some cases "Workspace Settings...") and then select "Use Shared Setting" from the "Build System" dropdown.
Tried this solution with Xcode 11.6, in Aug 2020, and it works.
Select the archive > Show in Finder
Show Package Contents
Delete the folder SwiftSupport
Go back to the archive > Distribute App
Setting "Embedded Content Contains Swift Code" to $(inherited) worked for me.
The warning after executing the CocoaPods command pod install helped me to find this out.
[!] The `applewatch Extension [Debug]` target overrides the `EMBEDDED_CONTENT_CONTAINS_SWIFT` build setting defined in `Pods/Target Support Files/Pods-applewatch Extension/Pods-applewatch Extension.debug.xcconfig'. This can lead to problems with the CocoaPods installation
- Use the `$(inherited)` flag, or <--------------
- Remove the build settings from the target.
Using Save for iOS App Store Deployment instead of Save for Ad Hoc Deployment Xcode export option solved this issue for me. Counterintuitively, you should use the first option even for TestFlight builds.
You also get this error when you upload an ipa that has a plist with export_method set to ad-hoc instead of app-store to itunes ...
Here's what I am doing now to solve this issue since my method above stopped working. Keep in mind that my code's main app is Obj-C and my watch app is Swift.
Make sure the "embedded Content Contains Swift Code" is set to:
YES for app target
NO for WatchKit Extension
YES for Watchkit App
After Archiving my XCode will not create the "[archive folder]/SwiftSupport/iphoneos", but will create and fill the "[archive folder]/Products/Applications/[app name].app/Watch/\ WatchKit\ App.app/Frameworks" with the Swift dylibs. So I created the following soft link:
ln -s "[archive folder]/Products/Applications/.app/Watch/\ WatchKit\ App.app/Frameworks" "[archive folder]/SwiftSupport/iphoneos"
Then when I submit via XCode Organize it is accepted without error.
If you simply copy the files rather than linking them then you risk the watch app exceeding the 50MB limit.
Setting Always Embed Swift Standard Libraries to Yes is only necessary for Objective-C targets which link against your own frameworks which depend upon Swift. In cases where you are not linking against (i.e., using) an internal framework which depends upon Swift, Xcode will embed the Swift standard libraries in your archive as long as there is at least one occurrence of importing a Swift standard library in a Swift file which is part of the build target.
In other words, if your target has a Swift file which doesn't import any Swift standard libraries––via "import Foundation", for example––then Xcode will not copy the Swift Standard libraries into the archive.
The fix for this issue is to ensure that at least one of the Swift files in your target is importing a swift standard library (e.g., "import Foundation").
Daniel Jalkut has a very informative post about Swift dependencies which sheds light into this issue.
I grappled with this issue for a while and nothing above worked. In a last desperate attempt I just deleted the SwiftSupport folder from my archive.
To my surprise it uploaded and completed processing successfully. Hope this help someone.
I managed to fix this error by unchecking the option "Strip Swift symbols".
App Store Connect distribution options
To delete the SwiftSupport folder from the .ipa I used the following script
ipa_path="${DIR_ON_CI}/ipa_name.ipa"
zip -d "${ipa_path}" "SwiftSupport*"
You'll need to set proper ipa_path. Nothing else seems to work in my case and the app was built on a CI where I have access to the .ipa after the archive is exported.

Using SBYZipArchive or other Zip Cocoa Pod in Swift not working

I have an OSX app that needs to be able to zip and unzip directories, and I figured it would be easy using a cocoapod. I've hit a brick wall.
I've installed Godzippa, Objective-Zip, zipzap, ZipKit, ZipArchive, SSZipArchive, and basically every other cocoapod that claims to provide "Zip" functionality, but I've failed to get any of them to work.
I'll share the steps to my failure, and perhaps someone will correct me where I've strayed the correct path:
1. Because I am working out of a Swift codebase, I created an Objective-C-Bridging Header, and set the corresponding attribute under Build Settings in the Swift Compiler Section.
2. I installed cocoapods in the application and included the desired cocoa pod in the Pod file, ran pod install, and restarted the application using the workspace.
3. Inside the bridging header, I imported the necessary objective-c headers of the corresponding cocoa-pod so I can use them in Swift. For example, for SBYZipArchive I had the following in my file I imported the < SBYZipArchive/SBYZipArchive.h> header.
4. I try to build the application and it fails on multiple places all referencing the zlib.h library.
5. I attempted to provide access to the zlib library by adding the libz.dylib to the Build Phases under Link Binary with Libraries.
6. I attempt to build the application, and it still doesn't love me.
To my knowledge the reason why none of these frameworks is working is because they are for some reason failing to access the zlib files that are necessary to do the actual data compression. Thats as far as I've figured out... Any help would be appreciated.
Update
I was able to do the zipping without using any of the above packages by simply setting up an NSTask. For those who may care more about zipping than they do using these tools here is how I did it:
var task = NSTask()
task.launchPath = "/usr/bin/zip"
task.arguments = ["-r", "/Users/$USERNAME/Documents/$PATHTODIR/zip1.zip", "/Users/$USERNAME/Documents/$PATHTODIR/filesToZip"]
task.launch()
When using NSTask you set the launch path to the tool you want to use, and then give the required arguments. so the above task is the equivalent to the command in UNIX:
zip -r /Users/$USERNAME/Documents/$PATHTODIR/zip1.zip /Users/$USERNAME/Documents/$PATHTODIR/filesToZip
Obviously swap out the variables I put in there for your own path
UPDATE
Although the UNIX zipper works perfect for the mac app, I am pretty sure I need one of the zip packages to be able to do this on iOS

How to link a dynamic library Xcode 5

Can you point me to a tutorial which shows how to link to a dynamic library.
I created a dynamic library. Now I've got no clue how to include it into your project.
What I tried is
1.I copied the dylib and header folder into my project.
2. I gave library search path as $(PROJECT_DIR)
3. I gave header search path as $(PROJECT_DIR)/include.
Now it builds and links just fine. But when I run it, it gives me this error
.yld: Library not loaded: /usr/local/lib/test_dynamic_lib.dylib
Now i read in documentation that you have to install the library in that path. How to do that?
or you can manipulate runpaths. I didnt get a clue what it says. I'm actually a beginner in cocoa development.
Can you explain how to do that? Or point to a tutorial. I couldn't find any.
I found the answer.
I wrote a build script on my target.
export DYLIB=myLibrary.dylib
mkdir "$TARGET_BUILD_DIR/$TARGET_NAME.bundle/Contents/Frameworks"
cp -f "$SRCROOT/$DYLIB "$TARGET_BUILD_DIR/$TARGET_NAME.bundle/Contents/Frameworks"
install_name_tool -change #executable_path/$DYLIB #loader_path/../Frameworks/$DYLIB"$TARGET_BUILD_DIR/$TARGET_NAME.bundle/Contents/MacOS/$PRODUCT_NAM
And yes thnx The Paramagnetic Croissant for poiting me in the right direction.

How to experiment with private APIs on iOS?

I have been exploring private APIs within iOS for the express purpose of experimentation. Does anyone have a sample of instantiating a class like MKTransitAnnotationView?
I've downloaded Erica Sadun's HeaderDumpKit and the class-dump binary. After making a few corrections to her perl script I dumped out a Headers directory and moved that into the project folder.
In the Other Linker Flags section of Build Settings I added:
-force_flat_namespace
-undefined suppress
When trying to call MKTransitAnnotationView I get dyld: Symbol not found: _OBJC_CLASS_$_MKTransitAnnotationView. So what have I missed?
Add your dumped header as a normal header file, then from your project navigator:
click on your project
click on your target
click on the Build Phases tab, then expand the Link Binary With Libraries section
drag/drop the binary from PrivateFramework folder that you want to use.
Then you should be all set.
Normally you shouldn't have to change your flags.

GUI-less App Bundle

I would like to create a helper application that has no GUI yet does have access to an app bundle. I was looking at the Xcode command line project templates, but these all just generate executable files. How can I create something like a command line tool that presents no application menu yet provides access to bundle resources in a .app? Am I thinking about this the wrong way?
Thanks.
Peter's answer (use LSUIElement) is probably what you're looking for. Occasionally, I've wanted to create an actual command-line app that also has an app bundle. In case other's come across the same scenario, here's what I've found...
The app bundle is not an executable. The true executable is buried inside: MyApp.app/Contents/MacOS/MyApp is the actual Mach-O executable for an app named MyApp. The standard Xcode templates link applications against AppKit.framework and have a main.m that defines the main() function for the executable that starts an NSApplication instance. You can put any executable in an app bundle, however, including a console-only app. Just replace the main() function in main.m in the application template with your console apps main() function and remove AppKit.framework from the app's linked frameworks.
If you want, you can replace main.m with a main.c that declares a main function if you want to avoid Objective-C entirely (though there's nothing necessarily Objective-C specific in main.m if you replace the contents of the main() function).
To run your application from the console, you have to specify the actual executable, not the app bundle, so you'd have to type MyApp.app/Contents/MacOS/MyApp at the command line. When I've used app bundles for console apps (to provide linked frameworks, resources, etc.), I often create a symlink to the executable and put the symlink in /usr/local/bin (or somewhere else on the path) during installation or first run.
I would like to create a helper application that has no GUI yet does have … an app bundle.
That's called an agent, and you make one by making a regular application and setting its LSUIElement key to the string “1”.