From b7ed6160ac8e8ceb45d5a94b46039492e4990341 Mon Sep 17 00:00:00 2001 From: Sangwan Kwon Date: Mon, 1 Jun 2020 13:46:33 +0900 Subject: [PATCH] Add dymanic loader for plugin Change-Id: Ie4f47bd85190922839983e7541b9302a6e55f4f7 Signed-off-by: Sangwan Kwon --- src/vist/common/CMakeLists.txt | 7 +++ src/vist/common/dynamic-loader.cpp | 52 +++++++++++++++++ src/vist/common/tests/CMakeLists.txt | 31 +++++++++++ src/vist/common/tests/dynamic-loadaer.cpp | 62 +++++++++++++++++++++ src/vist/common/tests/res/sample-plugin.cpp | 22 ++++++++ src/vist/common/tests/res/sample-plugin.hpp | 26 +++++++++ src/vist/dynamic-loader.hpp | 60 ++++++++++++++++++++ 7 files changed, 260 insertions(+) create mode 100644 src/vist/common/dynamic-loader.cpp create mode 100644 src/vist/common/tests/CMakeLists.txt create mode 100644 src/vist/common/tests/dynamic-loadaer.cpp create mode 100644 src/vist/common/tests/res/sample-plugin.cpp create mode 100644 src/vist/common/tests/res/sample-plugin.hpp create mode 100644 src/vist/dynamic-loader.hpp diff --git a/src/vist/common/CMakeLists.txt b/src/vist/common/CMakeLists.txt index ec46edd..7c50893 100644 --- a/src/vist/common/CMakeLists.txt +++ b/src/vist/common/CMakeLists.txt @@ -14,8 +14,15 @@ ADD_VIST_COMMON_LIBRARY(vist_common archive.cpp common.cpp + dynamic-loader.cpp stringfy.cpp thread-pool.cpp) +SET(TARGET "test-plugin") +ADD_LIBRARY(${TARGET} SHARED tests/res/sample-plugin.cpp) +TARGET_LINK_LIBRARIES(${TARGET} vist-common) + +INSTALL(TARGETS ${TARGET} DESTINATION ${PLUGIN_INSTALL_DIR}) + FILE(GLOB COMMON_TESTS "tests/*.cpp") ADD_VIST_TEST(${COMMON_TESTS}) diff --git a/src/vist/common/dynamic-loader.cpp b/src/vist/common/dynamic-loader.cpp new file mode 100644 index 0000000..92a7177 --- /dev/null +++ b/src/vist/common/dynamic-loader.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include + +namespace vist { + +DynamicLoader::DynamicLoader(const std::string& path, int flag) + : scopedHandle(init(path, flag)) +{ +} + +DynamicLoader::ScopedHandle DynamicLoader::init(const std::string& path, int flag) +{ + auto open = [&]() -> void* { + ::dlerror(); + + auto handle = ::dlopen(path.c_str(), flag); + if (handle == nullptr) { + if (auto error = ::dlerror(); error != nullptr) + ERROR(VIST) << "Failed to open library: " << error; + + THROW(ErrCode::RuntimeError) << "Failed to open library: " << path; + } + + return handle; + }; + + auto close = [&](void* handle) { + ::dlerror(); + + if (::dlclose(handle) != 0) + THROW(ErrCode::RuntimeError) << "Failed to close library: " << ::dlerror(); + }; + + return ScopedHandle(open(), close); +} + +} // namespace vist diff --git a/src/vist/common/tests/CMakeLists.txt b/src/vist/common/tests/CMakeLists.txt new file mode 100644 index 0000000..439fa43 --- /dev/null +++ b/src/vist/common/tests/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +SET(TARGET "vist-plugin-sample") + +INCLUDE_DIRECTORIES(SYSTEM) + +ADD_LIBRARY(${TARGET} SHARED sample.cpp) +SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_FLAGS "-fvisibility=default") +TARGET_LINK_LIBRARIES(${TARGET} vist-common) + +IF(DEFINED GBS_BUILD) + INSTALL(FILES libvist-plugin-sample.so + RENAME sample + DESTINATION ${PLUGIN_INSTALL_DIR}) +ELSE(DEFINED GBS_BUILD) + INSTALL(TARGETS ${TARGET} + RENAME sample + DESTINATION ${PLUGIN_INSTALL_DIR}) +ENDIF(DEFINED GBS_BUILD) diff --git a/src/vist/common/tests/dynamic-loadaer.cpp b/src/vist/common/tests/dynamic-loadaer.cpp new file mode 100644 index 0000000..780b93c --- /dev/null +++ b/src/vist/common/tests/dynamic-loadaer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include + +#include + +#include "res/sample-plugin.hpp" + +#include + +using namespace vist; + +TEST(DynamicLoaderTests, load) +{ + std::string path = std::string(PLUGIN_INSTALL_DIR) + "/libtest-plugin.so"; + DynamicLoader loader(path); + + auto factory = loader.load("SampleFactory"); + EXPECT_NE(factory, nullptr); + + auto samplePlugin = (*factory)(); + EXPECT_NE(samplePlugin, nullptr); + + EXPECT_EQ(samplePlugin->test(), "sample-plugin-test"); +} + +TEST(DynamicLoaderTests, not_exist_path) +{ + try { + DynamicLoader loader("not_exists"); + EXPECT_TRUE(false); + } catch (const std::exception&) { + EXPECT_TRUE(true); + } +} + +TEST(DynamicLoaderTests, not_exist_symbol) +{ + try { + std::string path = std::string(PLUGIN_INSTALL_DIR) + "/libtest-plugin.so"; + DynamicLoader loader(path); + + loader.load("not_exists"); + EXPECT_TRUE(false); + } catch (const std::exception&) { + EXPECT_TRUE(true); + } +} diff --git a/src/vist/common/tests/res/sample-plugin.cpp b/src/vist/common/tests/res/sample-plugin.cpp new file mode 100644 index 0000000..24a6639 --- /dev/null +++ b/src/vist/common/tests/res/sample-plugin.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include "sample-plugin.hpp" + +extern "C" SamplePlugin* SampleFactory() +{ + return new SamplePlugin; +} diff --git a/src/vist/common/tests/res/sample-plugin.hpp b/src/vist/common/tests/res/sample-plugin.hpp new file mode 100644 index 0000000..47c9561 --- /dev/null +++ b/src/vist/common/tests/res/sample-plugin.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include + +struct SamplePlugin { + using FactoryType = SamplePlugin * (*)(); + + std::string test() + { + return "sample-plugin-test"; + } +}; diff --git a/src/vist/dynamic-loader.hpp b/src/vist/dynamic-loader.hpp new file mode 100644 index 0000000..675e394 --- /dev/null +++ b/src/vist/dynamic-loader.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#include + +namespace vist { + +class DynamicLoader final { +public: + explicit DynamicLoader(const std::string& path, int flag = RTLD_LAZY); + + template + Symbol load(const std::string& name); + +private: + using ScopedHandle = std::unique_ptr>; + ScopedHandle init(const std::string& path, int flag); + + ScopedHandle scopedHandle; +}; + +template +T DynamicLoader::load(const std::string& name) +{ + ::dlerror(); + + auto symbol = ::dlsym(this->scopedHandle.get(), name.c_str()); + if (symbol == nullptr) { + if (auto error = ::dlerror(); error != nullptr) + ERROR(VIST) << "Failed to load symbol: " << error; + + THROW(ErrCode::RuntimeError) << "Failed to load symbol: " << name; + } + + return reinterpret_cast(symbol); +} + +} // namespace vist -- 2.34.1