首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从共享库动态加载时,Android dynamic_cast无法工作

从共享库动态加载时,Android dynamic_cast无法工作
EN

Stack Overflow用户
提问于 2020-10-23 05:13:15
回答 2查看 580关注 0票数 1

在将vsomeip移植到Android上时,我遇到了dynamic_cast问题。

为了简化情况,我创建了一个相当简单的测试app/lib结构,如下所示:

它包含一个库和一个应用程序:

  • libbase_1.so:实现类Final,它继承了Base_1和Base_2,提供了get()来返回std::shared
  • test_app:动态加载libbase_1.so (由dl_open编写),获取std::shared,并对std::shared进行动态强制转换。

动态cast在x86和其他arm平台(例如:使用linaro )上工作得很好;但是在Android上不能工作,它总是得到nullptr

AOSP的环境是:

  • NDK版本: R18
  • 构建系统: AOSP
  • 主机操作系统: Ubuntu 18.04
  • 编译器: Clang++ (9.0.3)
  • TARGET_ARCH: armv8a

以下是我的一些参考资料,但都不起作用:

有人有主意吗?非常感谢~~

完整的可运行的src可以从:Y247byBfl6JaTtjR6tYn/view?usp=共享下载。

还有粘贴在这里:

//Android.bp:可以由mm直接构建

代码语言:javascript
运行
复制
libbase_1_srcs = [
   "src_1.cpp",
   "src_2.cpp",
   "src_3.cpp",
   "lib_1.cpp",
]

main_srcs = [
   "main.cpp",
   "src_1.cpp",
   "src_2.cpp",
]

cc_defaults {
    name: "test_cast_defaults",
    cppflags: [
   "-std=c++11",
   "-frtti",
    ]
}

cc_library_shared {
    name: "libbase_1",
    vendor: true,
    srcs: libbase_1_srcs,
    defaults: [
        "test_cast_defaults"
    ],
    rtti: true,
}

cc_binary {
    name: "test_cast",
    srcs: main_srcs,
    vendor: true,
    defaults: [
        "test_cast_defaults"
    ],
    shared_libs: [
    ],
    rtti: true,
}

//CMakeLists.txt:测试X86或其他

代码语言:javascript
运行
复制
cmake_minimum_required(VERSION 3.1)
set(project_name "test_cast")
project(${project_name})

add_library(base_1 SHARED lib_1.cpp src_1.cpp src_2.cpp src_3.cpp)
target_include_directories(base_1 PUBLIC ${${project_name}_SOURCE_DIR}/)

add_executable(test_cast main.cpp src_1.cpp src_2.cpp)
target_include_directories(test_cast PUBLIC ${${project_name}_SOURCE_DIR}/)
target_link_libraries(test_cast PUBLIC dl)

//main.cpp

代码语言:javascript
运行
复制
#include <dlfcn.h>
#include <iostream>
#include "lib_1.h"
#include <memory>

#define libname "libbase_1.so"
#define funcname "get_plugin"

int main(void)
{
    void *handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
    void *func;
    if (handle == nullptr) {
        std::cout << "Can not find: " << libname << std::endl;
        return -1;
    }
    func = dlsym(handle, funcname);
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
        std::cout << "dlsym err: " << dlsym_error <<std::endl;
        return -1;
    }

    plugin_init_func func_get = reinterpret_cast<plugin_init_func>(func);
    get_plugin_func func_create = (*func_get)();

    auto base_1 = (*func_create)();
    auto base_2 = std::dynamic_pointer_cast<Base_2>(base_1);

    if (base_2) {
        std::cout << "dl: dynamic cast success!" << std::endl;
    } else {
        std::cout << "dl: dynamic cast failed!" << std::endl;
    }
    return 0;
}

//lib_1.cpp

代码语言:javascript
运行
复制
#include "lib_1.h"

get_plugin_func get_plugin(void)
{
    return Final::get;
}

//lib_1.h

代码语言:javascript
运行
复制
#ifndef __LIB_1_H__
#define __LIB_1_H__
#include "header_3.h"
typedef std::shared_ptr<Base_1> (*get_plugin_func)();
typedef get_plugin_func (*plugin_init_func)();
extern "C" {
    get_plugin_func get_plugin(void);
};
#endif

//报头_1.h

代码语言:javascript
运行
复制
#ifndef __HEADER_1__
#define __HEADER_1__
class Base_1 {
public:
    virtual ~Base_1();
};
#endif

//报头_2.h

代码语言:javascript
运行
复制
#ifndef __HEADER_2__
#define __HEADER_2__
class Base_2 {
public:
    virtual ~Base_2();
};
#endif

//报头_3.h

代码语言:javascript
运行
复制
#ifndef __HEADER_3__
#define __HEADER_3__
#include "header_1.h"
#include "header_2.h"
#include <iostream>
#include <memory>
class Final : public Base_2,
              public Base_1 {
public:
    static std::shared_ptr<Base_1> get(void) {
        std::shared_ptr<Base_1> base_1 = std::make_shared<Final>();
        auto base_2 = std::dynamic_pointer_cast<Base_2>(base_1);
        if (base_2) {
            std::cout << "in lib: dynamic cast success!" << std::endl;
        } else {
            std::cout << "in lib: dynamic cast failed!" << std::endl;
        }
        return base_1;
    }
    ~Final();
};
#endif

//src_1.cpp

代码语言:javascript
运行
复制
#include <header_1.h>
#include <iostream>
Base_1::~Base_1()
{
    std::cout << "in: " << __func__ << std::endl;
}

//src_2 src

代码语言:javascript
运行
复制
#include "header_2.h"
#include <iostream>
Base_2::~Base_2()
{
    std::cout << "in: " << __func__ << std::endl;
}

//src_3 src

代码语言:javascript
运行
复制
#include "header_3.h"
#include <iostream>
Final::~Final() {
    std::cout << "in: " << __func__ << std::endl;
}

成功运行(X86):

代码语言:javascript
运行
复制
in lib: dynamic cast success!
dl: dynamic cast success!
in: ~Final
in: ~Base_1
in: ~Base_2

失败运行(Android):

代码语言:javascript
运行
复制
in lib: dynamic cast success!
dl: dynamic cast failed!
in: ~Final
in: ~Base_1
in: ~Base_2
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-26 23:21:48

当我通过vsomeip与clang编译器一起使用CommonAPI时,我也遇到了同样的问题,只有变通办法才能帮助我修复它。这里有更多详细信息:https://github.com/nkh-lab/genivi-capi-someip-examples/blob/ndk/CMakeLists.txt

问题是,vsomeip_v3::configuration_pluginlibvsomeip3.solibvsomeip3-cfg.so中有相同的类型信息,而dynamic_pointer_cast使用错误的类型(例如,typeinfo表中的第一个条目)。因此,我们需要更改上述库的加载顺序,然后dynamic_pointer_cast将使用正确的库。

也用GENIVI/vsomeip/问题回答

票数 1
EN

Stack Overflow用户

发布于 2020-10-23 09:17:15

(这不是一个实际的解决方案,只是一个大的评论)

我认为不应该在主可执行文件和共享库中包含相同的对象模块。以下是避免这种情况的可能方法(Makefile):

代码语言:javascript
运行
复制
CXXFLAGS += -g -W -Wall -Wextra -fPIC
LDFLAGS  += -g

clean:
        rm *.o *.so main 2>/dev/null || true

main: LDFLAGS += -export-dynamic
main: LDLIBS += -ldl
main: main.o src_1.o src_2.o src_3.o
        ${CXX} ${LDFLAGS} -o $@ $^ ${LDLIBS}

libbase_1.so: LDFLAGS += -shared
libbase_1.so: lib_1.o
        ${CXX} ${LDFLAGS} -o $@ $^ ${LDLIBS}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64494220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档