Cmake add_definition to compute absolute path of a file - cmake

I have a project where compilation and test running is managed by cmake. The test involves reading a special test file, which is located in different directory from the test file and would need an absolute path. I define the path to the testfile in my tests.cpp like this:
#define ARPA_TESTFILEPATH "/path/to/project/root/arpa/toy_lm.arpa"
I want to pass that define via cmake so that other people can checkout the project and run the tests without modifying anything. I know I can add defines in cmake via:
add_definitions(-DARPA_TESTFILE="/path/to/project/root/arpa/toy_lm.arpa")
However how can I add a variable to the define so that it automatically resolves the path? I am looking for something like:
add_definitions(-DARPA_TESTFILE="$(PROJECTROOT)/arpa/toy_lm.arpa")
Is that possible?
EDIT:
Basically say the project is checked out in a directory
/home/pesho/project
the project directory contains CMakeLists.txt. How could I get the absolute path to the projects directory so that I can include it in a variable and then define it during compilation.

Put the path in a CACHE variable. It make it accessible through ccmake command :
set(PATH_TO_ARPA "${DEFAULT_PATH_TO_ARPA}" CACHE FILEPATH "Description of the option")
See documentation : http://www.cmake.org/cmake/help/v3.0/command/set.html

Related

Getting environment variable during runtime from file in cmake [duplicate]

I have a project under CMake with some files generated with python generator from XML files. I cannot specify all files generated by this generator in CMakeLists.txt so I use file globbing for this.
The problem is that when I update my XML files or generator sources (which are in the same repository) I would like to have my build system reconfigured so changed files are taken into account when rebuilding the code (via make for example).
Is it possible to make CMake treat some files like it treats CMakeLists.txt files and to make it regenerate build system when those file are changed?
It doesn't require any kind of workarounds. The standard way is to use CMAKE_CONFIGURE_DEPENDS property:
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS <filename>)
Yes, you should be able to do that by (ab)using configure_file(). Configuring a file makes the source a dependency of the CMake run, so that any changes in it cause a reconfiguration. Simply like this:
configure_file(MyInputFile.xml DummyOutput.xml)
Since it has been a while I will add to #roolebo's answer.
There's actually a better command to add a dependency on a file:
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS <relative_or_full_path_to_file>)
What might be confusing is that this command adds a property to the current directory. Well, it does not matter since you can set a full path to a file that resides outside of the current directory's scope, for instance: ../../config.json

cmake find all directories by name on the include path and add them to the include path

I am working with a library that nominally stores its internal headers in a directory that is not itself on the include path, although its parent is. Including the intended entry point header ends up failing because it links to other internal headers via quoted include without the directory name.
I do #include <SDL2/SDL.h> which the compiler does find, in /usr/include/SDL2/SDL.h on my system, but it then fails to find "begin_code.h" which is included several layers deeper in SDLs internal header code.
In file included from /usr/include/SDL2/SDL.h:32:
In file included from /usr/include/SDL2/SDL_main.h:25:
In file included from /usr/include/SDL2/SDL_stdinc.h:31:
In file included from /usr/include/SDL2/SDL_config.h:4:
In file included from /usr/include/x86_64-linux-gnu/SDL2/_real_SDL_config.h:33:
/usr/include/x86_64-linux-gnu/SDL2/SDL_platform.h:179:10: fatal error: 'begin_code.h' file not found
#include "begin_code.h"
^~~~~~~~~~~~~~
1 error generated.
Adding -iquote /usr/include/SDL2 manually works in my case, but what about in build environments where the SDL2 headers were downloaded to some local directory? The point of cmake is to work with local configurations that vary, so adding a hard-coded single path based on platform would be dumb. I want some future person who wants to compile my code with the SDL2 headers downloaded to ~/projects/headers/SDL2 to be able to compile after specifying only ~/projects/headers to their include path, for example, so they don't have to deal with SDLs internal issues.
It seems to me that all I need is to iterate on every dir on the -iquote path and, if it contains a directory name SDL2, add that directory to the -iquote. Does cmake make available the (system configuration dependent) -iquote path as an traversable list?
This question is my attempt to rephrase this unasnwered question for clarity.
Edit: I get that cmake is not responsible for fixing the issue, but cmake (or, rather, a CMakeList.txt file in my project) should be capable of working around this SDL bug. Hard-coding the assumed path is only reliable for build systems that install SDL2 headers via some standard package manager. I've never seen a unix dev manually download header files and stick them in the system include path, for fear that they might be overwritten or otherwise conflict with a future install of an official headers package. There are other valid places to put include files, so cmake should be able to search them. Isn't eliminating hard-coded paths half the point of cmake?
CMake doesn't provide a way for a custom iteration over include directories.
Instead, you could reformulate your intentions into the form "find a directory with the given header".
That form is expressed with command find_path, which is a natural way in CMake for search include directories.
E.g. that call:
# Task for CMake: Find a directory with "begin_code.h" header in it.
# Possibly, this is subdirectory 'SDL2' of a "normal" include directory.
find_path(SDL2_INCLUDE_DIR_1 "begin_code.h" PATH_SUFFIXES "SDL2")
will fill the variable SDL2_INCLUDE_DIR_1 with the directory containing the header begin_code.h.
This way works perfectly in case of local installation of SDL2, if that installation is hinted for CMake with CMAKE_PREFIX_PATH variable. For support other hints, e.g. SDL2DIR environment variable, you need to add appropriate PATHS options to your call:
find_path(SDL2_INCLUDE_DIR_1 "begin_code.h" PATH_SUFFIXES "SDL2" PATHS ENV SDL2DIR)
If you feel that SDL2 developers could rename the problematic file, but expect that file to be near the SDL2.h, then you could change the above command to search SDL2.h instead of begin_code.h:
find_path(SDL2_INCLUDE_DIR_1 "SDL2.h" PATH_SUFFIXES "SDL2" PATHS ENV SDL2DIR)

cmake configure_file() path in cmake_modules_path

I'm trying to write modules to use CMake with a custom compiler, however I'm stuck in CMakeDetermineCUSTOMCompiler.cmake. I'd like the modules to work either installed inside of CMake's Modules directory or an external directoy specified by CMAKE_MODULE_PATH.
To make it work installed in CMake's directory I can put:
configure_file(${CMAKE_ROOT}/Modules/CMakeCUSTOMCompiler.cmake.in
but then it doesn't work with CMAKE_MODULE_PATH. Is there any where I can reference the location of the current module? Or search the locations specified in CMAKE_MODULE_PATH?
Variable CMAKE_CURRENT_LIST_DIR is what you seek: it refers to the location of the currently processed file.
Note, that for use such reference inside function or macro, you need firstly to cache it.

CMake requires me to manually copy CMAKE_INCLUDE_PATH

I'm trying to test a project on a cluster where I can't install some libraries in the default locations, so I'm trying to override the default CMake search path with the CMAKE_INCLUDE_PATH environment variable.
Unfortunately it doesn't seem to be picked up. I'm having to set the path explicitly with
include_directories("." $ENV{CMAKE_INCLUDE_PATH})
but this seems like a bit of a hack. So I have two questions:
Is this expected behavior?
Is there some cleaner way to add a directory to CMake's include path via an environment variable?
First of all, there is a predefined cmake variable CMAKE_INCLUDE_PATH variable that is a ";-list of directories specifying a search path for the find_file() and find_path() commands." This is not meant to specify the compiler include path.
Secondly, good use of cmake should not involve environment variables. To the extent you can, you should use the conventional cmake find_package to configure your build paths. When you need to explicitly add a path to the compiler include search path, then, yes, include_directories is what you need. But you should a cmake cache variable rather than environment variable. For details on setting a cache variable, see this page, which says
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
For your example this becomes:
set(MYINCLUDE /usr/local/foo/include CACHE PATH "path to the foo include directory")
include_directories(${MYINCLUDE})
Then if you need to override the default /usr/local/foo/include, you may specify it with the command line used when invoking cmake; e.g., cmake -DMYINCLUDE=/home/foo/include .

CPack NSIS, generate installer for Windows

I´m trying to run packet generator within a VS project, it crashes while compiling because of the use of absolute path on installation from Targets and Files.
ABSOLUTE path INSTALL DESTINATION forbidden (by caller): ...
I checked twice and all installation directories are relative. I set quite a lot of variables as sub-folders of ${PROJECT_BINARY_DIR} (which should be relative) such as:
set(INSTALL_DIR ${PROJECT_BINARY_DIR}/bin)
set(LIB_DIR ${PROJECT_BINARY_DIR}/bin/lib)
set(EXT_DIR ${PROJECT_BINARY_DIR}/bin/ext)
...
does CMAKE/CPACK interpret those variables as absolute paths?
If so, is there a way to make CPack working properly with those variables?
How do I use CPack when sub-relative path are involved?
thanks
Ok I see, the ${PROJECT_BINARY_DIR} is interpreted as an ABSOLUTE path, from there all sub-folder of it will be rejected.
To avoid this problem I surrounded the install variables in if else blocks, and if it is the case of packaging then a relative folder will be used as follows:
if(PACK)
set(INSTALL_DIR bin)
set(LIB_DIR bin/lib)
set(EXT_DIR /bin/ext)
...
else(PACK)
set(INSTALL_DIR ${PROJECT_BINARY_DIR}/bin)
set(LIB_DIR ${PROJECT_BINARY_DIR}/bin/lib)
set(EXT_DIR ${PROJECT_BINARY_DIR}/bin/ext)
...
endif(PACK)
this solves it, but it is really dirty, waiting for a better function on new CPack version.
ciao
This fatal error is meant to tell you installation root should be specified at the moment when user executes the installer. I guess somewhere in your cmake config might have code like this:
INSTALL (TARGET myApp DESTINATION ${SOME_INSTALL_PATH}/bin )
If you assign SOME_INSTALL_PATH an absolute path when cmake cache is generated, you incur the CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION error, which gave you the "ABSOLUTE path INSTALL DESTINATION forbidden (by caller)" message.
To solve this problem, either always use relative path for installation DESTINATION or assign only package prefix to SOME_INSTALL_PATH variable.
For reference, following is the link to INSTALL command.
http://www.cmake.org/cmake/help/v3.0/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.html
There was also a similar question asked on the CMake mailing list.
http://public.kitware.com/pipermail/cmake/2013-May/054656.html