CMake Issues with find_path() [duplicate] - c++

Is there a way to pass C_INCLUDE_DIRS and LD_LIBRARY_PATH from cmake command line or is there a way to set env so that CMAKE can find and use them?

It is not fully clear what you intend to do with these variables. Here are some possibilities:
Inside a CMake script you can read environment variables using the syntax $ENV{<VARIABLE_NAME>}. So in your CMakeLists.txt you can have something like
message( "Found environment variable LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}" )
If you want to add the location contained in this variable to be available to your CMake target executables and libraries then you can use the link_directories() command as
link_directories( $ENV{LD_LIBRARY_PATH} )
Or if you have someone else's project and you want to instruct CMake to look for libraries in some additional directories you can use CMAKE_PREFIX_PATH or CMAKE_LIBRARY_PATH. For example to pass these variables in a command line you could do
cmake -D CMAKE_PREFIX_PATH=/path/to/custom/location

One should care when use an environment variable which denotes path and want the project to work on Windows. The problem is with a path separator: CMake uses forward slash, /, but Windows uses backslash, \.
For convert a path from the native (OS-specific) to the CMake, one may use file(TO_CMAKE_PATH) command flow:
# Save environment variable into the CMake but with the proper path separator
file(TO_CMAKE_PATH "$ENV{SOME_PATH_VAR}" SOME_PATH_VAR_CMAKE)
# Following commands could use the created CMake variable
include_directories(${SOME_PATH_VAR_CMAKE})
Also, find_* commands (e.g. find_path) have PATH and HINTS options, which can transform paths from environment variables automatically, using ENV <VAR> syntax:
find_path(MYLIB_INCLUDE_DIRECTORY # Result variable
mylib.h # File to search for
HINTS ENV SOME_PATH_VAR # Take a hint from the environment variable
)

If you want to do the (seems to me anyway) obvious thing with them, which is to get find_library and find_path to find things located therein, I finally figured out that you should use the INCLUDE and LIB. This is mentioned in the docs for find_library but it's not obvious that those are environment variables. So, e.g.:
export LIB=$LIB;$LD_LIBRARY_PATH
export INCLUDE=$INCLUDE;$C_INCLUDE_PATH;$CPLUS_INCLUDE_PATH
Would maybe get you where you want to be.

Related

How to make CMake use environment variable LD_LIBRARY_PATH and C_INCLUDE_DIRS

Is there a way to pass C_INCLUDE_DIRS and LD_LIBRARY_PATH from cmake command line or is there a way to set env so that CMAKE can find and use them?
It is not fully clear what you intend to do with these variables. Here are some possibilities:
Inside a CMake script you can read environment variables using the syntax $ENV{<VARIABLE_NAME>}. So in your CMakeLists.txt you can have something like
message( "Found environment variable LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}" )
If you want to add the location contained in this variable to be available to your CMake target executables and libraries then you can use the link_directories() command as
link_directories( $ENV{LD_LIBRARY_PATH} )
Or if you have someone else's project and you want to instruct CMake to look for libraries in some additional directories you can use CMAKE_PREFIX_PATH or CMAKE_LIBRARY_PATH. For example to pass these variables in a command line you could do
cmake -D CMAKE_PREFIX_PATH=/path/to/custom/location
One should care when use an environment variable which denotes path and want the project to work on Windows. The problem is with a path separator: CMake uses forward slash, /, but Windows uses backslash, \.
For convert a path from the native (OS-specific) to the CMake, one may use file(TO_CMAKE_PATH) command flow:
# Save environment variable into the CMake but with the proper path separator
file(TO_CMAKE_PATH "$ENV{SOME_PATH_VAR}" SOME_PATH_VAR_CMAKE)
# Following commands could use the created CMake variable
include_directories(${SOME_PATH_VAR_CMAKE})
Also, find_* commands (e.g. find_path) have PATH and HINTS options, which can transform paths from environment variables automatically, using ENV <VAR> syntax:
find_path(MYLIB_INCLUDE_DIRECTORY # Result variable
mylib.h # File to search for
HINTS ENV SOME_PATH_VAR # Take a hint from the environment variable
)
If you want to do the (seems to me anyway) obvious thing with them, which is to get find_library and find_path to find things located therein, I finally figured out that you should use the INCLUDE and LIB. This is mentioned in the docs for find_library but it's not obvious that those are environment variables. So, e.g.:
export LIB=$LIB;$LD_LIBRARY_PATH
export INCLUDE=$INCLUDE;$C_INCLUDE_PATH;$CPLUS_INCLUDE_PATH
Would maybe get you where you want to be.

How to let cmake use another opencv directory other than the system's in ubuntu?

Specifically, I want to include opencv from my/path/to/opencv/release where my own opencv is built other than the system's opencv lib in /usr/local/include. How can I set cmake to achieve this? I'm using Ubuntu 14.04.
To provide an example, below is a Find-CMake file for the Luajit library. Your CMake project has one that's probably called something like "FindOpenCV.cmake". It most likely has a default installation path that was manually added, such as: "/usr/include/luajit-2.0 /usr/local/include/luajit-2.0" and you would change these DIR's to your desired install directory. If the default path is contained in a variable, you could either find the definition of that variable and change it (preferably through a configuration option), or override it with a string.
# Try to find Lua or LuaJIT depending on the variable ENABLE_LUAJIT.
# Sets the following variables:
# LUA_FOUND
# LUA_INCLUDE_DIR
# LUA_LIBRARY
#
SET (LUA_FOUND FALSE)
SET (LUA_INTERPRETER_TYPE "")
SET (LUA_INTERPRETER_TYPE "LuaJIT")
SET (LUA_LIBRARY_NAME luajit-5.1)
SET (LUA_INCLUDE_DIRS /usr/include/luajit-2.0 /usr/local/include/luajit-2.0)
FIND_PATH (LUA_INCLUDE_DIR lua.h ${LUA_INCLUDE_DIRS}
HINT ${LUAJIT_INCLUDE_DIR_HINT}/include)
FIND_LIBRARY (LUA_LIBRARY NAMES ${LUA_LIBRARY_NAME} PATHS /usr/lib /usr/local/lib
HINT ${LUAJIT_INCLUDE_DIR_HINT}/bin)
#...
MARK_AS_ADVANCED ( LUA_INCLUDE_DIR LUA_LIBRARY)
There are multiple ways to achieve this, you can modify a FindOpenCV.cmake file, you set the cmake variable OpenCV_DIR before the library is found https://stackoverflow.com/a/9835300/2079934, you can export the environment variable OpenCV_DIR before you run CMake https://stackoverflow.com/a/16959771/2079934.
I would recommend not to hard-code any library paths into CMakeLists.txt, that would take away all the benefits of CMake. In Linux, I would use export to set OpenCV_DIR, in other OSes CMake GUI is more common there you could edit the path variable in the GUI.

KDevelop4: Set environment variable when before CMake

Related to my other question here (CMake: Force to use optional include and library path), how do I set an environment variable in Kdevelop4 when debugging the project / executing CMake?
I need to set CMAKE_PREFIX_PATH in order to give certain duplicate libraries installed in another path priority over libraries installed in /usr.
Not specific to Kdevelop, but you could change your CMakeLists.txt to include another CMake file, if it exists. This file would contain your ad-hoc configuration. For example :
# LocalConfig.cmake
set(CMAKE_PREFIX_PATH "/opt/hhd/geos")
# CMakeLists.txt
include(LocalConfig.cmake OPTIONAL)
find_package(geos)

Pass output of command line utility to compiler/linker

I want to pass result of the getconf PAGESIZE command output as preprocessor define to my program in form of -DPAGESIZE=`getconf PAGESIZE` for [[gnu::assume_aligned(PAGESIZE)]] in custom allocator declaration.
I tried the following:
add_definitions(-DPAGESIZE=`getconf PAGESIZE`)
But it expanded exactly as -DPAGESIZE="\`getconf" ... PAGESIZE`, where ... is contents of other CMAKE_CXX_FLAGS*. I.e. there is an issue with escaping of backticks in CMakeLists.txt files.
How to properly pass such an arguments to compiler/linker in CMakeLists.txt files? Maybe is there another way to achieve desired?
Also I tried add_definitions(-DPAGESIZE="$$(getconf PAGESIZE)") ($$ expanded as $ by cmake), but -DPAGESIZE and the rest part are splitted by cmake. add_definitions("-DPAGESIZE=$$(getconf PAGESIZE)") makes cmake to escape every dollar sign though.
According to documentation for add_definitions command, preprocessor definitions, passed to this command, are appended to COMPILE_DEFINITIONS property:
Flags beginning in -D or /D that look like preprocessor definitions are automatically added to the COMPILE_DEFINITIONS directory property for the current directory.
And content of COMPILE_DEFINITIONS property, according to its documentation is always escaped by CMake, so you cannot preserve special meaning of backticks in the build command:
CMake will automatically escape the value correctly for the native build system
Your may modify CMAKE_CXX_FLAGS manually, as you show in your comment.
The better way is to use execute_process command for run needed command at configuration stage, and use its output for add_definitions command. (Or use this output for create additional header file with configure_file).

cmake - find_library - custom library location

I'm currently trying to get CMake running for my project (on windows). I want to use a custom location where all libraries are installed. To inform CMake about that path I tried to do that:
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs)
But when I try to find the library with
find_library(CURL_LIBRARY NAMES curl curllib libcurl_imp curllib_static)
CMake can't find it.
When I set my prefix path to
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs/curl)
... the library is located.
So my question is:
How can I configure CMake properly to work with a directory structore at a custom location which looks like that:
D:/develop/cmake/libs/
-> libA
-> include
-> lib
-> libB
-> include
-> lib
-> ...
-> include
-> lib
In "include" lie the public headers and in "lib" are the compiled libraries.
edit:
The current workaround for me is, to do this before i search for libraries:
set(CUSTOM_LIBRARY_PATH D:/develop/cmake/libs)
file(GLOB sub-dir ${CUSTOM_LIBRARY_PATH}/*)
foreach(dir ${sub-dir})
if(IS_DIRECTORY ${dir})
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH};${dir})
endif()
endforeach()
But that way the default module for boost wont find it until it because the directory structore of boost is a bit different.
boost -> include -> boost-1_50 -> *.hpp
When I move the content if "boost-1_50" to "include" the library can be found but that way it's not possible to handle multiple versions right?
The simplest solution may be to add HINTS to each find_* request.
For example:
find_library(CURL_LIBRARY
NAMES curl curllib libcurl_imp curllib_static
HINTS "${CMAKE_PREFIX_PATH}/curl/lib"
)
For Boost I would strongly recommend using the FindBoost standard module and setting the BOOST_DIR variable to point to your Boost libraries.
I saw that two people put that question to their favorites so I will try to answer the solution which works for me:
Instead of using find modules I'm writing configuration files for all libraries which are installed. Those files are extremly simple and can also be used to set non-standard variables. CMake will (at least on windows) search for those configuration files in
CMAKE_PREFIX_PATH/<<package_name>>-<<version>>/<<package_name>>-config.cmake
(which can be set through an environment variable).
So for example the boost configuration is in the path
CMAKE_PREFIX_PATH/boost-1_50/boost-config.cmake
In that configuration you can set variables. My config file for boost looks like that:
set(boost_INCLUDE_DIRS ${boost_DIR}/include)
set(boost_LIBRARY_DIR ${boost_DIR}/lib)
foreach(component ${boost_FIND_COMPONENTS})
set(boost_LIBRARIES ${boost_LIBRARIES} debug ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-gd-1_50.lib)
set(boost_LIBRARIES ${boost_LIBRARIES} optimized ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-1_50.lib)
endforeach()
add_definitions( -D_WIN32_WINNT=0x0501 )
Pretty straight forward + it's possible to shrink the size of the config files even more when you write some helper functions. The only issue I have with this setup is that I havn't found a way to give config files a priority over find modules - so you need to remove the find modules.
Hope this this is helpful for other people.
Use CMAKE_PREFIX_PATH by adding multiple paths (separated by semicolons and no white spaces). You can set it as an environmental variable to avoid having absolute paths in your cmake configuration files
Notice that cmake will look for config file in any of the following folders
where is any of the path in CMAKE_PREFIX_PATH and name is the name of the library you are looking for
<prefix>/ (W)
<prefix>/(cmake|CMake)/ (W)
<prefix>/<name>*/ (W)
<prefix>/<name>*/(cmake|CMake)/ (W)
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
In your case you need to add to CMAKE_PREFIX_PATH the following two paths:
D:/develop/cmake/libs/libA;D:/develop/cmake/libB
There is no way to automatically set CMAKE_PREFIX_PATH in a way you want. I see following ways to solve this problem:
Put all libraries files in the same dir. That is, include/ would contain headers for all libs, lib/ - binaries, etc. FYI, this is common layout for most UNIX-like systems.
Set global environment variable CMAKE_PREFIX_PATH to D:/develop/cmake/libs/libA;D:/develop/cmake/libs/libB;.... When you run CMake, it would aautomatically pick up this env var and populate it's own CMAKE_PREFIX_PATH.
Write a wrapper .bat script, which would call cmake command with -D CMAKE_PREFIX_PATH=... argument.
You have one extra level of nesting.
CMAKE will search under $CMAKE_PREFIX_PATH/include for headers and $CMAKE_PREFIX_PATH/libs for libraries.
From CMAKE documentation:
For each path in the CMAKE_PREFIX_PATH list, CMake will check
"PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and
"PATH" when FIND_PROGRAM() is called, and "PATH/lib and "PATH" when
FIND_LIBRARY() is called.
I've encountered a similar scenario. I solved it by adding in this following code just before find_library():
set(CMAKE_PREFIX_PATH /the/custom/path/to/your/lib/)
then it can find the library location.