How to make package built with make install available for cmake? - cmake

So, I'm trying to build an application that requires gtkglextmm on CentOS. So far, I grabbed the source (from here) for gtkglext and gtkglextmm, and (finally) figured out how to compile them and install them using ./configure then make then sudo make install. That was pretty cool to get that to work.
Now, I'm trying to build Degate with cmake and it's complaining that it can't find gtkglextmm. What do I need to do to get the gtkglextmm library I built, available for cmake?
Rephrase: Built and installed library a with make,make install. Now want to build application b that depends on a with cmake. How?
Thanks!

This is a newcomer's notes made for my team as we adopt cmake. It summarizes briefly what I thought would be somewhere in a novice's example. Although with references and suitable for novices, I am very new to the material and this example may suffer accordingly.
General info for this question is at: https://cmake.org/Wiki/CMake:How_To_Find_Libraries - in particular, find_package can be used on any of the named packages listed by the help command:
cmake --help-module-list
Note: the 'Find' is omitted (e.g., FindLibXml2 -> find_package(LibXml2) )
However, for this type of library, it is more likely that it will not be in that list, in which case you want to use find_library and find_path instead. A simple example is:
find_library(SQLITE3_LIB sqlite3) # simple because I did not need to give paths
find_path(SQLITE3_PATH sqlite3.h)
target_link_libraries( your_target_name ${SQLITE3_LIB} )
include_directories( ${SQLITE3_PATH} )
You do not need to test if these have the '-NOTFOUND' return value because cmake will exit with an error if they do:
...
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
SQLITE3_LIB
linked by target "test" in directory /home/matlab/QFDC_ROOT/api
-- Configuring incomplete, errors occurred!
Note that the all-capitalized 'SQLITE3_LIB' and 'SQLITE3_PATH' are the variable names that I chose. You choose the variable names. If you have other libraries and include directories, you can list them before and after this one and separated by spaces (I ordered them by their link order consistently for both, although I think include paths are insensitive).
Your case may not be so simple, in which case you want to use the CMake features described at find_library for providing CMake more information about where it should find that library. There are other Q&A on specifically that topic - my favorite is to produce your own FindXXX.cmake (although it is a very terse answer pointing you to an example).
In many cases, it is helpful to run make VERBOSE=1 to help you troubleshoot the process, such as cd build && cmake .. && make VERBOSE=1.
For even better diagnostics, I used DLRdave's answer to print out the INCLUDE_DIRS and I used a simple message to return the results of my variables:
message( STATUS "SQLITE3_LIB: ${SQLITE3_LIB} SQLITE3_PATH: ${SQLITE3_PATH}")
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "dir='${dir}'")
endforeach()
EDIT NOTE: this answer was effectively re-written 2016-04-08 after discovering that the previous day's implementation erred and confused find_library() and find_path().

Related

How to use cmake file( GET_RUNTIME_DEPENDENCIES in an install statement?

How do you use file(GET_RUNTIME_DEPENDENCIES...) in a cmake install scripted statement? I can't find an example of this usage online, and the statement in the documentation and errors messages of using [[ ]] embedded custom scripting is not clear to me.
The impression I get is that at install time, this can be used to locate file dependencies of your cmake target and potentially bring them over with your install action, making it usable in standalone form.
For example, my application depends on QT and the expectation is that if this is configured correctly, the QT dlls needed for this application will be copied over to the bin. (I just want to be sure I don't have a misunderstanding of it's function in this context as well). It may not directly copy the files but I assume provides a list of files to copy that install will then process (all done at install time).
My naive attempt to just throw something at it to start is:
set(TARGET_NAME "myapp")
# installation settings
install(TARGETS ${TARGET_NAME}
[[
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${TARGET_NAME}
)]]
RUNTIME DESTINATION "${INSTALL_X_BIN}" COMPONENT libraries
LIBRARY DESTINATION "${INSTALL_X_LIB}" COMPONENT libraries
)
However this of course gives me:
CMake Error at applications/CMakeLists.txt:117 (install):
install TARGETS given target " file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${TARGET_NAME}
)" which does not exist.
-- Configuring incomplete, errors occurred!
I feel silly about this like I'm missing something pretty basic.
Zeroth, an update
As of the next version of CMake (3.21), you may not want to use file(GET_RUNTIME_DEPENDENCIES) in some cases. (Which would be a good thing, as it works... poorly. It has no ability to differentiate between 32-bit and 64-bit shared libraries, for one thing, so it's irritatingly common to get wrong-arch libs returned on Linux. Then again, this development won't change that fact.)
If you're on Windows, the most common platform to require GET_RUNTIME_DEPENDENCIES logic, the next version of CMake is looking to take another stab at this (hopefully, fourth(?) time's the charm) with a new generator expression: $<TARGET_RUNTIME_DLLS:target>.
It's documented as the "List of DLLs that the target depends on at runtime. This is determined by the locations of all the SHARED and MODULE targets in the target's transitive dependencies. [...] This generator expression can be used to copy all of the DLLs that a target depends on into its output directory in a POST_BUILD custom command."
Considering I currently have custom logic in a CMakeLists.txt to do precisely that, because it's the only way to make the library's unit tests executable from the build directory, I'm hopeful this new expression makes that a bit easier.
Further update...
($<TARGET_RUNTIME_DLLS> won't fix the problems with file(GET_RUNTIME_DEPENDENCIES), but some commits just merged into CMake's upcoming 3.21 branch purport to, by teaching it how to distinguish between libraries for different architectures. Hooray!)
First, a caveat
You mentioned Qt. No matter what you do here, this method is unlikely to work for Qt all by itself, because there's no way using only the runtime dependencies of a program/library that you can discover any Qt plugins or other components that your installation may also require. Qt's dependencies are more complex than just libraries.
(My answer here demonstrates how to obtain Qt plugin information for bundling purposes, using the QCocoaIntegrationPlugin QPA on macOS as an example. All of Qt's plugins are represented by their own IMPORTED CMake targets, in recent releases, so it's typically possible to write install(CODE ...) scripting which picks up those targets using generator expressions in a similar manner to the following code.)
file(GET_RUNTIME_DEPENDENCIES)
As Tsyvarev noted in comments, GET_RUNTIME_DEPENDENCIES is intended to be used in the install stage, not the configure stage. As such, it needs to be placed in an install(CODE ...) or install(SCRIPT ...) statement, which will cause the code evaluation to be delayed until after the build is complete. (In fact, install(CODE ...) inserts the given code right into the current directory's cmake_install.cmake script. You can examine the results just by looking at that file, without even having to run the install.)
The delayed evaluation also comes with a few wrinkles. Primarily: The code doesn't understand targets. The targets no longer exist at the install stage. So, to include any target info, you have to use generator expressions to insert the correct values.
While the CMake documentation indicates that variable references and escapes aren't evaluated inside bracket arguments, generator expressions are. So, you can compose the CODE wrapped in [[ ]] to avoid escaping everything.
You still have to be careful about variable expansion / escaping. Most variables (including any you create) aren't available in the install context — only a few are, like CMAKE_INSTALL_PREFIX. You have to either expand or set any others.
There are, AFAICT, no generator expressions to access arbitrary variables. There are some for specific variables/values, but you can't say something like $<LIST:MY_LIST_VAR> or $<VALUE:MY_STRING_VAR> to combine variables and bracket arguments.
So, if you want to use variables from the configure context in the CODE, where they'll be evaluated at install time, the easiest thing to do is to "transfer" them into the install script by set()-ing a variable in the CODE.
file(INSTALL TYPE SHARED_LIBRARY)
To install shared library dependencies, you can use the same file(INSTALL) command that CMake itself uses in cmake_install.cmake if you build a shared library target. It uses the TYPE SHARED_LIBRARY option to add some extra processing. The FOLLOW_SYMLINK_CHAIN option is also especially handy. Together they'll make file(INSTALL) both resolve symbolic links in the source files, and automatically recreate them in the destination path.
Example code
So all in all, you'd want to do something like this:
set(MY_DEPENDENCY_PATHS /path/one /path/two)
# Transfer the value of ${MY_DEPENDENCY_PATHS} into the install script
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES $<TARGET_FILE:mylibtarget>
EXECUTABLES $<TARGET_FILE:myprogtarget>
RESOLVED_DEPENDENCIES_VAR _r_deps
UNRESOLVED_DEPENDENCIES_VAR _u_deps
DIRECTORIES ${MY_DEPENDENCY_PATHS}
)
foreach(_file ${_r_deps})
file(INSTALL
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib"
TYPE SHARED_LIBRARY
FOLLOW_SYMLINK_CHAIN
FILES "${_file}"
)
endforeach()
list(LENGTH _u_deps _u_length)
if("${_u_length}" GREATER 0)
message(WARNING "Unresolved dependencies detected!")
endif()
]])
* – (Note that using the DIRECTORIES argument on a non-Windows system will cause CMake to emit a warning, as files' dependencies are supposed to be resolvable using only the current environment.)
If the code gets too complex, there's always the option to create a separate script file copy_deps.cmake in the ${CMAKE_CURRENT_SOURCE_DIR} and use install(SCRIPT copy_deps.cmake). (A previous version of this answer suggested using file(GENERATE...) to build the script — that won't work, as the file isn't written until after processing the CMakeLists.txt.)
Building onto this answer (thanks!) I created a recursive version for collecting all library dependencies and their dependants (and so on..) for a given executable:
install(CODE [[
function(install_library_with_deps LIBRARY)
file(INSTALL
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib"
TYPE SHARED_LIBRARY
FOLLOW_SYMLINK_CHAIN
FILES "${LIBRARY}"
)
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES ${LIBRARY}
RESOLVED_DEPENDENCIES_VAR RESOLVED_DEPS
UNRESOLVED_DEPENDENCIES_VAR UNRESOLVED_DEPS
)
foreach(FILE ${RESOLVED_DEPS})
if(NOT IS_SYMLINK ${FILE})
install_library_with_deps(${FILE})
endif()
endforeach()
foreach(FILE ${UNRESOLVED_DEPS})
message(STATUS "Unresolved from ${LIBRARY}: ${FILE}")
endforeach()
endfunction()
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:myexecutable>
RESOLVED_DEPENDENCIES_VAR RESOLVED_DEPS
UNRESOLVED_DEPENDENCIES_VAR UNRESOLVED_DEPS
)
foreach(FILE ${RESOLVED_DEPS})
install_library_with_deps(${FILE})
endforeach()
foreach(FILE ${UNRESOLVED_DEPS})
message(STATUS "Unresolved: ${FILE}")
endforeach()
]])
I also think its relevant to note that some variables (like CMAKE_INSTALL_PREFIX) can be used in the inner scope as they are, while others (like CMAKE_PREFIX_PATH) need to be re-set explicitly.
Going from here one might want to exclude specific system directories, this here likely collects too much.

Is it possible to alter CMAKE_MODULE_PATH from CMake commandline?

Edit: The accepted answer actually shows that it is pretty normally possible to set CMAKE_MODULE_PATH as any other CMake variable e.g. via the -DCMAKE_MODULE_PATH path CLI parameter. It seems that in my case there is some included CMake script that calls set(CMAKE_MODULE_PATH /library_path), which erases all previous paths set to the variable. That's why I couldn't get the variable to do what I wanted it to do. I'll leave the question here in case anybody else faces this kind of situation.
I'm building a (3rd party) project that uses the Protobuf library (but this question is general). My system has a system-wide install of a newer version of Protobuf than the project is compatible with. So I've downloaded and compiled from source an older version of Protobuf.
The project uses CMake, and in its CMakeLists.txt, there is:
find_package(Protobuf REQUIRED)
Which, however, finds the (incompatible) system install. Of course, CMake doesn't know about my custom build of Protobuf. But how do I tell it?
I've created a FindProtobuf.cmake file in, say, ~/usr/share/cmake-3.0/Modules/ and want the build process to use this one for finding Protobuf. But I haven't succeeded forcing CMake to pick up this one and not the system one. I think the reason is quite obvious from the CMake docs of find_package:
The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. ... If no module is found and the MODULE option is not given the command proceeds to Config mode.
So until I succeed to change CMAKE_MODULE_PATH, CMake will just pick up the FindProtobuf.cmake installed to the default system path and won't ever proceed to the "Config" mode where I could probably make use of CMAKE_PREFIX_PATH.
It's important for me to not edit the CMakeLists.txt since it belongs to a 3rd party project I don't maintain.
What I've tried (all without success):
calling CMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules cmake ... (the env. variable is not "transferred" to the CMake variable with the same name)
calling cmake -DCMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules ... (doesn't work, probably by design?)
calling Protobuf_DIR=path/to/my/protobuf cmake ... (the project doesn't support this kind of override for Protobuf)
It seems to me that, unfortunately, the only way to alter the CMAKE_MODULE_PATH used by find_package is to alter it from within CMakeLists.txt, which is exactly what I want to avoid.
Do you have any ideas/workarounds on how not to touch the CMakeLists.txt and still convince find_package to find my custom Protobuf?
For reference, the CMake part of this project is on github .
As a direct answer to your question, yes, you can set CMAKE_MODULE_PATH at the command line by running cmake -DCMAKE_MODULE_PATH=/some/path -S /path/to/src -B /path/to/build.
But that probably doesn't do what you want it to do; see below.
The Bitbucket link you supplied is dead, but here are a few suggestions that might help.
Avoid writing your own find modules, especially when the upstream supplies CMake config modules.
You can direct CMake to your custom Protobuf installation by setting one of CMAKE_PREFIX_PATH or Protobuf_ROOT (v3.12+) to the Protobuf install root.
You can tell find_package to try CONFIG mode first by setting CMAKE_FIND_PACKAGE_PREFER_CONFIG to true (v3.15+). Then set Protobuf_DIR to the directory containing ProtobufConfig.cmake.
Failing all else, you can manually set the variables documented in CMake's own FindProtobuf module, here: https://cmake.org/cmake/help/latest/module/FindProtobuf.html
All these variables can be set at the configure command line with the -D flag.
There are very few environment variables that populate CMake variables to start and I would avoid relying on them. There is an exhaustive list here: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html. CMAKE_MODULE_PATH is not among them.

How to set RPATH in CMAKE?

I wish to build and install a software locally to the $HOME/.local/ path instead of a system-wide /usr/ folder. The software uses CMAKE for compilation.
After installation, the software binaries and libraries get stored in $HOME/.local/bin/ and $HOME/.local/lib/, respectively. However, when I try to run the program, it throws an error that the required library is not found (which, by the way, is present in $HOME/.local/lib/).
The program works fine if I set the $LD_LIBRARY_PATH to $HOME/.local/lib. But I don't want to do this. Hence, instead of this, I would like to know how to specify the RPATH variable (which would point to $HOME/.local/lib) while compiling the software using CMAKE.
Kindly help.
I am using the following two lines in the CMakefile
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
(the first one is required only if you use MacOSX)
you may also use:
set(CMAKE_BUILD_RPATH "/my/libs/location")
specifying runtime path (RPATH) entries to add to binaries linked in the build tree (for platforms that support it). The entries will not be used for binaries in the install tree. See also the CMAKE_INSTALL_RPATH variable.
CMAKE_INSTALL_RPATH is a predefined list, so I can see scenarios where it would be better to do
list( APPEND CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib )
If you include( GNUInstallDirs ) you could also
list( APPEND CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_LIBDIR} )
I am a CMake novice though, so if someone sees an issue with the above please let me know.

Why does `cmake --verbose=1` give verbose cmake output but `cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON` does not?

My goal was to see details about an invocation of g++ called directly by cmake from the command line. I do not care about the output of make for the purposes of this question.
According to the official FAQ and the accepted answer on a related question, I should make sure CMAKE_VERBOSE_MAKEFILE:BOOL=ON is set in my generated CMakeCache.txt, by e.g. passing the commandline flag -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON. When I did that it re-queried a bunch of properties, but gave no extra information about the invocation.
However, calling cmake with the flag --verbose=1 showed me exactly what I needed.
What are these two options doing differently? Is --verbose=1 deprecated or otherwise discouraged?
No, that's not what the accepted answer and the CMake FAQ you link say, otherwise I would be surprised.
Precisely, they don't say that you should modify CMakeCache.txt. Don't modify that file, it's not a good practice, since one can easily make mistakes.
If you instead have followed exactly what both sources say, i.e.
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON .
make
or
cmake .
make VERBOSE=1
you would have seen a verbose output from the compilation and linking phases.
Alternatively, you should achieve the same effect if you put in your CMakeLists.txt file the following line:
set( CMAKE_VERBOSE_MAKEFILE on )
The fact that you do not see output in one of the cases might due to previously cached configurations.
I suggest you do if possible out-of-source builds so that in this case you can get rid of every CMake generated files and directories by just removing the build directory.
Then you could just recreate new configurations without interference from previously generated configurations and build files.
Of course, I might be wrong and you hit a bug, but it seems unlikely.
EDIT: That's because in the configuration phase you're not compiling, i.e. you are not using a Makefile, which is what the command line option set. It's not a verbose option for the cmake command itself at any stage (configuration, compiling, installing) of the project build. It will not show extra configuration info when you do cmake . but it should show you extra information when you run the make.
So CMAKE_VERBOSE_MAKEFILE is the wrong option to set if you want to get verbose output from CMake itself.

How to get CMake to build a Fortran program with MPI support?

I was trying to parallelize a Fortran program using MPI. I use CMake to do the build of my program. It was difficult to find support on getting CMake to create a working makefile for Fortran with MPI support on google, but from what I could gather, I added the following commands to my CMakeLists.txt script:
find_package(MPI REQUIRED)
add_definitions(${MPI_Fortran_COMPILE_FLAGS})
include_directories(${MPI_Fortran_INCLUDE_DIRS})
link_directories(${MPI_FortranLIBRARY_DIRS})
This will locate MPI on my system and then set the variables found in the following three commands. In my linking line, I added the MPI libraries variable to the list of the other libraries that my program needed to build.
target_link_libraries(${exe_name} otherlibs ${MPI_FortranLIBRARY_DIRS})
Doing cmake and then make worked to build the program and the program ran; however, when I tried to add more to the source which required me to include the mpif.h include file, my compilation failed due to not being able to find this header file. I also could not use mpi because the compiler cannot find the mpi.mod file in the path.
I inserted "message" commands into my CMakeLists.txt file and printed out the values of the variables that I was using for including and linking. It turns out that the variables, MPI_Fortran_INCLUDE_DIRS and MPI_FortranLIBRARY_DIRS weren't set to anything. A check of the module that CMake is actually using to set these variables (FindMPI.cmake) showed these variables to be non-existent. I changed my CMakeLists.txt file to use the correct variables:
find_package(MPI REQUIRED)
add_definitions(${MPI_Fortran_COMPILE_FLAGS})
include_directories(${MPI_Fortran_INCLUDE_PATH})
link_directories(${MPI_Fortran_LIBRARIES})
target_link_libraries(${exe_name} otherlibs ${MPI_Fortran_LIBRARIES})
Now when I execute make, the compiler could find both mpif.h as well as mpi.mod.
UPDATE:
I want to mention that this solution worked for cmake version 2.8.10.1. When I moved my CMakeLists.txt scripts to a different machine that has cmake version 2.8.4, I get the same error about mpi.mod missing during the link stage. I checked the FindMPI.cmake module and, sure enough, there are no variables that specify the language (i.e. there is no MPI_Fortran_LIBRARIES variable, just a MPI_LIBRARIES variable, and this variable is not getting set to the correct location of the mpi library on that system. So this solution will be dependent on cmake version.
Sounds like you are not using the mpi compiler. That is fine, but you have to add a lot of flags then. There is not really an mpi compiler but a wrapper that sets the flags to be able to use mpi. With cmake I was able to do this by defining the fortran compiler I was going to use BEFORE the call to cmake. It's not a nice solution since you loose portability, but it works. I'm trying to find a better solution and define inside cmake what compiler to use, but have not been able to do so. In other words, this works for me:
FC=mpif90 cmake ../.
make
I was having the same problem as you. Hope this solves the issue. If anybody finds how to define the fortran compiler INSIDE cmake please post it!
as you've already noticed, you misspelled the name of two variables, namely MPI_Fortran_LIBRARIES and MPI_Fortran_LIBRARIES
It is useful also to add:
cmake_minimum_required(VERSION 2.8.10)
at the very beginning of your CMake to be sure that these variables will be defined.