Multiple definitions in C++ [duplicate] - c++

This question already has answers here:
How do I create a header-only library?
(4 answers)
Closed 9 years ago.
In a file called gl_ext.h I have the following:
#ifndef GLEXT_H_INCLUDED
#define GLEXT_H_INCLUDED
#include <stdexcept>
#ifdef WIN32
#include <Windows.h>
#include <GL/GL.h>
#include <GL/glext.h>
# define glGetProcAddress(arg) wglGetProcAddress(arg)
#elif __linux__
#include <GL/gl.h>
#include <GL/glext.h>
# include <GL/glx.h>
# define glGetProcAddress(arg) glXGetProcAddress((const GLubyte*)arg)
#endif
PFNGLCREATESHADERPROC glCreateShader = 0;
namespace glext
{
bool load_gl_extensions()
{
static bool loaded = false;
if (loaded) {
return true;
}
if (!glCreateShader) {
glCreateShader =
(PFNGLCREATESHADERPROC)(glGetProcAddress("glCreateShader"));
if (!glCreateShader) {
throw "Failed to load glCreateShader";
}
}
}
}
#endif
When building from within qt creator using the following .pro file
QT += core gui opengl
TEMPLATE = app
TARGET = GLExtensions
INCLUDEPATH += .
LIBS += -lGL
HEADERS += gl_ext.h \
qtrenderer.h
SOURCES += main.cpp \
qtrenderer.cpp
The usage of this "header library" is as follows:
main.cpp
#include <QtGui/QApplication>
#include "qtrenderer.h"
int main(int argc, char * argv[]) {
QApplication app(argc, argv);
QtRenderer *renderer = new QtRenderer();
renderer->show();
app.exec();
}
qtrenderer.h
#ifndef QTRENDERER_H_INCLUDED
#define QTRENDERER_H_INCLUDED
#include <QtCore/QObject>
#include <QtOpenGL/QGLWidget>
#include <gl_ext.h>
class QtRenderer : public QGLWidget
{
Q_OBJECT
private:
QtRenderer(const QtRenderer &other);
QtRenderer &operator = (const QtRenderer &other);
protected:
virtual void paintGL();
virtual void initializeGL();
public:
QtRenderer();
~QtRenderer();
public slots:
virtual void updateGL();
};
#endif
qtrenderer.cpp
#include "qtrenderer.h"
QtRenderer::QtRenderer() :
QGLWidget() {
}
QtRenderer::~QtRenderer() {
}
void QtRenderer::initializeGL() {
try {
glext::load_gl_extensions();
} catch (...) {
throw std::runtime_error("Failed to load needed extensions.");
}
}
void QtRenderer::paintGL() {
swapBuffers();
}
void QtRenderer::updateGL() {
paintGL();
}
When building this source code using
gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
I get the following build errors:
qtrenderer.o: In function `glext::load_gl_extensions()':
/home/mehoggan/Devel/test_gl/./gl_ext.h:28: multiple definition of `glCreateShader'
main.o:/home/mehoggan/Devel/test_gl/./gl_ext.h:28: first defined here
Why is this so?

Well, the header gl_ext.h is included multiple times. Remember that #include is like replacing the #include statement with the content of the file in a copy&paste manner.
You should put the implementation of load_gl_extensions() into a .cpp file, and put only the declaration into the header file.
gl_ext.h:
//...
extern PFNGLCREATESHADERPROC glCreateShader;
namespace glext
{
bool load_gl_extensions();
}
gl_ext.cpp:
#include "gl_ext.h"
PFNGLCREATESHADERPROC glCreateShader = 0;
namespace glext
{
bool load_gl_extensions()
{
static bool loaded = false;
if (loaded) {
return true;
}
if (!glCreateShader) {
glCreateShader =
(PFNGLCREATESHADERPROC)(glGetProcAddress("glCreateShader"));
if (!glCreateShader) {
throw "Failed to load glCreateShader";
}
}
}
}
extern tells the compiler that the variable/function pointer (glCreateShader) is placed in a different compilation unit (every .cpp file is compiled as a different unit). The linker then inserts the correct memory-adress of your variable. Maybe you should do some research on how C++ compilation and linkage works.

The solution to the problem consisted of making the method inlined and declaring the function pointer as static.

Related

Undefined reference when compiling when using header and cpp file with templates in one of them

I've been trying to compile my project and I've encountered some problems when trying so. The error in particular that appears is:
[build] /usr/bin/ld: CMakeFiles/robot_control.dir/main.cpp.o:(.data.rel.ro._ZTVN4comm15cameraInterfaceE[_ZTVN4comm15cameraInterfaceE]+0x10): undefined reference to `comm::Interface<cv::Mat>::callbackMsg()'
My project is organized right now as it follows:
-${HOME_WORKSPACE}
|-main.cpp
|-src
|-communication.cpp
|-communication.hpp
The header file (communication.hpp) is:
#include <opencv2/opencv.hpp>
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <algorithm>
#ifndef COMM_GUARD
#define COMM_GUARD
namespace comm
{
struct lidarMsg
{
float angle_min, angle_increment, range_min, range_max;
int nranges, nintensities;
std::vector<int> ranges;
};
template <typename T>
class Interface
{
public:
Interface() : received{false} {};
virtual void callbackMsg();
bool receptionAccomplished()
{
return this -> received;
}
T checkReceived()
{
return this -> elementReceived;
}
protected:
bool received;
T elementReceived;
};
class cameraInterface : public Interface<cv::Mat>
{
public:
void callbackMsg(ConstImageStampedPtr &msg);
};
class lidarInterface : public Interface<lidarMsg>
{
public:
void callbackMsg(ConstLaserScanStampedPtr &msg);
};
}
#endif
The source file (communication.cpp) is:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
#include "communication.hpp"
#ifndef COMM_CPP_GUARD
#define COMM_CPP_GUARD
namespace comm
{
void cameraInterface::callbackMsg(ConstImageStampedPtr &msg)
{
std::size_t width = msg->image().width();
std::size_t height = msg->image().height();
const char *data = msg->image().data().c_str();
cv::Mat im(int(height), int(width), CV_8UC3, const_cast<char *>(data));
im = im.clone();
cv::cvtColor(im, im, cv::COLOR_RGB2BGR);
this->elementReceived = im;
received = true;
}
void lidarInterface::callbackMsg(ConstLaserScanStampedPtr &msg) {
this->elementReceived.angle_min = float(msg->scan().angle_min());
this->elementReceived.angle_increment = float(msg->scan().angle_step());
this->elementReceived.range_min = float(msg->scan().range_min());
this->elementReceived.range_max = float(msg->scan().range_max());
this->elementReceived.nranges = msg->scan().ranges_size();
this->elementReceived.nintensities = msg->scan().intensities_size();
for (int i = 0; i < this->elementReceived.nranges; i++)
{
if (this->elementReceived.ranges.size() <= i)
{
this->elementReceived.ranges.push_back(std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max));
}
else
{
this->elementReceived.ranges[i] = std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max);
}
}
}
}
#endif
The main file(main.cpp) includes the following header:
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <opencv2/opencv.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
#include <stdlib.h>
#include "src/communication.hpp"
I included the part of the #ifndef /#define /#endif since it is a solution that I found to this kind of problem in other problem. I've been toggling the CMakeLists.txt file but still no solution that could solve this error.
You can't do this:
virtual void callbackMsg();
You have to actually provide the implementation for all template methods within the .h file.

Header Only Library multiple definition errors [duplicate]

This question already has answers here:
multiple definition of a function
(3 answers)
Multiple definition and header-only libraries
(4 answers)
Closed 1 year ago.
I am having trouble in including a header only library. In my main Application when I include the header file it works fine, now when I need to reference some of the classes from it in a different file then I get multiple definition errors. I checked the header only file has #pragma once and #ifndef checks added
Here is the code (webview.h) which is a header only library included here.
Window.h
#pragma once
#include <memory>
#include <filesystem>
#include <webview.h>
namespace HL {
struct Props {
int width;
int height;
std::string title;
Props(const std::string& title = "My Test Application",
uint32_t width = 1600,
uint32_t height = 900)
: title(title), width(width), height(height)
{
}
};
class Window {
public:
Window(const Props& props)
{
init(props);
}
static Window* create(const Props props)
{
return new Window(props);
}
~Window()
{
terminate();
}
void terminate()
{
mWebview.terminate();
}
void init(const Props& props )
{
mProps.width = props.width;
mProps.height = props.height;
mProps.title = props.title;
mWebview = webview::webview(true, nullptr);
mWebview.set_title(mProps.title);
mWebview.set_size(1080, 800, WEBVIEW_HINT_NONE);
std::string uiFile = std::filesystem::current_path().u8string() + std::string("/ui/build/index.html");
mWebview.navigate(std::string("file://") + uiFile);
mWebview.run();
}
private:
webview::webview mWebview;
int mWidth = 1080;
int mHeight = 800;
std::string mTitle = "";
Props mProps;
};
};
Application.h
#pragma once
#include <Focus.h>
#include <string>
#include <memory>
#include "Window.h"
namespace HL
{
class Application : public Focus::Application
{
private:
Window *mWindow;
public:
Application(Focus::Sqlite* db): BaseApplication(db)
{
FOCUS_LOG_INFO("Initializing DB");
db->init();
}
void run()
{
startClients();
mWindow = Window::create(Props("Test Application"));
}
Window& getWindow()
{
return *mWindow;
}
void loadPlugins()
{
}
};
}
EventManager.h
Here is when I include Window.h which has webview.h include I get the linker errors
#pragma once
#include <memory>
#include <sqlite3.h>
#include "Event.h"
#include <string>
#include <json.hpp>
#include <sstream>
#include "Window.h"
using json = nlohmann::json;
namespace HL
{
class EventManager
{
private:
Window mWindow;
sqlite3* mDB;
public:
EventManager(Window& window, sqlite3* db) : mWindow(window), mDB(db) {}
void bindAll();
void persist(Event& event);
};
};
And the errors
/usr/bin/ld: CMakeFiles/hl.dir/src/main.cpp.o: in function `webview_create':
/home/naveed/Projects/hl/desktop/vendor/webview/webview.h:1305: multiple definition of `webview_create'; CMakeFiles/hl.dir/src/EventManager.cpp.o:/home/naveed/Projects/hl/desktop/vendor/webview/webview.h:1305: first defined here
/usr/bin/ld: CMakeFiles/hl.dir/src/main.cpp.o: in function `webview_destroy':

Including header files in C++ (class definition and method implementation)

I have already checked StackOverflow to find the solution to my problem, but I think I might be missing something. I am trying to define a class in a header file (.h) and implement its methods in a cpp file (.cpp), but it does not work.
main.cpp:
#include <iostream>
#include "Message.h"
using namespace std;
int main()
{
Message *t = new (Message);
t->display();
return 0;
}
Message.h:
#ifndef MESSAGE_H_INCLUDED
#define MESSAGE_H_INCLUDED
class Message {
public:
void display();
};
#endif // MESSAGE_H_INCLUDED
Message.cpp:
#include "Message.h"
void Message::display() {
cout << "Hello!";
}
I don't understand why I keep getting the following error
undefined reference to 'Message::display()'
Compile this with the command g++ -std=c++11 Message.cpp main.cpp

C++ using booleans across multiple files

//main.cpp
#include <iostream>
#include "worldActions.h"
using namespace std;
bool worldEvents = false;
void worldReactions(bool world);
int main (int argc, const char * argv[])
{
while (true)
{
if (worldAction == true)
{
worldEvents = true;
worldReactions(worldEvents);
}
else
{
worldEvents = false;
break;
}
}
return 0;
}
//1.cpp
#include <iostream>
#include "worldActions.h"
using namespace std;
bool worldAction;
//header
#ifndef worldActions_h
#define worldActions_h
bool worldAction = true;
#endif /* defined(__asdf_Story__worldActions__) */
When ever extern is used I get linking errors and when it's not I get redefinition errors. How can I fix this so I can use a global boolean?
You use extern bool worldAction; in the header and put the definition in the cpp file.
You are currently compiling a global worldAction into each file which includes your header. If more than one file includes the header or (as in your source file) any other file defines a variable with the same name, you'll get linker errors.
To fix this, change your header to declare the variable only
#ifndef worldActions_h
#define worldActions_h
extern bool worldAction;
#endif /* defined(__Julian_Story__worldActions__) */
and define/initialise it in your source file
#include <iostream>
#include "worldActions.h"
using namespace std;
bool worldAction = true;
use keyword externlike extern bool worldAction; & put definition bool worldAction = true in .cpp file

Cpp Pantheios Log Library, Debug Assertion Failed Error

I have a cpp project, a cpp cli project and a c# win forms project.
I use pantheios log library in my cpp native project. When i try to write log, i take this error :
Here is my codes :
Log.hpp
#ifndef INCLUDE_LOG_HPP
#define INCLUDE_LOG_HPP
#define PANTHEIOS_NO_INCLUDE_OS_AND_3PTYLIB_STRING_ACCESS // Faster compilation
/* Pantheios Header Files */
#include <pantheios/pantheios.hpp> // Pantheios C++ main header
#include <pantheios/inserters/args.hpp> // for pantheios::args
#include <pantheios/backends/bec.file.h> // be.file header
#include "Include/utility.hpp"
/* Standard C/C++ Header Files */
#include <exception> // for std::exception
#include <new> // for std::bad_alloc
#include <string> // for std::string
#include <stdlib.h>
#include <sstream>
#define PSTR(x) PANTHEIOS_LITERAL_STRING(x)
namespace Mtx
{
namespace log
{
class MTXMANAGER Logger
{
public:
void WriteLogIn(const std::string & log_text);
Logger();
~Logger();
};
}
}
#endif
Log.cpp
#include "Log.hpp"
namespace Mtx
{
namespace log
{
PANTHEIOS_EXTERN_C const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PANTHEIOS_LITERAL_STRING("mtx");//
Logger::Logger()
{
char path[MAX_PATH];
GetModuleFileName( NULL, path, MAX_PATH );
std::string::size_type pos = std::string( path ).find_last_of( "\\" );
strcpy(path,std::string( path ).substr( 0, pos).c_str());
std::strcat (path,"\\mtx-%D__.log");
/////
pantheios_be_file_setFilePath(PSTR(path), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_SHARE_ON_WINDOWS, PANTHEIOS_BEID_ALL);
}
Logger::~Logger()
{
}
void Logger::WriteLogIn(const std::string & log_text)
{
pantheios::log_INFORMATIONAL(PSTR(" [1] "),PSTR(log_text));
}
}
}
I take the error at this line :
pantheios::log_INFORMATIONAL(PSTR(" [1] "),PSTR(log_text));
How can i fix this error?
I am afraid I don't have a direct answer for you, but comparing what I have in my solution (which is similar in many aspects with your setup - .NET DLL calling a C++-native DLL, which has Pantheios-logging), here is what I have:
I have a project LOG, which has an InitInstance() and ExitInstance() (and ctors for the CWinApp-derived class - CLogApp)
CLogApp ctor/dtor are empty
The code in InitInstance() and ExitInstance():
BOOL CLogApp::InitInstance()
{
CWinApp::InitInstance();
int panres = pantheios::pantheios_init();
if( panres < 0 )
{
OutputDebugStringA("Could not initialise the Pantheios logging libraries!\n");
util::onBailOut(pantheios::emergency, "Failed to initialise the Pantheios libraries", PANTHEIOS_FE_PROCESS_IDENTITY, /*pantheios::*/pantheios_getInitCodeString(panres));
return FALSE;
}
else
{
pantheios_be_file_setFilePath(CErrorHandler::getLogPath().c_str(), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BEID_LOCAL);
PANTHEIOS_TRACE_NOTICE("STARTING LOGGING");
}
return TRUE;
}
int CLogApp::ExitInstance()
{
PANTHEIOS_TRACE_NOTICE("STOPPING LOGGING");
pantheios_uninit();
return 0;
}
I am not sure if this will help, but this code has been working for me for many years now.