I am attempting to use Gstreamer library on multiple platforms with my Qt project (for audio only). I already have it working on macOS with the binary files available online by just adding the framework to my .pro file:
LIBS += -F$$PWD/macOS/libs/ -framework GStreamer
INCLUDEPATH += $$PWD/macOS/libs/GStreamer.framework/Versions/1.0/Headers
DEPENDPATH += $$PWD/macOS/libs/GStreamer.framework/Versions/1.0/include
But now I want to use the binaries available at the same page for android. But because it is not "bundled" in a framework like on OS X I can't add it as easily. Furthermore the official explanations are made for a gradle build (which I don't know anything and don't use in Qt creator) and for use in Java. But, because I want to directly use the C API in Qt C++ I don't need JNI, and would like to directly use the library in my app like on OSX.
Thus, I tried to add the library like I would do it on any other linux, but recursively, since there is a multitude of library and header folders:
contains(ANDROID_TARGET_ARCH,arm64-v8a) {
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
GSTREAMER_INCLUDE_FILES = $$files($$PWD/android/libs/gstreamer/arm64/include/*, true)
for(FILE, GSTREAMER_INCLUDE_FILES) {
BASEDIR = $$dirname(FILE)
if(!contains(INCLUDEPATH, $$BASEDIR)){
INCLUDEPATH += $$BASEDIR
}
}
GSTREAMER_DEPEND_FILES = $$files($$PWD/android/libs/gstreamer/arm64/include/*, true)
for(FILE, GSTREAMER_INCLUDE_FILES) {
BASEDIR_DEP = $$dirname(FILE)
if(!contains(DEPENDPATH, $$BASEDIR_DEP)){
DEPENDPATH += $$BASEDIR_DEP
}
}
GSTREAMER_LIB_FILES = $$files($$PWD/android/libs/gstreamer/arm64/lib/*.a, true)
for(FILE, GSTREAMER_LIB_FILES) {
BASENAME = $$basename(FILE)
LIBS += -l$$replace(BASENAME,\.a,)
}
}
But when I try the include
#include <gst/gst.h>
, it doesn't work and output 37 errors on unknown members of the global namespace related to time management like :
/Users/user/Library/Android/sdk/ndk/19.2.5345600/sources/cxx-stl/llvm-libc++/include/ctime:70:9: error: no member named 'asctime' in the global namespace
using ::asctime;
~~^
I really don't know how to use gstreamer and bundle it for android from the available official binaries and don't want to use any wrapper like qt-gstreamer (which isn't maintained by the way) or JNI.
Thanks for any help or input !
Related
I have a simple C++ function compiled into a dylib file that I'm trying to run on an Android phone. The function is super simple, it just adds to numbers and returns the result. However, I keep getting this error:
Another exception was thrown: Invalid argument(s): Failed to load dynamic library 'libadd.dylib': dlopen failed: library "libadd.dylib" not found .
I'm really not sure what I'm doing wrong. I've done the following steps:
My Dart implementation:
import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
typedef C_ADD = ffi.Int Function(
ffi.Int a, ffi.Int b); // FFI signature of C function
typedef ADD = int Function(int a, int b);
void linkAndCallFunction() {
var libraryPath = path.join(Directory.current.path, "libadd.dylib");
final dylib = ffi.DynamicLibrary.open(libraryPath);
final ADD add = dylib.lookup<ffi.NativeFunction<C_ADD>>("add").asFunction();
final result = add(40, 2);
print(result);
}
I've added these to the build.gradle files:
build.gradle:
buildscript{
ext{
ndkVersion = "25.1.8937393"
}
...
and app/build.gradle:
android {
ndkVersion rootProject.ext.ndkVersion
externalNativeBuild {
cmake {
path "../../lib/CMakeLists.txt"
}
}
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10.2)
project(add LANGUAGES CXX C)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
add_library(add SHARED ./add.cpp)
and my file structure of the project looks like this:
lib/
- add.cpp
- add.o
- CMakeLists.txt
- libadd.dylib
- main.dart
it also may be worth mentioning that in order to compile add.cpp into a dylib I ran the following commands:
g++ -c add.cpp
ar rvs libadd.dylib add.o
and if you're wondering, add.cpp looks like this:
#define EXPORT extern "C" __attribute__((visibility("default")))
__attribute__((used))
EXPORT
int add(int a, int b){
return a + b;
}
Where is this error coming from? am I compiling to a dylib incorrectly?
The answer to this problem was relatively simple, it just stemmed from my lack of knowledge on how Android actually compiles to a static library. Hopefully it helps someone else who is trying to understand how to setup external C++ code in a flutter program.
The static library is generated automatically and is set up in CMakeLists.txt.
Firstly, I moved all the C++ files into the android folder. Then, I set up CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.10.2)
add_library( add // library name, will create libadd.so
SHARED
add.cpp
)
The problem before was that I was trying to manually compile the file myself, when I should have been letting CMakeLists do it instead. According to the android documentation:
"The convention CMake uses to name the file of your library is as follows:
liblibrary-name.so
For example, if you specify "native-lib" as the name of your shared library in the build script, CMake creates a file named libnative-lib.so. "
https://developer.android.com/studio/projects/configure-cmake
So when I run the program, the static library is created automatically and placed in the correct place. Then, the Dart FFI can find it with the DynamicLibrary.open() function. In this case, CMakeLists will generate a file called libadd.so, and I can callDynamicLibrary.open('libadd.so') and the program works.
I have Qt 6.3 CMake-project that contains two subdirectories "app" and "service", i want include Android service .so library into result APK.
With qmake-project i can achieve this like that at app.pri:
contains(ANDROID_TARGET_ARCH, arm64-v8a) {
release: ANDROID_EXTRA_LIBS = $$OUT_PWD/../service/libservice_arm64-v8a.so
debug: ANDROID_EXTRA_LIBS = $$OUT_PWD/../service/libservice_arm64-v8a.so
}
with CMake i tried to set(QT_ANDROID_EXTRA_LIBS C:/workspace/build-test-Android_Qt_6_3_0_Clang_arm64_v8a-Debug/service/libservice_arm64-v8a.so)
at app->CMakeLists.txt and it has no effect.
Found that QT_ANDROID_EXTRA_LIBS is 'target property' and should be set via set_target_properties() then it adds .so into result.
set_target_properties(project_name PROPERTIES
QT_ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_BINARY_DIR}/../service/libservice_${ANDROID_ABI}.so)
It's the first time I try to create a library c++ for Android/iOS.
I'm using Visual Studio 2015 - Xamarin.
First I created a project : Visual C++ -> Cross Platform -> Shared Library. In the hared library, I created 2 files.
SayHello.h :
#pragma once
#include <string.h>
class SayHello {
public:
SayHello();
~SayHello();
static char* Hello();
};
SayHello.cpp :
#include "SayHello.h"
extern "C"
{
SayHello::SayHello(){}
SayHello::~SayHello(){}
char * SayHello::Hello()
{
return "Hello !";
}
}
Then I generated a file libSayHello.so and created a project Android with xamarin to try to call the function hello.
There is my MainActivity.cs :
[DllImport("libSayHello.so")]
static extern String Hello();
protected override void OnCreate(Bundle bundle)
{
// I paste only my added code :
String hello = Hello();
Toast.MakeText(this.ApplicationContext, hello, ToastLength.Long);
}
I did all steps in this tutorial, but I have an exception :
System.DllNotFoundException: libSayHello.so
I searched for this, but I must be so noob cause I did not find anything. How should I use my libSayHello.so ?
EDIT:
There is my libSayHello.so seen with 7zip:
And my project :
I think this will be the best sample for you.
This all works according to the following scheme:
Android supports 7 CPU architectures.
But Xamarin supports 5 of them. So in the settings of your Xamarin.Android project check which architectures you will support:
[Xamarin.Droid.project]->[Properties]->[Android Options]->[Advanced]->[Supported architectures]
Check which archs are necessary for your project. According to this your shared library should be compiled for these archs. And you should put your shared libraries in Xamarin.Droid.project's folder lib:
To see them in Solution Explorer you should mention them in your Xamarin.Android project's .CSPROJ.
Add there next item groups:
<ItemGroup>
<AndroidNativeLibrary Include="lib\{ARCH}\libCLib.so">
<Abi>{ARCH}</Abi>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AndroidNativeLibrary>
</ItemGroup>
{ARCH} could be next: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64.
Now you can put DllImport in your code:
[DllImport("libCLib", EntryPoint = "clib_add")]
public static extern int Add(int left, int right);
I think you have to tell about entry point, because i had runtime errors without this statement System.EntryPointNotFoundException.
And don't forget to add next in your code:
using System.Runtime.InteropServices;
Confirm the library is put in "/lib/{arch}/" folder.
Try [DllImport("SayHello")]. the engine may add "lib" and ".so" automatically.
On Android NDK project we need to access bluetooth using a HAL interface. Our intention is to do something like this:
#include <hardware/hardware.h>
#include <hardware/bluetooth.h>
....
void load_Module(....)
{
hw_module_t* module;
hw_device_t* device;
bdt_log("Loading HAL lib + extensions");
err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0){
err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
if (err == 0) {
bt_device = (bluetooth_device_t *)device;
sBtInterface = bt_device->get_bluetooth_interface();
}
}
}
Everybody seems to do the same (in google example code). There appears to be a problem when we try to compile:
#include <hardware/hardware.h> no such file
We properly added a permission to manifest and properly added libraries at Android.mk
Do we need to add something more? Is there a working project that I can refer to?
You're trying to use libhardware on Android NDK project. libhardware is a part of Android framework, not a part of NDK.
https://github.com/android/platform_hardware_libhardware
So your project doesn't have true binary compatibility of Android if you can build your project with libhardware. It would work on some devices, some versions, but no guarantee.
From my experience, I believe you can build your code on AOSP. You need to modify Android.mk for AOSP not NDK.
I'm trying to use QtCreator (2.7.2) + QT (5.1.0) to build an application that runs on both desktop (Linux) and mobile (Android) platforms.
To achieve this, I need to use different pre-built libraries depending on the target platform.
How do I specify this in the .pro file?
The wizard only offers linux/mac/windows as platform choice like
unix:!mac {
message("* Using settings for Unix/Linux.")
LIBS += -L/path/to/linux/libs
}
I've tried
android {
message("* Using settings for Android.")
LIBS += -L/path/to/android/libs
}
But with both build targets only the unix:!mac gets executed/evaluated.
So my question is: How to detect the build target (called "Kits" now in QtCreator) in the .pro file and change library definitions accordingly?
I've so far only found out how to specify the platform (which seems to be the platform I'm building ON and not FOR) or the build variant RELEASE/DEBUG.
Other things I've found say I should prefix the LIB+= with the target platform like win32:LIB+=. But again, this won't work with android. Maybe I'm using a wrong syntax for the platform (android 4.2 on an arm-v7).
this works for me (Qt 5.3.2)
linux:!android {
message("* Using settings for Unix/Linux.")
LIBS += -L/path/to/linux/libs
}
android {
message("* Using settings for Android.")
LIBS += -L/path/to/android/libs
}
I'm using this in a .pro file, maybe it helps:
unix:!macx:
{
android:
{
INCLUDEPATH += "/usr/lib/boost/boost_1_47_0" \
inkscape
}
!android:
{
INCLUDEPATH += $$(BOOST_PATH) \
inkscape
}
}
macx:
{
INCLUDEPATH += "../../../../boost_1_54_0" \#$$(BOOST_PATH) \
inkscape
}