How to include external library in your lib? - c++

I am writing a library which itself uses a header-only 3rd-party library.
Currently, even if I build it as a static library, the client code still needs to add that 3rd-party library as well, as it is declared in my library's header file.
What can I do so that everything that's used by my code, ends up in the static library and the client code doesn't have to include what I have included in the header file?
There was a similar question, but the answer doesn't seem to work for me as I am building the static library with all of its dependencies (i.e. the include paths are configured and builds are successful).
To give you a better view, this is how my Core.h looks like:
#ifndef CORE_H
#define CORE_H
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
using namespace py::literals;
typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;
class Core
{
private:
py::scoped_interpreter guard{};
py::object cls;
py::object obj;
py::object startFunc;
py::object stopFunc;
py::object setCpuAffinityFunc;
py::object addCallbackFunc;
py::object removeCallbackFunc;
py::object getCallbacksFunc;
py::dict kwargs;
py::list callbackList;
public:
Core();
Core(bool showFeed);
...
As you can see, the issue here is the Pybind11 header-only library which is used in my code. Unfortunately, since these #include statements are included in my header file, the client code also needs to add pybind11 to their project in order for their project to build.
Is there any other way, other than converting all the py::* to void* and then including the header files in the Core.cpp file?

I found a solution for you. Consider your case: Client uses a library which uses a third library.
This can be assimilated by the following solution:
Client : .exe project is the client who know only Core project
Core : .lib project uses ThirdParty (Header_lib project) and can be used by Client project
Header_lib project is the ThirdParty lib
Solution configuration:
- Client Project depend from Core project:
-Core project depend from Header_Lib project:
In code:
Client create an instance cc of CCore object.
cc call useCoreParty function.
useCoreParty function uses ThirdParty
When i export core.lib:
DUMPBIN /SYMBOLS "G:\Core.lib" | findstr "useThirdParty"
I get:
This means that thirdparty part is included in your core.lib. Therefore, the client does not need to include thirdpaty's libs

I ended up using forward declaration, but not for the Pybind11 classes.
This is what I ended up doing :
//header file
#ifndef CORE_H
#define CORE_H
#include <iostream>
#include <string>
#include <vector>
#include <functional>
struct Wapper;
class Core
{
private:
Wapper* cls;
Wapper* obj;
Wapper* startFunc;
Wapper* stopFunc;
...
public:
Core();
...
};
and in the implementation file :
#include <pybind11/pybind11.h>
...
namespace py = pybind11;
using namespace py::literals;
struct Wrapper
{
py::object obj;
};
py::scoped_interpreter guard{};
Core::Core()
{
this->cls = new PyWrapper();
this->obj = new PyWrapper();
...
auto serviceUtilsModule = py::module::import("Module");
this->cls->obj = serviceUtilsModule.attr("SomeClass");
...
this->obj->obj = this->cls->obj(**kwargs);
...
}
This hides the pybind11 dependency from the client code and achieves what I was after!
Basically I forward declared a new type, made a pointer out of it and defined it inside the core.cpp. and since I defined in core.cpp I have many choices one of which was to add a py::object inside it and use that instead.
Side note:
I noticed the client project had to include Python's include and library folders or otherwise, it will complain about not finding Pybind11! This is truly bizarre! but since the client code will be running in an environment that must have a python package installed, its not an issue!
However, I'd also like to know why this is happening !

Related

Nested header dependencies (ROS, C++)

Short context: I am trying to make a Node working on ROS for a TIAGo robot (https://pal-robotics.com/robots/tiago/). It has a working tutorial node on adjusting its head, which works, but I'd now like to make a customized version of that.
I have neatly separated .cpp and .h files of both my node and the tutorial node. Now, I'd like to borrow some functions and definitions from that tutorial node to make my node work. When I build my ROS workspace using catkin, it yields errors concerning 'undefined reference'. I suspect it might be due to the ways I import headers. Some include headers coincide, and I do not know how to handle 'nested' dependencies. Here's what I mean (I've renamed the nodes to my_node and tutorial_node here for simplicity):
my_node.h
#ifndef MY_NODE_H
#define MY_NODE_H
// Declare included packages
#include <ros/ros.h>
#include <math.h>
#include <geometry_msgs/PointStamped.h>
#include <tutorial_node/tutorial_node.h>
// Declare TIAGo's centered viewpoint as a stamped point
geometry_msgs::PointStamped tiagoCenterView;
// Function declarations
geometry_msgs::PointStamped calculateDesiredPoint(geometry_msgs::PointStamped faceCenter);
int calculateCenterDistance(geometry_msgs::PointStamped point_a, geometry_msgs::PointStamped point_b);
void faceCallback(geometry_msgs::PointStamped msg);
#endif
my_node.cpp
#include "my_node/my_node.h"
{actual code content}
tutorial_node.h
#ifndef TUTORIAL_NODE_H
#define TUTORIAL_NODE_H
// C++ standard headers
#include <exception>
#include <string>
// Boost headers
#include <boost/shared_ptr.hpp>
// ROS headers
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <actionlib/client/simple_action_client.h>
#include <sensor_msgs/CameraInfo.h>
#include <geometry_msgs/PointStamped.h>
#include <control_msgs/PointHeadAction.h>
#include <sensor_msgs/image_encodings.h>
#include <ros/topic.h>
// OpenCV headers
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const std::string windowName = "Inside of TIAGo's head";
static const std::string cameraFrame = "/xtion_rgb_optical_frame";
static const std::string imageTopic = "/xtion/rgb/image_raw";
static const std::string cameraInfoTopic = "/xtion/rgb/camera_info";
// Intrinsic parameters of the camera
cv::Mat cameraIntrinsics;
// Our Action interface type for moving TIAGo's head, provided as a typedef for convenience
typedef actionlib::SimpleActionClient<control_msgs::PointHeadAction> PointHeadClient;
typedef boost::shared_ptr<PointHeadClient> PointHeadClientPtr;
PointHeadClientPtr pointHeadClient;
ros::Time latestImageStamp;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Definitions
void imageCallback(const sensor_msgs::ImageConstPtr& imgMsg);
void onMouse( int event, int u, int v, int, void* );
void createPointHeadClient(PointHeadClientPtr& actionClient);
#endif
tutorial_node.cpp
#include <tutorial_node/tutorial_node.h>
{actual code contents}
In my_node.h, I include tutorial_node.h, which contains some of the includes I actually need for my_node.cpp. For example, I need the pointHeadClient object defined in tutorial_node.h, as well as the actionlib/client/simple_action_client.h. Is that the proper way of including or are those spaghetti headers? If those are, what's the better way to handle this?
I suspect that's where my error is coming from so I'll save you the specifics so that I can figure the actual error out myself once this header problem is clear.

How to link multiple .cpp files in Code::Blocks for a single project?

While following the book C++ For Dummies, I have three files in my CodeBlocks project, main.cpp, Pen.h, and Pen.cpp. They look like this:
main.cpp:
#include <iostream>
#include "Pen.h"
//#include "Pen.cpp"
using namespace std;
int main()
{
Pen MyPen = Pen();
MyPen.test();
}
Pen.h:
#ifndef PEN_H_INCLUDED
#define PEN_H_INCLUDED
//#include "Pen.cpp" // Uncommenting this gives a different error
using namespace std;
class Pen
{
public:
// attributes omitted
// PROTOTYPES:
// other functions omitted
void test();
};
#endif // PEN_H_INCLUDED
Pen.cpp:
#include <iostream>
#include "Pen.h"
using namespace std;
//other function definitions omitted
void Pen::test()
{
cout << "Test successful." << endl;
}
When I run the code as listed above, I get an "undefined reference to `Pen::test()'" error. To fix this, I changed the #include statements at the top of main.cpp to:
#include <iostream>
//#include "Pen.h"
#include "Pen.cpp"
This works as intended and correctly prints out "Test successful."
My question is this: what in the world is the point of putting a function prototype in a header file if I have to import the .cpp file later on anyways?
EDIT: It turns out this was a problem with not knowing how to use Code::Blocks rather than with the C++ language.
Assuming you're using gcc, you can compile and link in one step by supplying multiple .cpp files via the command line.
g++ Pen.cpp main.cpp
clang should be similar.
clang++ Pen.cpp main.cpp
An #include should never reference a .cpp file. At all. There's no good reason to do it. Include your headers and then supply the names of all .cpp files when you compile. If your project gets big and you have too many .cpp files to reasonably list, then it's time to break out a makefile or similar.
In the main.cpp include the header file:
#include "Pen.h"
The Pen.h file it's ok.
You need to add the Pen.cpp file to the project tree.
Go to Project -> Add files... and add Pen.cpp

compile multiple files c++, doesnt name a type

I have a problem compiling multiple files with codeblocks. My problem is that the compiler doesnt recognize the class types that i created. I get the error doesnt name a type. I have add at all header files the #ifndef, #deffine. My files are:
forum.h
#include <list>
#include "thread.h"
class Forum
{
private:
std::list<Forum*> forums;
std::list<Thread*> themata;
}
thread.h
#include <list>
#include "forum.h"
#include "post.h"
class Thread
{
private:
Forum* forum; //gia tin allagi thesis otan ginei stick
int id;
std::list <Post*> lista;
}
post.h
#include "system.h"
class Post
{
private:
System* system;
}
What can i do for that ?
You have a circular header dependency. Use forward declarations to break it. For example, in forum.h, forward declare the Thread class instead of including its header like this:
#include <list>
class Thread;
class Forum
{
private:
std::list<Forum*> forums;
std::list<Thread*> themata;
};
Include the header in forum.cpp.

Swig given "unknown namespace" errors on namespace aliasing

I have a header file like
#include <MyUtils.h> // defines namespace MyUtils, and MyUtils::Math
namespace mum=MyUtils::Math;
class LocalClass{
public:
void eat( const mum::array& arr);
};
I have the usual %{ #include %}, %include structure in my .i file.
When I run swig I get:
Error: Unknown namespace 'MyUtils::Math'
How/why doesn't SWIG know about namespace aliasing?
Is there a work around other than using #ifndef SWIG preprocessor macros? (c.f. this discussion (I need to keep my c++ code independent of swig)
SWIG Version 2.0.4
Suppose to have a header
// MyUtils.h
namespace MyUtils {
namespace Math {
typedef int SomeType;
class array {
//
};
}
}
And another header
// MyHeader.h
#include <MyUtils.h>
namespace mum=MyUtils::Math;
class LocalClass {
public:
void eat( const mum::array& arr);
};
If you SWIG file looks like
// MySwigInterfaceFile.i
%module MySwigModule
#include "MyHeader.h
%include "MyHeader.h"
You run into trouble, SWIG will generate code that cannot compile for a number of reason
1) You need to include all headers, SWIG cannot recurse header, i.e. you must include MyUtils.h in your MySwigInterfaceFile.i before MyHeader.h, the same applies for the inclusion using the %include directive
2) You must write using namespace MyUtils::Math; following the inclusions using #include
3) To make SWIG aware of any typedefs inside nested namespaces, you must write
namespace MyUtils {
namespace Math {
%typedef int SomeType;
}
}
before the inclusions using %include
I recommend programmers to start out with many small projects to get hands-on experience with SWIG.
SWIG does appear to support namespace aliasing. I think the problem is likely in MyUtils.h; maybe there are pre-processor defines that you have to set in order for it to use the namespaces. You can define those on the SWIG command line.

Static Library "Undefined Reference" to object constructor

I'm having this issue where I cannot call the object constructor in main.cpp even after it has been included in main.h. The error message is:
C:\Users\Espresso\Projects\AZRA\Debug/../src/main.cpp:7: undefined reference to `g_editor::LevelEditor::LevelEditor()'
Where main.cpp contains
#include "main.h"
g_editor::LevelEditor g_levelEditor;
and main.h contains:
#include "g_editor/g_editor.h"
g_editor.h contains all of the header files of the objects in the library, which includes the levelEditor. g_editor.h:
#ifndef G_EDITOR_H_
#define G_EDITOR_H_
#pragma once
#include "g_editor/Objects/editor_module.h"
#include "g_editor/Objects/utility_window.h"
#include "g_editor/Objects/prompt_window.h"
#include "g_editor/LevelEditor/LevelEditor.h"
extern g_editor::LevelEditor g_levelEditor;
#endif
And finally, LevelEditor.h contains the constructor and member functions of LevelEditor:
#ifndef G_LEVEL_EDITOR_H_
#define G_LEVEL_EDITOR_H_
#pragma once
#include "../Objects/editor_module.h"
#include "Modules/collisionGrid_module.h"
#include "Modules/HUD_module.h"
#include "Modules/IO_module.h"
#include "Modules/ledge_module.h"
#include "Modules/segment_module.h"
#include "g_level/g_level.h"
using namespace g_level;
namespace g_editor
{
class LevelEditor
{
private:
std::vector<editor_module*> modules;
void loadModules();
public:
static LevelEditor& get()
{
static LevelEditor sSingleton;
return sSingleton;
}
LevelEditor();
~LevelEditor() {};
I apologize for the wall of text, I've been staring at this for a few days now and I have tried reordering the static libraries by precedence (which eliminated all issues save for this one.) Is there a design flaw in my current setup? I am using sSingletons, global externs, and static libraries.
There is no definition of LevelEditor::LevelEditor.
You are either missing a source file, or you forgot to add {}.
Edit: or, if your constructor does not do anything anyway, just remove the declaration.
Either
1) This function is missing:
LevelEditor(); // So now what does this do???? That's what is missing.
or
2) it isn't missing, but you didn't add the source module or library where this function is located to your linker settings.