Read all variables only defined in specific cmake file - cmake

I'm cross-compiling Android using ExternalProject, but when I pass CMAKE_TOOLCHAIN_FILE as CMAKE_ARGS, the linker fails. However, when I define cross-compile variables manually (e.g., -DCMAKE_SYSTEM_NAME="Android" ...) it links well.
It is unsafe to define variables manually, so I want to pass the values that are ONLY defined in Android toolchain file provided with android-sdk , but I don't know what variables are defined.
I want something like below code:
# Toolchain file is defined in CMAKE_TOOLCHAIN_FILE when using Android-NDK
get_file_property(result FILE "${CMAKE_TOOLCHAIN_FILE}" VARIABLES)
# parse ${result} to ${parsed_result} (e.g., -DVAR=VAR...)
ExternalProject_Add(
...
CMAKE_ARGS ${parsed_result}
...
)

Related

How can we pass a ${BASEWORK} directory from Bitbake recipe to CMAKE for using find library function from CMAKE?

I want to pass a variable BASEWORKDIR yocto recipe variable to CMake so that it can search for library in a particular folder using find_library() function for .so library. But it is not working. I printed it also I.e for debugging the Cmake file message(${BASEWORKDIR}) but this variable is empty. This variable is defined in Bitbake.conf file in my yocto system.
You could try something like this to use the Yocto environment variables in CMake:
if(DEFINED ENV{BASEWORKDIR})
set(YOCTO_BASEWORK_DIR $ENV{BASEWORKDIR} CACHE INTERNAL "Path retrieved from environment variable.")
endif()
This creates a new CMake variable called YOCTO_BASEWORK_DIR using the system environment variable BASEWORKDIR.

CMake variable contents dependent on build/install

Using the $<INSTALL_INTERFACE:...> and $<BUILD_INTERFACE:...> generator expressions I can set target properties to different values depending on whether the target is exported in the current build directory or installed globally. I am writing a custom macro to accompany my CMake package and targets and would like to make the macro behave differently depending on where it is exported (in the build directory) or installed. The macro is contained in a <package>-macros.cmake.in which is included from my <package>-config.cmake file and is configured into the build directory using configure_file and later installed. I tried using the generator expressions in variables set using the configure_file command, but obviously they are not intended to work that way. I assume my requirement is not that uncommon, how is it usually done using CMake?
Just create different <package>-config.cmake files for export() and for install(EXPORT). In that files you may have a variable which differentiate them.
You may even create both files from the same pattern using configure_file command with different CMake environment(variables):
<package>-config.cmake.in:
set(IS_BUILD_INTERFACE #IS_BUILD_INTERFACE#)
# other commands, inclusion of other files, etc.
<package>-macros.cmake:
if(IS_BUILD_INTERFACE)
# Part of build interface
else()
# Part of install interface
endif()
CMakeLists.txt:
# Prepare the file for build interface exporting
set(IS_BUILD_INTERFACE ON)
configure_file(<package>-config.cmake.in <package>-config.cmake #ONLY)
export(PACKAGE <package>)
# Prepare the file for install interface exporting
set(IS_BUILD_INTERFACE OFF)
configure_file(<package>-config.cmake.in <package>-config.cmake.install #ONLY)
install(FILES <package>-config.cmake.install DESTINATION cmake)

Cmake wildcard for External Project

I want to pass some settings to an External Project via a ProjectSettings.cmake file. I know I can use the CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE for this purpose (passed via CMAKE_ARGS to the ExternalProject_add()).
But I have to do this for many external projects that my main project builds and do not want to keep repeating it - I have a generic variable defined for CMAKE_ARGS that is presently passed to every call of ExternalProject_Add() and I want to just append to this.
Is there a wildcard mechanism for the PROJECT-NAME field of this CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE?
Or is there a way by which I can make the CMakeLists.txt of all the external projects I want to build include my ProjectSettings.cmake? Note that I do not have access to change all of them - hence the need to manipulate them from the parent project.
Wrapping reoccurring code centrally is one of the major purposes of CMake macros and functions.
So in your case this would look something like this:
macro(My_ExternalProject_Add _name)
ExternalProject_Add(
${_name}
CMAKE_ARGS -DCMAKE_PROJECT_${_name}_INCLUDE:FILEPATH=ProjectSettings.cmake
${ARGN}
)
endmacro()
The ARGN will add all parameters given after _name. So just place the macro() in your root CMakeLists.txt file and replace all ExternalProject_Add() calls with My_ExternalProject_Add().
Alternatively you could use CMAKE_ARGS -C ProjectSettings.cmake initial cache command line option to pre-load settings for an external project (then you won't need the project's name).
References
Function vs. Macro in CMake
How to define a cmake macro in a sub_directory that uses the CURRENT_SOURCE_DIR?
How to store CMake build settings

set PKG_CONFIG_PATH in cmake

I have built opencv locally and installed it to a local directory (not the system default ). opencv.pc is present under a folder pkgconfig in this local folder. How can I find this opencv.pc from cmake, because I want to link and include opencv files from my program.
pkg_search_module(<PREFIX> [REQUIRED] [QUIET] <MODULE> [<MODULE>]*)
does not have any parameter in which I can force the command to use a specific path (similar to HINTS with find_package()) and not the system default.
So basically .cmake works:
find_package(OpenCV REQUIRED HINTS "my/path/to/share/OpenCVConfig.cmake")
but I would like to use a opencv.pc located under my/path/to/pkgconfig/opencv.pc.
After doing some research and a hint from the #OlivierM, I found the answer.
Here are the steps:
Method I :
CMAKE_PREFIX_PATH can be set to find the .pc files
set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/libs/opencv-install")
Method II
A second method is to use the PKG_CONFIG_PATH, which is a system environment variable to look for .pc files.
set(ENV{PKG_CONFIG_PATH} "${CMAKE_SOURCE_DIR}/libs/opencv-install/lib/pkgconfig")
Irrespective of which method you use,
For old (traditional) CMake:
find_package(PkgConfig REQUIRED)
pkg_search_module(PKG_OPENCV REQUIRED opencv) # this looks for opencv.pc file
Please note that the PKG_OPENCV variable can be named anything. Whatever it is is named, its used as a prefix. For example if you name ABCD, then include directories will be ABCD_INCLUDE_DIRS
The variable PKG_OPENCV_INCLUDE_DIRS and PKG_OPENCV_LIBRARIES contains the header files (compile stage) and libraries (link stage) respectively.
One very important thing I noticed was that the variable PKG_OPENCV_LIBRARIES just provides the libraries and not the library path during the link stage. In order to use the library path as well in one command, one has to use
PKG_OPENCV_LDFLAGS
This variable contains the library path as well as all the libraries listed in the package config file.
for examaple:
include_directories(${PKG_OPENCV_INCLUDE_DIRS})
target_link_libraries (FINAL_BINARY ${PKG_OPENCV_LDFLAGS})
For modern CMake:
In modern CMake we don't want variables, we want targets.
find_package(PkgConfig REQUIRED)
# this looks for opencv.pc file and creates a new target
# IMPORTED_TARGET requires CMake >= 3.6.3
pkg_search_module(PKG_OPENCV REQUIRED IMPORTED_TARGET opencv)
All variables will still be created for backwards compatibility, but IMPORTED_TARGET will create a target you can use in your project which will automatically propagate all of its build and usage requirements:
target_link_libraries(my_proj PRIVATE PkgConfig::PKG_OPENCV)
You could set PKG_CONFIG_PATH with the CMake line:
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/my/path/to/pkgconfig")
I did this workaround in this file
Interestingly, it seems CMake 3.1 extends PKG_CONFIG_PATH with some CMake variable see: https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3df51470
I would propose you to call cmake with custom PKG_CONFIG_PATH variable, like below:
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:my/path/to/pkgconfig cmake <some args>
Or can make PKG_CONFIG_PATH update to be permanent for whole bash session:
$ export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:my/path/to/pkgconfig
$ cmake <some args>

Get C/CXX FLAGS set by commands add_definitions() and add_compile_options()

In my CMakeLists.txt, global C and CXX flags are set using commands add_definitions()
and
add_compile_options.
Many attempts to retrieve the C/CXX flags:
${CMAKE_C_FLAGS} and ${CMAKE_CXX_FLAGS} are empty
${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}} is the original default CMake value
(e.g. -g for CMAKE_C_FLAGS_DEBUG)
${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} same as above
get_cmake_property(def COMPILE_DEFINITIONS) is NOTFOUND
get_cmake_property(opt COMPILE_OPTIONS) is also NOTFOUND
I want to pass my custom C/CXX flags to an external project based on ./configure:
ExternalProject_Add( my_external_lib
DEPENDS Threads::Threads
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}
BUILD_IN_SOURCE 1
UPDATE_COMMAND echo "Full clean" && make distclean
CONFIGURE_COMMAND ${CMAKE_CURRENT_LIST_DIR}/configure
--prefix=${CMAKE_BINARY_DIR}
--cc=${CMAKE_C_COMPILER}
--cxx=${CMAKE_CXX_COMPILER}
--CFLAGS=${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}
--CXXFLAGS=${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}
--LDFLAGS=${CMAKE_STATIC_LINKER_FLAGS_${CMAKE_BUILD_TYPE}}
--ARFLAGS=${CMAKE_STATIC_LINKER_FLAGS_${CMAKE_BUILD_TYPE}}
--enable-static
)
(1) How to get compilation flags set by add_definitions() and add_compile_options?
Note: I use CMake version 3.3.2
While writing the question, I realize I am wondering another question:
I use ccache but the ./configure script does not see my environment variables CC and CXX when I set them like that:
get_cmake_property(launcher RULE_LAUNCH_COMPILE)
set(ENV{CC} ${launcher} ${CMAKE_C_COMPILER})
set(ENV{CXX} ${launcher} ${CMAKE_CXX_COMPILER})
(2) Are these above CMake statements correct?
Oops I have again another question:
I retrieve the LDFLAGS and ARFLAGS from the same variable ${CMAKE_STATIC_LINKER_FLAGS}.
(3) Is there another CMake variable to set ARFLAGS?
Several questions in one post, but all of them are simple:
Documentation link for add_definitions() explicitely refers to directory and target COMPILE_DEFINITION properties. The first of them is extracted by using get_directory_property(), the second by using get_target_property(). Any of them can also be extracted by using get_property(). get_cmake_property you tried to use is inapplicable here (it is used for other type of properties).
You set environment variables CC and CXX at configuration step, but all commands for ExternalProject_Add are executed at build step.
Currently ExternalProject_Add doesn't support simple setting environment variables. As adviced in this bugreport, for set variable's value without spaces you may prepend command with "VAR=VAL" clauses. But for your case this wouldn't work because of escaping problems.
See also CMake FAQ: How can I get or set environment variables?
[...]
environment variables SET in the CMakeLists.txt only
take effect for cmake itself (configure-time),
so you cannot use this method to set an environment variable
that a custom command might need (build-time).
Barring environment variable support by various CMake commands
(e.g. add_custom_command(), currently not supported yet),
an acceptable workaround may be to invoke shell scripts instead
which wrap the commands to be executed.
Simple wrapper script to set environment variables and run actual command:
wrapper.sh.in:
export "CC=ccache #CMAKE_C_COMPILER#"
export "CXX=ccache #CMAKE_XX_COMPILER#"
eval "$*"
CMakeLists.txt:
configure_file(wrapper.sh.in wrapper.sh #ONLY)
ExternalProject_Add(my_external_lib
...
CONFIGURE_COMMAND /bin/sh ${CMAKE_CURRENT_BINARY_DIR}/wrapper.sh
${CMAKE_CURRENT_LIST_DIR}/configure ...
BUILD_COMMAND /bin/sh ${CMAKE_CURRENT_BINARY_DIR}/wrapper.sh make
)
Note, that you should use wrapper for every command which requires this variables. In you case, these are CONFIGURE_COMMAND and BUILD_COMMAND.
Documentation for CMAKE_STATIC_LINKER_FLAGS says that these flags are used for linker, so you may probably use them as LDFLAGS. As for ARFLAGS, they are hardcoded directrly to CMAKE_C_ARCHIVE_CREATE variable, contained full command line for ar. By default this command simply uses linker flags, so your approach seems to be correct too.