Android cmake project with sub-directories "dlopen failed: cannot locate symbol" on api < 23
same code works fine on api >= 23
this test program will print a log if success
project structure:
src/main/cpp
+foo
CMakeLists.txt
foo.cpp
+utils
CMakeLists.txt
log-utils.h
log-utils.cpp
CMakeLists.txt
CMakeLists.txt(foo)
project(foo)
add_library(foo SHARED foo.cpp)
target_link_libraries(foo PUBLIC utils)
foo.cpp
#include <jni.h>
#include <utils/log-utils.h>
#include <cstring>
jint JNI_OnLoad(JavaVM* vm, void * reserved) {
const char * test = "test message";
printByte("JNI_OnLoad", test, strlen(test));
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
CMakeLists.txt(utils)
project(utils)
find_library(log-lib log)
add_library(utils SHARED log-utils.cpp)
target_link_libraries(utils ${log-lib})
log-utils.h
#ifndef LOG_UTILS_H
#define LOG_UTILS_H
void printByte(const char*tag, const char* content, unsigned int len);
#endif //LOG_UTILS_H
log-utils.cpp
#include "log-utils.h"
#include <cstring>
#include <cstdio>
#include <android/log.h>
static const char * TAG = "LOG_UTILS";
void printByte(const char*tag, const char* content, unsigned int len) {
char buff[len*2+1];
memset(buff, '\0', len*2+1);
for (int i = 0; i<len; ++i) {
sprintf(buff+i*2, "%02x", content[i] & 0xff);
}
__android_log_print(ANDROID_LOG_DEBUG, TAG, "%-12s%04d: %s\n", tag, len, buff);
}
CMakeLists.txt(root)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
include_directories(./)
add_subdirectory(utils)
add_subdirectory(foo)
MainActivity.kt
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("utils")
System.loadLibrary("foo")
}
}
// ...
}
two library: libfoo.so, libutils.so, libfoo.so depends on libutils.so. on Android 4.4 and 5.0, it just crash, and the system log:
09-10 17:36:33.388 10908-10908/? E/art: dlopen("/data/app/com.example.nativefoo-2/lib/x86/libfoo.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
09-10 17:36:33.388 10908-10908/? D/AndroidRuntime: Shutting down VM
09-10 17:36:33.389 10908-10908/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.nativefoo, PID: 10908
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
at java.lang.Runtime.loadLibrary(Runtime.java:371)
at java.lang.System.loadLibrary(System.java:989)
at com.example.nativefoo.MainActivity.<clinit>(MainActivity.kt:18)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Update1 2019.09.11 07:23 UTC Time
app/build.gradle
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.nativefoo"
minSdkVersion 18
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "x86"
}
}
}
I think libutils.so is loaded correct, see the logcat
09-11 15:27:29.622 D/dalvikvm: Not late-enabling CheckJNI (already on)
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: Added shared lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: No JNI_OnLoad found in /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440, skipping init
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libfoo.so 0x9d061440
09-11 15:27:29.672 E/dalvikvm: dlopen("/data/app-lib/com.example.nativefoo-1/libfoo.so") failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
You can see the whole Project at github NativeFoo
This was a very stupid mistake, my library name is libutils.so, but Android system also has a inner library called libutils.so. So, when I try to load libutils.so, it load the system library first, not mine! Because of that, my app never works as expected.
Related
I'm trying to compile a project with dlib & opencv. I am super new to CMake. It needs a BLAS library included. I have ATLAS installed, I've tried a couple things, but not found any that I can get to work. Is there a way to find a BLAS package installed and add it on Linux (Ubuntu 18.04)? Any help would be much appreciated.
Errors
main.cpp
#include <iostream>
#include <dlib/pixel.h>
#include <dlib/opencv.h>
#include <opencv2/opencv.hpp>
#include <dlib/image_processing.h>
#include <dlib/image_processing/frontal_face_detector.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
cv::Mat frame, half;
cv::VideoCapture cap;
dlib::array2d<dlib::bgr_pixel> dlibFrame;
try
{
cap.open(2);
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
return 1;
}
dlib::frontal_face_detector detector;
try
{
std::vector<dlib::rectangle> faces;
cv::namedWindow("Tracking Window");
while(cap.isOpened())
{
cap >> frame;
cv::resize(frame,half,cv::Size(),0.5,0.5);
dlib::assign_image(dlibFrame,dlib::cv_image<dlib::bgr_pixel>(half));
faces = detector(dlibFrame);
for(size_t i = 0;i < faces.size();++i)
{
auto& r = faces[i];
cv::Rect cvr = cv::Rect(r.left(),r.top(),r.width(),r.height());
cv::rectangle(half,cvr,cv::Scalar(255,0,0),2);
}
cv::imshow("Tracking Window",half);
if(cv::waitKey(1) == 27)
break;
}
}
catch(std::exception& e)
{
cout << e.what() << endl;
return 1;
}
cv::destroyAllWindows();
return 0;
}
CMake
cmake_minimum_required(VERSION 3.0.0)
project(ObjectTracking VERSION 0.1.0)
include(CTest)
enable_testing()
add_executable(ObjectTracking main.cpp)
find_package(BLAS REQUIRED)
find_package(OpenCV REQUIRED)
find_package(dlib REQUIRED)
target_link_libraries(ObjectTracking ${OpenCV_LIBS} dlib ${BLAS_LIBRARIES})
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
For Ubuntu 18.04, there are the following packages:
libblas-dev
libbas3
libcblas2
libcublas9.1 (if you have a Nvidia GPU and CUDA?)
I use OpenBLAS, so I'm not positive about which one to use.
An alternative is OpenBLAS. The repo is at: https://github.com/xianyi/OpenBLAS.git
To build it:
git clone https://github.com/xianyi/OpenBLAS.git
cd OpenBLAS
sudo make install
OpenBLAS detects your CPU and creates the appropriate binary.
I'm trying to build a simple hello world in SystemC with CMake.
Here's the SystemC file main.cpp:
#include <systemc.h>
using namespace std;
SC_MODULE (hello_world) {
SC_CTOR (hello_world) {
}
void say_hello() {
cout << "Hello World SystemC" << endl;
}
};
int sc_main(int argc, char* argv[]) {
hello_world hello("HELLO");
hello.say_hello();
return(0);
}
Here is the CMakeLists.txt:
cmake_minimum_required(VERSION 3.1)
project(SystemCExample)
set (CMAKE_PREFIX_PATH /usr/local/systemc-2.3.2)
include_directories(${CMAKE_PREFIX_PATH}/include)
find_library(systemc systemc ${CMAKE_PREFIX_PATH}/lib-linux64)
link_directories(${CMAKE_PREFIX_PATH}/lib-linux64)
set(CMAKE_CXX_STANDARD 11) # C++11...
set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required...
set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(SystemCExample systemc)
I keep getting the error:
/usr/local/systemc-2.3.2/include/sysc/kernel/sc_ver.h:179: error: undefined reference to `sc_core::sc_api_version_2_3_2_cxx201103L<&sc_core::SC_DISABLE_VIRTUAL_BIND_UNDEFINED_>::sc_api_version_2_3_2_cxx201103L(sc_core::sc_writer_policy)'
It points to sc_ver.h to the line:
api_version_check
(
SC_DEFAULT_WRITER_POLICY
);
The error mesage appears also when I replace the main.cpp with another simple example. How can I fix it?
Most likely you've built SystemC with C++98. It is default. Currently it requires that you use same C++ standard during library build and for your application.
Here are steps to build SystemC 2.3.2 with CMake
Download SystemC 2.3.2, unpack, change directory to systemc-2.3.2
cd /path/to/systemc-2.3.2
Create build directory:
mkdir build
Configure SystemC build with C++11 support. I also recommend to build it in Debug mode, this helps while learning. Later you can switch to Release builds to speed-up simulation
cmake ../ -DCMAKE_CXX_STANDARD=11 -DCMAKE_BUILD_TYPE=Debug
Build
cmake --build .
CMake will automatically export SystemC library targets to User Package Registry: https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#user-package-registry
Optionally you can install it somewhere, read CMake manual to learn how.
Now try to create sample SystemC project:
main.cpp
#include <systemc.h>
SC_MODULE (hello_world) {
SC_CTOR (hello_world)
{
SC_THREAD(say_hello);
}
void say_hello()
{
cout << "Hello World SystemC" << endl;
}
};
int sc_main(int argc, char* argv[])
{
hello_world hello("HELLO");
sc_start();
return (0);
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(test_systemc)
find_package(SystemCLanguage CONFIG REQUIRED)
set (CMAKE_CXX_STANDARD ${SystemC_CXX_STANDARD})
add_executable(test_systemc main.cpp)
target_link_libraries(test_systemc SystemC::systemc)
Build, run, expected output:
./test_systemc
SystemC 2.3.2 --- Oct 14 2017 19:38:30
Copyright (c) 1996-2017 by all Contributors,
ALL RIGHTS RESERVED
Hello World SystemC
I am writing a bluez C program to read battery service. I am using CMake for building the code.
My Cmake File is :
# CMakeLists file for module-bluez project
cmake_minimum_required(VERSION 3.02)
project (bluez-module)
find_package(PkgConfig REQUIRED)
# Adding dbus library
pkg_check_modules(DBUS REQUIRED dbus-1>= 1.6)
include_directories(${DBUS_INCLUDE_DIRS})
link_directories(${DBUS_LIBRARY_DIRS})
#Adding glib library
pkg_check_modules(GLIB REQUIRED glib-2.0>=2.23)
include_directories(${GLIB_INCLUDE_DIRS})
link_directories(${GLIB_LIBRARY_DIRS})
pkg_check_modules (DBUSGLIB REQUIRED dbus-glib-1)
include_directories(${DBUSGLIB_INCLUDE_DIRS})
link_directories(${DBUSGLIB_LIBRARY_DIRS})
# Adding bluetooth using extra libs
list(APPEND EXTRA_LIBS "bluetooth")
# Expose 'gattlib.h' to all sub-directories
include_directories(include)
add_executable(bluez-module scantest.c)
# Linking libraries
message(${DBUSGLIB_LIBRARIES})
target_link_libraries(bluez-module ${EXTRA_LIBS})
#target_link_libraries(bluez-module ${DBUS_LIBRARIES})
target_link_libraries(bluez-module ${DBUSGLIB_LIBRARIES})
target_link_libraries(bluez-module ${GLIB_LIBRARIES})
I have to use g_main_loop in my code. But after building the source file I always get the below error :
[ 50%] Linking C executable bluez-module
CMakeFiles/bluez-module.dir/scantest.c.o: In function `read_battery_service':
scantest.c:(.text+0x5b8): undefined reference to `g_dbus_setup_bus'
collect2: error: ld returned 1 exit status
My read_battery function code is as below :
int read_battery_service(struct hci_state *current_hci_state , char *dev_addr)
{
GError *error = NULL;
GDBusClient *client;
GOptionContext *context;
context = g_option_context_new(NULL);
main_loop = g_main_loop_new(NULL, FALSE);
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
return 0;
}
Just trying to initialize for to access dbus apis.
I have included these headers in the code
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <stdio.h>
#include <gdbus.h>
#include <glib/gmain.h>
What would be the issue ? Is glib.h contains the function g_main_loop_new ? Where should I find it ? Or Is CMake not linking glib properly ?
Looks like you are missing the gdbus linker flags. Try using
pkg_check_modules (DBUSGLIB REQUIRED dbus-glib-1) and add
target_link_libraries(module-bluez ${DBUS_LIBRARIES} ${DBUSGLIB_LIBRARIES})
and see if it helps.
I am trying to build a simple Qt5 application using CMake
The Qt5 project is the basic project generated when creating a new project with a Widget.
The project builds and runs successfully with QtCreator
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
The CMakeLists file have been written according to the example given in the Qt5 documentation. The path to the Qt5 directory is given in the cache.
http://doc.qt.io/qt-5/cmake-manual.html
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.11)
project(test0)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
# Find the QtWidgets library
find_package(Qt5Widgets)
# Tell CMake to create the executable
add_executable(test0 WIN32 main.cpp)
# Use the Widgets module from Qt 5.
target_link_libraries(test0 Qt5::Widgets)
The Cmake generation works fine.
I'm getting linking errors (undefined reference to methods belonging to the Widget class) when building the app using the Makfile generated by Cmake.
(here is a capture of the errors)
http://s31.postimg.org/edefl1m6j/Capturetest0.png
Any tips ?
System :
Windows 7
Compiler :
MinGW32
Versions :
QT 5.6.1 (mingw49_32)
CMake 3.6.0
Two mistakes in the CMakeLists
- widget.cpp has to be mentionend in add_executable as explained Tsyvarev
- use autouic in order to create the ui_widget.h associated with the widget.ui and widget.cpp
The working CMakeLists is the following :
cmake_minimum_required(VERSION 2.8.11)
project(test0)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
# Find the QtWidgets library
find_package(Qt5Widgets)
# Tell CMake to create the executable
add_executable(test0 WIN32 main.cpp widget.cpp widget.ui)
# Use the Widgets module from Qt 5.
target_link_libraries(test0 Qt5::Widgets)
For this simple code (taken from the boost-mpi documentation):
#include <boost/serialization/string.hpp>
#include <iostream>
#include <string>
#include <boost/mpi.hpp>
namespace mpi = boost::mpi;
int main(int argc, char *argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.rank() == 0) {
world.send(1, 0, std::string("Hello"));
std::string msg;
world.recv(1, 1, msg);
std::cout << msg << "!" << std::endl;
} else if (world.rank() == 1) {
std::string msg;
world.recv(0, 0, msg);
std::cout << msg << ", ";
std::cout.flush();
world.send(0, 1, std::string("world"));
};
return 0;
};
And for such CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(mpi-tests CXX)
FIND_PACKAGE(Boost 1.4 COMPONENTS mpi serialization REQUIRED)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(test ${Boost_LIBRARIES})
It cannot find boost_mpi:
CMake Error at /usr/share/cmake/Modules/FindBoost.cmake:1135 (message):
Unable to find the requested Boost libraries.
Boost version: 1.47.0
Boost include path: /usr/include
The following Boost libraries could not be found:
boost_mpi
But! I have installed next packages:
boost-graph-mpich2
boost-mpich2
boost-mpich2-devel
boost-mpich2-python
mpich2
mpich2-devel
Why it can't find? There are a plenty examples over Internet where people use FIND_PACKAGE(Boost 1.4 COMPONENTS mpi REQUIRED).
Boost might not be installed in a location that the module FindBoost searches. You can specify the prefix where Boost was installed by setting the variable BOOST_ROOT to your Boost installation prefix.
To your code I would add:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(mpi-tests CXX)
set( BOOST_ROOT "/path/to/boost/install/prefix" )
FIND_PACKAGE(Boost 1.4 COMPONENTS mpi serialization REQUIRED)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(test ${Boost_LIBRARIES})