Run gcc command from Qt Creator 5.4.0 - qt

I am trying to make a little IDE to compile c files. I am running under Ubuntu 14.04 and QtCreator 5.4.0. I wrote this code.
void MainWindow::on_pushButton_clicked()
{
QFile file("hello.c");
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
out << ui->plainTextEdit->toPlainText();
QProcess::execute("gcc hello.c -o hello");
}
Everything is OK until run the gcc command. When I click on the button I get this error:
In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
and my C code is here:
#include <stdio.h>
int main () {
printf("Hello World..");
return 0;
}

You haven't flushed the QTextStream buffer, so hello.c is empty when you call gcc on it. Use QTextStream 's flush() to flush the buffer, it also calls flush on the underlying device (the QFile here).

Related

Accessing an external variable from a C library

I am currently learning C and am trying to understand the possibilities of dynamic libraries.
My current question is, if I have a simple "Hello World" application in C called "ProgA", and this program dynamically loads a shared library with some example code called "LibB", can LibB access a global variable in ProgA, which was declared as external?
Given is the following example code for demonstration of the problem:
file header.h
#ifndef TEST_H
#define TEST_H
typedef struct test_import_s {
int some_field;
} test_import_t;
extern test_import_t newtestimport;
#endif
file prog_a.c
#include <stdio.h>
#include <windows.h>
#include "header.h"
test_import_t newtestimport = {
.some_field = 42
};
int main()
{
HINSTANCE hinstLib;
typedef void (*FunctionPointer)();
newtestimport.some_field = 42;
hinstLib = LoadLibrary("lib_b.dll");
if (hinstLib != NULL)
{
FunctionPointer initialize_lib_b;
initialize_lib_b = (FunctionPointer)GetProcAddress(hinstLib, "initialize_lib_b");
if (initialize_lib_b != NULL)
{
initialize_lib_b();
}
FreeLibrary(hinstLib);
}
return 0;
}
file lib_b.c
#include <stdio.h>
#include "header.h"
test_import_t *timp;
void initialize_lib_b() {
timp = &newtestimport;
int some_field = timp->some_field;
printf("Result from function: %d\n", some_field);
}
file CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(dynamic-library-2 C)
set(CMAKE_C_STANDARD 23)
add_library(lib_b SHARED lib_b.c)
set_target_properties(lib_b PROPERTIES PREFIX "" OUTPUT_NAME "lib_b")
add_executable(prog_a prog_a.c)
target_link_libraries(prog_a lib_b)
In the above example, the headerfile header.h defines the struct test_import_t and an external variable newtestimport using this struct. In the C file of the main program prog_a.c one property of this struct is assigned the value 42. It then dynamically loads the library lib_b.c using the Windows API and executes a function in it. The function then should access the variable newtestimport of the main program and print out the value of the variable (42).
This example does not work. The compiler throws the following error:
====================[ Build | prog_a | Debug ]==================================
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\cmake\win\x64\bin\cmake.exe --build C:\Users\user1\projects\learning-c\cmake-build-debug --target prog_a -j 9
[1/2] Linking C shared library dynamic-library-2\lib_b.dll
FAILED: dynamic-library-2/lib_b.dll dynamic-library-2/liblib_b.dll.a
cmd.exe /C "cd . && C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin\gcc.exe -fPIC -g -Wl,--export-all-symbols -shared -o dynamic-library-2\lib_b.dll -Wl,--out-implib,dynamic-library-2\liblib_b.dll.a -Wl,--major-image-version,0,--minor-image-version,0 dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin/ld.exe: dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj:lib_b.c:(.rdata$.refptr.newtestimport[.refptr.newtestimport]+0x0): undefined reference to `newtestimport'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
How can the example be fixed to accomplish the described goal?
Windows DLLs are self-contained, and can not have undefined references similar to newtestimport, unless these references are satisfied by another DLL.
How can the example be fixed to accomplish the described goal?
The best fix is to pass the address of newtestimport into the function that needs it (initialize_lib_b() here).
If for some reason you can't do that, your next best option is to define the newtestimport as a dllexport variable in another DLL, e.g. lib_c.dll.
Then both the main executable and lib_b.dll would be linked against lib_c.lib, and would both use that variable from lib_c.dll.
P.S. Global variables are a "code smell" and a significant source of bugs. You should avoid them whenever possible, and in your example there doesn't seem to be any good reason to use them.

Why do QProcess (Qt 5.15.1) and GDB lead to missing symbols?

I am currently having some trouble debugging a program that starts processes via QProcess.
Simply executing the binary without dbg works just fine but when I try to debug the executable with gdb I am getting a SIGTRAP when the process has started.
After that the stack always shows '??' instead of function names.
When continuing I get a SIGILL.
I found out that the trap is not caused when no breakpoint is set.
In my project I also get following output:
Probes-based dynamic linker interface failed.
I am not sure whether this is related to loaded plugins or libraries.
The problem can be reproduced (except from the " Probes-based dynamic linker interface failed." output) with the following code:
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QProcess proc;
QString exe = "echo";
QStringList arguments;
arguments << "Test";
proc.start(exe, arguments);
if (!proc.waitForFinished()) {
qDebug() << "failed to start" << proc.exitCode() << proc.errorString();
}
qDebug() << "process finished";
qDebug() << proc.readAllStandardOutput();
return a.exec();
}
My OS is arch linux (up to date)
Qt5: qt5-base 5.15.1-1
GDB: gdb 9.2-1
clang++: clang 10.0.1-1
Does anybody have an idea what is causing the SIGTRAP when debugging with dbg?

Qt output (qDebug qWarning etc) does not work if application is executed via cronjob

I created a reproduction sample for this:
#include <iostream>
#include <QtCore/QLoggingCategory>
#include <QtCore/QDebug>
#include <QtCore/QtCore>
using namespace std;
int main () {
int i;
QLoggingCategory::setFilterRules("*.debug=true\n");
QLoggingCategory LogO(NULL);
if (LogO.isDebugEnabled()) {
cout << "QDebug enabled\n";
} else {
cout << "QDebug disabled!\n";
}
cout << "Start!\n";
qDebug() << "qStart!";
cerr << "print to stderr.\n";
qWarning() << "qWarning";
return 0;
}
Build steps:
g++ -c -fPIC -I/usr/include/qt5 main.cpp -o main.o
g++ -fPIC main.o -L /usr/lib64 -lQt5Core -o testapp
When executing the application in an interactive shell, output redirection works as expected:
Setup:
./testapp > out 2> err
Output:
>>cat out:
QDebug enabled
Start!
>>cat err:
qStart!
print to stderr.
qWarning
However, it does not work if the application is executed as a cronjob, the output of qDebug() and qWarning() is missing:
Setup:
* * * * * username /home/username/temp/build/testapp 1> /home/username/temp/log/out 2> /home/username/temp/log/err
Output:
>>cat /home/username/temp/log/out
QDebug enabled
Start!
>>cat home/username/temp/log/err
print to stderr.
Enviroment vars
The output of env in the interative shell is as follows:
LS_COLORS=*long string*
SSH_CONNECTION=*censored*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=492
USER=username
SELINUX_ROLE_REQUESTED=
PWD=/home/username/temp/build
HOME=/home/username
SSH_CLIENT=*censored*
SELINUX_LEVEL_REQUESTED=
SSH_TTY=/dev/pts/0
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
HISTSIZE=1000
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env
OLDPWD=/home/username/temp/build/logs
The output of env when called via cronjob is as follows:
LS_COLORS=*long string*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=995
USER=username
PWD=/home/username
HOME=/home/username
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env
The issue is that qt behaves differently depending if it thinks that it is running in an (interactive?) terminal or not.
Quote:
One pitfall to be aware of: the destination of logging depends on an environment variable. If the variable QT_LOGGING_TO_CONSOLE is set to 1, the message functions will always log to the console. If set to 0, they will not log to the console, and will instead log to syslog, if enabled. When the environment variable is not set, the message functions log to a console if one is present (i.e. if the program is attached to a terminal). Thus, to ensure that the output of our example program goes to syslog, I set the environment variable to 0 within the program.
Therefore, the output of qDebug, QWarning etc. when executed from cron was not output via stderr, but directly handed over to journald.
TL;DR: quickfix: add QT_LOGGING_TO_CONSOLE=1 to /etc/crontab
.
.
PS: note if you need to debug an issue with QDebug:
be aware of this: https://bugzilla.redhat.com/show_bug.cgi?id=1227295
you can add QT_LOGGING_DEBUG=1 as an environment variable to make
qt output changes in logging behavior during execution.
cronjob redirects output and err to email address.
add >> /tmp/myscript.log 2>&1 in your crontab entry.
see this answer

breakpad not generate minidump on erase iterator twice

I find breakpad does not handle sigsegv sometimes.
and i wrote a simple example to reproduce it:
#include <vector>
#include <breakpad/client/linux/handler/exception_handler.h>
int InitBreakpad()
{
char core_file_folder[] = "/tmp/cores/";
google_breakpad::MinidumpDescriptor descriptor(core_file_folder);
auto exception_handler_ =
new google_breakpad::ExceptionHandler(descriptor,
nullptr,
nullptr,
nullptr,
true,
-1);
}
int main()
{
InitBreakpad();
// int* ptr = nullptr;
// *ptr = 1;
std::vector<int> sum;
sum.push_back(1);
auto it = sum.begin();
sum.erase(it);
sum.erase(it);
return 0;
}
and gcc is 4.8.5 and my comiple cmd is
g++ test_breakpad.cpp -I./include -I./include/breakpad -L./lib -lbreakpad -lbreakpad_client -std=c++11 -lpthread
run a.out, get "Segmentation fault" but no minidump is generated.
if i uncomment nullptr write, breakpad works!
what should i do to correct it?
GDB debug output:
(gdb) b google_breakpad::ExceptionHandler::~ExceptionHandler()
Breakpoint 2 at 0x402ed0: file src/client/linux/handler/exception_handler.cc, line 264.
(gdb) c
The program is not being run.
(gdb) r
Starting program: /home/zen/tmp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Breakpoint 1, google_breakpad::ExceptionHandler::ExceptionHandler (this=0x619040, descriptor=..., filter=0x0, callback=0x0, callback_context=0x0, install_handler=true, server_fd=-1) at src/client/linux/handler/exception_handler.cc:224
224 ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
Missing separate debuginfos, use: debuginfo-install glibc-2.17-157.el7_3.1.x86_64 libgcc-4.8.5-11.el7.x86_64 libstdc++-4.8.5-11.el7.x86_64
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6
(gdb) c
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
and i tried breakpad out of process dump, but still got nothing(nullptr write works).
After some debugging I think that the reason that the sum.erase(it) does not create a minidump in your example is due to stack corruption.
While debugging you can see that the variable g_handler_stack_ in src/client/linux/handler/exception_handler.cc is correctly initialized and the google_breakpad::ExceptionHandler instance is correctly added to the vector. However when google_breakpad::ExceptionHandler::SignalHandler is called the vector is reported empty despite no calls to google_breakpad::ExceptionHandler::~ExceptionHandler or any of the std::vector methods that would change the vector.
Some further data points that point to stack corruption is that the code works with clang++. Additionally, as soon as we change the std::vector<int> sum; to a std::vector<int>* sum, which will ensure that we don't corrupt the stack, the minidump is written to disk.

QT: Store QTextStream in QList

I'm trying to open multiple files simultaneously (random number of files) and store their textstreams in qlist for simple using in other code:
QList<QTextStream> files;
QList<QString> fnames;
fnames.append("file1.txt");
fnames.append("file2.txt");
// ..and so on with random iterations
// collect qtextsrams into qlist
foreach (QString file, fnames) {
QFile f(file);
f.open(QIODevice::ReadOnly);
QTextStream textStream(&f);
files2.append(&textStream);
}
// use qtextstreams in a loop
QList<QTextStream>::iterator i;
for (i = files.begin(); i != files.end(); ++i) {
qDebug() << i->readLine();
}
So i have an error:
/make debug
make -f Makefile.Debug
make[1]: Entering directory `/home/pixx/Workspace/collocs'
g++ -c -pipe -g -Wall -W -D_REENTRANT -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -Idebug -o debug/main.o main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:128: error: no matching function for call to ‘QList<QTextStream>::append(QTextStream*)’
/usr/include/qt4/QtCore/qlist.h:493: note: candidates are: void QList<T>::append(const T&) [with T = QTextStream]
/usr/include/qt4/QtCore/qlist.h:819: note: void QList<T>::append(const QList<T>&) [with T = QTextStream]
main.cpp:117: warning: unused variable ‘cc’
In file included from /usr/include/qt4/QtCore/QList:1,
from main.cpp:1:
/usr/include/qt4/QtCore/qtextstream.h: In member function ‘void QList<T>::node_copy(QList<T>::Node*, QList<T>::Node*, QList<T>::Node*) [with T = QTextStream]’:
/usr/include/qt4/QtCore/qlist.h:695: instantiated from ‘void QList<T>::detach_helper(int) [with T = QTextStream]’
/usr/include/qt4/QtCore/qlist.h:709: instantiated from ‘void QList<T>::detach_helper() [with T = QTextStream]’
/usr/include/qt4/QtCore/qlist.h:126: instantiated from ‘void QList<T>::detach() [with T = QTextStream]’
/usr/include/qt4/QtCore/qlist.h:254: instantiated from ‘QList<T>::iterator QList<T>::begin() [with T = QTextStream]’
main.cpp:133: instantiated from here
/usr/include/qt4/QtCore/qtextstream.h:258: error: ‘QTextStream::QTextStream(const QTextStream&)’ is private
/usr/include/qt4/QtCore/qlist.h:386: error: within this context
/usr/include/qt4/QtCore/qtextstream.h:258: error: ‘QTextStream::QTextStream(const QTextStream&)’ is private
/usr/include/qt4/QtCore/qlist.h:399: error: within this context
make[1]: Leaving directory `/home/pixx/Workspace/collocs'
make[1]: *** [debug/main.o] Error 1
make: *** [debug] Error 2
What should i fix?
I understand that it's very simple question, but i can't find right query for google :(
The first error, namely "no matching function for call to ‘QList::append(QTextStream*)’" is caused by you using & operator in this line:
files2.append(&textStream);
Your list is supposed to be made of QTextStream objects, not pointers to QTextStream objects.
But the real problem lies deeper. To put an object into a list, an object must have copy constructor. QTextStream doesn't have any, since it's not clear how different copies of a same text stream should work together. I suggest you create a list of pointers to text streams, as in "QList ". Of course, in that case don't forget to handle their destruction, when they are no longer needed:
foreach (QTextStream *cur, files) delete cur;
If you need to pass this list between different parts of your code, make multiple copies of it and such, you may need smart pointers (QSharedPointer), but I can hardly think of a task where you'd need to do it to text streams.
I found a solution, thanks Septagram for idea! QList files2; // file list to merge
QList<QTextStream> files;
QList<QString> fnames;
fnames.append("file1.txt");
fnames.append("file2.txt");
// ..and so on with random iterations
QList<QFile *> files2; // file list to merge
QList<QTextStream *> files3;
foreach (QString file, files) {
files2.append(new QFile(file)); // create file obj
files2.last()->open(QIODevice::ReadOnly); // open file
files3.append(new QTextStream(files2.last())); // create textstream
}
QList< QTextStream * >::iterator i3;
for (i3 = files3.begin(); i3 != files3.end(); ++i3) {
qDebug() << (*i3)->readLine();
}

Resources