How to change the reference path for get_filename_component in cmake? - cmake

I'm using get_filename_component in cmake to get the absolute path of a possibly relative path given in a variable.
And I want to do an out-of-tree/out-of-source-build.
It seems to me that get_filename_component is using CMAKE_SOURCE_DIR as reference-path.
Is there a way to change that or to workaround it?
One way I tried is to prefix my potential relative path with ${CMAKE_BINARY_DIR} but that stops working of the path given is not relative.

Assuming your relative path is always relative to CMAKE_BINARY_DIR, then you can handle this pretty easily using if(IS_ABSOLUTE ...):
if(NOT IS_ABSOLUTE ${MyPath})
set(MyAbsPath ${CMAKE_BINARY_DIR}/${MyPath})
endif()
If the subject file or dir exists at CMake run time, then you can always do a find_file call, passing the possible NAMES and PATHS. If the file exists and is found, the resulting variable will hold the full path to the file.
Or you can use the if(EXISTS ...) signature of if to check for the existence or not of the given file.

Related

Read a file or print a message in CMake

I'm trying to read a file's content and set a variable on the condition whether a file exists relative to the CMakeLists.txt script file. For example, I want to conditionally set an environment variable with the content of a file that resides on disk, and if it's not there I want to print a helpful message.
if (EXISTS pkgconfig-environment)
file(READ pkgconfig-environment LOCAL_PKG_CONFIG_PATH)
set(ENV{PKG_CONFIG_PATH} ${LOCAL_PKG_CONFIG_PATH})
else()
message("
I hope you know what you're doing with your pkg-config.
")
endif ()
The logic above never detects the file pkgconfig-environment, and it instead always prints the message. The file can be read into a cmake variable, but only if it exists.
There are two problems: first, file(READ ...) will fail the build sometimes because the file doesn't exist (I don't care if it's a directory and it fails. That's not my use case). Second, the parameter expected in the call if(EXISTS path) should probably be an absolute path, but I wanted the file to be tested for existence relative to the CMakeLists.txt script file.
Given how clearly the documentation states that exists-checks are supposed to be absolute paths, it leads me to think there's some way to determine the absolute path of a file from a relative path near the CMakeLists.txt.
To get the full path to the directory containing the current CMakeLists.txt file, use ${CMAKE_CURRENT_LIST_DIR}:
if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/pkgconfig-environment)
file(READ ${CMAKE_CURRENT_LIST_DIR}/pkgconfig-environment LOCAL_PKG_CONFIG_PATH)
set(ENV{PKG_CONFIG_PATH} ${LOCAL_PKG_CONFIG_PATH})
else()
message("
I hope you know what you're doing with your pkg-config.
")
endif ()

CMake and header search paths

I'm porting a project to CMake, and struggling to find how to set header search paths (previously set with compiler flags e.g. -I "../../Source").
I currently have:
target_include_directories (jni-bridge PRIVATE
"../../Analysis"
"../../Source"
)
But this does not work. How should I set the paths, and what location are they relative to?
Internally, CMake uses absolute paths as include directories. If relative path is used with target_include_directories, then it is interpreted relative to the current source directory (${CMAKE_CURRENT_SOURCE_DIR}).
The above is true when generator expressions are not used.
Generator expression $<INSTALL_INTERFACE:..> may (and strongly recommended to) use relative path which is interpreted relative to the install prefix.
Generator expression $<BUILD_INTERFACE:...> should use absolute path.
In case someone comes here for a simple and direct code example, referring to the example at https://cmake.org/examples/, append the following to the top-level CMakeLists.txt file:
target_include_directories( helloDemo
path/to/header1.h
path/to/header2.h
)

Why CMake doubles the path?

I am using UseLATEX, with commands
set(MainFile "Demo.tex")
set(InputFiles ${MainFile} Main.tex OtherFiles.tex)
then later I use it like
ADD_LATEX_DOCUMENT( ${MyFileName}
INPUTS "${InputFiles}" )
and everything works fine. If I change to
file(GLOB_RECURSE InputFiles src/*.tex)
then I receive messages with a list of files I wanted to put into InputFiles,
but preceeded with
"Could not find input file ${CMAKE_SOURCE_DIR}/${CMAKE_SOURCE_DIR}/OtherFiles.tex"
and of course that path does not exist. What is wrong?
Turning my comment into answer
Haven't worked with ADD_LATEX_DOCUMENT(), but it seems it appends the current directory itself and would need relative paths.
Just change your file(GLOB ...) command to output relative paths:
file(GLOB_RECURSE InputFiles RELATIVE "${CMAKE_SOURCE_DIR}" src/*.tex)

Cmake script problems find_path

I have put these two lines in my Findglm.cmake file to point to the headers for this header library.
find_path(glm_INCLUDE_DIR NAMES glm.hpp matrix_transform.hpp type_ptr.hpp PATHS
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2glm/core)
set(glm_INCLUDE_DIRS ${glm_INCLUDE_DIR})
However when I generate my Xcode project it says that it cannot locate matrix_transform.hpp and type_ptr.hpp
I have played around with this some more it appears to only find the first argument I am wondering if I am using find path wrong ?
I am using cmake 2.8.8 darwinports.
The find_path() command returns single directory. In your case, it's the first dir, which contains the first file.
If this glm will be always located in your source dir, it would be sufficient to do
include_directories(${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/core)
The find_path() is used to determine dir somewhere outside of your project.

CMake: Get the complete representation of a path minus relative elements

I want to take a variable that has been set to a combination of path elements (potentially both absolute and relative) and get the absolute path from it. Something like what boost::filesystem::system_complete() does in C++. For example, I have something like:
set(EXTERNAL_LIB_DIR "${CMAKE_SOURCE_DIR}/../external" CACHE PATH "Location of externals")
which works but in the UI it's a bit ugly, as it might end up looking like C:/dev/repo/tool/../external. I'm wondering if there's a CMake built-in command to turn that into C:/dev/repo/external before I go and script a macro to do it. find_path kind of does this, but it requires that the path already exist and something worth searching for be there. I want it to work whether the path exists or not (I might use it for an overridden CMAKE_INSTALL_PREFIX default, for example).
You can use:
get_filename_component(NEW_VAR ${EXTERNAL_LIB_DIR} REALPATH)
As of CMake 3.20, you can use the cmake_path command to normalize the path, which supersedes the get_filename_component command.
cmake_path(SET MY_NEW_PATH NORMALIZE ${EXTERNAL_LIB_DIR})
This also converts any backslashes (\) into forward-slashes cleanly.