I am working on a project which has several levels. Personally, I am new to qbs and there are not many document and examples on the internal about qbs.
environment:
Qt5.6.1; Qt creator 4.01; Ubuntu 16.04; Qbs 1.5.1
Here is the hierarchy of the project. On the top level, it has project.qbs:
import qbs
import qbs.File
Project{
var binaries = [
"component1/component1.qbs",
"component2/component2.qbs",
"subpro/subpro.qbs", // <- 1. the project I am working on
"ourlib/ourlib.qbs", // <- 2. the library I am using
]
return binaries
}
The subpro.qbs is something like:
import qbs
Project {
name: subpro
references:[
"app1/app1.qbs"
"app2/app2.qbs"
"myapp/myapp.qbs" //<- 3. the application I am working on
]
}
The myapp.qbs is like:
import qbs
CppApplication{
type: "application"
name: "myapp"
Group{
name: "project-install"
fileTagsFilter: "application"
qbs.install: false
qbs.install: "bin"
}
Depends {name:"cpp"}
Depends {name:"blah1"}
Depends {name:"ourlib"}
cpp.libraryPaths:["path_of_lib3rdParty"] // 4. set the 3rd party lib path
cpp.staticLibraries:["lib3rdParty.a"] // 5. set the 3rd party lib name
files["myapp.cpp","f2"...]
}
finally the qbs for our lib:
import qbs
DynamicLibrary{
name: "ourlib"
Group{
name: "project-install"
fileTagsFilter: "dynamiclibrary"
qbs.install: false
qbs.installDir: "debug"
}
Depends {name: "cpp"}
cpp.includePath:["..."]
cpp.libraryPaths:["path_of_lib3rdParty"] // 6. same as 4
cpp.staticLibraries:["lib3rdParty.a"] // 7. same as 5
}
When I run "qbs debug" under the project root folder.
The qbs shows:
linking ourlib.so
compiling myapp.cpp
ERROR: ...
/usr/bin/ld: cannot find -llib3rdParty_s.a
So, based on the error message, the qbs failed to build myapp.cpp and trying to find the lib3rdParty in myapp project. I added 4 and 5, still having the same error. It seem 6 and 7 are correct since there is no linking error from ourlib.so. How should I config the qbs to make the building process working?
Another question is about the keyword "references". Can I reference other qbs file in any level in a project? How it work? I got the same question about "Depends" as well.
Thanks
Rong
The cpp.dynamicLibraries and cpp.staticLibraries properties take a list of library names to be linked, i.e. the library name without the lib prefix or .so suffix.
For example, you'd use:
cpp.libraryPaths: ["/home/r0ng/tools/myapp/libs/relic/lib"]
cpp.dynamicLibraries: ["relic"]
However, since you already have the full file path of the dynamic library you wish to link, you can simply pass the full file path without having to specify cpp.libraryPaths at all, like so:
cpp.dynamicLibraries: ["/home/r0ng/tools/myapp/libs/relic/lib/librelic.so"]
That second method is preferred because it specifies the exact library to link to, rather than relying on the search path which may not necessarily pick the type of library you expect (if both a static and dynamic version exist).
I concede that our cpp.dynamicLibraries and cpp.staticLibraries properties should be better documented to explain their intended use.
Regarding references, yes, you can reference any file path regardless of its file system location.
Regarding Depends, that item's name property specifies the name of a product or module to create a dependency on. Such a product or module must already be present in your project tree, for example having been loaded as a result of using the qbsSearchPaths or references properties.
Related
I have a QBS Project which is a collection of subprojects, including static libraries, shared libraries, and a Qt GUI applications. The Qt GUI application has been giving me issue in that the linking stage fails, throwing several "/usr/bin/ld: cannot find {library}: File format not recognized" errors for libraries that are built earlier in the project chain. It does not do this for all libraries though, including libraries with near identical .qbs files as those which do throw this error.
Oddly enough, if I build the application on it's own, that is to say I run qbs from within the application's project directory rather than at the top level, it builds fine (assuming the dependent libraries all exist within their install directories). The main difference I see is that when building the full project, the cpp.libraryPaths for the application are ignored for all products in the project and the application attempts to link against the lib files produced in the build directory, while when building the application on it's own the cpp.libraryPaths are used as intended, and the files in the install directory are linked against successfully.
I have no idea why the lib files in the install directory can be linked against while files in the build directory throw errors. What could be causing the linking to fail in the first place? Additionally, how can I fix my project configuration so that I can build everything by calling qbs at the top level. Am I perhaps going about this in the wrong manner?
Here is the command I use to start the build:
qbs qbs.installRoot:. release
And a visual representation of the issue:
Poject <-- calling qbs here throws errors at linking application
|- LibraryOne
|- LibraryTwo
|- Application <-- calling qbs here works if libraries already built
And here is a very simplified reproduction of the relevent qbs files
-- SubOne.qbs and SubTwo --
// These are identical excluding the files
StaticLibrary {
name: // "One" or "Two"
files: [/*Files...*/]
Depends {
name: "Qt"
submodules: [/*core, etc...*/]
}
Depends { name: "cpp" }
// cpp depends and properties
Group {
fileTagsFilter: product.type
qbs.installDir: "lib"
qbs.install: true
}
}
-- App.qbs --
QtGuiApplication {
name: "App"
files: [/*Files...*/]
Depends { name: "One" } // I comment out these depends when building the Application on it's own
Depends { name: "Two" }
Depends { name: "cpp" }
cpp.includePaths: ["../One/include","..Two/include"]
cpp.libraryPaths: ["../lib"] // <-- Ignored during full project build
cpp.staticLibraries: ["One","Two"]
Group {
fileTagsFilter: product.type
qbs.installDir: "bin"
qbs.install: true
}
}
Never run qbs from a subdirectory. You should always run it on the top-level project file. In your root directory you should have a file like this:
// project.qbs
import qbs
Project {
// order doesn't matter here
references: [
"LibraryOne/SubOne.qbs",
"LibraryTwo/SubTwo.qbs",
"Application/App.qbs"
]
}
Secondly, you should not set the cpp.libraryPaths and cpp.staticLibraries in your application, as the Depends items which you have in your application, will already handle this (never comment them out).
Your cpp.includePaths properties should also not be set in the application, instead they should go into an Export item in each of your respective static libraries, like so:
StaticLibrary {
...
Export {
Depends { name: "cpp" }
cpp.includePaths: [product.sourceDirectory + "/include"]
}
...
}
Then run qbs -f project.qbs and everything should be built correctly.
I have a third party precompiled library (.lib+.dll) that I use in my Qt application.
In a regular (qmake) QtCreator project I have the following lines in my .pro file:
LIBS += -L$$PWD/lib/release -ltag
INCLUDEPATH += include/taglib
There is also an option in Projects tab -> Run -> "Add build library search path to PATH" which is by default ON. It ensures that LIBS path gets added to system PATH, so the dll can be found.
However, I can't find an equivalent in QBS. I have the following qbs file, which then gets included and added via Depends in my CppApplication file:
DynamicLibrary {
name: "taglib"
files: "lib/release/tag.dll"
Export {
Depends { name: "cpp" }
cpp.includePaths: [".","include/taglib"]
cpp.libraryPaths: ["lib/release"]
cpp.dynamicLibraries: "tag"
}
Group {
name: "taglib"
fileTagsFilter: ["dynamicLibrary"]
qbs.install: true
}
}
The linker passes but the application can't find the DLL at runtime and crashes.
Is it possible to add cpp.libraryPaths to system PATH at runtime?
Another option would be to copy the DLL file to build directory, but I can't figure out how to do that for precompiled libraries in QBS.
EDIT: I tried to use cpp.systemRunPaths which is documented here but it doesn't work.
I figured out how to copy prebuilt .dll files to build dir.
What was missing was FileTagger property since it seems QBS doesn't consider .dll files dynamic libraries.
FileTagger {
patterns: ["*.dll"]
fileTags: ["dynamicLibrary"]
}
The question still stands on how to add cpp.libraryPaths to system PATH on runtime. I found the following method in core.qbs:
setupRunEnvironment: {
var env;
if (qbs.targetOS.contains('windows')) {
env = new ModUtils.EnvironmentVariable("PATH", qbs.pathListSeparator, true);
env.append(binPath);
env.set();
}
...
}
I have no idea how to modify or invoke that method in my QBS files.
alan, your're on the right way. Just place
setupRunEnvironment: {
var env;
if (qbs.targetOS.contains('windows')) {
env = new ModUtils.EnvironmentVariable("PATH", qbs.pathListSeparator, true);
env.append(binPath);
env.set();
}
}
in the DynamicLibrary {} block, below the last Group {}. Change binPath to point to the folder with your shared libraries. This works at least with Windows.
Maybe you need to move Depends { name: "cpp" } out of the Export block.
I'm trying to build a qbs project using the leap motion library but on running the project am given the following error:
dyld: Library not loaded: #loader_path/libLeap.dylib
Referenced from: /Users/pball/Work/Code/Qt/build-LeapTest-Desktop-Debug/qtc_Desktop_95cbad6a-debug/install-root/LeapTest
Reason: image not found
My qbs file:
import qbs
CppApplication {
consoleApplication: true
files: "main.cpp"
Group { // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
cpp.includePaths: [".","/Users/pball/LeapSDK/include"]
cpp.libraryPaths: ["/Users/pball/LeapSDK/lib"]
cpp.dynamicLibraries: "Leap"
}
libLeap.dylib is in that location.
Using Qt 5.6.0
New to using qbs so any help / pointers greatly appreciated.
This is not a qbs-specific issue, but rather requires understanding of how dynamic libraries are loaded on macOS. Please check the documentation on dyld and Run-Path Dependent Libraries.
That said, based on the install name of your dependent shared library libLeap.dylib, if you copy it to the same directory as your LeapTest application binary, it should be loaded successfully.
Let's say I've downloaded some library xyz with headers and binaries and put it somewhere not in standard search paths. For each Product I can add the search paths and library to link to cpp.includePaths, cpp.libraryPaths, cpp.staticLibraries, etc.
Is there a better [standard] way to do this? If I'm building the library as part of my project it seems I can define the paths in an Exports item and then use a Depends item in each Product to automatically set the paths. This seems like a nice mechanism and I wonder if there isn't a way to use it for external dependencies as well.
The qbs docs are a little thin...
Thanks!
You would typically create your own module for xyz. You can add locations where QBS would search for modules and imports by setting the project's qbsSearchPaths-property. E.g. by setting it to "qbs" QBS would search for additional modules in the "qbs/modules" sub-directory of your project.
There you could place a file called "xyz.qbs" that would look like this:
import qbs
Module {
Depends { name: "cpp" }
property string xyzPath: "the/xyz/path"
cpp.includePaths: xyzPath + "/include"
cpp.libraryPath: xyzPath + "/lib"
cpp.staticLibraries: "xyz"
}
You could then use it by simply adding a Depend to your project:
import qbs
Project {
qbsSearchPaths: "qbs"
CppApplication {
name: "myApp"
files: "src/**"
Depends { name: "xyz" }
}
}
In my project (which uses waf/wscript based build system), I am now adding mongodb c++ driver APIs. I figured out that 'libmongoclient.a' is not getting added as a linker option (at compile time) and I get all undefined reference to the mongodb c++ driver API calls.
I want to understand, how do I modify my wscript so that it picks up the mongoclient related library by itself and links it properly. It perhaps involves updating the configuration function of wscript. I am new to the waf build system, and not sure how to change it.
I have built and installed the mongodb c++ driver as follows:
- INCLUDE: /usr/local/include/mongo/
- LIB: /usr/local/lib/libmongoclient.a
I posted a similar question earlier in this regard, and the above one is more specific problem statement.
https://stackoverflow.com/questions/30020574/building-project-with-waf-script-and-eclipse
Since I am just invoking ./waf from within eclipse, I believe, the options that I specify into Eclipse's build environment are not being picked up by the waf (and hence the library option for mongoclient).
I figured this out and the steps are as follows:
Added following check in the configure command/function.
conf.check_cfg(package='libmongoclient', args=['--cflags', '--libs'],
uselib_store='MONGOCLIENT', mandatory=True)
After this step, we need to add a package configuration file (.pc) into /usr/local/lib/pkgconfig path. This is the file where we specify the paths to lib and headers. Pasting the content of this file below.
prefix=/usr/local
libdir=/usr/local/lib
includedir=/usr/local/include/mongo
Name: libmongoclient
Description: Mongodb C++ driver
Version: 0.2
Libs: -L${libdir} -lmongoclient
Cflags: -I${includedir}
Added the above library into the build function to the sepcific program which depends on the above dependency (i.e. MongoClient).
mobility = bld(
target='bin/mobility',
features='cxx cxxprogram',
source='src/main.cpp',
use='mob-objects MONGOCLIENT',
)