Order of hint paths in cmake find_library - cmake

I'm using HINTS with find_library and was surprised to find that the last path had priority. Is this intentional or something that can be configured.
set(MY_HINT_PATHS_A "/path/to/a;/path/to/b")
find_library(MY_LIBRARY_A
NAMES MyLib
HINTS ${MY_HINT_PATHS_A}/lib
ONLY_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH
)
set(MY_HINT_PATHS_B "/path/to/b;/path/to/a")
find_library(MY_LIBRARY_B
NAMES MyLib
HINTS ${MY_HINT_PATHS_B}/lib
ONLY_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH
)
message("MY_LIBRARY_A: ${MY_LIBRARY_A}")
message("MY_LIBRARY_B: ${MY_LIBRARY_B}")
prints
MY_LIBRARY_A: /path/to/b/lib/libMyLib.a
MY_LIBRARY_B: /path/to/a/lib/libMyLib.a
I would have expected
MY_LIBRARY_A: /path/to/a/lib/libMyLib.a
MY_LIBRARY_B: /path/to/b/lib/libMyLib.a

CMake list is not a type, but an interpretation of string value. So any operations on list-variables are actually operations on strings.
${MY_HINT_PATHS_A}/lib doesn't append /lib to all elements in the list, it appends /lib only to the last element:
"/path/to/b;/path/to/a/lib"
It is absolutely equivalent to appending /lib to the variable's string-value.
For get desired effect you may use lib with PATH_SUFFIXES option to the find_library command. Or directly append /lib suffix to every element in the list.

Related

'find_library' returns the same value in the loop in CMake

I'm trying to loop over a list with library names in CMake. In each iteration I search the library with find_library:
set(LIB_NAMES "TKBO;TKBRep;")
set(LIBS_DIR /usr/local/OCCT/7.2.0/libd)
FOREACH(LIB_NAME ${LIB_NAMES})
FIND_LIBRARY(LIB ${LIB_NAME} PATHS ${LIBS_DIR})
MESSAGE("<<${LIB_NAME}>>")
MESSAGE("<<${LIB}>>")
target_link_libraries(mySharedLib ${LIB})
ENDFOREACH()
For the above, I get the output:
<<TKBO>>
<</usr/local/OCCT/7.2.0/libd/libTKBO.dylib>>
<<TKBRep>>
<</usr/local/OCCT/7.2.0/libd/libTKBO.dylib>>
While LIB_NAME updates, FIND_LIBRARY seems to be using an outdated value. I also tried to explicitly UNSET(LIB_NAME) at the end of the loop but that didn't help either.
What could I be overlooking?
The result of find_library is a CACHED variable, and once the library is found, the variable is not updated.
When search different libraries, it is better to use different result variables:
FOREACH(LIB_NAME ${LIB_NAMES})
set(LIB_VAR "LIB_${LIB_NAME}") # Name of the variable which stores result of the search
FIND_LIBRARY(${LIB_VAR} ${LIB_NAME} PATHS ${LIBS_DIR})
target_link_libraries(mySharedLib ${${LIB_VAR}})
ENDFOREACH()
Here LIB_TKBO variable is used for TKBO library, and LIB_TKBRep variable - for TKBRep library.
Solved by:
UNSET(LIB_NAME CACHE)
See here for a similar problem.

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
)

find_library chooses the static library instead of the shared library

This has been asked on SO before and there's even a related bug on this in CMAKE. However, my issue is a variation and the answer is not clear.
My wrinkle is that I'm cross-compiling for Windows on Linux using MinGW. Static libs are named like this libGLESv2.dll.a and libiconv.dll.a for the DLLs libGLESv2.dll and iconv.dll respectively.
Examples:
find_library(FOUND_LIB_X NAMES "zlib1.dll" PATHS ${CMAKE_FIND_ROOT_PATH}/bin/)
finds this: zlib1.dll
find_library(FOUND_LIB_Y NAMES "libGLESv2.dll" PATHS ${CMAKE_FIND_ROOT_PATH}/bin/)
finds this: libGLESv2.dll.a
find_library(FOUND_LIB_Y NAMES "iconv.dll" PATHS ${CMAKE_FIND_ROOT_PATH}/bin/)
finds this: libiconv.dll.a
The CMAKE bug seems to be referring to traditional situations where the static lib is named blah.lib (Windows) or blah.a (Linux). In this cross-compiler situation with mingw on Linux, they are named blah.dll.a
I need it to find the file literally called iconv.dll and nothing else. If it doesn't literally find that, then abort. Am I using the wrong CMAKE function? (don't use find_library()?)
CMake uses definite order between iterating library names and directories when search the library. E.g., according to documentation,
When more than one value is given to the NAMES option this command by default will consider one name at a time and search every directory for it.
That is, with libraries at dir1/name2 and dir2/name1
find_library(MYLIB NAMES name1 name2 PATHS dir1 dir2)
message(${MYLIB})
will print dir2/name1.
Specifying NAMES_PER_DIR option reverse the choice:
find_library(MYLIB NAMES name1 name2 NAMES_PER_DIR PATHS dir1 dir2)
message(${MYLIB})
will print dir1/name2.
Things are different with trying library's prefix and suffix:
Each library name given to the NAMES option is first considered as a library file name and then considered with platform-specific prefixes (e.g. lib) and suffixes (e.g. .so).
It seems that checking for lib<name>.so is performed immediately after <name> when iterating directories.
That is, with libraries at dir1/libname.so and dir2/name
find_library(MYLIB NAMES name PATHS dir1 dir2)
message(${MYLIB})
will print dir1/libname.so.
That is why libiconv.dll.a is found in your case: lib/ directory is searched as system specific path at step 5 of find_library search algorithm, but directory bin/, specified as PATH option, is searched only at step 6.
The simplest way to find what you want is to use NO_DEFAULT_PATH option, so searching in lib/ will not be performed at all:
find_library(FOUND_LIB_Y
NAMES "iconv.dll"
PATHS ${CMAKE_FIND_ROOT_PATH}/bin/
NO_DEFAULT_PATH
)

CMake use foreach and find_library to return full path of libraries

I used a list to store names of libraries, and I would like to use foreach and find_library to find full path of each library. But find_library just returned the path of the first library. I checked this post, but problem still exist. My CMake version is 3.4.3.
SET(VTKLIBS_DIR)
FOREACH(LIB ${VTKLIBS})
SET(FOUND_LIB)
FIND_LIBRARY(FOUND_LIB ${LIB})
LIST(APPEND VTKLIBS_DIR ${FOUND_LIB})
MESSAGE("Lib: ${LIB}")
MESSAGE("Found Lib: ${FOUND_LIB}")
UNSET(FOUND_LIB)
ENDFOREACH(LIB)
Command find_library sets cached variable, but simple form of command unset remove only simple variable's definition.
As noted by the link you provide, you need to store special value FOUND_LIB-NOTFOUND to the variable FOUND_LIB for force find_library to search another library while variable already contains path to the previous library:
FOREACH(LIB ${VTKLIBS})
SET(FOUND_LIB "FOUND_LIB-NOTFOUND")
FIND_LIBRARY(FOUND_LIB ${LIB})
LIST(APPEND VTKLIBS_DIR ${FOUND_LIB})
MESSAGE("Lib: ${LIB}")
MESSAGE("Found Lib: ${FOUND_LIB}")
ENDFOREACH(LIB)
Actually, this is some kind of trick, as cached variable FOUND_LIB isn't changed by simple set command. But when find_library implementation attempts to read cached value of the variable, it actually read value of simple variable with the same name.
Because find_library treats only *-NOTFOUND cached values as "library not found", your trick with assigning empty value to the variable doesn't work.
The better approach, as noted by #arrowd, would be using different names for variable, used in different find_library() call:
FOREACH(LIB ${VTKLIBS})
FIND_LIBRARY(FOUND_LIB_${LIB} ${LIB})
LIST(APPEND VTKLIBS_DIR ${FOUND_LIB_${LIB}})
MESSAGE("Lib: ${LIB}")
MESSAGE("Found Lib: ${FOUND_LIB_${LIB}}")
ENDFOREACH(LIB)
Such a way results for every find_library call will be stored separately, and the same library will not be searched again at the next time cmake being invoked. Also, such approach allows user to modify (in cache) paths to concrete libraries without affecting other ones.

How to add multiple include file names under NAMES while using FIND_PATH in CMAKE?

I am trying to include several header files under NAMES while using FIND_PATH, was wondering if there was a way to include them without specifying each one of them.
Currently i use below format for this purpose.
FIND_PATH(FILE_INCLUDE
NAMES "xyz/x.h"
"xy/y.h"
......
......
PATHS "${CMAKE_CURRENT_SOURCE_DIR}"
PATH_SUFFIXES xy/yx/xyz
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
I was wondering if there was a easier way to specify the list of NAMES as there are lot to be added.
CMake provides the following command for recursive files globing:
file(GLOB_RECURSE variable [RELATIVE path] [FOLLOW_SYMLINKS]
[globbing expressions]...) Command documentation:
http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:file