2
votes

I have a C++ project that requires two external libraries (boost and htslib). I link the libraries to my projects target octopus as follows:

find_package (Boost 1.65 REQUIRED COMPONENTS ${REQUIRED_BOOST_LIBRARIES} REQUIRED)
if (Boost_FOUND)
    target_include_directories (octopus PRIVATE ${Boost_INCLUDE_DIR})
    target_link_libraries (octopus ${Boost_LIBRARIES})
endif (Boost_FOUND)
find_package (HTSlib 1.4 REQUIRED)
if (HTSlib_FOUND)
    target_include_directories (octopus PRIVATE ${HTSlib_INCLUDE_DIRS})
    target_link_libraries (octopus ${HTSlib_LIBRARIES})
endif (HTSlib_FOUND)

Both boost and htslib are usually installed into /usr/local, and therefore have header files in /usr/local/include. However, users can specify alternative library locations by specifying CMake variables BOOST_ROOT and HTSLIB_ROOT.

The problem is that if only one of the libraries is given an alternative location, then the header files in the include directory of the other linked library (e.g. in /usr/local/include) get included for both libraries, and if incomparable versions of the library are installed then compilation can fail. For example, if I set BOOST_ROOT to ~/.linuxbrew then Boost_INCLUDE_DIR is correctly set to ~/.linuxbrew/include, but HTSlib_INCLUDE_DIRS is /usr/local/include, which contains /usr/local/include/boost, and for reasons I don't quite understand, these are the headers used for building, even though they are incompatible with the libraries in ~/.linuxbrew/lib/boost.

How can I ensure that the include directory for a linked library are used only for that library?

1
You cannot. You need to specify non-overlapping folders. (the problem is not with CMake but with filesystems). - Matthieu Brucher
Unrelated to your question, but the if(Xyz_FOUND) conditions in your code are unnecessary, because you're using REQUIRED in the find_package calls. That means CMake will error out when the packages are not found, so the ifs are never even reached in that case. - Angew is no longer proud of SO

1 Answers

0
votes

Which header file is considered is a matter of include directories order - the compiler will typically consider the first file that matches the given name in any of the include folders. While you cannot tell the compiler to look for one file in one specific directory and for the other in another specific directory, what you can determine to some degree is the order of the include directories. It sounds like in your case, the boost include directory should be checked before the other, so try the BEFORE keyword in the target_include_directories call, like this:

target_include_directories (octopus BEFORE PRIVATE ${Boost_INCLUDE_DIR})