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" }
}
}
Related
I am confused on the right way to get an external library integrated into my own Cmake project (This external project needs to be built along with my project, it's not installed separately, so we can't use find_library, or so I think)
Let's assume we have a project structure like this (simplified for this post):
my_proj/
--CMakeLists.txt
--src/
+---CMakeLists.txt
+---my_server.cpp
That is, we have a master CMakeLists.txt that basically sits at root and invokes CMakeLists for sub directories. Obviously, in this example, because its simplified, I'm not showing all the other files/directories.
I now want to include another C++ GitHub project in my build, which happens to be this C++ bycrypt implementation: https://github.com/trusch/libbcrypt
My goal:
While building my_server.cpp via its make process, I'd like to include the header files for bcrypt and link with its library.
What I've done so far:
- I added a git module for this external library at my project root:
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/trusch/libbcrypt
So now, when I checkout my project and do a submodule update, it pulls down bcrypt to ${PROJ_ROOT}/third_party
Next up, I added this to my ROOT CMakeLists.txt
# Process subdirectories
add_subdirectory(third_party/bcrypt)
add_subdirectory(src/)
Great. I know see when I invoke cmake from root, it builds bcrypt inside third_party. And then it builds my src/ directory. The reason I do this is I assume this is the best way to make sure the bcrypt library is ready before my src directory is built.
Questions:
a) Now how do I correctly get the include header path and the library location of this built library into the CMakeLists.txt file inside src/ ? Should I be hardcoding #include "../third_party/bcrypt/include/bcrypt/bcrypt.h" into my_server.cpp and -L ../third_party/libcrypt.so into src/CMakeLists.txt or is there a better way? This is what I've done today and it works, but it looks odd
I have, in src/CMakeLists.txt
set(BCRYPT_LIB,"../third_party/bcrypt/libbcrypt.so")
target_link_libraries(my app ${MY_OTHERLIBS} ${BCRYPT_LIB})
b) Is my approach of relying on sequence of add_directory correct?
Thank you.
The best approach depends on what the bcrypt CMake files are providing you, but it sounds like you want to use find_package, rather than hard-coding the paths. Check out this answer, but there are a few different configurations for find_package: MODULE and CONFIG mode.
If bcrypt builds, and one of the following files gets created for you:
FindBcrypt.cmake
bcrypt-config.cmake
BcryptConfig.cmake
that might give you an idea for which find_package configuration to use. I suggest you check out the documentation for find_package, and look closely at how the search procedure is set up to determine how CMake is searching for bcrypt.
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 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.
I require a very simple mechanism in my application, where my project is built as a shared library '.so' or '.dll', but what I want is:
ExampleAppOne.so
I get:
libExampleAppOne.so -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1 -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1.0 -> libExampleAppOne.so.1.0.0
I don't even want the 'lib' prefix. In the .pro file, all I can do is change the INSTALLS variable (that is because my third requirement IS that the library be built in a specific directory).
Also, I have a fourth, related requirement: When I ask QLibrary to load the library, I want it to specifically search for a library in a very specific path and a library that matches the EXACT name given to it. No 'lib' prefix matching, no 'version string' searching, no looking into LD_LIBRARY_PATH...
Any help is appreciated.
Regards,
rohan
add the following to you .pro file
# disables the lib prefix
CONFIG += no_plugin_name_prefix
# disable symlinks & versioning
CONFIG += plugin
Adding plugin to the CONFIG variable should disable versioning and the generation of symbolic links to the library.
I don't know of a simple way to disable the lib prefix though. You way want to dig into the provided QMake spec files to see how the default processing is implemented.