Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/rcpputils/find_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef RCPPUTILS__FIND_LIBRARY_HPP_
#define RCPPUTILS__FIND_LIBRARY_HPP_

#include <filesystem>
#include <string>

#include "rcpputils/visibility_control.hpp"
Expand Down Expand Up @@ -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.
Expand Down
26 changes: 26 additions & 0 deletions include/rcpputils/shared_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef RCPPUTILS__SHARED_LIBRARY_HPP_
#define RCPPUTILS__SHARED_LIBRARY_HPP_

#include <filesystem>
#include <string>
#include <stdexcept>

Expand All @@ -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);

Expand Down
16 changes: 13 additions & 3 deletions src/find_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 10 additions & 2 deletions src/shared_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <filesystem>
#include <iostream>
#include <string>

Expand All @@ -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) {
Expand All @@ -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)) {
Expand Down
5 changes: 3 additions & 2 deletions test/test_find_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "");
}
Expand Down
15 changes: 8 additions & 7 deletions test/test_shared_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <gtest/gtest.h>

#include <filesystem>
#include <memory>
#include <string>

Expand All @@ -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<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});

EXPECT_TRUE(endswith(library->get_library_path(), library_name)) <<
"Expected .../" << library_name << ", got " << library->get_library_path();
Expand All @@ -55,15 +56,15 @@ 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<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});
FAIL();
} catch (...) {
}

// Loading a valid library
library_name = rcpputils::get_platform_library_name("dummy_shared_library");
try {
auto library = std::make_shared<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});

// getting and asking for an unvalid symbol
EXPECT_THROW(library->get_symbol("symbol"), std::runtime_error);
Expand All @@ -73,7 +74,7 @@ TEST(test_shared_library, failed_test) {
}

try {
auto library = std::make_shared<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});

EXPECT_NO_THROW(library->unload_library());
EXPECT_THROW(library->unload_library(), std::runtime_error);
Expand All @@ -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<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});

// Positive: string overload delegates to const char* overload.
EXPECT_TRUE(library->has_symbol(std::string("print_name")));
Expand All @@ -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<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});

EXPECT_THROW(
library->get_symbol(std::string("nonexistent_symbol_xyz")),
Expand All @@ -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<rcpputils::SharedLibrary>(library_name);
auto library = std::make_shared<rcpputils::SharedLibrary>(std::filesystem::path{library_name});
EXPECT_FALSE(library->get_library_path().empty());
}

Expand Down