Is it possible from a C or C++ Linux program (say /usr/bin/foo), to programmatically launch another program (say /usr/bin/bar), and have foo exit normally and for bar to keep running?
system(3) isn't suitable as it blocks until the other program completes. I'd like something that returns immediately.
The programs are both GUI programs, but I suspect that isn't relevant.
Is there anything in Qt or boost::process that can help?
Is there any common Linux wrapper program I could run through system(3) to achieve this? I tried xdg-open but I don't think it's the right thing.
Basically I want the second program to "detach" from the first, and behave as if the user launched it via the system UI. (On MacOS, for example, there is an open command, so it would be like system("open /usr/bin/bar"))
With Qt, you can use bool QProcess::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), qint64 *pid = nullptr) as described here https://doc.qt.io/qt-5/qprocess.html#startDetached
Here is a minimal example of how to use it :
#include <QCoreApplication>
#include <QProcess>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
/*
* starting netstat with args
* in case the main event loop is exited
* netstat will be parented to init ( pid 1 ) and continue running
*/
QProcess::startDetached("/bin/netstat", QStringList() << "-pla" << "-ntuc");
return a.exec();
}
The classic way is using Fork-Exec: https://en.wikipedia.org/wiki/Fork%E2%80%93exec which is available in any Unix derived OS, including Linux. No need to add any library, framework, etc.
Related
When I launch xfreerdp process out of shell, it prints INFO messages to stdout and WARN/ERROR messages to stderr, as expected (this is just the default /log-level:info mode).
However, when I launch it via QProcess, the QProcess only signals with readyReadStandardError(), i.e. allowing me to read WARN/ERROR messages but never signals with readyReadStandardOutput(). Only when the process finishes (I close the xfreerdp window), the signal is emitted by QProcess and all the stdout is read by me (I have no idea, where was it kept all the way long?)
I have found two topics concerning the problem:
Qt: How to get live output of a running QProcess
stdout from QProcess is nowhere near realtime
I tried solutions proposed there:
1). I tried to use QIODevice::ReadWrite | QIODevice::Unbuffered as the third argument of QProcess::start(). It did not help -- same as it is described by the links.
2). I tried to call QProcess::readAllStandardOutput() every 100ms using QTimer. However, when I read this way, the output byte array is always empty (until the process is finished). So again, same as told by by the links, it did not help.
When I launch xfreerdp with QProcess with /log-level:debug or /log-level:trace, the problem does not hold. I get signals of stdout being ready. But there are lots and lots of DEBUG/TRACE messages.
I search for a way to solve the problem. But if I don't find it, I have two options: either to use the default /log-level:info option or /log-level:debug option. The first one is preferable for me but I am afraid that all that stdout is stuck somewhere and I would get with an overflow of some buffer and the whole thing would crash or it would be like a memory leak (maybe, I will try to explore QProcess source code). The second one is so here, probably, a better option, but the debug mode of xfreerdp is really quite too verbose.
UPDATE with the minimal reproducible example:
Alas, one need a vm to connect to.
If one launches the example (I have checked on Fedora 35 and Fedora 33), one will see that xfreerdp will output the INFO messages only after one will close the xfreerdp window, i.e., only after the process finishes.
//
// main.cpp
// g++ -o main main.cpp -std=c++11 -I/usr/include/qt5 -L/usr/lib64 -lQt5Widgets -lQt5Core
//
#include "QtWidgets/QApplication"
#include "QtCore/QProcess"
int main(int argc, char* argv[])
{
QApplication app{argc, argv};
QProcess p;
QObject::connect(&p, &QProcess::readyReadStandardOutput, [&](){
printf("%s", p.readAllStandardOutput().constData());
});
p.start("xfreerdp", {"/u:user", "/p:123456", "/v:10.38.31.133", "/cert:tofu"});
app.exec();
return 0;
}
I am sorry I was mistaken not to post the minimal reproducible example at once. Maybe, I should close the question and create a new once, so that more people could see it?
In your program, QProcess will do like works as entered in the terminal this command :
For seeing the result better I checked open in Terminal in the Run section of Qt Creator:
So I do this in Qt and add some changes to your code:
#include "QtWidgets/QApplication"
#include "QtCore/QProcess"
int main(int argc, char *argv[])
{
QApplication app { argc, argv };
QProcess *p = new QProcess();
QStringList pArgs;
pArgs << "/u:user" << "/p:123456" << "/v:10.38.31.133" << "/cert:tofu";
p->setProgram(QString("xfreerdp"));
p->setArguments(pArgs);
p->start();
QObject::connect(p, &QProcess::readyReadStandardOutput, [&]()
{
// printf("%s", p->readAllStandardOutput().constData());
qDebug() << p->readAllStandardOutput().constData() << Qt::endl;
});
app.exec();
return 0;
}
you should take Arguments to QProcess by using QStringList.
As I test it takes 15 to 16 seconds delay to show you results but this is my results:
There have been several posts regarding this, but I've not experienced the same. I'm running QT under Windows and trying to start an installer that will overwrite my app. I've been able to do this in C#, but being new to QT, I've not been able to find the "secret sauce" that allows the the launched process to outlive the app.
I've tried newing the process because someone mentioned that if they do that and don't delete the QProcess, then it was living on after the launcher app went away. I tried this, but as soon as my app quits, everything still goes away, albeit with a memory leak. I can't keep the app going because unlike Linux, Windows won't let you overwrite the application when it's running. Does anyone know how to do this?
What I need to do is really simple:
QString filename = ""full/path/to/installer.exe";
QProcess * pProcess = new QProcess();
int result = pProcess->startDetached(filename);
if (result)
QCoreApplication::quit();
else
QMessageBox::warning(this,tr("Oh NO!!"),tr("Couldn't start the installer!!!"),QMessageBox::Ok);
Actually, it works as described by OP.
This is my MCVE to demonstrate.
1) a child application testQProcessChild.cc:
#include <chrono>
#include <thread>
#include <iostream>
int main()
{
std::cout << "testQProcessChild started.\n"
<< "Sleeping for three seconds...\n";
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "testQProcessChild exits.\n";
return 0;
}
Compiled and tested:
$ g++ -std=c++11 -o testQProcessChild testQProcessChild.cc
$ ./testQProcessChild
testQProcessChild started.
Sleeping for three seconds...
testQProcessChild exits.
$
2) the Qt application testQProcessDetached.cc:
#include <QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QProcess qProcess;
//qProcess.closeWriteChannel();
//qProcess.closeReadChannel(QProcess::StandardOutput);
//qProcess.closeReadChannel(QProcess::StandardError);
if (qProcess.startDetached(QString::fromLatin1("./testQProcessChild"))) {
qDebug() << "./testQProcessChild started.";
} else {
qDebug() << "Cannot start ./testQProcessChild!";
}
qDebug() << "testQProcessDetached exiting.";
return 0;
}
with project file testQProcessDetached.pro:
SOURCES = testQProcessDetached.cc
QT = widgets
Compiled and tested:
$ qmake-qt5 testQProcessDetached.pro
$ make
$ ./testQProcessDetached
testQProcessChild started.
Sleeping for three seconds...
./testQProcessChild started.
testQProcessDetached exiting.
$ testQProcessChild exits.
Please note, that testQProcessDetached exits which can be seen as the prompt $ appears again. Round about 3 seconds later the output testQProcessChild exits. appears (to prove that testQProcessChild outlives testQProcessDetached).
I suspected that channel connections could be an issue. Hence, after first successful attempt, I commented the close???Channel() calls and repeated the test – with the same result as before.
I've tested in cygwin64 on Windows 10.
The sample testQProcessDetached.cc modified to become a GUI application:
#include <QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QPushButton qBtn(QString::fromUtf8("Start Child"));
qBtn.show();
QObject::connect(&qBtn, &QPushButton::clicked,
[&](bool) {
QProcess qProcess;
//qProcess.closeWriteChannel();
//qProcess.closeReadChannel(QProcess::StandardOutput);
//qProcess.closeReadChannel(QProcess::StandardError);
if (qProcess.startDetached(QString::fromLatin1("./testQProcessChild"))) {
qDebug() << "./testQProcessChild started.";
QApplication::quit();
} else {
qDebug() << "Cannot start ./testQProcessChild!";
}
});
return app.exec();
}
Compiled and tested:
$ qmake-qt5 testQProcessDetached.pro
$ make
$ ./testQProcessDetached
Click
testQProcessChild started.
Sleeping for three seconds...
./testQProcessChild started.
testQProcessDetached exiting.
$ testQProcessChild exits.
I compiled the second sample on VS2013 with Qt for Windows. It worked as well.
Thereby, I had to replace the relative path ./testQProcessChild with the absolute path (although both binaries resided in the same directory). As this is stated by OP as well, I didn't care about this.
A quick and dirty solution is to run your installer executable inside of a Windows command script and QProcess the command script. Then put a 3-5 second 'timeout' command at the start of the script to ensure that the original executable has finished.
It turns out that the method I posted does work, but it won't work if you run your app in the debugger. Apparently, as a safety precaution, the debugger closes all spawned threads/processes when the app terminates. Thank you all for your answers!!
I am developing a Qt 5.x application whose main function is more or less like that (simplified):
int main(int argc, char *argv[])
{
QApplication app(arg, argv);
QCommandLineParser cmdLineParser;
cmdLineParser.addHelpOption();
cmdLineParser.addVersionOption();
cmdLineParser.process(app);
/// *** SOME INITIALIZATION STUFF *** ///
app.exec();
}
I am experiencing some problems when I invoke the execution of application specifying the --version (or --help) option on command line: the application outputs the version (or the help) and then sometimes terminates with a segmentation fault...
I think it is due to the fact that when QCommandLineParser detects a built-in option on command line (--version or --help) simply calls QApplication's exit() for terminating the execution and this interferes with my own *** SOME INITIALIZATION STUFF *** (basically some other threads are started and maybe a prematurely call on exit() causes some problems)...
However, my question is: is it possible to make Qt avoid to go further in my *** SOME INITIALIZATION STUFF *** if a built-in option is detected on command line? In other words, is there a method to be called for knowing that a built-in option has been detected by the command line parser? Otherwise: is there a method for knowing that exit() has been called on application, and hence the application is terminating? If so, it would suffice to enclose my *** SOME INITIALIZATION STUFF *** in a if condition argumenting on that method and it would be fine...
Thanks for the support.
>> EDIT <<
I've done some further investigations... the behavior seems not be dependent on my own *** SOME INITIALIZATION STUFF ***... in fact even a "minimal, complete and verifiable example" as the following one sometimes terminates the execution with segmentation fault when the executable is triggered with --version on the command line:
#include <QApplication>
#include <QCommandLineParser>
int main(int argc, char *argv[])
{
// Instantiate the application
QApplication app(argc, argv);
app.setApplicationVersion("1.0.0");
// Prepare for parsing the command line
QCommandLineParser cmdLineParser;
cmdLineParser.setApplicationDescription("Test application");
// Add support for command line standard options (help & version)
cmdLineParser.addHelpOption();
cmdLineParser.addVersionOption();
// Perform actual parsing of command line
cmdLineParser.process(app);
// Let the application run
return app.exec();
}
Just to clarify, I am using Qt 5.3.2 on an ARM device running Linux OS.
I have a minimal example i am trying to get working. The end goal is to be able to communicate some information to a program that is waiting on a "cin" call. I guess that means something to do with Standard Input.
I am trying to use some Qt objects to help me at this stage. Although I am not using any other Qt stuff.
The example I am trying that gives me errors is:
#include <iostream>
#include <QtCore/QString>
#include <QtCore/QProcess>
#include <QtCore/QStringList>
int main() {
QProcess process;
QString prog = "test.exe";
// Starting "test.exe":
process.start(prog);
bool started = process.waitForStarted();
std::cout << started << std::endl;
// test.exe is waiting for cin, so give "2":
bool response = process.write("2\n");
std::cout << response << std::endl;
}
Here is the error messages:
1
QObject::startTimer: Timers can only be used with threads started with QThread
1
QProcess: Destroyed while process ("test.exe") is still running.
In rare cases you will have a Qt-app without QApplication or QCoreApplication. They start event loop, required for timers, events, signals/slots.
A console XML-parser could be such kind of event-less application.
Take a look e.g. here for a minimal QtCoreApplication app: How do I create a simple Qt console application in C++?
Start your process within a subclassed QWidget or QObject.
I wrote this program in Qt Creator but I'm not sure how to run it. Here is my code:
#include <QtCore/QCoreApplication>
using namespace std;
#include <iostream>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
string str;
cin >> str;
cout << " str is : " << str;
return a.exec();
}
When I run it my console shows this:
Starting /home/hamed/qt programs/test3-build-desktop/test3...
...and nothing happens. What should I do?
When copy pasting your code, it runs for me as expected (well, it doesn't terminate, but runs). Here is what I did in command line:
cd testproject
qmake -project
qmake
make
./testproject
As mentioned in the comment above, Qt itself is a library, so you are probably referring to some IDE when saying running it from "within Qt" - behaviour there is solely dependent on what IDE you are using.
Update:
From your message
Starting /home/hamed/qt programs/test3-build-desktop/test3...
I assume that you are using the QtCreator IDE, which does not allow you to enter things to console when running. I don't know whether you can get it to do so, but it works if you enter your project directory in console and use ./projectname. The building part mentioned above will be handled by QtCreator.
Another update:
Check out this thread for information on how to get it to work directly from QtCreator.
nothing happens!!
Your program is expecting an input, as you written here:
cin >> str;
what should i do?
Just type in something and press enter.
Add QTimer::singleShot(0, &a, SLOT(quit())); before the line return a.exec(); and don't forget to #include <QtCore/QTimer> (or you can make life easier and import the everything #include <QtCore>).
The a.exec() enters an event loop which waits for an event; normally in the form of user input with a graphical user interface. This however is a command line program and there isn't really a way for a user to send an event so it sits and waits forever. This is useful for server type applications but not what you're doing here. :)
(Note, this is one of many reasons your application might appear to be doing nothing. You may need to follow several of these answers before your program does what you expect)