I'm writing a cross-platform C++ program using Qt and I want to package/embed a number of binary executables within the program. The program should be able to execute these binaries at runtime.
I figured, I would need QResource and QProcess using start() and the ":/..." notation, but I don't seem to get the process running. Is there anything I am missing? Should it work like this? Does the binary need to be set as executable?
Background: I am writing a tool which uses Git and I don't want to require the end-user to install Git manually.
(Trying this on Mac OS X, BTW.)
Update:
I am using the following code (C++, Qt on Mac OS X):
QString program = ":/git";
QStringList arguments;
arguments << "help" << "commit";
myProcess->start(program, arguments);
The Git executable is in the project path, my resources.qrc references it like so:
<qresource prefix="/">
<file>git</file>
</qresource>
I'm not getting an error, but the program is not executed. Behavior is the same when I set program
to a non-existing file. Replacing ":/git"
by the absolute path to git works perfectly.
You can't execute a program directly from a resource.
If you had a program in a resource and you wanted to execute it, you'd first have to read it out of the resource, write it to a file, make the file executable, then execute it.
Also, when you say that you're not getting an error, that probably means that you aren't checking for errors properly.
Several years late, but the question is still relevant. I had the same problem when wanting to embed rclone.
In the .pro
file, add
# From http://stackoverflow.com/a/37561981
defineReplace(copyToDir) {
files = $$1
DIR = $$2
LINK =
for(FILE, files) {
LINK += $$QMAKE_COPY $$shell_path($$FILE) $$shell_path($$DIR) $$escape_expand(\\n\\t)
}
return($$LINK)
}
defineReplace(copyToBuilddir) {
return($$copyToDir($$1, $$OUT_PWD))
}
# Copy the binary files dependent on the system architecture
win32 {
message("Windows")
QMAKE_POST_LINK += $$copyToBuilddir($$PWD/rclone/windows/rclone.exe)
}else: unix:!macx {
message("Linux")
QMAKE_POST_LINK += $$copyToBuilddir($$PWD/rclone/linux/rclone)
}else: macx: {
# Here we want to place the binaries inside the application bundle, so the
# QMAKE_POST_LINK approach will not work because it places them in the same
# directory as the bundle and not inside it. Instead, use QMAKE_BUNDLE_DATA.
message("macOS")
MediaFiles.files += $$PWD/rclone/macOS/rclone
MediaFiles.path = Contents/MacOS
QMAKE_BUNDLE_DATA += MediaFiles
}
Notice how there are slight differences for each platform, but in general the approach is the same.
qmake
will copy this files to the destination directory, and they will be accessible by simply making the process call to the local relative directory.
In the following code, I call the executable from QML, and it's going to be very similar in C++ as well:
var rcloneCommand
if (Qt.platform.os === "windows") {
console.log("Windows")
rcloneCommand = "rclone.exe"
} else {
console.log("OSX/Linux")
rcloneCommand = "./rclone"
}
qProcess.start(rcloneCommand, ["--config", "rclone.conf", "-v", "copy", "--stats", "1s", source, destination]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With