Add dymanic loader for plugin 68/238768/1
authorSangwan Kwon <sangwan.kwon@samsung.com>
Mon, 1 Jun 2020 04:46:33 +0000 (13:46 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Mon, 1 Jun 2020 04:48:09 +0000 (13:48 +0900)
Change-Id: Ie4f47bd85190922839983e7541b9302a6e55f4f7
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/common/CMakeLists.txt
src/vist/common/dynamic-loader.cpp [new file with mode: 0644]
src/vist/common/tests/CMakeLists.txt [new file with mode: 0644]
src/vist/common/tests/dynamic-loadaer.cpp [new file with mode: 0644]
src/vist/common/tests/res/sample-plugin.cpp [new file with mode: 0644]
src/vist/common/tests/res/sample-plugin.hpp [new file with mode: 0644]
src/vist/dynamic-loader.hpp [new file with mode: 0644]

index ec46eddbcbf45ae01ea7fc6ef25e6865dd90a9db..7c50893e856a6de00215377a9e41033aacd02755 100644 (file)
 
 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 (file)
index 0000000..92a7177
--- /dev/null
@@ -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 <vist/dynamic-loader.hpp>
+
+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 (file)
index 0000000..439fa43
--- /dev/null
@@ -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 (file)
index 0000000..780b93c
--- /dev/null
@@ -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 <gtest/gtest.h>
+
+#include <vist/dynamic-loader.hpp>
+
+#include "res/sample-plugin.hpp"
+
+#include <string>
+
+using namespace vist;
+
+TEST(DynamicLoaderTests, load)
+{
+       std::string path = std::string(PLUGIN_INSTALL_DIR) + "/libtest-plugin.so";
+       DynamicLoader loader(path);
+
+       auto factory = loader.load<SamplePlugin::FactoryType>("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<SamplePlugin::FactoryType>("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 (file)
index 0000000..24a6639
--- /dev/null
@@ -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 (file)
index 0000000..47c9561
--- /dev/null
@@ -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 <string>
+
+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 (file)
index 0000000..675e394
--- /dev/null
@@ -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 <vist/exception.hpp>
+#include <vist/logger.hpp>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <dlfcn.h>
+
+namespace vist {
+
+class DynamicLoader final {
+public:
+       explicit DynamicLoader(const std::string& path, int flag = RTLD_LAZY);
+
+       template<typename Symbol>
+       Symbol load(const std::string& name);
+
+private:
+       using ScopedHandle = std::unique_ptr<void, std::function<void(void*)>>;
+       ScopedHandle init(const std::string& path, int flag);
+
+       ScopedHandle scopedHandle;
+};
+
+template<typename T>
+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<T>(symbol);
+}
+
+} // namespace vist