I have implemented in C++ a simple module system (for demonstrative purpose only). Unfortunately the program is not working correctly (it produces not the expected output, it prints nothing out).
Here is my source code:
module.hpp
#ifndef _MODULE_HPP
#define _MODULE_HPP
#include <memory>
/// Interface for modules.
class Module {
public:
virtual void run() = 0;
virtual ~Module(){};
};
/// Symbol of the module construtor function.
const auto MODULE_CONSTRUCTOR_SYMBOL = "create_module";
/// Type of the module constructor function.
using MODULE_CONSTRUCTOR = std::unique_ptr<Module> (*)();
#endif /* _MODULE_HPP */
first.hpp
#ifndef _FIRST_HPP
#define _FIRST_HPP
#include <iostream>
#include "module.hpp"
class First : public Module
{
public:
First();
virtual ~First();
virtual void run();
std::unique_ptr<Module> create_module(void);
};
extern "C"
{
typedef std::unique_ptr<Module> create_first_module_t(void);
std::unique_ptr<Module> create_module(void);
}
#endif /* _FIRST_HPP */
first.cpp
#include "first.hpp"
First::First()
{
}
std::unique_ptr<Module> First::create_module()
{
auto ptr = std::unique_ptr<Module>{};
std::cout << "Creation of first module" << std::endl;
return ptr;
}
First::~First()
{
std::cout << "Destruction of first module" << std::endl;
}
void First::run()
{
std::cout << "Running the first module" << std::endl;
}
second.hpp
#ifndef _SECOND_HPP
#define _SECOND_HPP
#include <iostream>
#include "module.hpp"
class Second : public Module
{
public:
Second();
virtual ~Second();
virtual void run();
std::unique_ptr<Module> create_module(void);
};
extern "C"
{
typedef std::unique_ptr<Module> create_second_module_t(void);
std::unique_ptr<Module> create_module(void);
}
#endif /* _SECOND_HPP */
second.cpp
#include "second.hpp"
Second::Second()
{
}
std::unique_ptr<Module> Second::create_module()
{
auto ptr = std::unique_ptr<Module>{};
std::cout << "Creation of second module" << std::endl;
return ptr;
}
Second::~Second()
{
std::cout << "Destruction of second module" << std::endl;
}
void Second::run()
{
std::cout << "Running the second module" << std::endl;
}
main.cpp
#include <memory>
#include <dlfcn.h>
#include "first.hpp"
#include "second.hpp"
int main(void)
{
if (void* firstModule = dlopen("libFirst", RTLD_NOW))
{
if (create_first_module_t* createFirstModule = (create_first_module_t*)dlsym(firstModule, "create_module"))
{
std::unique_ptr<Module> firstModule(createFirstModule());
firstModule.get()->run();
}
dlclose(firstModule);
}
if (void* secondModule = dlopen("libSecond", RTLD_NOW))
{
if (create_second_module_t* createSecondModule = (create_second_module_t*)dlsym(secondModule, "create_module"))
{
std::unique_ptr<Module> secondModule(createSecondModule());
secondModule.get()->run();
}
dlclose(secondModule);
}
return 0;
}
Here are the instructions for the g++ compiler (on a linux machine):
g++ -Wall -Wextra -shared -fPIC first.cpp -o first.so -ldl
g++ -Wall -Wextra -shared -fPIC second.cpp -o second.so -ldl
g++ -Wall -Wextra -c main.cpp
g++ -o main main.o first.so -ldl
The expected output should be the following:
$ LD_LIBRARY_PATH=. ./main ./first.so
Creation of first module
Running the first module
Destruction of first module
$ LD_LIBRARY_PATH=. ./main ./first.so ./second.so
Creation of first module
Creation of second module
Running the first module
Running the second module
Destruction of first module
Destruction of second module
Something is wrong with my implementation, but I do not know where the mistakes are.
I hope that someone can help me with my problem.
Related
I am trying to created a shared library in c++ and to initialize the library i define a function with __attribute__ ((constructor)) , but this function is not at all getting invoked.
Any idea why __attribute__ ((constructor)) is not getting called here?
lib.h file
#include <iostream>
using namespace std;
class lib {
public:
int i=0;
lib() { i=5; }
~lib() { cout << "calling lib destructor" << endl; }
static lib* getInstance();
void set() { i=i+25; }
int get() { return i; }
private:
static lib Obj;
};
lib.cpp
#include "lib.h"
lib lib::Obj;
lib* lib::getInstance()
{
return &Obj;
}
void __attribute__ ((constructor)) init_fn(void) ;
void init_fn(void)
{
lib::getInstance()->set();
}
i am creating a shared object using below command
g++ -Wall -Wextra -fPIC -shared lib.cpp -Wl,-soname,libfoo.so -o libfoo.so
Once shared library is created , i am linking it with a main program
main.cpp
#include <iostream>
#include "lib.h"
using namespace std;
int main()
{
cout << lib::getInstance()->get() << endl; // Expecting a output of 30, but always getting 5
cout << "End of program" << endl;
return 0;
}
g++ -L./ -Wall -o main main.cpp -lfoo (linking with shared object libfoo.so)
output:
./main
5
End of program
calling lib destructor
init_fn() function with constructor attribute is not at all getting invoked during loading of the shared object libfoo.so.
Tried on various c++ compilers (clang and g++), but i am not able to make it work.
Anything i am doing wrong while creating shared object? Please help me .
I want to dynamically link a shared library and assign a function from it to a std::function. Here is the code:
function.cpp:
#include <array>
#ifdef __cplusplus
extern "C" {
#endif
double function(std::array<double, 1> arg)
{
return arg[0] * 2;
}
#ifdef __cplusplus
}
#endif
main.cpp:
#include <functional>
#include <iostream>
#include <fstream>
#include <array>
#include <functional>
#ifdef __linux__
#include <dlfcn.h>
#endif
int main()
{
void *handle;
double (*function)(std::array<double, 1>);
char *error;
handle = dlopen("/home/oleg/MyProjects/shared_library_test/libFunction.so", RTLD_LAZY);
if (!handle)
{
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror();
*(void **) (&function) = dlsym(handle, "function");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
std::cout << "Native function output: " << function(std::array<double, 1>{ 3.0 }) << std::endl;
dlclose(handle);
std::function<double(std::array<double, 1>)> std_function(*function);
std::cout << "std::function output: " << std_function(std::array<double, 1>{ 3.0 }) << std::endl;
exit(EXIT_SUCCESS);
}
Build shared library:
g++ -Wall -Wextra -g -std=c++17 -shared -o libFunction.so -fPIC function.cpp
Build main:
g++ -Wall -Wextra -g -std=c++17 main.cpp -ldl
Running the program leads to the following output:
Native function output: 6
Segmentation fault
So, as you can see, I successfully compile the library and load it in my main program. However, assigning the function pointer to std::function doesn't work.
Please, help!
You better do conversion in C++ style:
using function_ptr = double (*)(std::array<double, 1>);
function_ptr function = reinterpret_cast<function_ptr>( dlsym(handle, "function") );
But the culprit is that you cannot call this function directly or indirectly through std::function wrapper after you close shared library:
dlclose(handle);
// function cannot be used anymore
note it can be better to use RAII for this:
std::unique_ptr<void *,int(void*)> handle( dlopen("/home/oleg/MyProjects/shared_library_test/libFunction.so", RTLD_LAZY), dlclose );
then you do not need to call dlclose() manually
Note: it is a bad idea to call exit from main() in C++, use return instead, details can be found here Will exit() or an exception prevent an end-of-scope destructor from being called?
I have a small doubt in the compilation of a c++ code along with a shared library.
So I have two files main.cpp and sample.cpp.
main.cpp
#include <iostream>
using namespace std;
#include "sample.h"
myStruct obj;
void populateData() {
obj.s = "hello world";
}
myStruct giveData() {
cout << "Inside main: " << obj.s << endl;
return obj;
}
int main() {
populateData();
}
sample.h
#ifndef SAMPLE_H
#define SAMPLE_H
#include <string>
struct myStruct {
std::string s;
void populateData();
};
myStruct giveData();
#endif
sample.cpp
#include "sample.h"
#include <iostream>
#include <boost/python.hpp>
using namespace std;
void myStruct :: populateData() {
cout << giveData().s;
}
BOOST_PYTHON_MODULE(boosts) {
using namespace boost::python;
class_<myStruct>("struct")
.add_property("s", &myStruct::s)
.def("populateData", &myStruct::populateData)
;
}
I compile the program using
g++ -c -fPIC sample.cpp
g++ -c -fPIC main.cpp
g++ -shared -Wl,-soname,boosts.so -o boosts.so sample.o main.o -lpython2.7 -lboost_python
g++ -o main main.o
./main
Now, when I run the main, it populates the string inside the obj. But when I run a python script, that imports the boosts.so, the obj.s is empty.
I am guessing it is because the library boosts.so is not properly linked with the executable main.
How do I fix this?
So I am supposed to link these 3 files but when I run use.cpp and it tells me there is a problem with print_foo and print so there must be a problem with my linking or declarations;(FYI I am using Xcode to compile)
This is the header file
// my.h (HEADER FILE)
extern int foo;
void print_foo();
void print(int);
This is my.cpp
// my.cpp
#include "my.h"
#include "std_lib_facilities_5.h"
void print_foo() {
cout << foo;
}
void print(int i) {
cout << i;
}
int main() {
return 0;
}
And this is use.cpp
// use.cpp
#include "my.h" /* Declaration made available here */
int foo;
int main() {
foo = 7;
print_foo();
print(99);
return 0;
}
You did not mention how you are compiling them, on unix like systems you can do
$ gcc my.cpp use.cpp -o my
to compile
You must delete the main in
my.cpp
You can't have two main.
Let's say I have the following class:
class bar
{
public:
bar();
void helloworld(int date)
{ std::cout << "Hello world, the date is: " << date << std::endl; }
};
What would I have to do in the interface file to expose the inlined helloworld() method? I looked into the %inline, but it doesn't seem to do what I'm looking for, which is exposing this as a callable method.
Any help would be appreciated
You can do it like this:
/* bar_module.i */
%module bar_module
%{
#include "bar.h"
%}
%include "bar.h"
/* bar.h */
#include <iostream>
class bar
{
public:
bar();
void helloworld(int date)
{ std::cout << "Hello world, the date is: " << date << std::endl; }
};
/* bar.cc */
#include "bar.h"
bar::bar() {}
# test.py
import bar_module
bar_module.bar().helloworld(47)
# Build commands
swig -o bar_module_wrap.cc -python -c++ bar_module.i
g++ -o bar_module_wrap.os -c -fPIC -I/usr/include/python2.7 bar_module_wrap.cc
g++ -o bar.os -c -fPIC -I/usr/include/python2.7 bar.cc
g++ -o _bar_module.so -shared bar_module_wrap.os bar.os
# Test command
python test.py
# Output
Hello world, the date is: 47