|
|
If you want to write software which compiles and runs on different
|
|
|
operating systems, you have to take care for the special properties of
|
|
|
the different platforms. On different operating systems there are subtle
|
|
|
differences, e.g. on FreeBSD you should not use malloc.h, while it is
|
|
|
perfectly ok to use it on Linux. These differences are typically handled
|
|
|
by providing a header file which contains a bunch of define-statements
|
|
|
according to the platform properties, usually named config.h:
|
|
|
|
|
|
#define HAVE_MALLOC_H 1
|
|
|
/* #undef HAVE_SYS_MNTTAB_H 1 */
|
|
|
/* #undef HAVE_SYS_MNTENT_H 1 */
|
|
|
#define HAVE_SYS_MOUNT_H 1
|
|
|
|
|
|
This header file is then included in the source files and handled
|
|
|
appropriately:
|
|
|
|
|
|
foo.c:
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
#ifdef HAVE_MALLOC_H
|
|
|
#include <malloc.h>
|
|
|
#else
|
|
|
#include <stdlib.h>
|
|
|
#endif
|
|
|
|
|
|
void do_something()
|
|
|
{
|
|
|
void *buf=malloc(1024);
|
|
|
...
|
|
|
}
|
|
|
|
|
|
The contents of config.h depend on the platform where the sources are
|
|
|
compiled, so there needs to be a way to generate this header file before
|
|
|
the actual compilation process starts. If you are using autotools-based
|
|
|
software, you probably know the `./configure` step, which has to be
|
|
|
executed before starting `make`. The `./configure` script does some
|
|
|
system introspection and generates from the gathered information the
|
|
|
`config.h` header file. CMake is able to do the same, and I'll show you
|
|
|
how to do it.
|
|
|
|
|
|
Additionally to the builtin commands, cmake offers more commands
|
|
|
implemented by cmake script files, called modules. These files are
|
|
|
located in the cmake module directory, on UNIX systems is this by
|
|
|
default `/usr/local/share/CMake/Modules`.
|
|
|
|
|
|
To use commands from these modules, they have to be included in the
|
|
|
CMakeLists.txt. CMake comes with several modules for checking the
|
|
|
system, they all follow the same style, as an example here
|
|
|
CHECK_INCLUDE_FILES:
|
|
|
|
|
|
INCLUDE (CheckIncludeFiles)
|
|
|
# usage: CHECK_INCLUDE_FILES (<header> <RESULT_VARIABLE> )
|
|
|
|
|
|
CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
|
|
|
CHECK_INCLUDE_FILES ("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H)
|
|
|
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
|
|
|
|
|
The CMake module CheckIncludeFiles offers the command
|
|
|
CHECK_INCLUDE_FILES(). The first argument to this command is the
|
|
|
header you want to check for. The second argument is the variable which
|
|
|
will contain the result. If the given header was found, it is set to 1,
|
|
|
otherwise it is empty. If another header is required to use the header
|
|
|
you are looking for, you have to list the header files separated by
|
|
|
semicolons, as you can see above. To see what CHECK_INCLUDE_FILES()
|
|
|
exactly does, have a look at the implementation:
|
|
|
`/usr/local/share/CMake/Modules/CheckIncludeFiles.cmake` . There you'll
|
|
|
see that it tries to compile a simple source file which includes the
|
|
|
specified header files. The results of the tests are stored in the file
|
|
|
CMakeCache.txt, so if you want to check later whether the test succeeded
|
|
|
or not look in the CMakeCache.txt file :
|
|
|
|
|
|
//Have include HAVE_MALLOC_H
|
|
|
HAVE_MALLOC_H:INTERNAL=1
|
|
|
|
|
|
As long as the result is in the cache, the test won't be executed again.
|
|
|
If you want it to be executed again, either delete the file
|
|
|
CMakeCache.txt, then all tests will be executed again, or just remove
|
|
|
the entries for the variables you want to have tested again. This can
|
|
|
save some time. If the test failed, and you want to find out why, open
|
|
|
`CMakeFiles/CMakeError.log` and search for the header name (or function,
|
|
|
etc.) you were testing for. There you should see the code which failed
|
|
|
to compile or link, the compile command and the error message. Together
|
|
|
with the implementation of the test in CheckIncludeFiles.cmake you
|
|
|
should be able to figure out what went wrong.
|
|
|
|
|
|
Ok, now that we have tested whether e.g. malloc.h exists and have the
|
|
|
result in the cmake variable HAVE_MALLOC_H, we still have to create a
|
|
|
header `config.h`. To do this, we use the cmake command
|
|
|
`CONFIGURE_FILE()`, as you have seen above. This copies a source file to
|
|
|
a target file and edits it while doing so, see the man page for details.
|
|
|
So we write a source file named `config.h.in`, but you could give it any
|
|
|
name you want (with autotools it's also usually named `config.h.in`):
|
|
|
|
|
|
#cmakedefine HAVE_MALLOC_H 1
|
|
|
#cmakedefine HAVE_SYS_MOUNT_H
|
|
|
|
|
|
Now when cmake runs, it will replace `#cmakedefine`. If HAVE_MALLOC_H
|
|
|
and HAVE_SYS_MOUNT_H are true, it will produce a `config.h`:
|
|
|
|
|
|
#define HAVE_MALLOC_H 1
|
|
|
#define HAVE_SYS_MOUNT_H
|
|
|
|
|
|
If both are false, it will produce:
|
|
|
|
|
|
/* #undef HAVE_MALLOC_H */
|
|
|
/* #undef HAVE_SYS_MOUNT_H */
|
|
|
|
|
|
By including this header into your source files you can check these
|
|
|
properties using `#ifdef`. You can insert such checks in any of the
|
|
|
CMakeLists.txt in your project, not only in the top-level
|
|
|
CMakeLists.txt. If you have several *configured* headers, you shouldn't
|
|
|
name them all `config.h`, this might lead to problems with the include
|
|
|
path. Better give them names like `config.h`, `config-foo.h` for the
|
|
|
configure header in the subdirectory `foo/` and `config-bar.h` in the
|
|
|
`bar/` subdirectory, etc.
|
|
|
|
|
|
The other commands coming with cmake to do system checks follow this
|
|
|
style, so we can handle them much shorter now.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckIncludeFiles)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_INCLUDE_FILES(headers variable)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H)
|
|
|
|
|
|
As just discussed at length, this can be used to check for the existence
|
|
|
of a header.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckFunctionExists)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_FUNCTION_EXISTS(function variable)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: CHECK_FUNCTION_EXISTS(madvise HAVE_MADVISE)
|
|
|
|
|
|
Checks whether the given function exists. This is done by linking a
|
|
|
small program, which may not result in undefined references.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckSymbolExists)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_SYMBOL_EXISTS(symbol headers variable)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: CHECK_SYMBOL_EXISTS((LC_MESSAGES "locale.h"
|
|
|
HAVE_LC_MESSAGES)
|
|
|
|
|
|
Checks whether the given symbol exists if the specified headers are
|
|
|
included. "Symbol" is defined as something that is either a preprocessor
|
|
|
macro, or whose address can be taken. Notably, this **does not** include
|
|
|
values of a C enumeration.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckLibraryExists)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_LIBRARY_EXISTS(library function location variable)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: CHECK_LIBRARY_EXISTS(volmgt volmgt_running ""
|
|
|
HAVE_VOLMGT)
|
|
|
|
|
|
Checks whether the given library exists and contains the given function.
|
|
|
This is done by linking a small program which uses the function and
|
|
|
links to the library. In the location parameter an additional link
|
|
|
directory (-Ldir) can be given if required.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckTypeSize)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: SET(CMAKE_EXTRA_INCLUDE_FILES header)
|
|
|
CHECK_TYPE_SIZE(type variable)
|
|
|
SET(CMAKE_EXTRA_INCLUDE_FILES)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: SET(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
|
|
|
CHECK_TYPE_SIZE("struct ucred" STRUCT_UCRED)
|
|
|
SET(CMAKE_EXTRA_INCLUDE_FILES)
|
|
|
|
|
|
Checks whether the specified type exists and returns the size of the
|
|
|
type. In the variable the size of the type will be returned,
|
|
|
additionally a variable HAVE_STRUCT_UCRED will be set to true if the
|
|
|
type exists. Please not that you have to set
|
|
|
CMAKE_EXTRA_INCLUDE_FILES to the required headers for this type, and
|
|
|
you should reset it after calling CHECK_TYPE_SIZE. If you are not
|
|
|
really interested in the size of the type, but only whether it exists or
|
|
|
not, you can also use STRUCT_UCRED directly, if the type doesn't exist,
|
|
|
it will be empty and so also evaluate to FALSE (as will
|
|
|
HAVE_STRUCT_UCRED).
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckPrototypeExists)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_PROTOTYPE_EXISTS(function headers variable)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Example: CHECK_PROTOTYPE_EXISTS(mkstemps "stdlib.h;unistd.h"
|
|
|
HAVE_MKSTEMPS_PROTO)
|
|
|
|
|
|
Checks whether the *headers* provide the declaration for the given
|
|
|
*function*, i.e. it does not check whether using *function* will lead to
|
|
|
undefined references.
|
|
|
|
|
|
-----
|
|
|
|
|
|
- Module: INCLUDE (CheckCXXSourceCompiles)
|
|
|
INCLUDE (CheckCSourceCompiles)
|
|
|
|
|
|
<!-- end list -->
|
|
|
|
|
|
- Usage: CHECK_CXX_SOURCE_COMPILES(source variable)
|
|
|
CHECK_C_SOURCE_COMPILES(source variable)
|
|
|
|
|
|
Checks whether the code given in *source* will compile and link. You can
|
|
|
set CMAKE_REQUIRED_LIBRARIES, CMAKE_REQUIRED_FLAGS and
|
|
|
CMAKE_REQUIRED_INCLUDES accordingly if additional libraries or
|
|
|
compiler flags are required.
|
|
|
|
|
|
|
|
|
----
|
|
|
This page was initially populated by conversion from its [original location](https://public.kitware.com/Wiki/CMake:How_To_Write_Platform_Checks) in another wiki. |