I have a two macro names, for example:
macro(my_macro1)
# stuff only to use in this macro
endmacro()
macro(my_macro2)
# stuff only to use in this macro
endmacro()
I'd like to dynamic call the macros based a variable name, for example:
if (...)
set (ver 1)
else ()
set (ver 2)
endif ()
my_macro${ver} # this is my idea
Any help?
As #Tsyvarev has commented CMake doesn't support dynamic function names. So here are some alternatives:
Simple Approach
macro(my_macro ver)
if(${ver} EQUAL 1)
my_macro1()
elseif(${ver} EQUAL 2)
my_macro2()
else()
message(FATAL_ERROR "Unsupported macro")
endif()
endmacro()
set(ver 1)
my_macro(ver)
set(ver 2)
my_macro(ver)
A call() Function Implementation
Building on #Fraser work here is a more generic call() function implementation:
function(call _id)
if (NOT COMMAND ${_id})
message(FATAL_ERROR "Unsupported function/macro \"${_id}\"")
else()
set(_helper "${CMAKE_BINARY_DIR}/helpers/macro_helper_${_id}.cmake")
if (NOT EXISTS "${_helper}")
file(WRITE "${_helper}" "${_id}(\$\{ARGN\})\n")
endif()
include("${_helper}")
endif()
endfunction()
set(ver 1)
call(my_macro${ver})
set(ver 2)
call(my_macro${ver})
Related
I'm currently configuring build of my project and decided to split CMakeLists.txt into subfiles which are responsible for a single build sub-task (like testing, packaging, compiling, etc...). The problem is the cmake subfiles needs info about how to do their tasks. So I decided to require some variables to be set before including the module. It looks like
CpackMylib.cmake:
if(NOT DEFINED MYLIB_PACKAGE_NAME)
message(FATAL_ERROR "MYLIB_PACKAGE_NAME variable must be set")
endif()
if(NOT DEFINED MYLIB_VERSION_MAJOR)
message(FATAL_ERROR "MYLIB_VERSION_MAJOR variable must be set")
endif()
if(NOT DEFINED MYLIB_VERSION_MINOR)
message(FATAL_ERROR "MYLIB_VERSION_MINOR variable must be set")
endif()
if(NOT DEFINED MYLIB_VERSION_PATCH)
message(FATAL_ERROR "MYLIB_VERSION_PATCH variable must be set")
endif()
set(CPACK_PACKAGE_VERSION_MAJOR ${MYLIB_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${MYLIB_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${MYLIB_VERSION_PATCH})
set(CPACK_DEBIAN_PACKAGE_NAME "${MYLIB_PACKAGE_NAME}-${MYLIB_VERSION_MAJOR}")
set(CPACK_DEBIAN_PACKAGE_FILE_NAME ${MYLIB_PACKAGE_NAME}-${MYLIB_VERSION_MAJOR})
#other settings...
include(CPack)
And the root CMakeLists.txt:
set(MYLIB_VERSION_MAJOR 0)
set(MYLIB_VERSION_MINOR 0)
set(MYLIB_VERSION_PATCH 1)
set(MYLIB_PACKAGE_NAME ${PROJECT_NAME})
include(cmake/CpackMylib.cmake)
So I require to define project-specific variables that will be used for creation packages using CPack. I'm new to CMake and this just seems natural to do things that way. But I'm not sure if it is sort of common approach when dealing with CMake.
Does it make sense to define all variable the CMake submodules needs and provide them in the root CMakeLists.txt?
I'm generating my vcxproj and sln files for MSVC with CMake. I want to copy some dlls in build directory as POST_BUILD event which are different according whether I'm building Debug or Release configuration and whether it is x86 or x64 architecture. I'm using add_custom_command the following way
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${FILES_TO_COPY} ${CMAKE_CURRENT_BINARY_DIR})
I want to set FILES_TO_COPY to different values according to architecture and configuration or to use different add_custom_command according the same conditions. But CMake MSVC is multi config generator and CMAKE_BUILD_TYPE is empty under it and I cannot simply write something like:
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set (FILES_TO_COPY
"${CMAKE_SOURCE_DIR}/Externals/DLLs/bdb/Debug/i386/libdb52d.dll")
elseif (CMAKE_BUILD_TYPE STREQUAL "Release")
set (FILES_TO_COPY
"${CMAKE_SOURCE_DIR}/Externals/DLLs/bdb/Release/i386/libdb52.dll")
else ()
message (FATAL_ERROR "Invalid configuration name ${CMAKE_BUILD_TYPE}.")
endif ()
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set (FILES_TO_COPY
"${CMAKE_SOURCE_DIR}/Externals/DLLs/bdb/Debug/x64/libdb52d.dll")
elseif (CMAKE_BUILD_TYPE STREQUAL "Release")
set (FILES_TO_COPY
"${CMAKE_SOURCE_DIR}/Externals/DLLs/bdb/Release/x64/libdb52.dll")
else ()
message (FATAL_ERROR "Invalid configuration name ${CMAKE_BUILD_TYPE}.")
endif ()
else ()
message (FATAL_ERROR "Unsupported architecture with ${CMAKE_SIZEOF_VOID_P}
bytes pointer size.")
endif ()
How to do this properly?
try this:
set(arch "i386")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(arch "x64")
endif()
set(FILES_TO_COPY "${CMAKE_SOURCE_DIR}/Externals/DLLs/bdb/$<CONFIG>/${arch}/libdb52$<$<CONFIG:Debug>:d>.dll")
This question already has an answer here:
CMake use foreach and find_library to return full path of libraries
(1 answer)
Closed 6 years ago.
I have some helper functions which help me locate shared and static libraries in the filesystem:
I have a helper function which performs the actual search, given a name and a suffix:
function(do_find_lib LIB_NAME SUFFIX OUT)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${SUFFIX})
find_library(FOUND ${LIB_NAME})
if(NOT FOUND)
message(SEND_ERROR "unable to find library ${LIB_NAME}")
endif()
message(STATUS "search: ${LIB_NAME}.${SUFFIX} result: ${FOUND}")
set(${OUT} ${FOUND} PARENT_SCOPE)
endfunction()
The function find_static_lib sets the appropriate suffix, and calls do_find_lib:
function(find_static_lib LIB_NAME OUT)
if (WIN32 OR MSVC)
set(SUFFIX ".lib")
elseif (UNIX)
set(SUFFIX ".a")
endif()
do_find_lib(${LIB_NAME} ${SUFFIX} FOUND)
message(STATUS "static lib search: ${LIB_NAME} result: ${FOUND}")
set(${OUT} ${FOUND} PARENT_SCOPE)
endfunction()
Similarly, the function find_shared_lib sets the appropriate suffix, and calls do_find_lib:
function(find_shared_lib LIB_NAME OUT)
if (WIN32 OR MSVC)
set(SUFFIX ".dll")
elseif (UNIX)
set(SUFFIX ".so")
endif()
do_find_lib(${LIB_NAME} ${SUFFIX} FOUND)
message(STATUS "shared lib search: ${LIB_NAME} result: ${FOUND}")
set(${OUT} ${FOUND} PARENT_SCOPE)
endfunction()
As required, elsewhere in my cmake hierarchy I use these functions to find various libraries
The first time I use it, it works:
First I search for tcmalloc static library.
find_shared_library(tcmalloc_minimal TCMALLOC)
Here is the resulting output:
-- search: tcmalloc_minimal.a result: /usr/local/lib/libtcmalloc_minimal.a
-- static lib search: tcmalloc_minimal result: /usr/local/lib/libtcmalloc_minimal.a
The second time I use it, it breaks:
Next I search for protobuf shared library.
find_shared_library(protobuf PROTOBUF)
Here is the resulting output:
-- search: protobuf.so result: /usr/local/lib/libtcmalloc_minimal.a
-- shared lib search: protobuf result: /usr/local/lib/libtcmalloc_minimal.a
Error:
Wah? Searching for protobuf with suffix .so finds the previous search result, /usr/local/lib/libtcmalloc_minimal.a
Question:
Why is this happening?
Is there a bug in my functions?
What do I need to do to correctly search for the requisite library?
Notes:
I have completed deleted my build directory and rebuild the makefiles, so don't believe this is an issue with a cache.
From the documentation on find_library:
A cache entry named by <VAR> is created to store the result of this command.
If the library is found the result is stored in the variable and the search will not be repeated unless the variable is cleared.
This cmake mailing list answer shows you have to set the variable to FOUND-NOTFOUND in order to clear the cache.
set(FOUND FOUND-NOTFOUND)
However, it could be argued that this is an anti-pattern, as doing this defeats the caching behaviour of find_library
It would be be better to use a unique variable name for each unique search.
Here the variable is called FOUND_${LIB_NAME}${SUFFIX}:
function(do_find_lib LIB_NAME SUFFIX OUT)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${SUFFIX})
find_library(FOUND_${LIB_NAME}${SUFFIX} ${LIB_NAME})
if(NOT FOUND_${LIB_NAME}${SUFFIX})
message(SEND_ERROR "unable to find library ${LIB_NAME}")
endif()
set(${OUT} ${FOUND_${LIB_NAME}${SUFFIX}} PARENT_SCOPE)
endfunction()
I'm building an external library using CMake with ExternalProject_Add. I've used the answer here to generate the following (which captures command line input to CMake in order to pass it to the ExternalProject_Add command):
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
foreach(CACHE_VAR ${CACHE_VARS})
get_property(CACHE_VAR_HELPSTRING CACHE ${CACHE_VAR} PROPERTY HELPSTRING)
if(CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line.")
get_property(CACHE_VAR_TYPE CACHE ${CACHE_VAR} PROPERTY TYPE)
if(CACHE_VAR_TYPE STREQUAL "UNINITIALIZED")
set(CACHE_VAR_TYPE)
else()
set(CACHE_VAR_TYPE :${CACHE_VAR_TYPE})
endif()
set(CMAKE_ARGS "${CMAKE_ARGS} -D${CACHE_VAR}${CACHE_VAR_TYPE}=\"${${CACHE_VAR}}\"")
endif()
endforeach()
The ExternalProject_Add command looks like this:
ExternalProject_Add(external_lib
URL ${EXTERNALLIB_SOURCE_DIR}
PREFIX ${EXTERNALLIB_PREFIX}
CMAKE_ARGS "${CMAKE_ARGS};-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
INSTALL_DIR ${EXTERNALLIB_INSTALL_DIR}
BINARY_DIR "${EXTERNALLIB_PREFIX}/lib"
)
I cannot figure out how to properly pass the CMAKE_ARGS variable to this command. Obviously, the other variables work fine, but the CMAKE_ARGS one seems not to be expanded properly as I know it contains what I want it to contain. Am I doing something wrong syntacticly with CMake?
set(CMAKE_ARGS "${CMAKE_ARGS} -D${CACHE_VAR}${CACHE_VAR_TYPE}=\"${${CACHE_VAR}}\"")
You want to create one big string from all options. Try simple list instead:
list(APPEND CMAKE_ARGS "-D${CACHE_VAR}${CACHE_VAR_TYPE}=${${CACHE_VAR}}")
I am having problems at the moment trying to get my cmake to see my opencv.
I have installed opencv and can run the some of the sample problems and some give the same error as the the error I get in my cmake file (when running the sample programs through terminal)
I have tried to change the environment variable path as described in
http://answers.opencv.org/question/35125/cmake-linking-error-opencv_found-to-false-ubuntu/
My bashrc file now looks like
CMAKE_PREFIX_PATH=/home/durham/Desktop/OpenCV/opencv-2.4.9:$CMAKE_PREFIX_PATH
CPATH=/home/durham/Desktop/OpenCV/opencv-2.4.9/include:$CPATH LD_LIBRARY_PATH=/home/durham/Desktop/OpenCV/opencv-2.4.9/lib:$LD_LIBRARY_PATH PATH=/home/durham/Desktop/OpenCV/opencv-2.4.9bin:$PATH
PKG_CONFIG_PATH=/home/durham/Desktop/OpenCV/opencv-2.4.9/lib/pkgconfig:$PKG_CONFIG_PATH
PYTHONPATH=/home/durham/Desktop/OpenCV/opencv-2.4.9/lib/python2.7/dist-packages:$PYTHONPATH
and the contents of /etc/ld.so.conf are
include /etc/ld.so.conf.d/*.conf
include /home/durham/Desktop/OpenCV/opencv-2.4.9
The cmake file I am trying to run looks like this
cmake_minimum_required(VERSION 2.6)
if(POLICY CMP0020) cmake_policy(SET CMP0020 NEW) endif(POLICY CMP0020)
SET(CMAKE_VERBOSE_MAKEFILE TRUE) SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/config)
ADD_DEFINITIONS(-DQT_THREAD_SUPPORT -D_REENTRANT -DQT_NO_DEBUG
-DIQRMODULE)
SET(QT_MT_REQUIRED TRUE) find_package(Qt5Widgets) FIND_PACKAGE(OpenCV REQUIRED)
IF(NOT DEFINED IQR_INCLUDE_DIR) set (IQR_INCLUDE_DIR "/usr/include/iqr") #default for linux ENDIF(NOT DEFINED IQR_INCLUDE_DIR)
IF(NOT EXISTS ${IQR_INCLUDE_DIR}) message(STATUS "not exists IQR_INCLUDE_DIR: ${IQR_INCLUDE_DIR}") set (IQR_INCLUDE_DIR $ENV{IQR_INCLUDE_DIR} CACHE PATH "" FORCE) IF(NOT EXISTS ${IQR_INCLUDE_DIR})
message(STATUS "IQR_INCLUDE_DIR set to ${IQR_INCLUDE_DIR}")
message(FATAL_ERROR "Please specify iqr include directory using IQR_INCLUDE_DIR env. variable") ENDIF(NOT EXISTS ${IQR_INCLUDE_DIR}) ENDIF(NOT EXISTS ${IQR_INCLUDE_DIR})
IF(WIN32) IF(NOT DEFINED IQR_LIB_DIR)
set (IQR_LIB_DIR $ENV{IQR_LIB_DIR} CACHE PATH "" FORCE) ENDIF(NOT DEFINED IQR_LIB_DIR)
IF(NOT EXISTS ${IQR_LIB_DIR})
message(FATAL_ERROR "Please specify phidgets include directory using IQR_LIB_DIR env. variable") ENDIF(NOT EXISTS ${IQR_LIB_DIR}) ENDIF(WIN32)
SET(libSrc
moduleArDroneBottomCamera.cpp
)
INCLUDE_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${IQR_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${OPENCV_INCLUDE_DIR} ardrone_sdk/ ardrone_sdk/VP_SDK/ ardrone_sdk/VLIB/Stages/ ardrone_sdk/VP_SDK/VP_Os/ ardrone_sdk/VP_SDK/VP_Os/linux/ ardrone_sdk/VP_SDK/VP_Stages/ )
ADD_SUBDIRECTORY(ardrone_sdk)
ADD_LIBRARY(moduleArDroneBottomCamera SHARED ${libSrc})
IF(WIN32) set(IQR_LIBS "${IQR_LIB_DIR}/libIqrItem.dll") ENDIF(WIN32)
TARGET_LINK_LIBRARIES (moduleArDroneBottomCamera ${OPENCV_LIBRARIES} pc_ardrone ${QT_LIBRARIES} ${IQR_LIBS} )
qt5_use_modules(moduleArDroneBottomCamera Core Widgets Network)
SET_TARGET_PROPERTIES(moduleArDroneBottomCamera PROPERTIES PREFIX "")
IF(UNIX) set (IQR_INSTALL_DIR $ENV{HOME}) ENDIF(UNIX)
IF(WIN32) set (IQR_INSTALL_DIR $ENV{USERPROFILE}) ENDIF(WIN32)
INSTALL(TARGETS moduleArDroneBottomCamera LIBRARY DESTINATION ${IQR_INSTALL_DIR}/iqr/lib/Modules RUNTIME DESTINATION ${IQR_INSTALL_DIR}/iqr/lib/Modules )
But when I try to generate this using the cmake gui I get the following output (cant post images yet so its in the link)
http://postimg.org/image/4e553z6rh/
I am running Ubuntu 14.04. Any suggestions?
Thanks
D
Fast and dirty solution: try to install opencv (You know, make && sudo make install). After installation header files should be inc /usr/local/include and library files should be in /usr/local/lib .
The problem might lay somewhere ind FindOpenCV.cmake file, so You might as well try to understand what it is doing and maybe fix it - CMake syntax is fairly straightforward.
It might check in a default instalation location instead where it lies right now, or some rarely used environment variable.