diff --git a/include/rcpputils/find_library.hpp b/include/rcpputils/find_library.hpp index fbe8547..2c1b919 100644 --- a/include/rcpputils/find_library.hpp +++ b/include/rcpputils/find_library.hpp @@ -19,6 +19,7 @@ #ifndef RCPPUTILS__FIND_LIBRARY_HPP_ #define RCPPUTILS__FIND_LIBRARY_HPP_ +#include #include #include "rcpputils/visibility_control.hpp" @@ -50,6 +51,17 @@ std::string find_library_path(const std::string & library_name); * empty string when the library does not exist. */ RCPPUTILS_PUBLIC +std::string path_for_library( + const std::filesystem::path & directory, const std::string & library_name); + +/// Overload to disambiguate string-literal calls between the std::filesystem::path +/// and the (deprecated) std::string overloads. +RCPPUTILS_PUBLIC +std::string path_for_library(const char * directory, const std::string & library_name); + +/// \deprecated Use the std::filesystem::path overload instead. +[[deprecated("Use path_for_library(const std::filesystem::path &, ...) instead.")]] +RCPPUTILS_PUBLIC std::string path_for_library(const std::string & directory, const std::string & library_name); /// Create the filename corresponding to the library name. diff --git a/include/rcpputils/shared_library.hpp b/include/rcpputils/shared_library.hpp index 89f5f46..784f5b9 100644 --- a/include/rcpputils/shared_library.hpp +++ b/include/rcpputils/shared_library.hpp @@ -15,6 +15,7 @@ #ifndef RCPPUTILS__SHARED_LIBRARY_HPP_ #define RCPPUTILS__SHARED_LIBRARY_HPP_ +#include #include #include @@ -31,13 +32,38 @@ namespace rcpputils class SharedLibrary { public: + /// The library is loaded in the constructor. + /** + * \param[in] library_path The library filesystem path. + * \throws std::bad_alloc if allocating storage for the callback fails + * \throws std::runtime_error if there are some invalid arguments or the library + * was not load properly + */ + RCPPUTILS_PUBLIC + explicit SharedLibrary(const std::filesystem::path & library_path); + + /// The library is loaded in the constructor. + /** + * This overload exists to disambiguate string-literal calls between the + * std::filesystem::path and the (deprecated) std::string constructors. + * + * \param[in] library_path The library path as a C-string. + * \throws std::bad_alloc if allocating storage for the callback fails + * \throws std::runtime_error if there are some invalid arguments or the library + * was not load properly + */ + RCPPUTILS_PUBLIC + explicit SharedLibrary(const char * library_path); + /// The library is loaded in the constructor. /** * \param[in] library_path The library string path. * \throws std::bad_alloc if allocating storage for the callback fails * \throws std::runtime_error if there are some invalid arguments or the library * was not load properly + * \deprecated Use the std::filesystem::path overload instead. */ + [[deprecated("Use SharedLibrary(const std::filesystem::path &) instead.")]] RCPPUTILS_PUBLIC explicit SharedLibrary(const std::string & library_path); diff --git a/src/find_library.cpp b/src/find_library.cpp index 820252d..a49c7f6 100644 --- a/src/find_library.cpp +++ b/src/find_library.cpp @@ -66,16 +66,26 @@ std::string find_library_path(const std::string & library_name) return {}; } -std::string path_for_library(const std::string & directory, const std::string & library_name) +std::string path_for_library( + const std::filesystem::path & directory, const std::string & library_name) { - const std::filesystem::path path = - std::filesystem::path(directory) / filename_for_library(library_name); + const std::filesystem::path path = directory / filename_for_library(library_name); if (std::filesystem::is_regular_file(path)) { return path.generic_string(); } return {}; } +std::string path_for_library(const char * directory, const std::string & library_name) +{ + return path_for_library(std::filesystem::path{directory}, library_name); +} + +std::string path_for_library(const std::string & directory, const std::string & library_name) +{ + return path_for_library(std::filesystem::path{directory}, library_name); +} + std::string filename_for_library(const std::string & library_name) { return kSolibPrefix + library_name + kSolibExtension; diff --git a/src/shared_library.cpp b/src/shared_library.cpp index a3f6a76..d6bf66d 100644 --- a/src/shared_library.cpp +++ b/src/shared_library.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include @@ -21,12 +22,13 @@ namespace rcpputils { -SharedLibrary::SharedLibrary(const std::string & library_path) +SharedLibrary::SharedLibrary(const std::filesystem::path & library_path) { lib = rcutils_get_zero_initialized_shared_library(); + const std::string path_str = library_path.string(); rcutils_ret_t ret = rcutils_load_shared_library( &lib, - library_path.c_str(), + path_str.c_str(), rcutils_get_default_allocator()); if (ret != RCUTILS_RET_OK) { if (ret == RCUTILS_RET_BAD_ALLOC) { @@ -40,6 +42,12 @@ SharedLibrary::SharedLibrary(const std::string & library_path) } } +SharedLibrary::SharedLibrary(const char * library_path) +: SharedLibrary(std::filesystem::path{library_path}) {} + +SharedLibrary::SharedLibrary(const std::string & library_path) +: SharedLibrary(std::filesystem::path{library_path}) {} + SharedLibrary::~SharedLibrary() { if (rcutils_is_shared_library_loaded(&lib)) { diff --git a/test/test_find_library.cpp b/test/test_find_library.cpp index 0c63b0c..f57e7de 100644 --- a/test/test_find_library.cpp +++ b/test/test_find_library.cpp @@ -137,12 +137,13 @@ TEST(test_find_library, library_path) const std::string expected_library_path = pair.first; const std::string test_lib_dir = pair.second; - const std::string test_lib_actual = rcpputils::path_for_library(test_lib_dir, "test_library"); + const std::string test_lib_actual = + rcpputils::path_for_library(std::filesystem::path{test_lib_dir}, "test_library"); // The returned path must point to the same file as the expected path. EXPECT_EQ(test_lib_actual, expected_library_path); const std::string bad_path = rcpputils::path_for_library( - test_lib_dir, + std::filesystem::path{test_lib_dir}, "highly_unlikely_12_library_34567_name_890.txt.exe"); EXPECT_EQ(bad_path, ""); } diff --git a/test/test_shared_library.cpp b/test/test_shared_library.cpp index 3b992a1..f9c00a4 100644 --- a/test/test_shared_library.cpp +++ b/test/test_shared_library.cpp @@ -14,6 +14,7 @@ #include +#include #include #include @@ -34,7 +35,7 @@ TEST(test_shared_library, valid_load) { const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); try { - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); EXPECT_TRUE(endswith(library->get_library_path(), library_name)) << "Expected .../" << library_name << ", got " << library->get_library_path(); @@ -55,7 +56,7 @@ TEST(test_shared_library, failed_test) { // loading a library that doesn't exists std::string library_name = rcpputils::get_platform_library_name("error_library"); try { - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); FAIL(); } catch (...) { } @@ -63,7 +64,7 @@ TEST(test_shared_library, failed_test) { // Loading a valid library library_name = rcpputils::get_platform_library_name("dummy_shared_library"); try { - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); // getting and asking for an unvalid symbol EXPECT_THROW(library->get_symbol("symbol"), std::runtime_error); @@ -73,7 +74,7 @@ TEST(test_shared_library, failed_test) { } try { - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); EXPECT_NO_THROW(library->unload_library()); EXPECT_THROW(library->unload_library(), std::runtime_error); @@ -84,7 +85,7 @@ TEST(test_shared_library, failed_test) { TEST(test_shared_library, has_symbol_string_overload) { const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); // Positive: string overload delegates to const char* overload. EXPECT_TRUE(library->has_symbol(std::string("print_name"))); @@ -95,7 +96,7 @@ TEST(test_shared_library, has_symbol_string_overload) { TEST(test_shared_library, get_symbol_string_overload_throws_on_missing) { const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); EXPECT_THROW( library->get_symbol(std::string("nonexistent_symbol_xyz")), @@ -104,7 +105,7 @@ TEST(test_shared_library, get_symbol_string_overload_throws_on_missing) { TEST(test_shared_library, get_library_path_non_empty) { const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); - auto library = std::make_shared(library_name); + auto library = std::make_shared(std::filesystem::path{library_name}); EXPECT_FALSE(library->get_library_path().empty()); }