I'm creating my first GUI application with C++ using gtkmm and Glade.
I had to merge various tutorials, because none I found is supporting Glade in combination with Gtk::Application and various classes.
See the code below:
main.cpp
int main(int argc, char **argv)
{
std::cout << "Start" << std::endl;
auto app = Gtk::Application::create(argc,argv,"org.gtkmm.ex");
auto builder = Gtk::Builder::create();
builder->add_from_file("gui02.glade");
HelloWorld* helloworld;
std::cout << "helloworld compl." << std::endl;
app->run(*helloworld);
return 0;
}
helloworld.hpp
#include <gtkmm.h>
class HelloWorld : public Gtk::Window
{
protected:
Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button *btn1;
Gtk::Label *lb1;
public:
HelloWorld(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade);
protected:
void on_button1_clicked();
};
helloworld.cpp
#include "helloworld.hpp"
using namespace std;
using namespace Gtk;
HelloWorld::HelloWorld(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade) :
Gtk::Window(cobject), builder(refGlade)
{
builder->get_widget("label1", lb1);
builder->get_widget("button1", btn1);
btn1->signal_clicked().connect(sigc::mem_fun(*this, &HelloWorld::on_button1_clicked));
}
void HelloWorld::on_button1_clicked()
{
lb1->set_text("HW!");
}
Compiling using:
g++ main.cpp helloworld.cpp -o main `pkg-config gtkmm-3.0 --cflags --libs`
Result in the command line:
Start
helloworld compl.
Segmentation fault (core dumped)
Debugging with gdb (relevant extract, you get the full output if neccessary)
Glib::RefPtr::operator-> (this=0x7fffffffdd10) at /usr/include/glibmm-2.4/glibmm/refptr.h:260
260 return pCppObject_;
Thread 1 "main" received signal SIGSEGV, Segmentation fault.
0x00007ffff7a4799e in Gtk::Widget::signal_hide() () from /usr/lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
Because I'm quite new to C++ (having some experience with C#), I'm not so used to pointers. Where is the error in this case?
Using a different code, where I create a Window* and use "app->run(*window)" works pretty fine, so the error occurs somewhere in the new app->run() and the outsourcing in class "HelloWorld".
Your code crashes here app->run(*helloworld);
You try to dereference an empty pointer. That pointer does not point to an object in memory.
Do it like this:
HelloWorld* helloworld = new HelloWorld();
std::cout << "helloworld compl." << std::endl;
app->run(*helloworld);
Related
I am trying to compile a GTKmm C++ program using g++ (clang), however I can't seem to find the header files that I need. I have run the installation .sh file for GTK+, and I have also tried directly installing GTKmm via Homebrew, but I am still getting this error:
fatal error: 'gtkmm/button.h' file not found
I thought it would be as simple as adding an include directory, but I have tried searching my hard drive for GTK-related things and am still not finding anything. What should I do?
I am using a Macbook running MacOS Big Sur.
Update:
My code is this:
helloworld.h
#ifndef GTKMM_EXAMPLE_HELLOWORLD_H
#define GTKMM_EXAMPLE_HELLOWORLD_H
#include <gtkmm/button.h>
#include <gtkmm/window.h>
class HelloWorld : public Gtk::Window {
public:
HelloWorld();
virtual ~HelloWorld();
protected:
//Signal handlers:
void on_button_clicked();
//Member widgets:
Gtk::Button m_button;
};
#endif
helloworld.cpp
#include "helloworld.h"
#include <iostream>
HelloWorld::HelloWorld()
: m_button("Hello World") // creates a new button with label "Hello World".
{
// Sets the border width of the window.
set_border_width(10);
// When the button receives the "clicked" signal, it will call the
// on_button_clicked() method defined below.
m_button.signal_clicked().connect(sigc::mem_fun(*this,
&HelloWorld::on_button_clicked));
// This packs the button into the Window (a container).
add(m_button);
// The final step is to display this newly created widget...
m_button.show();
}
HelloWorld::~HelloWorld()
{
}
void HelloWorld::on_button_clicked()
{
std::cout << "Hello World" << std::endl;
}
main.cpp
#include "helloworld.h"
#include <gtkmm/application.h>
int main (int argc, char *argv[]) {
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
HelloWorld helloworld;
//Shows the window and returns when it is closed.
return app->run(helloworld);
}
This code comes from here.
I am compiling by first navigating to the directory of the files listed above, and running g++ main.cpp -o helloworld.
Because I have installed Homebrew, g++ uses clang++.
Ok, I have figured it out.
I needed to install both GTK+ and GTKmm via Homebrew. This put the library into /usr/local/include. Note that the question code still won't work, because it is using the wrong directory (I installed gtk+3 and gtkmm3). Refer to this answer for more information.
I have the following code:
#include <iostream>
class commaNumpunct: public std::numpunct<char> {
protected:
char_type do_decimal_point() const { return ','; }
};
int main(int argc, char** argv) {
std::locale locale;
std::locale locale2(locale, new commaNumpunct());
std::cout.imbue(locale2);
std::cout << 1.43 << std::endl;
return 0;
}
If I compile it normally:
g++ main.cpp
I get:
1,43
as expected. If I compile it:
g++ -fno-rtti main.cpp
I get:
Program received signal SIGSEGV, Segmentation fault.
__cxxabiv1::__dynamic_cast (src_ptr=src_ptr#entry=0x614c20, src_type=0x7ffff7dcb740 <typeinfo for std::locale::facet>,
dst_type=dst_type#entry=0x7ffff7dcd068 <typeinfo for std::locale::facet::__shim>, src2dst=src2dst#entry=-2) at /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/dyncast.cc:72
72 /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/dyncast.cc: No such file or directory.
Is there a way to use locale in this way and simultaneously have RTTI turned off?
Probably not.
Facets are accessed using std::use_facet. The fact that it might throw a bad_cast is a pretty strong indication that is contains a dynamic_cast. So would need RTTI.
I'm developing a fuse filesystem and before calling fuse_main_real() I'm starting a std::thread in a class instance to do some background work.
this->t_receive = new std::thread([this] { this->receive(); });
However, it seems like fuse_main_real() kills this thread when going into background.
If I start the program with the -f option, which tells fuse to stay in the foreground, the problem does not occur and the thread survives.
I'm not sure what fuse does to go into background.
How do I make my thread survive being backgrounded?
Edit: Here's a basic example that exposes the problem:
#define FUSE_USE_VERSION 30
#include <iostream>
#include <thread>
#include <fuse.h>
static void thread_method()
{
while (true)
{
std::cout << "test" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
struct testop : fuse_operations
{ };
static struct testop ops;
int main(int argc, char** argv)
{
std::thread(thread_method).detach();
fuse_main_real(argc, argv, &ops, sizeof(fuse_operations), NULL);
}
Compile with
g++ -D_FILE_OFFSET_BITS=64 `pkg-config --cflags fuse` -lfuse -lpthread -std=c++14 -o test.o test.cpp
Command that works (repeatedly says "test"):
./test.o -f /home/test/testmountpoint
Command that doesn't work and shows the problem (says "test" once):
./test.o /home/test/testmountpoint
The libfuse wiki says that
Miscellaneous threads should be started from the init() method. Threads started before fuse_main() will exit when the process goes into the background.
(This is like my other question but this one is for another thing, even if it's related)
I've got a big issue in my project. I've got a library which handle XML and can throw exception. And, using it for creating a configuration file class show my first bug : exceptions aren't handled in the library, at all, and with every exception.
In the library I wrote :
try {
throw std::exception();
}
catch (...)
{
printf("caught\n");
}
But, the exception isn't handled and call std::terminate immediately :
terminate called after throwing an instance of 'std::exception'
what(): std::exception
The compilation flags are the simplest one : -fPIC -std=c++11 -g -Wall for the library, and -std=c++11 -g -Wall for the executable (plus the libraries and variant build defines). Also, I'm using G++ 5.4.0, under Linux (Linux Mint to be precise).
This is my main :
#include "ns/core/C_Configuration.hpp"
#include <iostream>
using namespace std;
using namespace ns;
int
main (int argc, char** argv)
{
try {
C_Configuration c ("test.xml");
c.load ("test.xml");
} catch (const std::exception& ex) {
cout << ex.what () << endl;
} catch (...) {
cout << "Caught." << endl;
}
return 0;
}
The C_Configuration.hpp :
#include <string>
#include <exception>
namespace ns
{
class C_Configuration
{
public:
C_Configuration (std::string);
bool load (std::string file);
};
} // namespace ns
And, this is the C_Configuration.cpp :
#include "ns/core/C_Configuration.hpp"
#include <cstdio>
using namespace std;
namespace ns
{
C_Configuration::C_Configuration (string)
{ }
bool
C_Configuration::load (string file)
{
try {
throw exception();
} catch (const exception& ex) {
printf ("In C_Configuration : %s\n", ex.what ());
} catch (...) {
printf ("In C_Configuration : caught\n");
}
return true;
}
} // namespace ns
Buid commands :
g++ -m64 -g -shared -fPIC -std=c++11 -o libns_framework.so C_Configuration.cpp
g++ -m64 -g -L. -o exe main.cpp -lns_framework
Note : I give this example, but it works as expected, the exception is caught in the library, not like in my main project. If you want to investigate more, you can check my project code here.
The problem is when :
The try-catch block is inside the library ;
The try-catch block is outside the library ;
In any case, the exception is thrown inside the library. But, exception thrown outside are caught in the executable code :
int
main (int argc, char** argv)
{
try {
throw 1;
} catch (...) {
cout << "Caught" << endl;
}
// Useless code
return 0;
}
This code just write Caught in the output.
So, my question is simple : Is C++ exception not handled within libraries, or I just forgot a compilation flag ? I need to say in the executable code, the exceptions work fine.
Thanks for your help.
EDIT : Oh god, my bad. Problem solved. Into the deepest part of my build configuration, an ld took the place of g++. Now the exception is working fine. Thanks for you help.
Simple. Never use ld with C++. I changed all ld commands in my project to g++ but seems I forgot for this library.
In short, I was using ld for building my library but g++ for the main executable. So the exceptions worked in the executable but not in the library because ld does not includes the C++ libraries which handle the exception system.
According to gcc manual:
if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ or GCJ driver, as appropriate for the languages used in the program, or using the option -shared-libgcc, such that it is linked with the shared libgcc.
Shared libraries (in C++ and Java) have that flag set by default, but not main executables. In any case, you should use it on both.
Test Case:
lib.cpp:
#include "lib.hpp"
#include <string>
#include <iostream>
using namespace std;
int function_throws_int() {
try {
throw 2;
}
catch (...) {
cout << "int throws lib" << endl;
throw;
}
return -1;
}
int function_throws_string() {
try {
throw std::string("throw");
}
catch (...) {
cout << "throws string lib" << endl;
throw;
}
}
lib.hpp:
int function_throws_int();
int function_throws_string();
Compile command line:
g++ -m64 -g -shared-libgcc -shared -fPIC -std=c++11 -o libtest.so lib.cpp
main.cpp:
#include "lib.hpp"
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char ** argv) {
try {
function_throws_int();
}
catch (const string & e) {
cout << "string caught main" << endl;
}
catch (int i) {
cout << "int caught main" << endl;
}
return 0;
}
Compile command line:
g++ -m64 -g -shared-libgcc -o main -L. main.cpp -ltest
Execute:
LD_LIBRARY_PATH=. ./main
Output:
int throws lib
int caught main
I'm on Linux, the question is concerning shared objects of C++ classes.
The problem comes when my shared objects try to use resources linked into the main executable. I have the following codes:
loader.cpp:
#include <dlfcn.h>
#include <iostream>
#include "CommonInfo.h"
using namespace std;
int main(int argc, char** argv) {
for(int i=1; i<argc; ++i) {
string pth = "./";
pth.append(argv[i]);
void* dh = dlopen(pth.c_str(), RTLD_NOW);
if(dh==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo::GetInfoFunc getInfo = (CommonInfo::GetInfoFunc)(dlsym(dh,"getInfo"));
if(getInfo==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo* info = getInfo();
cout << "INFO: " << info->getX() << endl;
delete info;
}
return 0;
}
CommonInfo.h:
#include <string>
class CommonInfo {
public:
typedef CommonInfo* (*GetInfoFunc)();
private:
std::string x;
public:
CommonInfo(const std::string& nx);
std::string getX() const;
};
EDIT:
I accidentaly forgot to ctrl-c + ctrl-v the source of CommonInfo.cpp here. Of course, it is there during compilation, so CommonInfo.cpp:
#include "CommonInfo.h"
CommonInfo::CommonInfo(const std::string& nx) : x(nx) {
}
std::string CommonInfo::getX() const {
return x;
}
A Plugin.h header:
#include "CommonInfo.h"
extern "C" CommonInfo* getInfo();
A very simple Plugin.cpp:
#include <iostream>
#include "Plugin.h"
#include "CommonInfo.h"
using namespace std;
CommonInfo* getInfo() {
return new CommonInfo("I'm a cat!");
}
Compiling is done with:
g++ -rdynamic -ldl -Werror CommonInfo.cpp loader.cpp -o loader
g++ -shared -fPIC -Werror Plugin.cpp -o Plugin.so
Running:
./loader Plugin.so
And there goes the error:
./loader: symbol lookup error: ./Plugin.so: undefined symbol: _ZN10CommonInfoC1ERKSs
Indeed, looking inside Plugin.so with nm Plugin.so | grep -i CommonInfo it gives an 'U' for this symbol (unresolved), which is perfectly ok.
Also, looking inside the binary of loader with nm loader.so | grep -i CommonInfo I could find the symbol with 'T', which is also ok.
Question is, shouldn't dlfcn.h unresolve the symbol in question from the main binary? Without this feature it becomes quite hard to use these stuff... Do I have to write a class factory function for CommonInfo, load it with dlfcn from the plugin and call that?
Thanks in advance,
Dennis
I haven't looked closely at your code, but I have in the past found behavior like you describe in the title when I did not link the executable with -E. (Or -Wl,-E when linking with gcc rather than ld.)
Note that not all platforms let the shared libraries take symbols from the calling binary. Linux and the *BSDs allow you to. But if you ever want to port to, say, Windows, you will not be able to use this pattern. I believe there are also some Unix-type OS's that won't let you do this. (It's been a while so I don't remember... Maybe it was Solaris?)