qmake: how to build dependencies without TEMPLATE=subdirs - qt

TL;DR: Is there a way to build a target from a .pro file in a different project without using TEMPLATE = subdirs?
Long version:
I have a complex project (mycomplexproject) with lots of subirs and *.pro files. One module (moduleA) depends on a DLL built in a different project outside of this project (anotherproject). Because reasons I cannot create a *.pro file with a subdirs template in somerootdir.
Is there a way to add a dependency in moduleA.pro so anotherproject is built whenever moduleA is built and anotherproject.dll does not exist without having to create a *.pro file in somerootdir?
somerootdir/
anotherproject/ // must be independent of mycomplexproject
anotherproject.pro
lib/
anotherproject.dll // the result of building anotherproject
[...]
mycomplexproject/
core/
core.pro
modules/
moduleA/
moduleA.pro // depends on anotherproject.dll built from anotherproject.pro
moduleB/
moduleB.pro
modules.pro // uses subdir template
mycomplexproject.pro // uses subdir template
P.S.: moduleA is only built under certain circumstances, and building anotherproject is only necessary if moduleAis built.

Related

How to add and compile my QT application in Yocto image (which contains QT-5 layer.)?

I am trying to add a qt widgets application/project to my yocto image and compile it through it. I know that I have to add a custom layer and make a recipe which has reference to the files of the qt application. I have also inherited qmake5 and inserted DEPENDS += "qtbase", but I am confused about which files to refer through SRC_UI in my recipe. The QT application file is a bare bone project called "hi" which contains no additional code and pops up a plain helloworld window. The project file contains following files:
main.cpp
hi.pro
hi.pro.user
mainwindow.cpp
mainwindow.h
ui_mainwindow.h
A reference recipe using above mentioned files would be really helpful.Thanks.
I have an old response about QT recipes in Yocto.
Check: how to build simple qt application using yocto?
It contains a reference hello world recipe.
You just need to copy your files into recipes' folder and specify all files in SRC_URI or:
If your project is collected under one folder hi:
Place hi under: qtexample/files and specify it in the recipe:
SRC_URI = "file://hi"
S = "${WORKDIR}/hi"
EDIT:
Do not forget to mention the files to package:
FILES_${PN} = "/opt/*"
EDIT2:
If your recipe depends on a library or set of tools at run time, check what recipes are providing those libraries and add in your recipe:
RDEPENDS_${PN} += "recipe"
where recipe is what providing your runtime dependency.

Use a precompiled plugin (via a shared library) in a QML application

I have a QML plugin compiled (to a .so) by another project. I want to re-use this in my own QML application without re-building it each time. I want to copy the .so over and, with minimal additional code, be able to write:
import QQuickMapboxGL 1.0
at the top of my QML files and have it work.
Where do I need to copy the .so in my QML project, and how do I need to add it to the project so that the QML runtime can find it?
What I've tried:
Create a QQuickMapboxGL directory with libqmapboxgl.so in it.
Create a qmldir file in that directory with the contents:
plugin qmapboxgl
Add the following to my .pro file:
INSTALL_DIR = $$PWD/../install
target.path = $$INSTALL_DIR
# Copy the QQuickMapboxGL folder to the install directory
plugin.files = QQuickMapboxGL/*
plugin.path = $$INSTALL_DIR/QQuickMapboxGL
INSTALLS += target plugin
Add a make install build step.
The result of this mad hackery was:
plugin cannot be loaded for module "QQuickMapboxGL": Plugin verification data mismatch in '/my/build/QQuickMapboxGL/libqmapboxgl.so'
I have verified that the plugin and my application are both being compiled with the same version of g++ (g++-5 (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904) and the same Qt download (5.7.0).
The main problem is that the .so is not a QML Plugin; no class inherits from QQmlExtensionPlugin or related. It is just a shared library of code.
Was able to workaround this by:
Adding the header files for MapboxGL to my project
In my main.cpp:
#include "3rdparty/mapbox-gl-native/platform/qt/include/qmapbox.hpp"
Calling QMapbox::registerTypes(); (inside main)
Copying libmapboxgl.so (built via Mapbox's make/cmake) inside a libs directory.
In myproject.pro adding: LIBS += -L./libs -lqmapboxgl
In my QML code import QQuickMapboxGL 1.0 and then using MapboxMap
Copying libmapboxgl.so to somewhere that is referenced by LD_LIBRARY_PATH

Configuring Qt builds with Jenkins

I have several Qt projects that are dependent upon a Qt library that I've developed.
The project files (.pro) for projects which use the library define the LIBS and PRE_TARGETDEPS paths. For example: -
PRE_TARGETDEPS += ../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug/projectlibrary.dylib
LIBS += -L../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug -lProjectLibrary
As you can see, there is a defined path to the linked library and they have been building with Shadow Builds, via Qt Creator. The file hierarchy is like this: -
Projects
ProjectLibrary_Qt_5_2_1_clang_64bit-Debug
ProjectLib.dylib (the built library)
DependentProject
DependentProject.pro
(dylib is an OSX extension, but it could equally be .lib for Windows, or .so for linux)
However, Jenkins creates a different folder structure:-
jobs
ProjectLib
workspace
Project.dylib
DependentProject
workspace
DependentProject.pro
Now there is an extra directory (workspace), which would need this reflected in the .pro file and the names of the folders are different.
Obviously, If I just call qmake on the .pro with a Jenkins build, the path to the library is going to be wrong.
So, do I need to create a separate .pro just to be able to reflect the paths when building with Jenkins, or is there another way to handle specifying the location of libraries in the project file, for Jenkins, without having to change the directory structures?
Solution 1) Based on your current build configration
Modify your .pro file like this :
isEmpty(PROJECT_PATH) {
PROJECT_PATH=../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug
}
LIBS += -L$${PROJECT_PATH} -lProjectLibrary
Then in Jenkins , you should pass PROJECT_PATH={path to your project} to qmake
Solution 2)
Using git submodule to fetch ProjectLibrary as a part of your building project. Then you don't need to build the ProjectLibrary by Qt Creator manually.

What are key differences between sbt-pack and sbt-assembly?

I've just stumbled upon the sbt-pack plugin. The development stream seems steady. It's surprising to me as I believed that the only plugin for (quoting sbt-pack's headline) "creating distributable Scala packages." is sbt-assembly (among the other features).
What are the key differences between the plugins? When should I use one over the other?
(Disclaimer: I maintain sbt-assembly)
sbt-assembly
sbt-assembly creates a fat JAR - a single JAR file containing all class files from your code and libraries. By evolution, it also contains ways of resolving conflicts when multiple JARs provide the same file path (like config or README file). It involves unzipping of all library JARs, so it's a bit slow, but these are heavily cached.
sbt-pack
sbt-pack keeps all the library JARs intact, moves them into target/pack directory (as opposed to ivy cache where they would normally live), and makes a shell script for you to run them.
sbt-native-packager
sbt-native-packager is similar to sbt-pack but it was started by a sbt committer Josh Suereth, and now maintained by highly capable Nepomuk Seiler (also known as muuki88). The plugin supports a number of formats like Windows msi file and Debian deb file. The recent addition is a support for Docker images.
All are viable means of creating deployment images. In certain cases like deploying your application to a web framework etc., it might make things easier if you're dealing with one file as opposed to a dozen.
Honorable mention: sbt-progard and sbt-onejar.
Although Eugene Yokota's explanation is complete, I would like to explain the mentioned plugins with package command in the aspect of usages and how different results are generated.
Directory settings and build.sbt
lazy val commonSettings = Seq(
organization := "stackOverFlow",
scalaVersion := "2.11.12",
version := "1.0",
)
lazy val app = (project in file ("app")).
enablePlugins(PackPlugin).
settings(commonSettings)
Above build.sbt file declares project called app and includes all the source files in the app directory. To enable Pack plugins, enablePlugins(PackPlugin) should be included in the sbt file.
Also, I've put the below line in project/plugins.sbt file to use pack plugins in our project
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.9.3")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
The package is already integrated into the sbt by default, so you don't have to explicitly specify the plugins using addSbtPlugins. However, the sbt-pack and sbt-assembly plugins are not included in the sbt by default, so you have to specify that you want to use them. addSbtPlugin is a way to say that "I want to use xxx, yyy plugins in my project" to your sbt.
Also, I implemented two contrived scala files in the ./app/src/main/scala:
AppBar.scala
class AppBar {
def printDescription() = println(AppBar.getDescription)
}
object AppBar {
private val getDescription: String = "Hello World, I am AppBar"
def main (args: Array[String]): Unit = {
val appBar = new AppBar
appBar.printDescription()
}
}
AppFoo.scala
class AppFoo {
def printDescription() = println(AppFoo.getDescription)
}
object AppFoo {
private val getDescription: String = "Hello World, I am AppFoo"
def main (args: Array[String]): Unit = {
val appFoo = new AppFoo
appFoo.printDescription()
}
}
sbt package
This is very basic sbt command included in the sbt to help you distribute your project through the jar file. The jar file generated by the package command is located in the projectDirectoy/target/scala-2.11/app_2.11-1.0.jar (Here, the specified scalaVersion and version setting keys included in the build.sbt file are used to generate the jar file name).
When you look inside the jar, you can see the class files generated by the sbt tool, which is the result of compiling the sources in the app/src/main/scala. Also, it includes a MANIFEST file.
$vi projectDirectoy/target/scala-2.11/app_2.11-1.0.jar
META-INF/MANIFEST.MF
AppBar$.class
AppBar.class
AppFoo.class
AppFoo$.class
Note that it only includes the class files generated from the scala files located in the app/src/main/scala directory. The jar file generated by the package command does not include any scala related libraries such as collection in the scala library (e.g., collection.mutable.Map.class). Therefore, to execute the program you may require scala library because the generate jar file only contains the minimal classes generated from the scala sources that I implemented. That is the reason why the jar file contains AppBar.class, AppBar$.class for companion object, etc.
sbt-assembly
As mentioned by the Eugene Yokota, sbt-assembly also help you distribute your project through generating the jar file; however the generated jar file includes not only the class files generated by your source code, but also all the libraries that you need to execute the program. For example, to execute the main function defined in the AppFoo object, you may need scala libraries. Also, when you add external libraries in your project, which can be included by adding the dependencies to the libraryDependencies key.
libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.3")
For example, you can include json4s libraries in your project, and jar files related to supporting json4s in your project also will be added to the final jar file generated by the sbt-assembly. In other words, when you invoke assembly in your sbt, it generates one jar file containing all the requirements to execute your program, so that you don't need another dependency to execute yout program.
When you prompt assembly command in your sbt shell, then it will generate one jar file in your target directory. In this case, you may find the app-assembly-1.0.jar in the app/target/scala-2.11 directory. When you look inside the jar file, you can find that it contains lots of classes.
$vi projectDirectoy/target/scala-2.11/app_2.11-1.0.jar
ETA-INF/MANIFEST.MF
scala/
scala/annotation/
scala/annotation/meta/
scala/annotation/unchecked/
scala/beans/
scala/collection/
scala/collection/concurrent/
scala/collection/convert/
scala/collection/generic/
scala/collection/immutable/
scala/collection/mutable/
scala/collection/parallel/
scala/collection/parallel/immutable/
scala/collection/parallel/mutable/
scala/collection/script/
scala/compat/
scala/concurrent/
scala/concurrent/duration/
scala/concurrent/forkjoin/
scala/concurrent/impl/
scala/concurrent/util/
scala/io/
scala/math/
scala/ref/
scala/reflect/
scala/reflect/macros/
scala/reflect/macros/internal/
scala/runtime/
scala/sys/
scala/sys/process/
scala/text/
scala/util/
scala/util/control/
scala/util/hashing/
scala/util/matching/
AppBar$.class
AppBar.class
AppFoo$.class
AppFoo.class
......
As mentioned before, because the jar file generated by the assembly contains all the dependencies such as scala and external libraries to execute your program in the jar, you may think that you can invoke the main functions defined in the AppFoo object and AppBar object.
jaehyuk#ubuntu:~/work/sbt/app/target/scala-2.11$ java -cp './*' AppFoo
Hello World, I am AppFoo
jaehyuk#ubuntu:~/work/sbt/app/target/scala-2.11$ java -cp './*' AppBar
Hello World, I am AppBar
Yeah~ you can execute the main function using the generated jar file.
sbt-pack
sbt-pack is almost same as the sbt-assembly; it saves all the library on which your project depends as jar files required to execute your program. However, sbt-pack doesn't integrate all the dependencies into one jar files, instead, it generates multiple jar files which correspond to one library dependencies and your classes (e.g., AppFoo.class).
Also, interestingly it automatically generates scripts for invoking all the main functions defined in your scala source files and Makefiles to install the program. Let's take a look at the pack directory created after you prompt pack command on your sbt shell.
jaehyuk#ubuntu:~/work/sbt/app/target/pack$ ls
bin lib Makefile VERSION
jaehyuk#ubuntu:~/work/sbt/app/target/pack$ ls bin/
app-bar app-bar.bat app-foo app-foo.bat
jaehyuk#ubuntu:~/work/sbt/app/target/pack$ ls lib/
app_2.11-1.0.jar sbt_2.12-0.1.0-SNAPSHOT.jar scala-library-2.11.12.jar
jaehyuk#ubuntu:~/work/sbt/app/target/pack$
As shown in the above, two directories and two files are created; bin contains all the script files to execute the functions defined in your sources (each file is a script that helps you execute the main method defined in your scala files); lib contains all the required jar files to execute your program; and lastly Makefile can be used to install your program and dependent libraries in your system.
For the details, please refer the github pages for each plugins.

QT Creator fails to build when TEMPLATE=subdirs is added

I'm new to QT Creator. I want to create a QT project with an exe and a static lib.
If I create the exe project first, it builds/rebuilds fine for every build configuration.
However, when i add TEMPLATE = subdirs to the end of the .pro file it stops building correctly. But it appears that is necessary to add static libs to the project. Any idea what I may be doing wrong?
Thanks.
The idea is to have a .pro file with TEMPLATE = subdirs on the toplevel and then the executable in one subdirectory and the library in another. Add both directories to SUBDIRS.
AFAIK it is not (easily) possible with qmake to build something and also recurse in one .pro file.
I am not sure about Qt Creator support, but it is easy to create the TEMPLATE = subdirs .pro file by hand.
edit:
I'm sorry, I did not understand what you are trying to do, can you explain better?
Does this help:
The template can be overridden by specifying a new template type with the -t command line option. This overrides the template type after the .pro file has been processed. With .pro files that use the template type to determine how the project is built, it is necessary to declare TEMPLATE on the command line rather than use the -t option.
from here

Resources