I'm trying to write a C++0x wrapper around dlopen()/dlsym() to dynamically load functions from shared objects:
class DynamicLoader
{
public:
DynamicLoader(std::string const& filename);
template<class Signature>
std::function<Signature> load(std::string const& functionName);
private:
void *itsLibraryHandle;
};
DynamicLoader::DynamicLoader(std::string const& filename)
{
itsLibraryHandle = dlopen(filename.c_str(), RTLD_LAZY);
if(!itsLibraryHandle)
{ /* Throw Some Error */ }
}
template<class Signature>
std::function<Signature> DynamicLoader::load(std::string const& functionName)
{
return <insert magic here> dlsym(itsHandle, functionName.c_str());
}
Is there a way to convert the void* function pointer returned by dlsym into a std::function?
try this:
static_cast<Signature*>()
seems works in VC10
complete test:
#include <functional>
void test()
{}
template <typename Signature>
std::function<Signature> cast(void* f)
{
return static_cast<Signature*>(f);
}
int main()
{
std::function<void()> f = cast<void()>(&test);
return 0;
}
Based on what I see here: http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_pointer.hpp>
template< typename Signature >
std::function<Signature> DynamicLoader::load(std::string const& name)
{
namespace ft = boost::function_types;
typedef typename ft::function_pointer< typename ft::components<Signature>::type >::type fp_t;
fp_t fun_ptr;
*reinterpret_cast<void**>(&fun_ptr) = dlsym(itsHandle, name.c_str());
return fun_ptr;
}
I've never used dlsym so I don't understand why the cast is being done that way and not simply casting dlsym's return like so:
fun_ptr = reinterpret_cast<fp_t>(dlsym(itsHandle, name.c_str());
You just need to cast result of dlsym() call to a proper type. Here's a complete working example:
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <dlfcn.h>
class DynamicLoader
{
public:
DynamicLoader(std::string const& filename) :
m_handle(dlopen(filename.c_str(), RTLD_LAZY))
{
if (!m_handle)
{
throw std::logic_error("can't load library named \"" + filename + "\"");
}
}
template<class T>
std::function<T> load(std::string const& functionName) const
{
dlerror();
void* const result = dlsym(m_handle, functionName.c_str());
if (!result)
{
char* const error = dlerror();
if (error)
{
throw std::logic_error("can't find symbol named \"" + functionName + "\": " + error);
}
}
return reinterpret_cast<T*>(result);
}
private:
void* const m_handle;
};
int main()
{
DynamicLoader const loader("/lib64/libz.so.1");
auto const zlibVersion = loader.load<char const* (void)>("zlibVersion");
std::cout << "zlib version: " << zlibVersion() << std::endl;
return 0;
}
Related
I am following a tutorial on making JIT compiler with LLVM (code is shown below and most recent version of LLVM is used). Everything works other than this line (if I comment this function, code compiles):
return (T)symbol.get().getAddress();
which gives the following error:
JIT.cpp:22:29: error: ‘std::remove_reference_t<llvm::orc::ExecutorAddr> {aka class llvm::orc::ExecutorAddr}’ has no member named ‘getAddress’
return (T)symbol.get().getAddress();
Code
#pragma once
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <memory>
#include <type_traits>
namespace FooLang
{
class JIT
{
private:
std::unique_ptr<llvm::orc::LLJIT> lljit;
public:
JIT(std::unique_ptr<llvm::orc::LLJIT> _lljit) : lljit(std::move(_lljit)) {}
void registerSymbols(
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)> symbolMap) {
auto &mainJitDylib = this->lljit->getMainJITDylib();
llvm::cantFail(mainJitDylib.define(
absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner(
mainJitDylib.getExecutionSession(), this->lljit->getDataLayout())))));
}
template <typename T, typename = std::enable_if_t<std::is_pointer<T>::value && std::is_function<std::remove_pointer_t<T>>::value>>
llvm::Expected<T> lookup(const std::string &name)
{
auto symbol = this->lljit->lookup(name);
if (!symbol)
{
return symbol.takeError();
}
return (T)symbol.get().getAddress();
}
template <typename T, typename = std::enable_if_t<std::is_function<T>::value>>
inline llvm::Expected<T *> lookup(const std::string &name)
{
return this->lookup<T *>(name);
}
static llvm::Expected<JIT> create(std::unique_ptr<llvm::Module> &module, std::unique_ptr<llvm::LLVMContext> &context)
{
auto lljit = llvm::orc::LLJITBuilder().create();
auto &jd = lljit.get()->getMainJITDylib();
jd.addGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess('_')));
if (!lljit)
{
return lljit.takeError();
}
if (auto err = lljit.get()->addIRModule(llvm::orc::ThreadSafeModule(std::move(module), std::move(context))))
{
return std::move(err);
}
return JIT(std::move(lljit.get()));
}
};
} // namespace FooLang
And it is used like following:
int run(IRgen* ir_gen)
{
auto jit = JIT::create(ir_gen->module, ir_gen->llvm_context);
jit->registerSymbols(
[&](llvm::orc::MangleAndInterner interner) {
llvm::orc::SymbolMap symbolMap;
// Add symbols here
symbolMap[interner("printf")] = llvm::JITEvaluatedSymbol::fromPointer(printf);
return symbolMap;
});
auto entry = jit->lookup<int()>("main");
if (!entry)
{
llvm::errs() << entry.takeError();
return 1;
}
return entry.get()();
}
In a recent change auto symbol = this->llvmjit->lookup(name); will return an ExecutorAddr instead of a JITEvaluatedSymbols, see: https://reviews.llvm.org/rG16dcbb53dc7968a3752661aac731172ebe0faf64
Your pasted code returns a template parameter type T and doesn't show the caller so I can't see what you intend to return. My suggestion is that you probably want to use ExecutorAddr::toPtr but I can't be sure.
I'm not sure about this piece of code:
#include <functional>
#include <list>
#include <iostream>
void f() { std::cout << "HI!\n"; }
struct fobj
{
void operator()() const { std::cout << "Bye!\n"; }
};
using slot_t = std::function<void()>;
std::list<slot_t> slot_list;
template<class F>
inline std::size_t insert_slot(F f)
{
auto it = slot_list.insert(slot_list.begin(), f);
return reinterpret_cast<std::size_t>(&*it);
}
inline slot_t& recover_slot(std::size_t conn_id)
{ return *reinterpret_cast<slot_t*>(conn_id); }
int main()
{
std::size_t conn1_id = insert_slot(f);
std::size_t conn2_id = insert_slot(fobj());
recover_slot(conn1_id)(); // HI!
recover_slot(conn2_id)(); // Bye!
}
I don't see the reinterpret_cast<T*>(some_size_t) any different from static_cast<T*>(some_void_ptr), but I'm not really sure how risky the former is.
So I'm trying to use the Cereal library and I've come to an issue I can't seem to overcome. Essentially the doc's say it is possible to deserialize Types with no default constructor. Yet in the implementation notes it says Define a serialize or save/load pair as you normally would yet the serialize/load options cannot be defined in a valid manner if there is no default constructor. I take this to mean, the load_and_construct function takes the place of load. Yet when implementing a relatively simple example seen below.
"main.cpp"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <memory>
#include <cereal/access.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/portable_binary.hpp>
struct string_wrapper {
const std::string str;
string_wrapper(const std::string& _a) : str{_a} {}
template <class Archive>
void save(Archive& _archive) const {
_archive(str);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<string_wrapper>& _construct) {
std::string a;
_archive(a);
_construct(a);
}
};
struct wrapper_of_string_wrappers {
const std::vector<string_wrapper> strs;
wrapper_of_string_wrappers(
const std::vector<string_wrapper>& _a
) : strs{_a} { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
std::vector<string_wrapper> strs;
_archive(strs);
_construct(strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
std::vector<string_wrapper> as;
as.push_back({"Hello"});
as.push_back({"World"});
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs[0].str << " " << (*test).strs[1].str << std::endl;
}
std::cin.get();
return 0;
}
This code obviously is kind of pointless, its just a minimal example to illustrate the problem I'm running into.
From this page
Non-default constructors are currently only supported for serializing pointers
Your problem here is you are trying to serialize non pointer values with no default constructor here
std::vector<string_wrapper> strs;
_archive(strs);
To solve your problem you need either make default constructor for string_wrapper with save/load pair or use string_wrapper as pointer in wrapper_of_string_wrappers.
Here is working code for second option(string_wrapper remains same):
struct wrapper_of_string_wrappers {
//const std::vector<std::unique_ptr<string_wrapper>> strs;
//const string_wrapper strs;
const std::unique_ptr<string_wrapper> strs;
wrapper_of_string_wrappers(
//const std::vector<std::unique_ptr<string_wrapper>>& _a
const string_wrapper _a
) : strs{ new string_wrapper(_a) } { }
wrapper_of_string_wrappers(
const wrapper_of_string_wrappers& w
) : strs{ new string_wrapper(*w.strs) } { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
//std::vector<std::unique_ptr<string_wrapper>> strs;
std::unique_ptr<string_wrapper> strs;
_archive(strs);
_construct(*strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
string_wrapper as("Hello");
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs->str << std::endl;
}
std::cin.get();
return 0;
}
I have the following three files, of which I cannot find the source of an error that it is producing:
Main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include "ResourceHolder.h"
namespace Textures
{
enum ID { Landscape, Airplane, Missile };
}
int main()
{
//...
try
{
ResourceHolder<sf::Texture, Textures::ID> textures;
textures.load(Textures::Airplane, "Airplane.png");
}
catch (std::runtime_error& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
//...
}
ResourceHolder.h
#pragma once
#include <map>
#include <string>
#include <memory>
#include <stdexcept>
#include <cassert>
template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
void load(Identifier id, const std::string& fileName);
Resource& get(Identifier id);
const Resource& get(Identifier id) const;
private:
void insertResource(Identifier id, std::unique_ptr<Resource> resource);
std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
};
ResourceHolder.cpp
#include "ResourceHolder.h"
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& fileName)
{
//Create and load resource
std::unique_ptr<Resource> resource(new Resource());
if (!resource->loadFromFile(fileName)) {
throw std::runtime_error("ResourceHolder::load - Failed to load " + fileName);
}
//If loading was successful, insert resource to map
insertResource(id, std::move(resource));
}
template <typename Resource, typename Identifier>
Resource& ResourceHolder<Resource, Identifier>::get(Identifier id)
{
auto found = mResourcemap.find(id);
assert(found != mResourceMap.end());
return *found->second();
}
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::insertResource(Identifier id, std::unique_ptr<Resource> resource)
{
//Insert and check success
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource)));
assert(inserted.second);
}
If I were to remove the try-catch combination in main.cpp, the code compiles fine; However, if I leave it there it gives me an LNK2019 (Unresolved external symbol) Error.
What is the source of this error, and how would I fix it?
You can't define templates inside .cpp files. They have to be defined in the header so the compiler can see the implementation and generate the specific classes.
Here's a better question/answer on why it is so Why can templates only be implemented in the header file?.
EDIT: What's wrong in the get function
Two things.
First is this auto found = mResourcemap.find(id);. Your map name is incorrect, m should be upper case -> mResourceMap.
Then the line return *found->second();. The map iterator contains a pair, and the first and second members are not functions but data members. You should write return *found->second;.
I would advise you to understand the structures you're working with before using templates. The compile errors with templates are pretty messy and harder to read. Also you could make a separate test program and make a resource manager with no templates to understand your errors more easily, then build the template on top of your working resource manager.
With all the other answers providing you with enough information to why your code don't compile and might not be valid, this is a resource manager i wrote for SFML some time ago, might be of use to you:
HPP FILE:
#ifndef RESOURCEMANAGER_HPP
#define RESOURCEMANAGER_HPP
/************ INCLUDES ***********/
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
class ResourceManager
{
private:
std::map<std::string,std::unique_ptr<sf::Texture>> listImageContainer;
std::map<std::string,std::pair<std::unique_ptr<sf::SoundBuffer>,std::unique_ptr<sf::Sound>>> listSoundContainer;
std::map<std::string,std::unique_ptr<sf::Font>> listFontContainer;
public:
ResourceManager();
std::unique_ptr<sf::Sound>& LoadSound(const std::string);
std::unique_ptr<sf::Font>& LoadFont(const std::string);
std::unique_ptr<sf::Texture>& LoadImage(const std::string);
~ResourceManager();
};
#endif
CPP FILE:
#include "ResourceManager.hpp"
ResourceManager::ResourceManager()
{
}
std::unique_ptr<sf::Sound>& ResourceManager::LoadSound(const std::string _fileName)
{
if (listSoundContainer.find(_fileName) == listSoundContainer.end())
{
std::unique_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer());
if (soundBuffer->loadFromFile("assets/sound/" + _fileName) != false)
{
std::unique_ptr<sf::Sound> sound(new sf::Sound(*soundBuffer));
listSoundContainer[_fileName] = std::make_pair(std::move(soundBuffer), std::move(sound));
return listSoundContainer[_fileName].second;
}
else
{
std::cerr << "Error loading sound..." << std::endl;
}
}
else
{
return listSoundContainer[_fileName].second;
}
}
std::unique_ptr<sf::Font>& ResourceManager::LoadFont(const std::string _fileName)
{
if (listFontContainer.find(_fileName) == listFontContainer.end())
{
std::unique_ptr<sf::Font> font(new sf::Font());
if (font->loadFromFile("assets/font/" + _fileName)!=false)
{
listFontContainer[_fileName] = std::move(font);
return listFontContainer[_fileName];
}
else
{
std::cerr << "Error loading font..." << std::endl;
}
}
else
{
return listFontContainer[_fileName];
}
}
std::unique_ptr<sf::Texture>& ResourceManager::LoadImage(const std::string _fileName)
{
if (listImageContainer.find(_fileName) == listImageContainer.end())
{
std::unique_ptr<sf::Texture> texture(new sf::Texture);
if (texture->loadFromFile("assets/image/" + _fileName)!=false)
{
listImageContainer[_fileName] = std::move(texture);
return listImageContainer[_fileName];
}
else
{
std::cerr << "Error loading image: " << _fileName << std::endl;
}
}
else
{
return listImageContainer[_fileName];
}
}
ResourceManager::~ResourceManager(){}
How to use:
ResourceManager resourceManager;
auto& sound = resourceManager.LoadSound("nice.wav");
auto& image = resourceManager.LoadImage("head.png");
auto& sound2 = resourceManager.LoadSound("nice.wav"); //<--- already loaded
sound.play();
etc...
I'm fairly green when it comes to c++0x, lambda, and such so I hope you guys can help me out with this little problem.
I want to store a bunch of callbacks in a vector and then use for_each to call them when the time is right. I want the callback functions to be able to accept arguments. Here's my code right now. The trouble is in void B::do_another_callbacks(std::string &)
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <vector>
#include <iostream>
#include <algorithm>
class A {
public:
void print(std::string &s) {
std::cout << s.c_str() << std::endl;
}
};
typedef boost::function<void(std::string&)> another_callback;
typedef boost::function<void()> callback;
typedef std::vector<callback> callback_vector;
typedef std::vector<another_callback> another_callback_vector;
class B {
public:
void add_callback(callback cb) {
m_cb.push_back(cb);
}
void add_another_callback(another_callback acb) {
m_acb.push_back(acb);
}
void do_callbacks() {
for_each(m_cb.begin(), m_cb.end(), this);
}
void do_another_callbacks(std::string &s) {
std::tr1::function<void(another_callback , std::string &)> my_func = [] (another_callback acb, std::string &s) { acb(s); }
for_each(m_acb.begin(), m_acb.end(), my_func(_1, s));
}
void operator() (callback cb) { cb(); }
private:
callback_vector m_cb;
another_callback_vector m_acb;
};
void main() {
A a;
B b;
std::string s("message");
std::string q("question");
b.add_callback(boost::bind(&A::print, &a, s));
b.add_callback(boost::bind(&A::print, &a, q));
b.add_another_callback(boost::bind(&A::print, &a, _1));
b.do_callbacks();
b.do_another_callbacks(s);
b.do_another_callbacks(q);
}
I thought I might be able to do something like this...
void do_another_callbacks(std::string &s) {
for_each(m_acb.begin(), m_acb.end(), [&s](another_callback acb) {
acb(s);
});
}
But that doesn't compile in MSVC2010
The problem with the long example is that my_func(_1,s) is evaluated right there and then. You need to use std::bind (or boost::bind) to invoke the function on each element in the range.
The alternative code that you posted does indeed work, but the whole example fails to compile because of the code in do_callbacks:
void do_callbacks() {
for_each(m_cb.begin(), m_cb.end(), this);
}
this is of type B*, which is not callable. If you define a result_type typedef to match the return type of operator() then you could use std::ref(*this) instead. The following code compiles and runs under MSVC10:
#include <functional>
#include <vector>
#include <iostream>
#include <algorithm>
class A {
public:
void print(std::string &s) {
std::cout << s.c_str() << std::endl;
}
};
typedef std::function<void(std::string&)> another_callback;
typedef std::function<void()> callback;
typedef std::vector<callback> callback_vector;
typedef std::vector<another_callback> another_callback_vector;
class B {
public:
void add_callback(callback cb) {
m_cb.push_back(cb);
}
void add_another_callback(another_callback acb) {
m_acb.push_back(acb);
}
void do_callbacks() {
std::for_each(m_cb.begin(), m_cb.end(), std::ref(*this));
}
void do_another_callbacks(std::string &s) {
std::for_each(m_acb.begin(), m_acb.end(), [&s](another_callback acb) {
acb(s);
});
}
typedef void result_type;
void operator() (callback cb) { cb(); }
private:
callback_vector m_cb;
another_callback_vector m_acb;
};
int main() {
A a;
B b;
std::string s("message");
std::string q("question");
b.add_callback(std::bind(&A::print, &a, s));
b.add_callback(std::bind(&A::print, &a, q));
b.add_another_callback(std::bind(&A::print, &a, std::placeholders::_1));
b.do_callbacks();
b.do_another_callbacks(s);
b.do_another_callbacks(q);
}