What is the purpose of a .cmake file? - cmake

I might be googling wrongly, but I'm unable to find what's the purpose of .cmake files.
I've just stumbled across the CMake tool for a project I've to work with and I'm having a hard time to understand how it works. I do understand that running the CMake command in a directory containing a CMakeLists.txt executes the commands in that file (along with the commands in the CMakeLists.txt contained in the sub-directories) but the purpose of .cmake files is a lot more fuzzy.
It seems that they are used to define functions/set variables that are thereafter used in the CMakeLists.txt but I'm not sure. How are they used by the CMake tool ?

You can include it with the include command. Similar to how other languages allow you to split source files into modules or header files, they can contain function definitions, macros which can then be reused across multiple CmakeLists.
See https://cmake.org/cmake/help/v3.0/command/include.html
Note that you can actually include any file, but a .cmake extension is commonly used.

Within this file you can define functions of macros which can be used in your CMakeLists.txt file. But there are some more other applications for .cmake files. For example if you want to provide a library or tool they should at least contain a <name>Config.cmake so that your library can be used with the find_package() command. Further information can be found in CMake Wiki

CMake input files are written in the "CMake Language" in source files named CMakeLists.txt or ending in a .cmake file name extension.
https://cmake.org/cmake/help/latest/manual/cmake-language.7.html
This means they're one and the same thing. "CMakeLists.txt" is simply the default name. If you decide to split the code (CMake is technically just another interpreted language) into separate files/modules (that you can include into each other), they obviously can't all have the same name, so you would use the ".cmake" extension. Theoretically, you could call "CmakeLists.txt" as "CmakeLists.cmake", but then cmake won't be able to find it by default, so you'd have to pass the filename as a command-line argument. So it is just a difference of naming conventions. Everything you can put in one file, you can put in the other, and vice-versa.

Related

Which file organization for CMake? Should CMakeLists.txt include other files?

I use CMake to configure, build and install a C++ code.
I have defined some user options.
I have added an option to let CMake download external depedencies.
Etc, etc.
For the moment, everything concerning CMake is written in a single file CMakeLists.txt. There is also a configuration file 'config.cmake' which allows users to define various parameters such as verbosity level, paths to libraries, flags for compilers, etc.
What is a good file organization for CMake?
Should CMakeLists.txt file be divided into subfiles?
Thank you very much for your help!
A good file organization depends on how large your CMake logic is, or how large you expect it to become. Generally speaking:
Functionality that may get reused a lot you probably will want to organize into "per topic" .cmake files which contain macros, and include them in your other CMakeLists.txt files to load that functionality. You'll find lots of these already out there on the web (custom Find*.cmake files for locating particular system libraries are quite common, for example.) A common convention is to have a directory "CMake" in your toplevel source directory, although other configurations are possible.
If you have a lot of different build targets with their own unique source files (multiple libraries in a single project, for example) it is good practice to separate those into subdirectories and have one CMakeLists.txt file per subdirectory, with the toplevel CMakeLists.txt file using add_subdirectory to "hook them in" to the main build.
A "typical" structure for a project could look like this:
project/
CMakeLists.txt
README
CMake/
FindSpecialtyLib1.cmake
FindSpecialtyLib2.cmake
CustomCMakeMacroA.cmake
etc...
include/
CMakeLists.txt (for installing headers, etc. if needed.)
src/
CMakeLists.txt (top level switching logic per user settings, etc.)
lib1/
CMakeLists.txt
src1.cxx
src2.cxx
lib2/
CMakeLists.txt
src1.cxx
src2.c
private_header.h
That's just a hypothetical example, of course - you'll want to shape your logic to your specific project. Since you mention a config.cmake file, it's probably worth mentioning that the majority of variable setting of that sort is usually done in the cmake-gui or from -D definitions at the CMake command line, in my experience. A config.cmake works as a way to group options, but most users are probably going to start with the gui when it comes to setting things. I also recommend checking the CMake email archives for specific questions - I've found it to be an extremely helpful resource.

How is CMake used? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
It is notoriously difficult to get any useful information on CMake as a beginner. So far, I've seen a few tutorials on how to set up some very basic project or another. However, none of these explain the reasoning behind anything that is shown in them, always leaving many holes to fill.
What does calling CMake on a CMakeLists mean? Is it supposed to be called once per build tree or what? How do I use different settings for each build if they all use the same CMakeLists.txt file from the same source?
Why does each subdirectory need its own CMakeLists file? Would it make sense to use CMake on a CMakeLists.txt other than the one at the root of the project? If so, in what cases?
What's the difference between specifying how to build an executable or library from the CMakeLists file in their own subdirectory versus doing it in the CMakeLists file at the root of all source?
Can I make a project for Eclipse and another for Visual Studio, just changing the -G option when calling CMake? Is that even how it's used?
None of the tutorials, documentation pages or questions/answers I've seen so far give any useful insight towards understanding how to use CMake. The examples are just not thorough. No matter what tutorials I read, I feel like I'm missing something important.
There are many questions asked by CMake newbies like me that don't ask this explicitly, but that make obvious the fact that, as newbs, we have no idea how to deal with CMake or what to make of it.
What is CMake for?
According to Wikipedia:
CMake is [...] software for managing the build process of software
using a compiler-independent method. It is designed to support
directory hierarchies and applications that depend on multiple
libraries. It is used in conjunction with native build environments
such as make, Apple's Xcode, and Microsoft Visual Studio.
With CMake, you no longer need to maintain separate settings specific to your compiler/build environment. You have one configuration, and that works for many environments.
CMake can generate a Microsoft Visual Studio solution, an Eclipse project or a Makefile maze from the same files without changing anything in them.
Given a bunch of directories with code in them, CMake manages all the dependencies, build orders and other tasks that your project needs done before it can be compiled. It does NOT actually compile anything. To use CMake, you must tell it (using configuration files called CMakeLists.txt) what executables you need compiled, what libraries they link to, what directories there are in your project and what is inside of them, as well as any details like flags or anything else you need (CMake is quite powerful).
If this is correctly set up, you then use CMake to create all of the files that your "native build environment" of choice needs to do its job. In Linux, by default, this means Makefiles. So once you run CMake, it will create a bunch of files for its own use plus some Makefiles. All you need to do thereafter is type "make" in the console from the root folder every time you're done editing your code, and bam, a compiled and linked executable is made.
How does CMake work? What does it do?
Here is an example project setup that I will use throughout:
simple/
CMakeLists.txt
src/
tutorial.cxx
CMakeLists.txt
lib/
TestLib.cxx
TestLib.h
CMakeLists.txt
build/
The contents of each file are shown and discussed later on.
CMake sets your project up according to the root CMakeLists.txt of your project, and does so in whatever directory you executed cmake from in the console. Doing this from a folder that isn't the root of your project produces what is called an out-of-source build, which means files created during compilation (obj files, lib files, executables, you know) will be placed in said folder, kept separate from the actual code. It helps reduce clutter and is preferred for other reasons as well, which I will not discuss.
I do not know what happens if you execute cmake on any other than the root CMakeLists.txt.
In this example, since I want it all placed inside the build/ folder, first I have to navigate there, then pass CMake the directory in which the root CMakeLists.txt resides.
cd build
cmake ..
By default, this sets everything up using Makefiles as I've said. Here is what the build folder should look like now:
simple/build/
CMakeCache.txt
cmake_install.cmake
Makefile
CMakeFiles/
(...)
src/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
lib/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
What are all of these files? The only thing you have to worry about is the Makefile and the project folders.
Notice the src/ and lib/ folders. These have been created because simple/CMakeLists.txt points to them using the command add_subdirectory(<folder>). This command tells CMake to look in said folder for another CMakeLists.txt file and execute that script, so every subdirectory added this way must have a CMakeLists.txt file within. In this project, simple/src/CMakeLists.txt describes how to build the actual executable and simple/lib/CMakeLists.txt describes how to build the library. Every target that a CMakeLists.txt describes will be placed by default in its subdirectory within the build tree. So, after a quick
make
in console done from build/, some files are added:
simple/build/
(...)
lib/
libTestLib.a
(...)
src/
Tutorial
(...)
The project is built, and the executable is ready to be executed. What do you do if you want the executables put in a specific folder? Set the appropriate CMake variable, or change the properties of a specific target. More on CMake variables later.
How do I tell CMake how to build my project?
Here are the contents, explained, of each file in the source directory:
simple/CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(Tutorial)
# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)
The minimum required version should always be set, according to the warning CMake throws when you don't. Use whatever your version of CMake is.
The name of your project can be used later on, and hints towards the fact you can manage more than one project from the same CMake files. I won't delve into that, though.
As mentioned before, add_subdirectory() adds a folder to the project, which means CMake expects it to have a CMakeLists.txt within, which it will then run before continuing. By the way, if you happen to have a CMake function defined you can use it from other CMakeLists.txts in subdirectories, but you have to define it before you use add_subdirectory() or it won't find it. CMake is smarter about libraries, though, so this is likely the only time you will run into this kind of problem.
simple/lib/CMakeLists.txt:
add_library(TestLib TestLib.cxx)
To make your very own library, you give it a name and then list all the files it's built from. Straightforward. If it needed another file, foo.cxx, to be compiled, you would instead write add_library(TestLib TestLib.cxx foo.cxx). This also works for files in other directories, for instance add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx). More on the CMAKE_SOURCE_DIR variable later.
Another thing you can do with this is specify that you want a shared library. The example: add_library(TestLib SHARED TestLib.cxx). Fear not, this is where CMake begins to make your life easier. Whether it's shared or not, now all you need to handle to use a library created in this way is the name you gave it here. The name of this library is now TestLib, and you can reference it from anywhere in the project. CMake will find it.
Is there a better way to list dependencies? Definitely yes. Check down below for more on this.
simple/lib/TestLib.cxx:
#include <stdio.h>
void test() {
printf("testing...\n");
}
simple/lib/TestLib.h:
#ifndef TestLib
#define TestLib
void test();
#endif
simple/src/CMakeLists.txt:
# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)
# Link to needed libraries
target_link_libraries(Tutorial TestLib)
# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)
The command add_executable() works exactly the same as add_library(), except, of course, it will generate an executable instead. This executable can now be referenced as a target for things like target_link_libraries(). Since tutorial.cxx uses code found in the TestLib library, you point this out to CMake as shown.
Similarly, any .h files #included by any sources in add_executable() that are not in the same directory as the source have to be added somehow. If not for the target_include_directories() command, lib/TestLib.h would not be found when compiling Tutorial, so the entire lib/ folder is added to the include directories to be searched for #includes. You might also see the command include_directories() which acts in a similar fashion, except that it does not need you to specify a target since it outright sets it globally, for all executables. Once again, I'll explain CMAKE_SOURCE_DIR later.
simple/src/tutorial.cxx:
#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
test();
fprintf(stdout, "Main\n");
return 0;
}
Notice how the "TestLib.h" file is included. No need to include the full path: CMake takes care of all that behind the scenes thanks to target_include_directories().
Technically speaking, in a simple source tree like this you can do without the CMakeLists.txts under lib/ and src/ and just adding something like add_executable(Tutorial src/tutorial.cxx) to simple/CMakeLists.txt. It's up to you and your project's needs.
What else should I know to properly use CMake?
(AKA topics relevant to your understanding)
Finding and using packages: The answer to this question explains it better than I ever could.
Declaring variables and functions, using control flow, etc.: check out this tutorial that explains the basics of what CMake has to offer, as well as being a good introduction in general.
CMake variables: there are plenty, so what follows is a crash course to get you on the right track. The CMake wiki is a good place to get more in-depth information on variables and ostensibly other things as well.
You may want to edit some variables without rebuilding the build tree. Use ccmake for this (it edits the CMakeCache.txt file). Remember to configure when done with the changes and then generate makefiles with the updated configuration.
Read the previously referenced tutorial to learn about using variables, but long story short:
set(<variable name> value) to change or create a variable.
${<variable name>} to use it.
CMAKE_SOURCE_DIR: The root directory of source. In the previous example, this is always equal to /simple
CMAKE_BINARY_DIR: The root directory of the build. In the previous example, this is equals to simple/build/, but if you ran cmake simple/ from a folder such as foo/bar/etc/, then all references to CMAKE_BINARY_DIR in that build tree would become /foo/bar/etc.
CMAKE_CURRENT_SOURCE_DIR: The directory in which the current CMakeLists.txt is in. This means it changes throughout: printing this from simple/CMakeLists.txt yields /simple, and printing it from simple/src/CMakeLists.txt yields /simple/src.
CMAKE_CURRENT_BINARY_DIR: You get the idea. This path would depend not only on the folder the build is in, but also on the current CMakeLists.txt script's location.
Why are these important? Source files will obviously not be in the build tree. If you try something like target_include_directories(Tutorial PUBLIC ../lib) in the previous example, that path will be relative to the build tree, that is to say it will be like writing ${CMAKE_BINARY_DIR}/lib, which will look inside simple/build/lib/. There are no .h files in there; at most you will find libTestLib.a. You want ${CMAKE_SOURCE_DIR}/lib instead.
CMAKE_CXX_FLAGS: Flags to pass on to the compiler, in this case the C++ compiler. Also worth noting is CMAKE_CXX_FLAGS_DEBUG which will be used instead if CMAKE_BUILD_TYPE is set to DEBUG. There are more like these; check out the CMake wiki.
CMAKE_RUNTIME_OUTPUT_DIRECTORY: Tell CMake where to put all executables when built. This is a global setting. You can, for instance, set it to bin/ and have everything neatly placed there. EXECUTABLE_OUTPUT_PATH is similar, but deprecated, in case you stumble upon it.
CMAKE_LIBRARY_OUTPUT_DIRECTORY: Likewise, a global setting to tell CMake where to put all library files.
Target properties: you can set properties that affect only one target, be it an executable or a library (or an archive... you get the idea). Here is a good example of how to use it (with set_target_properties().
Is there an easy way to add sources to a target automatically? Use GLOB to list everything in a given directory under the same variable. Example syntax is FILE(GLOB <variable name> <directory>/*.cxx).
Can you specify different build types? Yes, though I'm not sure about how this works or the limitations of this. It probably requires some if/then'ning, but CMake does offer some basic support without configuring anything, like defaults for the CMAKE_CXX_FLAGS_DEBUG, for instance.
You can either set your build type from within the CMakeLists.txt file via set(CMAKE_BUILD_TYPE <type>) or by calling CMake from console with the appropriate flags, for example cmake -DCMAKE_BUILD_TYPE=Debug.
Any good examples of projects that use CMake? Wikipedia has a list of open-source projects that use CMake, if you want to look into that. Online tutorials have been nothing but a letdown to me so far in this regard, however this Stack Overflow question has a pretty cool and easy-to-understand CMake setup. It's worth a look.
Using variables from CMake in your code: Here's a quick and dirty example (adapted from some other tutorial):
simple/CMakeLists.txt:
project (Tutorial)
# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)
# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)
simple/TutorialConfig.h.in:
// Configured options and settings
#define Tutorial_VERSION_MAJOR #Tutorial_VERSION_MAJOR#
#define Tutorial_VERSION_MINOR #Tutorial_VERSION_MINOR#
The resulting file generated by CMake, simple/src/TutorialConfig.h:
// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1
With clever use of these you can do cool things like turning off a library and such. I do recommend taking a look at that tutorial as there are some slightly more advanced things that are bound to be very useful on larger projects, sooner or later.
For everything else, Stack Overflow is brimming with specific questions and concise answers, which is great for everyone except the uninitiated.

CMake find package files, how are the config files used?

I have a project that uses a 3rd party library (let's call it somelib) for which I wrote a cmake file to search for it.
This is the somelibConfig.cmake file I wrote and placed in /usr/local/lib/cmake/somelib/:
FIND_LIBRARY(somelib_LIBRARY somelib
PATHS /usr/local/lib
NO_DEFAULT_PATH
)
SET(somelib_LIBRARIES ${somelib_LIBRARY})
FIND_PATH(somelib_INCLUDE_DIR somelib.hpp
PATHS /usr/local/include/somelib
NO_DEFAULT_PATH
)
SET(somelib_INCLUDE_DIRS ${somelib_INCLUDE_DIR})
Then, if I do find_package(somelib REQUIRED) it works ok.
However, if I move and rename somelibConfig.cmake to myproject/CMakeModules/Findsomelib.cmake (this directory is added to CMAKE_MODULE_PATH), after find_package I see that variables somelib_INCLUDE_DIRS and somelib_LIBRARY are correctly filled, but somelib_FOUND is not set (and even so, find_package does not abort the compilation).
Is that *Config.cmake valid for a Find*.cmake?
How is it possible that all the variables but the *_FOUND one are set?
Why does not find_package with REQUIRED abort the compilation if *_FOUND is not set?
Config files and find-modules are fundamentally different.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
Only the developers of somelib ship a config file (if they do). If they don't, then you need to write a find-module to find somelib. Such a find-module should not be copied to /usr/local as you did. Just keep it with your project and ask the somelib developers to ship a config file instead. config files shipped by upstream is superior to find modules written by you. It doesn't matter if somelib upstream does not use cmake. Both Qt and LLVM ship config files when using non-cmake buildsystems.
One example of inferiority is that when writing a find-module you need to set the _FOUND variable. More information about writing find-modules is here:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#manual:cmake-developer%287%29
If you are searching in default library folder your parameters should not contain NO_DEFAULT_PATH.
Try this,
SET(libraryName "somelibrary.so") #in linux .a or .so
FIND_LIBRARY(LIBRARY ${libraryName}
PATHS "/usr/local/lib/cmake/somelib/"
)
MESSAGE("library path ${LIBRARY})
If this was successful, LIBRARY_FOUND will be set.
P.S: Note the quotes

Package & library management & installation, and interface with cmake

I have a specific question which serves as context for a more general question.
There is a scientific package called LAMMPS, and it is usually used as an executable. However, it supports use as a "library". To try to do things right, I put it in /usr/local/lib/lammps. It contains a lammps/src/ directory, which has around 40 source files. Using the instructions provided, I compiled lammps as a .so file in lammps/src/liblammps_serial.so.
I also have separate code in "~/code/ljtube/". This uses cmake to try to find the library. Thus, I wrote a FindLAMMPS.txt so that I could use
FIND_PACKAGE (lammps)
in my CMakeLists. I modified the libtool config file to search in /usr/local/ successfully. I found that it searches in /usr/local/lib/ for a .so file and in /usr/local/include/ for a .h file. So I made a dynamic link to the .so file in /usr/local/lib/, and I copied the .h file from the lammps/src/ to /usr/local/include/.
CMake can now find those two files, but it cannot link to anything else in lammps/src/. It seems absurd to need to make a separate FIND_PACKAGE for each of the .h's I want to include (group.h, fix.h, force.h, pair.h, etc.). It also seems ridiculous to dump the whole package of .h files into the /usr/local/include/ directory. I will be using this code both locally and on a cluster, and possibly distributing it to other group members.
How can I make CMake find what I want to find without hard coding in the location of /usr/local/lib/lammps/src/? Phrased more generically, how should I manage large packages like these to make them easy to link to in the code I write, even if the original developer did not use the best conventions?
(As a side note, I am using a shared library because it seems like the right choice, but I'm not especially married to it. Should I be using a static library? Is there a way for CMake to find an already-compiled library relative to the current source directory, and might that be a better way to implement this? I know that I will be using LAMMPS in multiple projects, so having a local shared copy superficially seems to make the most sense.)
Normally a find_package call yields a variable specifying the path to the "includes" folder of the package. This would then be added in the caller's CMakeLists.txt via include_directories.
For example, to use find_package for boost, you could do:
find_package(Boost) # sets ${Boost_INCLUDE_DIRS} and ${Boost_LIBRARIES}
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(foo foo.cc)
target_link_libraries(foo ${Boost_LIBRARIES})
endif()
Regarding your side note, you could use find_library and/or find_path to find the library and its headers given a known location.
Both these commands can be invoked in such a way as to avoid searching in common locations, e.g. by setting PATHS to the known location and using NO_DEFAULT_PATH in the find commands.
Another alternative is for your projects to make use of the ExternalProject_Add function which is described in more detail in this article. From this article:
The ExternalProject_Add function makes it possible to say “download this project from the internet, run its configure step, build it and install it”
A downside to this approach is that each of your projects would end up with its own copy of the third party sources and lib.

Ignoring a single file when using include_directories with CMake

is there anyway to tell CMake to ignore one specific header file when using include_directories ?
Since the directories are not expanded into single files I can't just list(REMOVE_ITEM ..) the file out.
cheers Daniel
An include_directories call in CMakeLists does not result in a list of all available header-files. It simply passes those directories directly to the compiler as a search-dir for your "#include <...>" E.g. look at the documentation for the "-I" option of GCC 4.6.
In addition: I am not sure why you would want to exclude a single file. Very often you can work around a problematic header file, by creating your own header-file in your own project which includes everything except that single-file...
If you really, really want something like this and you insist on solving it with CMake, you will probably end up with file-globing all header-files, copying (without that one file of course) them manually to a new include-dir and then include that new dir.