[QBS] RFC: Deployment support for qbs
Mathieu Bouchard
mbouchar at gmail.com
Wed Feb 22 06:54:31 CET 2012
Hi Christian,
I'm not really fond of using a variable named "files" to tell qbs that the
current section refers to a target. This seems to add some magic to the
syntax and make the concept somewhat illogical to use.
As for the rest, I think that this covers everything that is unix/linux
related. For the Debian support, is there a way to ship a default system
configuration that is used for every user? In a normal Debian packaging
workflow, the last step before submitting the package to the archive is to
test the package in a clean environment to be sure that the source code can
be compiled completely from the sources files on a clean Debian install,
and I don't think it would be really clean to call "qbs probe" from the
package rules file. When the package is integrated into the archive, the
source code is also sent to a list of servers that create the architecture
specific binaries for all the supported architectures.
You could also probably cover more platforms by adding custom targets
support. For example, I currently use some "undocumented" qmake functions
to add custom targets to the build process. They are used to provide a
"make installer" target on Windows that calls makensis to create an
installer file. On OSX, this is used to call macqtdeploy.
On Tue, Feb 21, 2012 at 10:39 AM, Christian Kandeler <
christian.kandeler at nokia.com> wrote:
> Hi,
>
> in the last couple of days, I've thought a bit about what deployment
> support could look like in the Qt Build Suite. Here's what I've come up
> with. The following description is meant to be conceptually complete and
> provides concrete examples. It might therefore appear a bit lengthy.
> Bear with me.
>
>
> 1) Defining "Deployment"
>
> Deployment can be viewed as
> a) the last part of the build process or
> b) as a dedicated process that follows after building.
> The distinction is not academic, as we will see below.
> In the simplest model, deployment is just a "make install" that puts
> binaries and/or other resources from your project into the local file
> system. However, while this might cover your needs for some project that
> is supposed to be executed on your local machine, it is not enough if
> files are to be deployed to other machines, e.g. for distributing your
> software or, in the case of cross-compilation, even just testing.
> Therefore, we split the concept of "Deployment" into two sub-concepts,
> which we will call "Local Installation" and "Remote Deployment".
>
>
> 2) The example project
>
> Let's assume our project is a simple library consisting of one source
> and one header file. There is also a small test application that uses
> the library's services. Without any deployment support, the project
> could look like this:
>
> import qbs.base 1.0
>
> Project {
> Product {
> type: "dynamiclibrary"
> name: "mylib"
> Depends { name: "cpp" }
> files: [ "mylib.h", "mylib.cpp" ]
> }
>
> Product {
> type: "application"
> name: "mylibTestApp"
> Depends { name: "cpp" }
> files: [ "main.cpp" ]
> }
> }
>
>
> 3) "Local Installation" in qbs
>
> This concept exists already: Products can have the "installed_content"
> property, which enables them to install files. This happens as part of
> the build process, i.e. qbs currently implements definition a) of the
> deployment term.
> In our example above, you would want to install the header file and the
> shared object, because they are needed to compile and link dependent
> applications, respectively. You would not want to install the test app,
> because it is not needed globally - you can just run it from the build
> directory (or, in the case of cross-compilation, you cannot even run it
> locally at all). So the library product now looks like the following,
> while the rest of the project stays the same:
>
> Product {
> type: [ "dynamiclibrary", "installed_content" ]
> name: "mylib"
> Depends { name: "cpp" }
> files: "mylib.cpp"
>
> Group {
> qbs.installDir: "/usr/lib"
> files: target
> fileTags: "install"
> }
>
> Group {
> qbs.installDir: "/usr/include"
> files: "mylib.h"
> fileTags: [ "hpp", "install" ]
> }
> }
>
> Note that in the case of cross-compilation, "qbs.installDir" will be
> interpreted as being relative to a sysroot, which is a directory
> specified in the platform description. The same directory is also used
> when building the project, e.g. for gcc's '--sysroot' option.
>
> Issues with the above approach:
> - The "target" keyword used above does not yet exist. Currently
> there is no way to refer to the build result of a product.
> - The fact that the installation is part of the build process means
> that if files are supposed to be installed to "global" locations in the
> host file system, the user is forced to build the project as root. If
> the install step were separate, the user could build normally and
> afterwards do "sudo qbs install".
>
>
> 4) "Remote Deployment" in qbs
>
> There is an important difference between local installation and remote
> deployment: While it is rather unambiguous what the former means, the
> latter can have very different variations. For our example project,
> remote deployment could mean:
> - Building a Debian package, copying the package to a device and
> installing it there (e.g. the Harmattan use case).
> - Copying the files into a directory tree that has been mounted via
> a network file system, thereby copying it to a device.
> - Copying (parts of) the files to a device via rsync.
> - Building a tarball and uploading it to a web server for distribution.
> - Putting the files into a self-extracting archive or some other
> form of installer.
> - ...
> It seems hopeless to cover all these cases in qbs itself. However, what
> qbs can do is to prepare the actual deployment in a sensible way.
>
> 4a) Specifying what to deploy
>
> Just as for local installation, this can be done by introducing a
> corresponding file tag. Let's assume you have cross-compiled the example
> project and you now want to deploy it to some device for testing:
>
> Product {
> type: [ "dynamiclibrary", "installed_content" ]
> name: "mylib"
> Depends { name: "cpp" }
> files: "mylib.cpp"
>
> Group {
> qbs.installDir: "/usr/lib"
> files: target
> fileTags: [ "install", "deploy" ]
> }
>
> Group {
> qbs.installDir: "/usr/include"
> files: "mylib.h"
> fileTags: [ "hpp", "install" ]
> }
> }
>
> Product {
> type: "application"
> name: "mylibTestApp"
> Depends { name: "cpp" }
> files: [ "main.cpp" ]
>
> Group {
> qbs.installDir: "/usr/bin"
> files: target
> fileTags: "deploy"
> }
> }
>
> Note that in contrast to local installation, deployment does not include
> the header file, since it is not needed on the device itself.
> Conversely, it does include the test application, because it is run there.
> However, this is not the only deployment case. When you are done with
> testing, you want to distribute your library. If you intend to build a
> "devel"-like package, you actually deploy the same files that you
> install locally:
>
> Product {
> type: [ "dynamiclibrary", "installed_content" ]
> name: "mylib"
> Depends { name: "cpp" }
> files: "mylib.cpp"
>
> Group {
> qbs.installDir: "/usr/lib"
> files: target
> fileTags: [ "install", "deploy" ]
> }
>
> Group {
> qbs.installDir: "/usr/include"
> files: "mylib.h"
> fileTags: [ "hpp", "install", "deploy" ]
> }
> }
>
> Product {
> type: "application"
> name: "mylibTestApp"
> Depends { name: "cpp" }
> files: [ "main.cpp" ]
> }
>
> You can support both cases via a property (does not work like this
> currently, but should):
>
> Project {
> id: myProject
> property bool testing: true
>
> Product {
> type: [ "dynamiclibrary", "installed_content" ]
> qbs.installDir: "/tmp"
> name: "mylib"
> Depends { name: "cpp" }
> files: "mylib.cpp"
>
> Group {
> qbs.installDir: "/usr/lib"
> files: target
> fileTags: [ "install", "deploy" ]
> }
>
> Group {
> qbs.installDir: "/usr/include"
> files: "mylib.h"
> baseFileTags: [ "hpp", "install" ]
> fileTags: myProject.testing ? baseFileTags :
> baseFileTags.concat("deploy")
> }
> }
>
> Product {
> type: "application"
> name: "mylibTestApp"
> Depends { name: "cpp" }
> files: [ "main.cpp" ]
>
> Group {
> qbs.installDir: "/usr/bin"
> files: target
> fileTags: myProject.testing ? "deploy" : []
> }
> }
> }
>
>
> 4b) Deploying
>
> As explained above, qbs cannot be responsible for the complete
> deployment process, but it can do some preparation for common use cases.
> For instance, packaging often involves copying the files to be packaged
> into a directory structure mirroring the one on the target system. For
> instance, the abovementioned "devel package" case for our example
> project could look like this, if you are targetting a dpkg-based system:
>
> $ qbs deploy myProject.testing:false project.deployRoot:debian/mylib
>
> This would remove the contents of the given directory if it exists
> already and then copy all files that have a "deploy" tag to their
> respective "installDir"s, prepending the value of the "deployRoot"
> property. In this example, you would then call dpkg-buildpackage in the
> same directory. This is outside the scope of qbs, but it builds nicely
> on qbs' work. (Alternatively, you would perhaps want to integrate qbs
> into the dpkg-buildpackage flow via the rules file.)
> Now let's assume that for testing, you do not want the overhead of
> package creation. Instead, you just want to copy file by file to the
> device using scp. In such a case, you don't need "qbs deploy", since
> that would just be an unnecessary indirection. What you do need,
> however, is the list of files to copy over, preferably in a simple,
> easily parsable format:
>
> $ qbs dump-deploy-info myProject.testing:true
>
> For our example project, this would result in output similar to the
> following:
> /home/icke/myproject/build/debug/mylib.so|/usr/lib/mylib.so
> /home/icke/myproject/build/debug/mylibTestApp|/usr/bin/mylibTestApp
>
>
> That's it. Opinions?
>
>
> Christian
> _______________________________________________
> QBS mailing list
> QBS at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/qbs
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/qbs/attachments/20120222/650b7ff3/attachment.html>
More information about the Qbs
mailing list