Is it possible to refer to an additional .txt-file inside the CMakeLists.txt? [duplicate] - cmake

I use some libraries that I don't want built as part of every project that uses them. A very understandable example is LLVM, which has 78 static libraries. Even having the cmake code to find and import these in every cmakefile is excessive.
The obvious solution seems to be to use the "include" command, and to factor out relevant chunks of cmake script into *.cmake files, and set up a CMAKE_MODULE_PATH environment variable.
Except it just plain doesn't work. Cmake doesn't find the file I specify in the include command.
On the off-chance, I even tried specifying the path in the environment variable several ways - once with backslashes, once with forward slashes... - and I restarted the command prompt each time and checked that the environment variable was present and correct.
In the cmake manual, it kind of implies that a "file" is different from a "module" - only a module gets the automatic add-the-extension-and-search-the-path treatment. But there is no explanation of what the difference is. I guessed that the missing extension might be enough (as with standard modules) but clearly it isn't.
Searching the manual for "module" isn't much help as the word seems to be overloaded. For example, a module is also a dynamic library loaded using LoadLibrary/dl_open.
Can anyone explain what the difference is between a file and a module in this context, and how I create my own module so that the cmake include command can find and use it?
I'm using cmake 2.8.1 on Windows.
EDIT
I'm pretty confident that the problem here is not understanding how cmake is supposed to work. I think what I should be doing is writing something that find_package can work with.
As things stand though, I'm still some way from being able to answer my own question.

I believe that a CMake 'module' is simply a file that can be used with the find_package directive. That is, when you run find_package(Module), it searches for a file in the MODULE_PATH that is named FindModule.cmake.
That said, if you include a file without the extension, it too will search through your MODULE_PATH for that file.cmake. In a CMake project I'm working on, I have a very similar directory structure as to what you propose.
+ root/
+ CMakeLists.txt
+ cmake/
| + FindMatlab.cmake
| + TestInline.cmake
| + stdint.cmake
+ src/
+ include/
In CMakeLists.txt I have:
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package (Matlab) # runs FindMatlab.cmake
include(TestInline) # defines a macro:
test_inline (CONFIG_C_INLINE)
include(stdint) # simply executes flat CMake code
Perhaps your issue is that you are trying to define the Module path from the environment. Instead, try to simply append to it within the very CMakeList you try to access the modules/files.

I had this same question after reading the CMake include() command documentation. It states:
Load and run CMake code from the file given. [...snip for brevity...] If a module is specified instead of a file, the file with name .cmake is searched first in CMAKE_MODULE_PATH, then in the CMake module directory.
This leaves a lot of interpretation as to what CMake considers a module vs. a file, because a CMake module is a file on the file system after all. So what's the difference?
The CMake source code is the only place I could find the answer. Basically CMake considers the argument to include() to be a file if it looks like an absolute path. This means:
On Linux/Unix
The argument starts with either '/' or '~'
On Windows
The argument's second character is ':' (as in C:)
The argument starts with '\'
CMake assumes anything else that doesn't meet the above criteria is a Module. In which case it appends '.cmake' to the argument and searches the CMAKE_MODULE_PATH for it.

File is CMake listfile, example is CMakeLists.txt. Use following command to get the list of command used in
cmake --help-command-list
Module is a cmake file (*.cmake) which contain cmake commands.
As Matt B. put, the CMAKE_MODULE_PATH is not environment variable of your shell, but cmake variable.
To append your module path to CMAKE_MODULE_PATH
LIST(APPEND CMAKE_MODULE_PATH ${YourPath})
Or if you perfer your modules to be used first
LIST(INSERT CMAKE_MODULE_PATH 0 ${Yourpath})

Related

How to use cpplint code style checking with CMake?

The only online resources I have found are the CMake documentation on CMAKE_<LANG>_CPPLINT (link here) and this example (link here), but I cannot figure out how to actually use it inside a CMakeLists.txt file.
I tried the example provided, but I can't make it work. FYI, I installed cpplint as explained here.
As of now, I can run the cpplint python script inside CMakeLists.txt using this CMake command:
execute_process(COMMAND cpplint path/To/File/To/Analyse.cpp)
However, I am pretty sure that this is not the right way to do this.
Recommended way to use static analysis tools with CMake was presented in Daniel Pffeifer's "Effective Cmake" (https://www.youtube.com/watch?v=rLopVhns4Zs&amp=&t=77m13s).
You can either define it when calling cmake, eg.:
cmake "-DCMAKE_CXX_CPPLINT=cpplint" ..
or put it into CMakeLists.txt:
set(CMAKE_CXX_CPPLINT "cpplint")
Recommended option is the first one (we shouldn't define in a project what isn't a project requirement).
CMake will call cpplint for each file it compiles. You can pass extra arguments after semicolon (e.g. -DCMAKE_CXX_CPPLINT=cpplint;--linelength=100).
Downsides of this method:
Errors count will not get accumulated (because cpplint is invoked for each file separately).
It will not check header files (as opposed to what D. Pffeifer says in his presentation, include files are not being scanned by cpplint).
Note that you can use other static analysis tools the same way:
Clan Tidy "-DCMAKE_CXX_CLANG_TIDY=/usr/bin/clang-tidy-3.9;-checks=*"
CppCheck "-DCMAKE_CXX_CPPCHECK=/usr/bin/cppcheck;--std=c++11"
IWYU "-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=/usr/bin/iwyu;--transitive_includes_only"
LWYU cmake -DCMAKE_LINK_WHAT_YOU_USE=TRUE
clazy
Some of them will require "compilation database" (set(CMAKE_EXPORT_COMPILE_COMMANDS ON)).
I failed to use CMAKE_<LANG>_CPPLINT to check code style.
I make it by using add_custom_target.
download cpplint.py
then download cpplint.cmake or write yourselt.
Suppose that there is a source code directory named src in your project, code those statements into your CMakeLists.txt.
aux_source_directory(${CMAKE_SOURCE_DIR}/src src)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}) #I put cpplint.cmake in $CMAKE_SOURCE_DIR
include(cpplint)
add_style_check_target(phoenix-cpplint "${src}")
Note:
you should pass the whole list, so use "${src}" instead of ${src}.
By default nothing depends on the custom target, see add_custom_target.
If there's still some problem, debug your CMakeLists.txt.
I have been struggling with the same problem.
I tried it with CMake 3.10.2 and the comment by user2449761 is still true. Using set(CMAKE_CXX_CPPLINT "cpplint") still does not check any header files.
The answer by kgbook does not work anymore, since aux_source_directory does not list the header files. You can, however, use
get_target_property(src staticcodecheck SOURCES)
That will give you all the non-system headers. The rest can be kept the same. As for running cpplint at a specific time, you might try
add_custom_command(TARGET ${TARGET}
PRE_BUILD
...
That will replace add_custom_target(${TARGET_NAME}... in his cpplint.cmake.
Hope this helps.
The following is how I am running cpplint on all files in the src directory for a project.
file(GLOB_RECURSE SRC_FILES "${PROJECT_SOURCE_DIR}/src/**/*")
add_custom_command(TARGET target PRE_BUILD COMMAND cpplint ${SRC_FILES})
This runs every time, it fails the build when there are cpplint issues, and it runs on all files in the src directory. You may also want to consider adding cpplint specific arguments to the command, such as --quiet or --extensions for example.

Best practices with CMake with non-standard include and library directories

I have been trying to build Mozilla RR on a Linux box at work using CMake. We have a slightly eccentric arrangement where shared libraries are stored on network drives in locations like /sw/external/product-name/linux64_g63.dll/. Further, I have built some dependencies for the project in $HOME/sw/. (I am not a sudoer on this box.)
I am rather baffled as how I am supposed to communicate to CMake to look in non-standard directories. So far I have fudged:
PKG_CONFIG_PATH=$HOME/sw/capnproto-0.6.1/lib/pkconfig \
CC=gcc-6.3 CXX=g++-6.3 \
cmake \
-DCMAKE_INSTALL_PREFIX=$HOME/sw/rr-5.1.0 \
-DPYTHON_EXECUTABLE=$HOME/bin/python2 \
-DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/ \
../src/
Which is obviously not a scalable solution, but it does at least complete the configuration successfully and emit some Makefiles.
If I omit -DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/, CMake fails, complaining about a missing libseccomp-2.2.3 dependency. But it works if I do have that definition, telling me that CMake understands where the libseccomp-2.2.3 files are and so will properly add the paths to the necessary compiler invocations.
However, make does not succeed, because gcc fails to find a required header file from the libseccomp probject. Examining make VERBOSE=1, I find that CMake hasn't added -I$HOME/sw/libseccomp-2.2.3/include to the gcc invocation.
I feel like this is not the right approach. The other answers I have looked at tell me to modify the CMakeLists.txt file, but surely
that is not going to be scalable across multiple CMake projects, and
for each project, that will need me to maintain a separate CMakeLists.txt file for every platform (Solaris/Linux/Darwin/Cygwin) I build the software on.
Is there a canonical solution to solving this problem? Perhaps a per-site configuration file that will tell CMake how to find libraries and headers, for all projects I build on that site?
Your approach is correct, but cmake is never told to include SECCOMP - see end of this post.
The way cmake can be informed about custom dependency directory depends on how the dependency is searched (i.e. on what is written in CMakeLists.txt).
find_package/find_library/find_path/find_program
If dependency is found with one of above-mentioned commands, custom search directories can be easily added with CMAKE_PREFIX_PATH. There is no need to add full path to include, lib or bin - when package root is added find_-command will check appropriate sub-directories. CMAKE_PREFIX_PATH can be also set with environment variable.
Second option is CMAKE_FIND_ROOT_PATH. Every path added to CMAKE_FIND_ROOT_PATH list treated as separate root directory and is searched before system root directory.
Note that CMAKE_FIND_ROOT_PATH will be ignored by find_-commands with NO_CMAKE_FIND_ROOT_PATH argument.
Following four variables may be used to tune the usage of CMAKE_FIND_ROOT_PATH:
CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
When use of host system default libraries is undesired setting CMAKE_FIND_ROOT_PATH_MODE_INCLUDE and CMAKE_FIND_ROOT_PATH_MODE_LIBRARY to ONLY is a good practice. If dependency library or header is not found in CMAKE_FIND_ROOT_PATH the configuration will fail. If cmake is allowed search system paths too, it is most likely that errors will occur during linking step or even runtime.
See find_package docs for more details.
find_package only
All above applies to find_package command too.
find_package can operate in two modes MODULE and CONFIG.
In MODULE mode cmake uses Find[PackageName].cmake script (module) to find dependent package. CMake comes with large number of modules and custom modules can be added with CMAKE_MODULE_PATH variable. Often find-modules can be informed about custom search paths via environment or cmake variables.
E.g. FindGTest.cmake searches path stored in GTEST_ROOT variable.
If no find module is available, find_package enters CONFIG mode. If a dependency package provides [PackageName]Config.cmake or [LowercasePackageName]-config.cmake cmake can be easily informed about that package with [PackageName]_DIR variable.
Example:
CMakeLists.txt contains:
find_package(Qt5)
FindQt5.cmake is not available, but ~/Qt5/Qt5.8/lib/cmake/Qt5Config.cmake file exists, so add
-DQt5_DIR="${HOME}/Qt5/Qt5.8/lib/cmake"
to cmake call.
pkg-config
CMake can use information provided by external pkg-config tool. It is usually done with pkg_check_modules command. Directory used by pkg-config can be customized with PKG_CONFIG_PATH environment variable. According to cmake documentation instead of setting PKG_CONFIG_PATH, custom .pc-files directories can be added via CMAKE_PREFIX_PATH. If CMake version is pre-3.1, PKG_CONFIG_USE_CMAKE_PREFIX_PATH have to be set to TRUE(ON) to enable this feature.
Methods of customizing dependencies search path is defined by CMakeLists.txt content. There is no universal solution here.
And now back to missing SECCOMP headers...
In CMakeLists.txt SECCOMP header is found with
find_path(SECCOMP NAMES "linux/seccomp.h")
but I cannot find any command telling CMake to use the found header. For example:
target_include_directories(<target_name> ${SECCOMP})
or globally:
include_directories(${SECCOMP})
I belive that CMakeLists.txt should be fixed. It is not a platform dependent solution.

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 pass variable to cpack?

I have a cmake project which one of the install targets is a collection of files. This files change depending on the configuration (Release, Debug...).
I would like to be able to install the files like so:
install(DIRECTORY $<TARGET_FILE_DIR:tgt>
DESTINATION bin
COMPONENT files)
But cmake does not support that. Generator variables do not apply to DIRECTORY. So I was wondering if there is a way to either save the directory somewhere. Either the cache or a file and then load it into cpack.
So I guess the question is how to pass a variable from cmake to cpack?
This is a rather late answer, but I happened upon this question trying to solve a somewhat different problem that could also be summarized as: "How do I pass a variable to CPack?" In my case, I was making this call from a customized version of CPackDeb.cmake copied to my workspace:
find_program(OPKG_CMD NAMES opkg-build HINTS "${OPKG_HINT}")
# ^^^^^^^^^^^^
# This is what I wanted to pass to CPack
I was setting OPKG_HINT in a file included from my top-level CMakeLists.txt, but it was not getting passed through to cpack; the above find_program() invocation was seeing an empty string for OPKG_HINT.
The solution turned out to be stupid simple: just prepend CPACK_ to the variable name!
If I do this in CMakeLists.txt:
set(CPACK_OPKG_HINT "${_sysroot_top}/aarch64-poky-linux/usr/bin")
then I can put this in my CPackDeb.cmake file and it works fine:
find_program(OPKG_CMD NAMES opkg-build HINTS "${CPACK_OPKG_HINT}")
Anyway, this wound up being a bit of an X-Y problem for the OP, but... if you really need to set a variable at CMake time in such a way that it's accessible to cpack, prefixing the variable name with CPACK_ seems to do the trick nicely...
The following setup work if you use a "single-configuration generators (such as make and Ninja)" and call CMake with
cmake -DCMAKE_BUILD_TYPE=Release <source_dir>
https://cmake.org/cmake/help/v3.0/variable/CMAKE_BUILD_TYPE.html
You can define the ${dir} variable in another way if you like.
IF (CMAKE_BUILD_TYPE STREQUAL "Release")
SET(dir release_dir)
ELSE()
SET(dir debug_dir)
ENDIF()
INSTALL(DIRECTORY ${dir} DESTINATION bin COMPONENT files)
Until now this seems to be the best answer (from someone on the cmake mail list)
install(DIRECTORY path/to/Debug/dir
DESTINATION bin
CONFIGURATIONS Debug
COMPONENT files
)
install(DIRECTORY path/to/Release/dir
DESTINATION bin
CONFIGURATIONS Release
COMPONENT files
)
CMake 3.5 supports generator expressions for the DIRECTORY arguments. See installing directories.

pkg_check_modules cannot find *.pc.cmake

I am using a 3rd party library rbdl, which contains rbdl.pc.cmake, which 'I suppose' is included for using pkg_check_modules in a cmake file.
I update PKG_CONFIG_PATH to point at the rbdl folder
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CMAKE_BINARY_DIR}/externals/rbdl")
pkg_check_modules(RBDL rbdl)
but pkg_check_modules says it cannot find the module.
When I manually duplicate rbdl.pc.cmake, rename the copy into rbdl.pc and run pkg-config --cflags --libs rbdl in terminal, then my cmake also start working!
Interestingly, now even if I delete rbdl.pc, rbdl module if perfectly found by rbdl.pc.cmake!
So my questions are:
What is the difference between *.pc and *.pc.cmake?
How do I correctly setup my cmake to work with original rbdl.pc.cmake?
Why rbdl.pc.cmake starts to be accepted by pkg_check_modules after that tweak with duplicating it, renaming the copy and running pkg-config manually?
You understand it wrong! rbdl.pc.cmake is just a template file. It is not supposed to be used by you! Take a look into CMakeLists.txt line 160 -- configure_file() used to render variables ("quoted" by # in template file) and produce a rbdl.pc (a real pkg-config) file. Latter should be installed (some way) and then will be available to pkg-config hence can be used in your project.
pkg-config is stupid do not interpret or validate compiler/linker flags any way, so your renamed file "works" (yeah, producing invalid command line for compiler/linker).
I wish you to read CMake documentation before trying to code something using it! It'll save your time and give you a necessary knowledge which stops you from doing stupid things like you described in your question ;-)