I am new to Swig and I need help in debugging this error.
My motive is to create a logging system with less time consuming using Swig, C++ , Perl. But i got error while passing the string parameter form Perl to C++ via swig.
I have placed my entire code and error below.
Please help me to solve this issue. Thanks in future.
Logger.cpp
#include <stdexcept>
#include <string>
#include <ctime>
#include "Logger.h"
using namespace std;
Logger* Logger::pInstance = nullptr;
Logger& Logger::instance()
{
lock_guard<mutex> guard(sMutex);
printf("instance");
if (pInstance == nullptr)
pInstance = new Logger();
return *pInstance;
}
void Logger::Cleanup()
{
lock_guard<mutex> guard(Logger::sMutex);
delete Logger::pInstance;
Logger::pInstance = nullptr;
}
Logger::Logger()
{
printf("Constructor\n");
mOutputStream.open("log.out", ios_base::app);
if (!mOutputStream.good()) {
throw runtime_error("Unable to initialize the Logger!");
}
}
void Logger::log(const string& inMessage, const string& inLogLevel)
{
lock_guard<mutex> guard(sMutex);
logHelper(inMessage, inLogLevel);
}
void Logger::logHelper(const std::string& inMessage, const std::string& inLogLevel)
{
mOutputStream << "[ " << current_time() << " ]" << inLogLevel << ": " << inMessage << endl;
}
string Logger::current_time()
{
time_t rawtime;
struct tm * timeinfo;
char buffer[80];
time (&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer,sizeof(buffer),"%d-%m-%Y %H:%M:%S",timeinfo);
std::string str(buffer);
return str;
}
Logger::~Logger(){
printf("deconstructor\n");
mOutputStream.close();
}
Logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <mutex>
class Logger
{
public:
Logger();
~Logger();
Logger& instance();
void log(const std::string& inMessage,
const std::string& inLogLevel);
protected:
static Logger* pInstance;
std::ofstream mOutputStream;
void Cleanup();
void logHelper(const std::string& inMessage,
const std::string& inLogLevel);
std::string current_time();
private:
std::mutex sMutex;
};
#endif
Logger.i
%module Logger
%{
#include "Logger.h"
%}
%include "Logger.h"
ch.pl
use strict;
use warnings;
use Cwd qw( abs_path );
use File::Basename qw( dirname );
use lib dirname(abs_path($0));
use Logger;
my $p=new Logger::Logger();
$p->instance();
$p->log("test message");
Error message*
TypeError in method 'Logger_log', argument 2 of type 'std::string' at ch1.perl line 19.
You need to include a typemap for std::string in your interface file so SWIG knows how to handle the type, see chapter 9.4 in the manual:
9.4.1 std::string The std_string.i library provides typemaps for converting C++ std::string objects to and from strings in the target
scripting language.
%module Logger
%include "std_string.i"
%{
#include "Logger.h"
%}
%include "Logger.h"
If I use this and run ch.pl like this:
use strict;
use warnings;
use lib '.';
use Logger;
my $p = Logger::Logger->new();
$p->instance();
$p->log("test message", "DEBUG");
I get output:
Constructor
instanceConstructor
deconstructor
The content of the log.out file is:
[ 22-05-2020 17:35:12 ]DEBUG: test message
Related
I have a dll with lib.h:
#pragma once
#ifdef EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
extern "C" API void test1(std::vector<ValueType*>* functions);
and lib.cpp:
#include "pch.h"
#include <iostream>
#include <vector>
#include "ValueType.h"
#include "NumberValue.h"
#include "TestLib.h"
void test1(std::vector<ValueType*>* functions) {
functions->push_back(new NumberValue(123321));
And main file, that uses this dll is:
#include <iostream>
#include <vector>
#include <Windows.h>
#include "ValueType.h"
using namespace std;
typedef void (__cdecl* importedInitFunction)(std::vector<ValueType*>*);
importedInitFunction test1F;
std::vector<ValueType*> values;
int main() {
while (1) {
HMODULE lib = LoadLibrary("DllTest1.dll");
test1F = (importedInitFunction)GetProcAddress(lib, "test1");
test1F(&values);
FreeLibrary(lib);
std::cout << values.at(0)->asString();
system("pause");
}
return 0;
}
When I'm trying to compile my code, I catch an error because values.at(0) is removed.
How to prevent deleting my variable when calling FreeLibrary(lib) ? or
How to implement alternative way ?
Another classes that used:
ValueType.h:
#pragma once
#include <string>
class ValueType {
public:
virtual double asDouble() { return 999; }
virtual std::string asString() { return ""; }
};
NumberValue.h:
#pragma once
#include <string>
#include "ValueType.h"
class NumberValue : public ValueType {
public:
double m_value;
NumberValue(double value) : m_value(value) {}
virtual double asDouble() {
return m_value;
}
virtual std::string asString() {
return std::to_string(m_value);
}
};
I've read a lot of questions regarding this matter, but none of them seem to solve my issue. Code below:
Logger.cpp
#include "Includes.h"
namespace DemoProject {
class Logger {
public:
static void Logger::printm(CEGUI::String Message) {
std::cout << currentDateTime() << " >> " << Message << std::endl;
}
private:
static const std::string currentDateTime() {
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%d-%m-%Y %X", &tstruct);
return buf;
}
};
}
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#pragma once
#include "Includes.h"
namespace DemoProject {
class Logger {
public:
static void Logger::printm(CEGUI::String Message);
};
}
#endif
Includes.h
#ifndef INCLUDES_H
#define INCLUDES_H
#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>
#include <CEGUI/CEGUI.h>
#include <CEGUI/RendererModules/OpenGL/GLRenderer.h>
#include <SDL.h>
#include <SDL_opengl.h>
#include "Logger.h"
#endif
Sorry for bad formating of the post, but that's the best I could do. I am mostly a C# developer, but I am trying to learn C++ through doing different exercises I create on my own. From a C# developers view, this code is okay, but I don't know, I'm still a beginner.
There are a couple of things you're doing weird. But the most important is you don't need to declare the class again in the .cpp file. You just implement the functions:
namespace DemoProject {
void Logger::printm(CEGUI::String Message) {
std::cout << currentDateTime() << " >> " << Message << std::endl;
}
static const std::string currentDateTime() {
...
}
}
You also didn't declare currentDateTime in the header, so that won't compile right. You also don't need to scope the class in the declaration since you're already in the class, so your header should look like:
namespace DemoProject {
class Logger {
public:
static void printm(CEGUI::String Message);
static const std::string currentDateTime();
};
}
I've looked around, and I can't quite figure out where I'm going wrong, as I seem to be following the correct convention when using interfaces, but perhaps I'm overlooking something. The exact error I'm getting is:
undefined reference to `vtable for Icommand'
I've only just begun to seperate my classes and class declarations into separate header files, so perhaps I'm missing a preprocessor directive somewhere.
main.cpp:
#include <iostream>
#include <string>
#include <cstdlib>
#include "Icommand.h"
#include "Command.h"
using namespace std;
void pause();
int main(){
Icommand *run = new Command("TEST");
cout << run->getCommand() << endl;
delete run;
pause();
}
void pause(){
cin.clear();
cin.ignore(cin.rdbuf()->in_avail());
cin.get();
}
Icommand.h:
#ifndef ICOMMAND_H
#define ICOMMAND_H
#include <string>
#include <vector>
class Icommand
{
private:
public:
Icommand(){}
virtual ~Icommand(){}
virtual bool run(std::string object1) = 0;
virtual bool run(std::string object1, std::string object2) = 0;
virtual std::string getCommand() const;
};
#endif // ICOMMAND_H
Command.h:
#ifndef COMMAND_H
#define COMMAND_H
#include <string>
#include <vector>
#include "Icommand.h"
class Command : public Icommand {
private:
std::string command;
std::vector<std::string> synonymns;
Command(); // private so class much be instantiated with a command
public:
Command(std::string command) : command(command){}
~Command(){}
bool run(std::string object1);
bool run(std::string object1, std::string object2);
std::string getCommand() const;
};
#endif // COMMAND_H
Command.cpp:
#include <string>
#include <vector>
#include "Command.h"
bool Command::run(std::string object1){
return false;
}
bool Command::run(std::string object1, std::string object2){
return false;
}
std::string Command::getCommand() const {return command;}
In Icommand.h, replace
virtual std::string getCommand() const;
with
virtual std::string getCommand() const = 0;
to make it pure virtual. Then the compiler can generate a vtable for Icommand. Alternatively, implement Icommand::getCommand.
I have a class Cl with public member
static std::ofstream &_rout;
In main file
ofstream out("output.txt");
ofstream& Cl::_rout(out);
But I have a compilation error: illegal definition or redefinition.
How can I correct it?
Try this.
Logger.h
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
class Logger{
public:
static void open( const string & logFile);
static void close();
// write message
static void write( const string & message);
private:
Logger();
ofstream fileStream;
//Logger instance (singleton)
static Logger instance;
};
Logger.cpp
#include "Logger.h"
Logger Logger::instance;
Logger::Logger(){}
void Logger::open( const string& logFile){
instance.fileStream.open(logFile.c_str());
}
void Logger::close(){
instance.fileStream.close();
}
void Logger::write(const string& message){
ostream& stream = instance.fileStream ;
stream << message<< endl;
}
main.cpp
#include "Salida/Logger.h"
int main(){
Logger::open(path);
Logger::write("text");
Logger::close();
return 0;
}
You can only set the reference at the static/global scope
#include<CL.h>
ofstream& Cl::_rout(out);
int main() {
// ...
}
It is not possible to re-set a reference after it was declared (and initialized). You could achieve what you are after by using pointers instead of references:
class Cl {
static std::ofstream* _rout;
};
std::ofstream* CL::_rout = NULL;
int main() {
ofstream out("output.txt");
Cl::_rout = &out;
}
Note that the pointer will be valid only until out goes out of scope. If this is an issue, allocate the memory dynamically:
ofstream* out = new ofstream("output.txt");
Cl::_rout = out;
And don't forget to delete it when you no longer need the object to avoid memory leaks
Well, you could use the following approach:
#include <fstream>
class CI
{
public:
static std::ofstream &_rout;
};
static std::ofstream out("output.txt");
std::ofstream& CI::_rout = out;
int main()
{
}
The problem with this, however, is that the name of the output file is fixed (hard-coded into the program).
I suggest that you use a pointer instead of a reference:
#include <cstddef>
#include <fstream>
class CI
{
public:
static std::ofstream *_rout;
};
std::ofstream* CI::_rout = NULL;
int main()
{
const char *output_file = "output.txt";
std::ofstream out(output_file);
CI::_rout = &out;
}
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.