From cf9cbbfde538054fc6dd7ad9d925c28bd773c85a Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 1 Dec 2015 23:27:50 +0300 Subject: [PATCH] Worked arrounf calling conventions, dropped dependency on boost::function for modern compilers, updatet the docs and improved some of the examples --- example/getting_started.cpp | 1 + example/tutorial2/tutorial2.cpp | 1 + example/tutorial3/tutorial3.cpp | 1 + example/tutorial6/tutorial6.cpp | 1 + example/tutorial8/refcounting_api.hpp | 1 + example/tutorial9/tutorial9.cpp | 46 +++++++++++++----------- include/boost/dll/import.hpp | 48 +++++++++++++++++-------- test/shared_library_get_symbol_test.cpp | 14 ++++++++ test/test_library.cpp | 8 +++++ 9 files changed, 86 insertions(+), 35 deletions(-) diff --git a/example/getting_started.cpp b/example/getting_started.cpp index 5086e50..9a14985 100644 --- a/example/getting_started.cpp +++ b/example/getting_started.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "shared_lib_path.hpp" diff --git a/example/tutorial2/tutorial2.cpp b/example/tutorial2/tutorial2.cpp index 8ddc4b2..93bbe7f 100644 --- a/example/tutorial2/tutorial2.cpp +++ b/example/tutorial2/tutorial2.cpp @@ -9,6 +9,7 @@ //[callplugcpp_tutorial2 #include // for import_alias +#include #include #include "../tutorial_common/my_plugin_api.hpp" diff --git a/example/tutorial3/tutorial3.cpp b/example/tutorial3/tutorial3.cpp index da29dff..33b638b 100644 --- a/example/tutorial3/tutorial3.cpp +++ b/example/tutorial3/tutorial3.cpp @@ -8,6 +8,7 @@ //[callplugcpp_tutorial3 #include // for import_alias #include +#include #include #include "../tutorial_common/my_plugin_api.hpp" diff --git a/example/tutorial6/tutorial6.cpp b/example/tutorial6/tutorial6.cpp index 953a3b0..3ad2282 100644 --- a/example/tutorial6/tutorial6.cpp +++ b/example/tutorial6/tutorial6.cpp @@ -7,6 +7,7 @@ //[callplugcpp_tutorial6 #include +#include #include typedef boost::function callback_t; diff --git a/example/tutorial8/refcounting_api.hpp b/example/tutorial8/refcounting_api.hpp index 9b87019..ef87788 100644 --- a/example/tutorial8/refcounting_api.hpp +++ b/example/tutorial8/refcounting_api.hpp @@ -47,6 +47,7 @@ inline boost::shared_ptr bind(my_refcounting_api* ptr) { //[plugcpp_get_plugin_refcounting #include +#include inline boost::shared_ptr get_plugin( boost::filesystem::path path, const char* func_name) { diff --git a/example/tutorial9/tutorial9.cpp b/example/tutorial9/tutorial9.cpp index 8e576de..188d6b8 100644 --- a/example/tutorial9/tutorial9.cpp +++ b/example/tutorial9/tutorial9.cpp @@ -9,35 +9,39 @@ //[callplugcpp_tutorial9 #include // for import +#include #include #include namespace dll = boost::dll; -template -struct helper { -private: - dll::shared_library lib_; - Func* f_; - -public: - helper(const char* library, const char* function) - : lib_(library) - , f_(&lib_.get(function)) - {} - - inline operator Func* () const { - return f_; - } -}; - int main() { typedef HANDLE(__stdcall GetStdHandle_t)(DWORD ); // function signature with calling convention - typedef HANDLE(GetStdHandle_no_call_conv_t)(DWORD ); // function signature without calling convention - boost::function plugin = helper("Kernel32.dll", "GetStdHandle"); - std::cout << "1. GetStdHandle() returned " << plugin(STD_OUTPUT_HANDLE) << std::endl; - std::cout << "2. GetStdHandle() returned " << helper("Kernel32.dll", "GetStdHandle")(STD_OUTPUT_HANDLE) << std::endl; + // OPTION #0, requires C++11 compatible compiler. +/*<-*/ +#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) /*->*/ + auto get_std_handle = dll::import( + "Kernel32.dll", + "GetStdHandle" + ); + std::cout << "0.0 GetStdHandle() returned " << get_std_handle(STD_OUTPUT_HANDLE) << std::endl; + + // You may put the `get_std_handle` into boost::function<>. But boost::function can not compile with + // Signature template parameter that contains calling conventions, so you'll have to remove the calling convention. + boost::function get_std_handle2 = get_std_handle; + std::cout << "0.1 GetStdHandle() returned " << get_std_handle2(STD_OUTPUT_HANDLE) << std::endl; +/*<-*/ +#endif /*->*/ + + // OPTION #1, does not require C++11. But without C++11 dll::import<> can not handle calling conventions, + // so you'll need to hand write the import. + dll::shared_library lib("Kernel32.dll"); + GetStdHandle_t& func = lib.get("GetStdHandle"); + + // Here `func` does not keep a reference to `lib`, you'll have to deal with that on your own. + std::cout << "1.0 GetStdHandle() returned " << func(STD_OUTPUT_HANDLE) << std::endl; + return 0; } diff --git a/include/boost/dll/import.hpp b/include/boost/dll/import.hpp index 629a709..0d95b6d 100644 --- a/include/boost/dll/import.hpp +++ b/include/boost/dll/import.hpp @@ -11,10 +11,13 @@ #include #include #include -#include #include #include +#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +# include +#endif + #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif @@ -26,21 +29,32 @@ namespace boost { namespace dll { + namespace detail { + template - class refc_function { + class library_function { boost::shared_ptr lib_; - T* func_ptr_; + T& f_; public: - refc_function(const boost::shared_ptr& lib, T* func_ptr) BOOST_NOEXCEPT + library_function(const boost::shared_ptr& lib, T* func_ptr) BOOST_NOEXCEPT : lib_(lib) - , func_ptr_(func_ptr) + , f_(*func_ptr) {} +#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) operator T*() const BOOST_NOEXCEPT { - return func_ptr_; + return &f_; // it is safe to take address using `&`, because `f_` is guaranteed not to be an object and `operator&` could not be redefined. } +#else + template + inline auto operator()(Args&&... args) const + -> decltype( f_(static_cast(args)...) ) + { + return f_(static_cast(args)...); + } +#endif }; template @@ -48,8 +62,13 @@ namespace detail { template struct import_type >::type> { - typedef boost::dll::detail::refc_function base_type; - typedef boost::function type; + typedef boost::dll::detail::library_function base_type; + +#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + typedef boost::function type; +#else + typedef boost::dll::detail::library_function type; +#endif }; template @@ -66,8 +85,8 @@ namespace detail { /*! -* Returns boost::function or boost::shared_ptr that holds an imported function or variable -* from the loaded library and refcounts usage +* Returns callable object or boost::shared_ptr that holds the symbol imported +* from the loaded library. Teturned value refcounts usage * of the loaded shared library, so that it won't get unload until all copies of return value * are not destroyed. * @@ -86,6 +105,7 @@ namespace detail { * * \code * boost::function f = import("test_lib.so", "integer_func_name"); +* auto f_cpp11 = import("test_lib.so", "integer_func_name"); * \endcode * * \code @@ -98,7 +118,7 @@ namespace detail { * \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*. * \param mode An mode that will be used on library load. * -* \return boost::function if T is a function type, or boost::shared_ptr if T is an object type. +* \return callable object if T is a function type, or boost::shared_ptr if T is an object type. * * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. * Overload that accepts path also throws std::bad_alloc in case of insufficient memory. @@ -143,8 +163,8 @@ BOOST_DLL_IMPORT_RESULT_TYPE import(const boost::filesystem::path& lib, const ch /*! -* Returns boost::function or boost::shared_ptr that holds an imported function or variable -* from the loaded library and refcounts usage +* Returns callable object or boost::shared_ptr that holds the symbol imported +* from the loaded library. Teturned value refcounts usage * of the loaded shared library, so that it won't get unload until all copies of return value * are not destroyed. * @@ -175,7 +195,7 @@ BOOST_DLL_IMPORT_RESULT_TYPE import(const boost::filesystem::path& lib, const ch * \param name Null-terminated C or C++ mangled name of the function or variable to import. Can handle std::string, char*, const char*. * \param mode An mode that will be used on library load. * -* \return boost::function if T is a function type, or boost::shared_ptr if T is an object type. +* \return callable object if T is a function type, or boost::shared_ptr if T is an object type. * * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. * Overload that accepts path also throws std::bad_alloc in case of insufficient memory. diff --git a/test/shared_library_get_symbol_test.cpp b/test/shared_library_get_symbol_test.cpp index 5cd9b07..2341a97 100644 --- a/test/shared_library_get_symbol_test.cpp +++ b/test/shared_library_get_symbol_test.cpp @@ -81,6 +81,20 @@ void refcountable_test(boost::filesystem::path shared_library_path) { BOOST_TEST(*i2 == 100); } + { + boost::function f = import_alias(shared_library_path, "ref_returning_function"); + BOOST_TEST(f() == 0); + + f() = 10; + BOOST_TEST(f() == 10); + + boost::function f1 = import_alias(shared_library_path, "ref_returning_function"); + BOOST_TEST(f1() == 10); + + f1() += 10; + BOOST_TEST(f() == 20); + } + { boost::shared_ptr i = import(shared_library_path, "const_integer_g"); BOOST_TEST(*i == 777); diff --git a/test/test_library.cpp b/test/test_library.cpp index 04a41a5..6aaca1d 100644 --- a/test/test_library.cpp +++ b/test/test_library.cpp @@ -1,5 +1,6 @@ // Copyright 2011-2012 Renato Tegon Forti // Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015, Antony Polukhin. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt @@ -58,6 +59,11 @@ namespace namespace1 { namespace namespace2 { namespace namespace3 { } std::string info("I am a std::string from the test_library (Think of me as of 'Hello world'. Long 'Hello world')."); + + int& ref_returning_function() { + static int i = 0; + return i; + } }}} @@ -67,6 +73,8 @@ BOOST_DLL_ALIAS(foo::variable, foo_variable) BOOST_DLL_ALIAS(namespace1::namespace2::namespace3::do_share, do_share) BOOST_DLL_ALIAS(namespace1::namespace2::namespace3::info, info) BOOST_DLL_ALIAS(const_integer_g, const_integer_g_alias) +BOOST_DLL_ALIAS(namespace1::namespace2::namespace3::ref_returning_function, ref_returning_function) + int integer_g = 100;