Can the output from CMake's FindBoost feature be silenced? - c++

CMake's FindBoost feature, called using find_package(Boost ... ), creates a lot of output that looks like this:
-- Boost version: 1.57.0
-- Found the following Boost libraries:
-- system
# ... other libraries ...
Can this output be silenced?
Setting set(Boost_DEBUG OFF) seems to have no effect.
(For those curious about why this might be desirable: our build system is very tightly controlled; we do not intend external developers to be able to build our code in arbitrary environments (and in fact we hard-code the paths to our compilers, libraries, etc in our CMake files). So there's not really any value to seeing this output when building, and it can make it easier for developers to miss information that's actually important.)

Use QUIET option for find_package(Boost...) call. It will supress "Found the following Boost libraries:" message.

Related

Converting from qmake to cmake, how do I find libraries in the same way?

in qmake I can have something like this:
LIBS += -lopengl32 \
-lglu32
This will automatically find and link the OpenGL and GLU with my application. How can I do the same in cmake? Is it as simple as:
target_link_libraries(${TARGET_NAME} opengl32 glu32)
If so, how does cmake know where to find these libraries? Is there a way to do this that involves a find_libraries call instead? The above (if it works), would give me anxiety.
Yes, there is a way.
About the sample you provided:
target_link_libraries(${TARGET_NAME} opengl32 glu32)
In this case, when you just list libraries to be linked against, CMake will just pass them to the linker, without any additional work; it is the linker, who must find them.
About the CMake way of including libraries:
However, CMake may help you much much more. Pls take a look at the following code snippet, that represents the preferred way of finding libraries in CMake:
#NOTE: this is a complete & working CMakeLists.txt
project(my_opengl_program)
set(TARGET_NAME ${PROJECT_NAME})
set(TARGET_SOURCES my_opengl_program.cpp my_opengl_program.h)
add_executable(${TARGET_NAME} ${TARGET_SOURCES})
find_package(OpenGL REQUIRED)
target_link_libraries(${TARGET_NAME} OpenGL::GL OpenGL::GLU)
Instead of using find_library directly, use find_package. It will find the libraries you need (by employing find_library internally) and set various helpful variables for you.
Also, most of the packages will also define so-called import libraries, OpenGL::GL and OpenGL::GLU in your case, that can be used for linking. The wonderful thing about linking against the CMake targets is that your executable will inherit all relevant compile/link requirements from the target used for linking. Of course, "import libraries" are also CMake targets :)
Please note that there are NO additional compile/link options, include directories, compile definitions, etc... for your executable. Everything that is necessary is inherited from OpenGL::GL and OpenGL::GLU.
CMake also provides packages for many standard libraries (scroll down to "Find Modules").
About searching for libraries
You can always use find_library directly, and in that case, it is your responsibility to take care of all requirements the library imposes.
Determining the places to search for libraries may be quite complex, and is driven by various CMake variables, as well as parameters passed to find_library. In the simplest case, when no related CMAKE_* variables are changed, and when the find_library is called with basic syntax, like:
find_library(GL_LIB opengl32)
fund_library(GLU_LIB glu32)
Search for openGL32 and glu32 will be controlled by CMAKE_SYSTEM_PREFIX_PATH, CMAKE_SYSTEM_LIBRARY_PATH CMake variables.
In the end, here is the complete documentation for find_library, find_package, cmake supported libraries (scroll down to "Find Modules"), target_link_libraries
[update]
find_library vs find_package
The question was raised about the difference between find_library and find_package.
Briefly, these two commands do not "compete" but rather "complement" each other. One may think about find_library as a low-level interface for including libraries. In this context, find_package would be a much higher interface, that is easier to use. On the other hand, find_package requires additional support from the library maintainers, or from the CMake directly.
Digging a little deeper into the problem:
Suppose that some library is introduced using
find_library (SOME_OTHER_LIB some_other_lib_name). If the lib was found, the variable SOME_OTHER_LIB will contain the path to the library, which is enough for linking, using target_link_libraries.
But to really use the library, sources need to include SOME_OTHER_LIB specific headers, i.e. another find_path(...) needs to be introduced, to locate headers, followed by target_include_directories(...). Also, compile options required by the library also need to be extracted somehow, and introduced using target_compile_options(...)
Of course, if the SOME_OTHER_LIB is used on more than one place, all target_include_directories, target_compile_options, and target_link_libraries must be used all over.
The same process must be repeated for every foreign library that is used.
One can quickly spot the pattern, and this is exactly where find_package becomes handy. All that low-level work is hidden from the end-user (i.e. developer using CMake), and she/he is presented with a clean and unified interface. The downside is that find_package requires a "kind of driver" that will "drive" the process of including the foreign library. All libraries that are directly supported by CMake may be found on cmake-modules (scroll down to "Find Modules").
The icing on the cake, almost all find modules also create so-called "import libraries" (OpenGL::GL and OpenGL::GLU in your case) that are cmake targets holding all requirements of the 3rd party library. All those data are inherited by just linking against the import library, making the code much cleaner.
Unfortunately, there are no "enforcements" about the naming of created import libraries (just guidelines), so the only solution is to check the documentation. For OpenGL module, it can be found on FindOpenGL page.

c++17 parallel algorithms and CMake

It looks like more and more standard libraries implementations are relying on TBB for their parallel algorithms. This is a bit surprising to me, as I didn't think that standard libraries would have external dependencies (outside of stuff like pthread), but that's a different question I imagine.
My issue is that I need to bake this into my CMakeLists.txt files now.
First bad news: There is no official CMake support for TBB, and TBB itself does not provide any FindTBB.cmake file. You can find it here and there on the web, but if standard libraries start relying on it, it would be nice to have it officially supported by CMake. Is this coming further down the line?
Then, I need to have some slightly convoluted code in my CMakeLists.txt file to find_package(TBB REQUIRED) and link the corresponding targets when required (depending on the standard library, version, etc.). It looks like Conan is already offering a package that hides all that stuff from the user. You just get parallelstl and that's it. Will we have something similar in CMake in the future?
We can already use these parallel algorithms in CMake today, but it would be great to make it easier to create such projects.
I have Ubuntu 21.10 with GCC and TBB (libtbb-dev 2020.3-1) installed.
Since TBB uses pkg-config what worked for me is this:
# file CMakeLists.txt
find_package(PkgConfig REQUIRED)
pkg_search_module(TBB REQUIRED tbb)
link_libraries(PkgConfig::TBB)
Unfortunately, when I later installed intel-oneapi 2021.4.0 which includes its own TBB (in /opt/intel/oneapi) this stopped working.
This newer version of TBB cannot be used as a backed for GCC's (parallel) STL apparently (generates compilation errors in my system), so I did this in order to pick the system's TBB and not the /opt/intel version.
link_libraries(-ltbb) #(PkgConfig::TBB)
This defeats the purpose of CMake, so I am also looking for a more robust solution.
My recommendation at the moment is do not install oneapi's TBB if what you want is to make it work with system's GCC.

Set LINK_FLAGS for INTERFACE libraries in cmake

I am working on a header-only C++11 library which uses modern CMake. By "modern," I mean not only using CMake v3.0+ but also trying to use as much as possible the best practices in Daniel Pfeifer's talk.
I have done some research on my question, but the answers are mostly regarding modifying the LINK_FLAGS directly in the global level, which I do not want to have. Right now, in my project, I require a minimum version of 3.9.0 of CMake because of some features I am using.
My question is about whether/how to add LINK_FLAGS coming from two of my dependencies: BLAS and LAPACK. Basically, I have the following excerpt from my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.9.0)
project(polo VERSION 1.0.0 LANGUAGES C CXX)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
add_library(polo INTERFACE)
add_library(polo::polo ALIAS polo)
target_compile_features(polo INTERFACE cxx_std_11)
target_include_directories(polo
INTERFACE
$<BUILD_INTERFACE:${polo_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(polo
INTERFACE
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
set_property(
TARGET
polo
PROPERTY LINK_FLAGS
${BLAS_LINKER_FLAGS}
${LAPACK_LINKER_FLAGS}
)
As far as I can understand from documentations of the FindBLAS and FindLAPACK modules, I need to inform my users at least about {BLAS,LAPACK}_LIBRARIES and {BLAS,LAPACK}_LINKER_FLAGS. For the former, I think I have handled the issue properly. However, for the latter, I need to use either set_target_properties or set_property. Between the two, the latter seems to give me a cleaner solution in that I can use both variables coming from Find{BLAS,LAPACK} modules together. When I try to build my library using the above solution, I get the obvious error:
CMake Error at src/CMakeLists.txt:32 (set_property):
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "LINK_FLAGS" is not allowed.
My question is two folds:
Should I use *_LINKER_FLAGS coming from the modules at all, and,
If yes, how should I integrate them cleanly into my CMake project?
As for the 2. above, I have seen some suggestions/answers for using target_link_libraries, but I am not sure whether that is the option to go for.
Thank you for your time!
First of all, I do apologize to the community for cross posting the issue.
Matthieu has tried helping me with two options:
Providing a helper function so that the consumers of the library could call the function to properly handle the LINK_FLAGS, and,
The IMPORTED library option, which he has kept as the final answer (please see the comments there for the motivation).
Unfortunately, neither of these solutions seem to work. The first one is not a clean way of informing the consumer about your dependencies. The second version seems to work with INTERFACE libraries, but any consumer that depends on the INTERFACE library that build an object, such as, e.g., a C-API of the header-only library that builds a SHARED library, has problems building and installing the IMPORTED library.
The solution seems to be to use CMake v3.13 and above, which, as of the posting date, is in the release candidate (rc3) state. Apparently, CMake v3.13 will be introducing INTERFACE_LINK_OPTIONS for such purposes.
EDIT. CMake v3.13 has been released.
The nice thing is that you can provide a helper .cmake for them (called polo-config.cmake).
One option inside the .cmake file is to create an IMPORTED library, which you hold the flags that you want, probably as PUBLIC this time, so that they are propagated to the next user.
Of course, you need to add the library properly, setting up the include paths, the path to the library...

CMake: set path to MPI headers and binaries manually

I am developing an MPI application which requires to be run with a specific implementation of MPI (let's call it MPIvA). On my workstation, another implementation of MPI (let's call it MPIvB) is installed.
My application is built using CMake and the find_library(MPI) obviously points to MPIvB. It compiles and runs without hassle.
I compiled MPIvA on my workstation. How can I make CMake use these headers and binaries?
CMake comes with a FindMPI module, that does all the heavy lifting for you.
In your CMakeLists.txt, instead of calling find_library(MPI), use find_package like so:
#### MPI
find_package(MPI REQUIRED)
if (MPI_FOUND)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
else (MPI_FOUND)
message(SEND_ERROR "This application cannot compile without MPI")
endif (MPI_FOUND)
Then wherever you link your application, link against the ${MPI_LIBRARIES}:
target_link_libraries(example-app ${MPI_LIBRARIES})
Now cmake will automatically find a MPI implementation in your system. If you have multiple different MPI versions, and want to specify which one to compile with, you can set the MPI_C_COMPILER and MPI_CXX_COMPILER variables to the corresponding mpicc and mpicxx compiler wrappers. The CMake module will then use those to figure out all the required compiler and linker flags itself.
Example:
cmake -DMPI_C_COMPILER=/usr/share/mvapich/bin/mpicc your-project-dir
To make sure cmake is using the correct MPI, start in a new empty build directory.
More information on the FindMPI module here: https://cmake.org/cmake/help/v3.0/module/FindMPI.html
In order to compile against MPIvA on your workstation, you'll need CMake to find those headers and binaries first. The following link describes how CMake's find_library's search order works: https://cmake.org/cmake/help/v3.0/command/find_library.html
I'd suggest adding MPIvA to the CMAKE_LIBRARY_PATH. See the top answer to the following question for an example:
How do I instruct CMake to look for libraries installed by MacPorts?
Well, this is not a new post but it may be useful to others in the future.
Even though the previous answers can also work, I think that the a better approach is to use the CMAKE_PREFIX_PATH option, ie sth like
CMAKE_PREFIX_PATH=~/my-libs-install-path ccmake ..
Now, some other comments:
All MPI libraries should be interchangeable, ie code that uses the MPI specification should compile and run with any MPI implementation (eg MPIvA and MPIvB which I am assuming are intelmpi,openmpi or mpich).
Regarding this answer (my reputation doesn't allow me to comment so I reply here):
find_package(MPI REQUIRED)
if (MPI_FOUND)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
else (MPI_FOUND)
message(SEND_ERROR "This application cannot compile without MPI")
endif (MPI_FOUND)
even though the functionality would be mostly as expected, the following is functionally equivalent:
find_package(MPI REQUIRED)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
The REQUIRED part in the findpackage(MPI REQUIRED) command will cause the command to fail if MPI is not found, so the if(MPI_FOUND) part is useless and the else clause will actually never be executed.
Finally, regarding the include_directories command, in my tests was not required if you are using targets, eg
target_link_libraries(my_app PUBLIC MPI::C)
is enough.
the built in cmake will interfere with your desired library more often than not, especially if you are using different clusters as usually default compilers are not the latest version you might need, the work around this is to have your own FindMYMPI.cmake and take the control.
Otherwise command line option or changing it with the ccmake GUI is also a possibility as provided in the above answers.
In this specific case, I succeeded using the following environment variable:
export MPI_HOME=/your/path/to/prefix
Please set it before using cmake, or empty the build directory.

How should I setup a C++ project on github so that it is portable?

I would like to start a C++ project on GitHub such that I will be able to clone/build on different operating systems (for example, OSX and unix). There will be lots of dependencies that need to be installed (for example curl, libxml2, etc), and much as possible I'd like to avoid having the user need to manually install the deps on the system. Is it possible to do this?
It depends on how much you want to bite off.
The short answer is let CMake do the work. It will generate projects for whatever platform and they should be usable. You don't need to distribute binaries for this, assuming they are readily available to you (and to them, by extension).
Here is an example that sets up sqlite, boost, and eigen that I used for one of my projects.
cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules)
# boost
find_package(Boost 1.42.0 REQUIRED )
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
find_package(Eigen REQUIRED)
include_directories(${EIGEN_INCLUDE_DIRS})
find_package(Sqlite3 REQUIRED)
include_directories(${SQLITE3_INCLUDE_DIR})
set(CMAKE_CXX_FLAGS "-std=c++0x")
include_directories(.)
link_libraries(
${Boost_LIBRARIES}
${SQLITE3_LIBRARIES}
)
add_executable(igd_sqlite
main.cpp
)
You'd take this and generate visual studio projects, makefiles, etc. Then build the project as you normally would.
CMake supports lots of libraries out of the box, though sometimes you do have to google for less popular ones and add them to your project.
I use it for my day-to-day work, even when I don't need cross platform.
When I do actually want to distribute binaries, I usually setup an external folder with the binary files.
Here is an example:
https://github.com/tomisarobot/curl_race
This works great if you don't have a lot of external dependencies and if they aren't huge. When that isn't the case, then I'd recommend putting each plattform in different repositories. Your source should be in its own too. You can use subprojects if you want, though that isn't strictly necessary. External deps dont change that often, so its not always worth the overhead. Usually I just write a bash script to document where to get everything. This script is usually necessary for a distribution build anyway.
Things like the maven-nar-plugin exist, though I am unaware of its maturity. If you're just creating all the binaries to distribute with your source anyway, then maybe it isn't that attractive. I don't see a lot of talk about it, so I assume adoption is low. Having seen what maven does for Java, it should be more popular.
Few thoughts
1) Tools
When possible, include the tool sources in the repository so that one can build them as a first-time-only step
When not possible, clearly specify what minimum version of what tool is required so that the user can install them herself
Possibly check if the dependency requirements are satisfied by running a script
2) Language
Compile with strict language compliance. For example
g++ -std=c++11 -pedantic