I'm failing to change the LogLevel of the wxLog functionalities.
What I would like to achieve: Log everything to a log-file.
In the following sample code logging basically works, but I see only messages with a LogLevel of Warning or Error. I thought that settting a logLevel using wxLog::SetLogLevel(wxLOG_Info); should be enough, but obviously I'm missing something. Any hints?
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/stdpaths.h>
class TestApp : public wxApp
{
public:
virtual bool OnInit();
private:
FILE* m_pLogFile;
};
bool TestApp::OnInit()
{
m_pLogFile = fopen("c:\\tmp\\foo.txt", "a+");
if (m_pLogFile == NULL)
{
return false;
}
wxLogStderr* pFileLogger = new wxLogStderr(m_pLogFile);
delete wxLog::SetActiveTarget(pFileLogger);
wxLog::SetLogLevel(wxLOG_Info);
wxLogError(L"Error");
wxLogWarning(L"Warning");
wxLogInfo(L"Info");
wxLogVerbose(L"Verbose");
wxLogDebug(L"Debug");
wxFrame* pFrame = new wxFrame(NULL, wxID_ANY, L"Title");
pFrame->Show();
return true;
}
wxIMPLEMENT_APP(TestApp);
Due to unfortunate historical reasons wxLogInfo() is actually exactly the same as wxLogVerbose() and for equally unfortunate backwards compatibility reasons, verbose logging must be enabled by explicitly calling wxLog::SetVerbose(true), so without it neither "Info" nor "Verbose" are logged (and with it both would be).
Actually we probably should finally fix this in wxWidgets 3.2, so hopefully it won't work like this in the next version. But for now you need to call SetVerbose() to enable these messages in addition to setting the log level.
Related
I have been trying to figure out why this is happening and maybe it is just due to inexperience at this point but could really use some help.
When I run my code, which is compiled into a DLL using C++20, I get that a debug assertion has failed with the expression being __acrt_first_block == header.
I narrowed down where the code is failing, but the weird part is that it runs just fine when I change the Init(std::string filePath function signature to not contain the parameter. The code is below and hope someone can help.
Logger.h
#pragma once
#include "../Core.h"
#include <memory>
#include <string>
#include "spdlog/spdlog.h"
namespace Ruby
{
class RUBY_API Logger
{
public:
static void Init(std::string filePath);
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return coreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return clientLogger; }
private:
static std::shared_ptr<spdlog::logger> coreLogger;
static std::shared_ptr<spdlog::logger> clientLogger;
};
}
Logger.cpp
namespace Ruby
{
std::shared_ptr<spdlog::logger> Logger::coreLogger;
std::shared_ptr<spdlog::logger> Logger::clientLogger;
void Logger::Init(std::string filePath)
{
std::string pattern{ "%^[%r][%n][%l]: %v%$" };
auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, true);
// Setup the console and file sinks
std::vector<spdlog::sink_ptr> coreSinks;
coreSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
coreSinks.push_back(fileSink);
// Bind the sinks to the core logger.
coreLogger = std::make_shared<spdlog::logger>("RUBY", begin(coreSinks), end(coreSinks));
// Set the Patterns for the sinks
coreLogger->sinks()[0]->set_pattern(pattern);
coreLogger->sinks()[1]->set_pattern(pattern);
// Tell spdlog to flush the file loggers on trace or worse message (can be changed if necessary).
coreLogger->flush_on(spdlog::level::trace);
// Set the default level of the logger
coreLogger->set_level(spdlog::level::trace);
// Do the same for the client logger
std::vector<spdlog::sink_ptr> clientSinks;
clientSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
clientSinks.push_back(fileSink);
clientLogger = std::make_shared<spdlog::logger>("APP", begin(clientSinks), end(clientSinks));
clientLogger->sinks()[0]->set_pattern(pattern);
clientLogger->sinks()[1]->set_pattern(pattern);
clientLogger->flush_on(spdlog::level::trace);
clientLogger->set_level(spdlog::level::trace);
}
}
Entrypoint.h
#pragma once
#ifdef RB_PLATFORM_WINDOWS
extern Ruby::Application* Ruby::CreateApplication();
int main(int argc, char** argv)
{
Ruby::Logger::Init("../Logs/Recent_Run.txt");
RB_CORE_INFO("Initialized the logger.");
auto app = Ruby::CreateApplication();
app->Run();
delete app;
return 0;
}
#else
#error Ruby only supports windows
#endif // RB_PLATFORM_WINDOWS
For anyone else who runs into a similar problem, here is how I fixed it.
Essentially the function signature for the Init() function was the problem. The std::string parameter was causing the debug assertion to fire, my best guess as of right now was because of move semantics but that part I am still not sure on. So there are a couple of ways that I found to fix this.
Method 1:
Make the parameter a const char*. I don't quite like this approach as it then relies on C style strings and if you are trying to write a program in modern C++, this is a huge step backwards.
Method 2:
Make the parameter a const std::string&. Making it a const reference to a string prevents the move semantics (again as far as I know) and the assertion no longer fires. I prefer this fix as it keeps the program in modern C++.
I hope this helps anyone who has similar issues, and be careful with statics and move semantics.
I'm going to preface this question by saying that I am not entirely new to wxWidgets, though I would not consider myself all that experience either.
I'm having a problem which I have narrowed down through testing to be with the wxWidgets wxBoxSizer classes. From what I can tell, I don't think I'm doing anything wrong, and they work while the application is running; however, when the application closes and everything terminates, it seems that about a third of the time it will double-free something and seg fault. I'm writing and building on a linux system, and there doesn't seem to be any problems with anything but these sizers.
I did have many more windows within the HomeFrame class before I stripped it to search for bugs, but the code below still causes the double-free:
I've also looked around StackOverflow and other code forums to see if anyone was having a similar issue, but I couldn't find anything. I'm thinking that it may have something to do with the way I'm storing the sizer pointers in the class as members?
HomeFrame.h:
#pragma once
#include <wx/frame.h>
#include <wx/sizer.h>
namespace qzrgui
{
class HomeFrame: public wxFrame
{
public:
HomeFrame();
~HomeFrame();
private:
// Sizers
wxBoxSizer* _topSizer;
wxBoxSizer* _leftSizer;
wxBoxSizer* _rightSizer;
// Functions
void _setup();
void _createWindows();
};
}
HomeFrame.cpp:
#include "HomeFrame.h"
namespace qzrgui
{
HomeFrame::HomeFrame() :
wxFrame(nullptr, wxID_ANY, "Quizzer")
{
_setup();
}
HomeFrame::~HomeFrame()
{
}
void HomeFrame::_createWindows()
{
// Create sizers.
_topSizer = new wxBoxSizer(wxOrientation::wxHORIZONTAL);
_leftSizer = new wxBoxSizer(wxOrientation::wxVERTICAL);
_rightSizer = new wxBoxSizer(wxOrientation::wxVERTICAL);
}
void HomeFrame::_setup()
{
_createWindows();
}
}
Quizzer.h (wxApp base class):
#pragma once
#include <wx/app.h>
namespace qzrgui
{
class Quizzer : public wxApp
{
public:
virtual bool OnInit();
};
};
Quizzer.cpp:
#include "Quizzer.h"
wxIMPLEMENT_APP(qzrgui::Quizzer);
#include "frames/HomeFrame.h"
namespace qzrgui
{
bool Quizzer::OnInit()
{
wxFrame* frame = new HomeFrame();
frame->Show(true);
return true;
}
}
There is nothing in the code shown here which could result in a crash. You do definitely have (three) memory leak(s) in your code, as you create 3 sizers not associated with any window or another sizer and never delete them, but, while wrong, this can't result in a crash.
There is also not enough information to diagnose what you're seeing. As always with a crash, please build your code with debug information and run it under debugger to see what exactly happens. If you're under a Unix-like system (or even under MSW with the latest MSVS 2019 version), you should also compile with address sanitizer enabled to find the real problem before the crash happens.
Overview
I am trying to develop a C++ application which allows for user-created plugins.
I found a nice library called Pluma (http://pluma-framework.sourceforge.net/) which functionally seems to be exactly what I want.
After going through their tutorial, I was able to (with a bit of difficulty) convince the plugin to compile. However, it refuses to play nice and connect with the main program; returning various errors depending on how I try to implement them.
Problem
If I comment out the line labeled 'Main problem line' (in the last file, main.cpp), the plugin compiles successfully, and the main app can recognize it, but it says that "Nothing registered by plugin 'libRNCypher'", and none of the functions can be called.
If I compile that line, the main application instead says "Failed to load library 'Plugins/libRNCypher.so'. OS returned error: 'Plugins/libRNCypher.so: undefined symbol: _ZTIN5pluma8ProviderE".
My guess is that it has something to do with the way the plugin was compiled, as compiling it initially did not work and Code::Blocks told me to compile with "-fPIC" as a flag (doing so made it compile).
Code
Code below:
Main.cpp
#include "Pluma/Pluma.hpp"
#include "CryptoBase.h"
int main()
{
pluma::Pluma manager;
manager.acceptProviderType< CryptoBaseProvider >();
manager.loadFromFolder("Plugins", true);
std::vector<CryptoBaseProvider*> providers;
manager.getProviders(providers);
return 0;
}
CryptoBase.h
#ifndef CRYPTOBASE_H_INCLUDED
#define CRYPTOBASE_H_INCLUDED
#include "Pluma/Pluma.hpp"
#include <string>
#include <vector>
#include <bitset>
//Base class from which all crypto plug-ins will derive
class CryptoBase
{
public:
CryptoBase();
~CryptoBase();
virtual std::string GetCypherName() const = 0;
virtual std::vector<std::string> GetCryptoRecApps() const = 0;
virtual void HandleData(std::vector< std::bitset<8> > _data) const = 0;
};
PLUMA_PROVIDER_HEADER(CryptoBase)
#endif // CRYPTOBASE_H_INCLUDED
RNCypher.h (This is part of the plugin)
#ifndef RNCYPHER_H_INCLUDED
#define RNCYPHER_H_INCLUDED
#include <string>
#include <vector>
#include <bitset>
#include "../Encoder/Pluma/Pluma.hpp"
#include "../Encoder/CryptoBase.h"
class RNCypher : public CryptoBase
{
public:
std::string GetCypherName() const
{
return "RNCypher";
}
std::vector<std::string> GetCryptoRecApps() const
{
std::vector<std::string> vec;
vec.push_back("Storage");
return vec;
}
void HandleData(std::vector< std::bitset<8> > _data) const
{
char letter = 'v';
_data.clear();
_data.push_back(std::bitset<8>(letter));
return;
}
};
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase);
#endif // RNCYPHER_H_INCLUDED
main.cpp (This is part of the plugin)
#include "../Encoder/Pluma/Connector.hpp"
#include "RNCypher.h"
PLUMA_CONNECTOR
bool connect(pluma::Host& host)
{
host.add( new RNCypherProvider() ); //<- Main problem line
return true;
}
Additional Details
I'm compiling on Ubuntu 16.04, using Code::Blocks 16.01.
The second error message seems to not come from Pluma itself, but a file I also had to link, #include <dlfcn.h> (which might be a Linux file?).
I would prefer to use an existing library rather than write my own code as I would like this to be cross-platform. I am, however, open to any suggestions.
Sorry for all of the code, but I believe this is enough to reproduce the error that I am having.
Thank You
Thank you for taking the time to read this, and thank you in advance for your help!
All the best, and happy holidays!
I was not able to reproduce your problem, however looking at
http://pluma-framework.sourceforge.net/documentation/index.htm,
I've noticed that:
in your RNCypher.h file you miss something like
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase)
it seems also that there's no file CryptoBase.cpp containing something like
#include "CryptoBase.h"
PLUMA_PROVIDER_SOURCE(CryptoBase, 1, 1);
finally, in CryptoBase.h I would declare a virtual destructor (see Why should I declare a virtual destructor for an abstract class in C++?) and provide a definition to it, while you should not declare a default constructor without providing a definition to it (see for instance Is it correct to use declaration only for empty private constructors in C++?); of course the last consideration is valid unless there's another file in which you have provided such definitions.
This happens on all platforms but this description is for iPhone 5s 8.4 simulator, through the Xcode.
I have been working on the game using C++ and cocos2d-x version 3.6 and Cocostudio 2.3.1. All was fine until i updated to the official release of cocos 3.7. App started getting crashes. One of those is particularly interesting regarding UIPageView. So my header and cpp files are like that:
MKEpochSelectionScene.h
#include "cocos2d.h"
#include "cocos-ext.h"
#include <cocos/ui/CocosGUI.h>
class MKEpochSelectionScene : public cocos2d::Scene {
public:
bool init();
CREATE_FUNC(MKEpochSelectionScene);
private:
cocos2d::ui::PageView * mainPageView;
void previousEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
void nextEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
void showEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
};
MKEpochSelectionScene.cpp
#include "MKEpochSelectionScene.h"
#include <editor-support/cocostudio/CocoStudio.h>
#include "MKGameScene.h"
#include "MKLevelSelectionScene.h"
USING_NS_CC;
bool MKEpochSelectionScene::init()
{
if(!Scene::init()) return false;
auto node = CSLoader::createNode("UI/Epoch/Layer.csb");
this->addChild(node);
auto buttonLeft = node->getChildByName<ui::Button *>("Button_Left");
CCASSERT(buttonLeft != nullptr, "Button left is null");
buttonLeft->addTouchEventListener(CC_CALLBACK_2(MKEpochSelectionScene::nextEpoch,this));
auto buttonRight = node->getChildByName<ui::Button *>("Button_Right");
CCASSERT(buttonRight != nullptr, "Button right is null");
buttonRight->addTouchEventListener(CC_CALLBACK_2(MKEpochSelectionScene::previousEpoch,this));
//******CRASHING LINE
mainPageView = (cocos2d::ui::PageView *)node->getChildByName("selectEpoch");
//******CRASHING LINE
CCASSERT(mainPageView != nullptr, "Main pageview is nil");
CCASSERT(mainPageView->getPages().size() > 0, "Page view has zero pages");
return true;
}
//Other methods
//....
}
Sooo.... The thing happens with the mainPageView. Crash occurs on the line where i reference UIPageView from the design file and assign it to the mainPageView ivar. Crash does not say anything, but crashes in the NavMesh file at the following:
So it crashes when i try to pushscene as to switch to this scene from mainMenu. There is one more thing... If i use local variable like: auto mainPageView instead of ivar in the init() method, it does not crash. And if i comment the UIPageView referencing at all e.g. crashing line - it does not crash.
What i have tried: Updated Cocostudio to 2.3.1.1 which is the latest. Republished all of the UI using that new version. Cleaned all caches and stuff of the build. Updates to the new cocos engine version by creating new project with the new version and copying over files from the old version and importing into the project. This is just to say that i have tried several things.
Any help would be appreciated. And i am sure this might be a silly mistake of mine...
Cheers!
I think you are triggering this bug:
https://github.com/cocos2d/cocos2d-x/issues/12962
It is going to fixed in v3.7.1
I'm having a strange issue when compiling an open source library. When compiling for the device, Xcode compiles it just fine and deploys it no problem. However, when I compile for the simulator, I get duplicate symbol errors during the linking phase.
I've checked a few of these out, and it seems these symbols were all implemented in the .hh file as opposed to the .m file. Obviously this is bad code structure, and the errors make sense. However, what doesn't make sense is why there are no errors for the device build.
Each of these .hh files contains #pragma once at the top of the file. My initial thought was that this wasn't working as expected, but upon removal I get compile-time errors for both device and simulator builds stating I've redefined these symbols. Hmm, so I then tried replacing #pragma once with
#ifndef EXAMPLE_DEFINE
#define EXAMPLE_DEFINE
// code
#end if
But this yields identical results to the #pragma once.
Due to the sheer number of code changes that would be required, it isn't feasible for me to go through and fix every error manually, especially since I'll want to be able to update the codebase easily. So is there any reason this is not failing for the device, and how I could make simulator builds perform the same way?
EDIT: I've also tested using #import instead of #include, but it too yields the same results
EDIT 2: After more testing, I've found that if I define a Preprocessor macro in the target's build settings, the code inside the #ifndef never gets called, as is expected. For whatever reason, it looks like defining the new definition in the .hh file isn't being carried over into the next compilation of the file.
Also, as requested, here's an excerpt from the build log
duplicate symbol __ZZN12DelegateFuncIFvR16DualTextMenuItemRKN5Input5EventEEEC1IZN25MultiChoiceSelectMenuItem4initEPPKciiibSB_P12ResourceFaceEUlS1_S5_E_EERKT_PNSt3__19enable_ifIXntsr3std11is_functionISG_EE5valueEvE4typeEENKS8_ISF_EUlRKNS7_7StorageES1_S5_E_cvPFvSR_S1_S5_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/Main-FB93852047D42061.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/OptionView.o
duplicate symbol __ZZN12DelegateFuncIFbiRKN5Input5EventEEEC1IZN15MultiChoiceView4initER19MultiChoiceMenuItemb9_2DOriginEUliS3_E_EERKT_PNSt3__19enable_ifIXntsr3std11is_functionISC_EE5valueEvE4typeEENKS6_ISB_EUlRKNS5_7StorageEiS3_E_cvPFbSN_iS3_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/Main-FB93852047D42061.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/OptionView.o
duplicate symbol __ZZN12DelegateFuncIFvR12TextMenuItemRKN5Input5EventEEEC1IN14YesNoAlertView2noMUlS1_S5_E_EEERKT_PNSt3__19enable_ifIXntsr3std11is_functionISB_EE5valueEvE4typeEENKS8_ISA_EUlRKNS7_7StorageES1_S5_E_cvPFvSM_S1_S5_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/ButtonConfigView.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/MenuView.o
ld: 16 duplicate symbols for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
and here's one of the offending files (AlertView.hh):
#pragma once
#include <gui/View.hh>
#include <gui/MenuItem/MenuItem.hh>
#include <util/gui/BaseMenuView.hh>
#include <util/rectangle2.h>
#include <util/DelegateFunc.hh>
class AlertView : public View
{
public:
constexpr AlertView() { }
Rect2<GC> labelFrame;
Gfx::Text text;
BaseMenuView menu;
Rect2<int> rect;
Rect2<int> &viewRect() { return rect; }
void init(const char *label, MenuItem **menuItem, bool highlightFirst);
void deinit() override;
void place() override;
void inputEvent(const Input::Event &e) override;
void draw(Gfx::FrameTimeBase frameTime) override;
};
class YesNoAlertView : public AlertView
{
public:
YesNoAlertView() { }
typedef DelegateFunc<void (const Input::Event &e)> InputDelegate;
MenuItem *menuItem[2] = {nullptr};
// Optional delegates
InputDelegate &onYes() { return onYesD; }
InputDelegate &onNo() { return onNoD; }
void init(const char *label, bool highlightFirst, const char *choice1 = nullptr, const char *choice2 = nullptr)
{
yes.init(choice1 ? choice1 : "Yes"); menuItem[0] = &yes;
no.init(choice2 ? choice2 : "No"); menuItem[1] = &no;
assert(!onYesD);
assert(!onNoD);
AlertView::init(label, menuItem, highlightFirst);
}
void deinit() override
{
logMsg("deinit alert");
AlertView::deinit();
onYesD = {};
onNoD = {};
}
InputDelegate onYesD;
InputDelegate onNoD;
private:
TextMenuItem yes
{
[this](TextMenuItem &, const Input::Event &e)
{
auto callback = onYesD;
removeModalView();
if(callback) callback(e);
}
};
TextMenuItem no
{
[this](TextMenuItem &, const Input::Event &e)
{
auto callback = onNoD;
removeModalView();
if(callback) callback(e);
}
};
};
It shows you have tried the header guards but my suggestion is once you check for following
link.
http://en.wikipedia.org/wiki/Include_guard
http://c2.com/cgi/wiki?RedundantIncludeGuards
The update shows it is linker error for symbols and this is for the library you are using.