Copying files with qmake
Sometimes you need to copy certain files from source directory to build directory together with your application binaries. And Qt’s qmake tool is capable of performing such operations.
Some geniuses might actually want to use scripts for that, but it’s better not to, because it’s the cross-platform development we’re talking about, and your xcopy
from Windows works only on Windows, so it’s better to find some universal method. And qmake
has such a thing, although it is not properly documented.
QMAKE_COPY
- performs file copying, and on different platforms it transforms into xcopy
, or cp
, or else.
QMAKE_COPY_DIR
- same thing, but for directories. For instance, on Linux/Mac it adds -r
option to cp
.
So, let’s take the following structure of the source folder:
webengine-recipes/
├── README.md
├── main.cpp
├── resources
│ ├── pages
│ │ ├── assets
│ │ │ ├── 3rdparty
│ │ │ │ ├── markdown.css
│ │ │ │ ├── marked.min.js
│ │ │ │ └── qt_attribution.json
│ │ │ ├── custom.css
│ │ │ └── custom.js
│ │ ├── burger.html
│ │ ├── cupcakes.html
│ │ ├── images
│ │ │ ├── burger.jpg
│ │ │ ├── cupcakes.jpg
│ │ │ ├── pasta.jpg
│ │ │ ├── pizza.jpg
│ │ │ ├── skewers.jpg
│ │ │ ├── soup.jpg
│ │ │ └── steak.jpg
│ │ ├── pasta.html
│ │ ├── pizza.html
│ │ ├── skewers.html
│ │ ├── soup.html
│ │ └── steak.html
│ ├── qml
│ │ ├── RecipeList.qml
│ │ └── main.qml
│ └── resources.qrc
├── webengine-recipes.pro
└── webengine-recipes.pro.user
We want to copy pages
directory to the build directory, so it would be near the application executable (so we could use relative paths to .html
files).
Here’s how to do it in the .pro
file:
TEMPLATE = app
QT += quick quickcontrols2 webengine
SOURCES += main.cpp
RESOURCES += resources/resources.qrc
DISTFILES +=
OTHER_FILES += \
$$PWD/resources/pages
!isEmpty(target.path): INSTALLS += target
# copies the given files to the destination directory
defineTest(copyToDestDir) {
files = $$1
dir = $$2
# replace slashes in destination path for Windows
win32:dir ~= s,/,\\,g
for(file, files) {
# replace slashes in source path for Windows
win32:file ~= s,/,\\,g
QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$shell_quote($$file) $$shell_quote($$dir) $$escape_expand(\\n\\t)
}
export(QMAKE_POST_LINK)
}
copyToDestDir($$OTHER_FILES, $$OUT_PWD/resources/)
Thanks to Jake for the function. Although, I had to modify it a bit: replace $$quote
with $$shell_quote
and $$DESTDIR
with $$OUT_PWD
.
Note the trailing /
and the absence of it in paths to source and destination. Turned out, Windows is quite sensitive to such things.
So, files are copied, problem is solved.
However, since I mentioned cross-platform development, you should know, that on different platforms build directory is organized differently.
Linux - everything is in the same directory:
build-webengine-recipes-Desktop_Qt_5_11_0_GCC_64bit-Debug/
├── [some-other-files]
├── resources
│ ├── assets
│ │ ├── 3rdparty
│ │ │ ├── markdown.css
│ │ │ ├── marked.min.js
│ │ │ └── qt_attribution.json
│ │ ├── custom.css
│ │ └── custom.js
│ ├── burger.html
│ ├── cupcakes.html
│ ├── images
│ │ ├── burger.jpg
│ │ ├── cupcakes.jpg
│ │ ├── pasta.jpg
│ │ ├── pizza.jpg
│ │ ├── skewers.jpg
│ │ ├── soup.jpg
│ │ └── steak.jpg
│ ├── pasta.html
│ ├── pizza.html
│ ├── skewers.html
│ ├── soup.html
│ └── steak.html
└── webengine-recipes
Windows - build directory has debug
and release
folders:
build-webengine-recipes-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug
¦ [some-other-files]
¦
+---debug
¦ [some-other-files]
¦ webengine-recipes.exe
¦
+---release
+---resources
¦ burger.html
¦ cupcakes.html
¦ pasta.html
¦ pizza.html
¦ skewers.html
¦ soup.html
¦ steak.html
¦
+---assets
¦ ¦ custom.css
¦ ¦ custom.js
¦ ¦
¦ +---3rdparty
¦ markdown.css
¦ marked.min.js
¦ qt_attribution.json
¦
+---images
burger.jpg
cupcakes.jpg
pasta.jpg
pizza.jpg
skewers.jpg
soup.jpg
steak.jpg
Mac OS - there is an .app
bundle and everything else is just lying “outside”:
build-webengine-recipes-Desktop_Qt_5_11_0_clang_64bit-Debug/
├── [some-other-files]
├── resources
│ ├── assets
│ │ ├── 3rdparty
│ │ │ ├── markdown.css
│ │ │ ├── marked.min.js
│ │ │ └── qt_attribution.json
│ │ ├── custom.css
│ │ └── custom.js
│ ├── burger.html
│ ├── cupcakes.html
│ ├── images
│ │ ├── burger.jpg
│ │ ├── cupcakes.jpg
│ │ ├── pasta.jpg
│ │ ├── pizza.jpg
│ │ ├── skewers.jpg
│ │ ├── soup.jpg
│ │ └── steak.jpg
│ ├── pasta.html
│ ├── pizza.html
│ ├── skewers.html
│ ├── soup.html
│ └── steak.html
└── webengine-recipes.app
└── Contents
├── Info.plist
├── MacOS
│ └── webengine-recipes
├── PkgInfo
└── Resources
└── empty.lproj
As you can see, relative path to our resources
directory is different on each platform, so we need to add some #ifdef
stuff in order for this to work:
QString webPagesPathLastMile = "/resources/";
#if defined(Q_OS_MAC)
webPagesPathLastMile = "/../../../resources/";
#elif defined(Q_OS_WIN)
webPagesPathLastMile = "/../resources/";
#endif
QString webPagesPath = QString("file:///%1%2")
.arg(app.applicationDirPath())
.arg(webPagesPathLastMile);
qDebug() << webPagesPath;
Speaking of Mac OS, if you only need to target this one, then everything is dramatically easier for you. Instead of using this function with QMAKE_COPY_DIR
, just add these lines into your .pro
file:
...
OTHER_FILES += \
$$PWD/resources/pages
APP_QML_FILES.files = $$OTHER_FILES
APP_QML_FILES.path = Contents/Resources
QMAKE_BUNDLE_DATA += APP_QML_FILES
And then you’ll get the following structure in your build directory:
build-webengine-recipes-Desktop_Qt_5_11_0_clang_64bit-Debug/
├── [some-other-files]
└── webengine-recipes.app
└── Contents
├── Info.plist
├── MacOS
│ └── webengine-recipes
├── PkgInfo
└── Resources
├── empty.lproj
└── pages
├── assets
│ ├── 3rdparty
│ │ ├── markdown.css
│ │ ├── marked.min.js
│ │ └── qt_attribution.json
│ ├── custom.css
│ └── custom.js
├── burger.html
├── cupcakes.html
├── images
│ ├── burger.jpg
│ ├── cupcakes.jpg
│ ├── pasta.jpg
│ ├── pizza.jpg
│ ├── skewers.jpg
│ ├── soup.jpg
│ └── steak.jpg
├── pasta.html
├── pizza.html
├── skewers.html
├── soup.html
└── steak.html
Social networks
Zuck: Just ask
Zuck: I have over 4,000 emails, pictures, addresses, SNS
smb: What? How'd you manage that one?
Zuck: People just submitted it.
Zuck: I don't know why.
Zuck: They "trust me"
Zuck: Dumb fucks