CMake ignoring CMAKE_MODULE_PATH - cmake

I'm having trouble getting CMake's include() statement to recognize CMAKE_MODULE_PATH. I'm hoping to do something like this:
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(Foo.cmake)
with this style of directory tree:
.
├── cmake
│   └── Foo.cmake
├── CMakeLists.txt
However, I get the error:
include could not find load file:
Foo.cmake
Based on the docs for include() and CMAKE_MODULE_PATH, I thought that this should be possible.
If I keep the same tree but modify the include, it loads fine:
include(cmake/Foo.cmake)
Am I mistaken or doing something wrong?
Thanks!

It should be a module name - without .cmake extension - for apply CMAKE_MODULE_PATH variable when search the file with include command:
# This searches a *module* and uses 'CMAKE_MODULE_PATH' variable
include(Foo)
# This searches a *file* and doesn't use 'CMAKE_MODULE_PATH' variable
include(Foo.cmake)
The signature of include function
include(<file|module> [OPTIONAL] [RESULT_VARIABLE ]
[NO_POLICY_SCOPE])
means that its first argument could be either a file or a module.
And CMAKE_MODULE_PATH variable is applied only when search a module:
If a module is specified instead of a file, the file with name <modulename>.cmake is searched first in CMAKE_MODULE_PATH, then in the CMake module directory.
The name of the file - <modulename>.cmake - suggests that module name shouldn't have .cmake suffix.

Related

How can we refer external cmake file from main CMakeLists.txt file?

Let's say I have some protobuf related cmake code as a library that resides inside CMakeLists.pro file and I need to include this library as a external file configuration. How to do that ?
I think this question is asking how to make cmake modules. IE you have helper code and would like to make it easily available.
A normal top level project has a top level cmake folder. Here is an example of what that would look like.
cmake
tests
src
.gitignore
CMakeLists.txt
README.md
Inside the cmake folder say you have a cmake module called foo.cmake
(It's important to make the file end with .cmake file extension)
Anyway this is what your foo.cmake may look like
# Include guards need at least cmake 3.10
include_guard() # Good practice to use an include_guard()
function(bar)
...
endfunction()
Now in your main cmakelists how do you call this function? Simple.
cmake_minimum_required(VERSION 3.18)
# Add the cmake folder to the cmake module path, this makes it easier to include files
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
# Include foo.cmake
include(foo)
# Call the bar function you defined in foo.cmake
bar()
And that's how you can refer to external cmake file from the main CMakeLists.txt

Should I modify CMAKE_MODULE_PATH in PackageConfig.cmake

I am writing a MyPackageConfig file for my project with exported targets so that other projects can easily find MyPackage and it's dependencies. It looks like this:
include(CMakeFindDependencyMacro)
find_dependency(LIB1_WITHOUT_CMAKE_CONFIG)
find_dependency(LIB2_WITH_CMAKE_CONFIG)
include (Some/Install/Dir/MyPackageTargets.cmake)
I am wondering if it is smart to add the following lines to the MyPackageConfig.cmake before the find_dependency calls
# Find target dependencies
# Allows packages linking with MyPackage to use the find modules that
# MyPackage used to find it's dependencies. Since this path is appended to
# the existing module path, the calling package's module path will take
# precedence
list(APPEND CMAKE_MODULE_PATH #CMAKE_INSTALL_PREFIX#/lib/cmake/MyPackage/modules)
# Allows packages linking with MyPackage to find MyPacakge's dependencies if
# they don't already have them. Since this path (or these paths) are
# appended to the existing prefix path, the calling package's prefix
# path will take precedence
list(APPEND CMAKE_PREFIX_PATH #CMAKE_PREFIX_PATH#)
find_dependency(LIB1_WITHOUT_CMAKE_CONFIG)
find_dependency(LIB2_WITH_CMAKE_CONFIG)
Good idea? No?
Longer explanation of my rationale:
How does YourPackage that uses MyPackage find LIB1?
(i). You could write your own FindLIB1.cmake but that's duplication of effort
(ii). I could install my FindLIB1.cmake alongside my MyPackageConfig.cmake in a Modules dir. But you will have to include this path in your module path.
My suggestion: Add a line before find_dependency(LIB1_WITHOUT_CMAKE_CONFIG) modifying the module path like so:
list(APPEND CMAKE_MODULE_PATH #CMAKE_INSTALL_PREFIX#/lib/cmake/mstk/modules)
This will ensure that if you have a FindLIB1.cmake, it will be used but if you don't mine will be found and used.
How do you know where the LIB1 and LIB2 reside (including LIB2's Config file)?
By adding the line
list(APPEND CMAKE_PREFIX_PATH #CMAKE_PREFIX_PATH#)
I tell your package where I searched and found my dependencies (but only if you didn't already have them in the CMAKE_PREFIX_PATH you specified)
Yes, you may change variables like CMAKE_MODULE_PATH or CMAKE_PREFIX_PATH for the purpose of your config script.
Any "good" project should be prepared to prepending/appending CMAKE_PREFIX_PATH, because this variable could normally be set by a user (when call cmake). As for CMAKE_MODULE_PATH, module's names in different directories are rarely conflicted.
Some hints:
You may restore the variables at the end of your script. Such way you won't affect the calling code when changing the variables:
# Store old value of the variable
set(old_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
# Change variable, use it, ...
# ...
# Restore the variable at the end
set(CMAKE_MODULE_PATH ${old_CMAKE_MODULE_PATH})
Note, however, that find_dependency returns from the script if an (inner) package not found, so restoring the variable won't trigger in that case. But usually find_package() is called with REQUIRED keyword, so failing to find the inner package would be fatal.
Instead of changing CMAKE_PREFIX_PATH you may set other variables which affect only specific find script and doesn't affect others. E.g many find scripts use XXX_ROOT variables for hint about location.
For find config script itself, you may use PATHS or HINTS options of find_package():
# Was:
#- list(APPEND CMAKE_PREFIX_PATH #CMAKE_PREFIX_PATH#)
#- find_dependency(LIB2_WITH_CMAKE_CONFIG)
# Replace with:
find_dependency(LIB2_WITH_CMAKE_CONFIG
PATHS #CMAKE_PREFIX_PATH# # Where to find config script
NO_DEFAULT_PATH # Do not search other places
)

Multiple CMakeLists

Suppose I have a directory structure as follows:
/main.cpp
/CMakeLists.txt
/foo/foo.cpp
/foo/CMakeLists.txt
where my /CMakeLists.txt file contains the following:
project(Test)
add_subdirectory("foo")
add_executable(Test main.cpp foo/foo.cpp)
target_link_libraries(Test ${OpenNI_LIB})
and my /foo/CMakeLists.txt file contains the following:
find_library(OpenNI REQUIRED)
When I use the line add_subdirectory("foo") in the first CMakeLists.txt, what actually happens? Does it search for a second CMakeLists.txt file in foo, and add the contents to the first? Will any variables defined the second file be available in the first? And specifically in this example, will the variable ${OpenNI_LIB} be recognised in the first, given that it is defined in the second?
Thanks.
Does it search for a second CMakeLists.txt file in foo
Yes, it does
and add the contents to the first?
No it doesn't. It performs a number of configuring actions such as finding libraries etc and a generates separate Makefile and/or other build-time artifacts.
And specifically in this example, will the variable ${OpenNI_LIB} be recognised in the first, given that it is defined in the second?
no, unless such a construction
find_library(OpenNI REQUIRED) # this sets variables for OpenNI
# in the context of foo/CMakeLists.txt
set(OpenNI_LIB ${OpenNI_LIB} PARENT_SCOPE) # this copies ${OpenNI_LIB}
# into the context of /CMakeLists.txt
is used in foo/CMakeLists.txt
By default variables defined in a subdirectory's CMakeLists.txt are also defined in the subdirectory's subdirectories, that is if foo/ in turn contained bar/ with its own CMakeLists.txt, then within bar/'s CMakeLists.txt ${OpenNI_LIB} would be set.
P.S. message(STATUS "Some message with ${VAR}") in doubtful places of CMakeLists.txt is your friend. Just look into cmake output.

Change cmake source search location

I have the following directory structure:
├───3rd
│ └───lua // this is git submodule, I can't modify anything here
│ ├───doc
│ └───src
└───cmake
└───lua // CMakeLists.txt for ../../3rd/lua is here
I'm pulling external library to my repo let's say lua. There's no cmake support in the distrubution. And I can't build it on windows with nmake. Then I want to create a CMakeLists.txt somewhere in my repo for lua.
Let's say I place CMakeLists.txt for lua in ./cmake/lua/CMakeLists.txt. Relative to this location I have to specify sources prefixed with ../../3rd/lua/src/ which is not nice
set(SOURCES
../../3rd/lua/src/lapi.c
../../3rd/lua/src/lauxlib.c
../../3rd/lua/src/lbaselib.c
<...>)
add_library(liblua ${SOURCES}).
Putting ../../3rd/lua/src/ into a variable and prefixing each of the source files with it is not nice too. So I want to change base search path for source files with ${PROJECT_SOURCE_DIR}/../../3rd/lua/src. And I also want to affect base path for include_directories. I thought changing PROJECT_SOURCE_DIR to this will do, but it has no effect at all.
I used a script found here CMAKE: Print out all accessible variables in a script to list all variables and all of them referring to CMakeLists.txt location I changed to ${PROJECT_SOURCE_DIR}/../../3rd/lua/src:
set(CMAKE_CURRENT_LIST_DIR C:/dev/lua-external-cmake/3rd/lua/src)
set(CMAKE_CURRENT_SOURCE_DIR C:/dev/lua-external-cmake/3rd/lua/src)
set(CMAKE_HOME_DIRECTORY C:/dev/lua-external-cmake/3rd/lua/src)
set(CMAKE_SOURCE_DIR C:/dev/lua-external-cmake/3rd/lua/src)
set(PROJECT_SOURCE_DIR C:/dev/lua-external-cmake/3rd/lua/src)
set(Project_SOURCE_DIR C:/dev/lua-external-cmake/3rd/lua/src)
It seems there is no such variable, since this change had no effect. I'm aware that changing some of those is utterly wrong. I did it just to find out if there will be any effect.
So, how do I change source search location and base path for include files in cmake?
There is no source search path in CMake. But you can easily "rebase" sources using common cmake commands:
set(SOURCES
lapi.c
lauxlib.c
lbaselib.c
<...>)
set(SOURCES_ABS)
foreach(source ${SOURCES})
list(APPEND SOURCES_ABS ${PROJECT_SOURCE_DIR}/../../3rd/lua/src/${source})
endforeach()
add_library(liblua ${SOURCES_ABS}).

Changing cmake directories

I'm writing a cmake file for a project which has the following structure
project/ (root)
libraries/ (contains (precompiled) libraries
src/
code/ (contains a set of fortran files)
My CMakeLists.txt file is currently in project/ and effectively is just
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (sc1 sc1.f90)
target_link_libraries(sc1 ${PROJ_LIBRARY})
This creates my binary in the same folder as the source code, when I actually want it in the level above (i.e. in the src folder - this structure will be changed so we have a bin folder eventually), but haven't worked out how to do it.
Some answers on SO say you have to have a CMakeLists.txt file in every folder - is this correct? Is it possible to set an environment variable or use a CMake variable (e.g. http://cmake.org/cmake/help/v2.8.8/cmake.html#command:set). It's also not very clear from some answers whether the solutions they have posted are C++ specific (as that is what language CMake most often seems to be used for).
Edit
I found out that I can change it to the behaviour I want by modifying it slightly:
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (src/sc1 ${projsrc}/sc1.f90)
target_link_libraries(src/sc1 ${PROJ_LIBRARY})
However, this doesn't explain why my behaviour is different to how it should be, according to arrowdodger below. I'm also still trying to work out how to display the values of environment variables; I've tried the following with no luck:
message(${RUNTIME_OUTPUT_DIRECTORY})
message($ENV{RUNTIME_OUTPUT_DIRECTORY})
message(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
message($ENV{CMAKE_RUNTIME_OUTPUT_DIRECTORY})
By default, binaries will appear in respective subdirectory of your build dir. By respective i mean the directory that contains CMakeLists.txt with add_executable() call.
For example, if you have following CMakeLists.txt
add_executable(tgt1 src1.f90)
add_executable(tgt2 subdir/src2.f90)
in the root folder, you will get both binaries in ${CMAKE_BINARY_DIR}. So if you wish tgt2 to be in ${CMAKE_BINARY_DIR}/subdir, you need to add CMakeLists.txt there and call add_executable(tgt2 src2.f90) from there.
You can change this behavior:
CMAKE_LIBRARY_OUTPUT_DIRECTORY, CMAKE_RUNTIME_OUTPUT_DIRECTORY and others.
You can also set respective target properties.