[CMake] Imported targets and include ordering

rleigh at codelibre.net rleigh at codelibre.net
Thu Aug 11 12:24:34 EDT 2016


I've come across an odd situation where I'm unsure what the most 
portable and recommended solution would be.

I'm linking a program against the CURL and ICU libraries.  CURL has 
traditional variables for the includes and libraries; ICU has imported 
targets.

In FindICU:
           set_target_properties(${_ICU_imported_target} PROPERTIES
             INTERFACE_INCLUDE_DIRECTORIES "${ICU_INCLUDE_DIR}")

In my code:

find_package(CURL)
find_package(ICU COMPONENTS uc data)
[...]
list(APPEND libxerces_c_DEPS ${CURL_LIBRARIES})
include_directories(${CURL_INCLUDE_DIRS})
list(APPEND libxerces_c_DEPS ICU::uc ICU::data)

And the resulting includes on the compiler invocation:

/usr/bin/CC   -DHAVE_CONFIG_H -D_FILE_OFFSET_BITS=64 -I. 
-I/tmp/b2/xerces-source/src -Isrc -I/tmp/b2/xerces-source/tests -isystem 
/tmp/b2/superbuild-install/include -msse2 -MD -MT 
tests/CMakeFiles/XSValueTest.dir/src/XSValueTest/XSValueTest.cpp.o -MF 
tests/CMakeFiles/XSValueTest.dir/src/XSValueTest/XSValueTest.cpp.o.d -o 
tests/CMakeFiles/XSValueTest.dir/src/XSValueTest/XSValueTest.cpp.o -c 
/tmp/b2/xerces-source/tests/src/XSValueTest/XSValueTest.cpp

The problem is this:
CURL is in /usr/local/include
ICU v55 is in /usr/local/include
ICU v57 is in /tmp/b2/superbuild-install/include with its libs in 
/tmp/b2/superbuild-install/lib

CMAKE_PREFIX_PATH is set appropriately, and all the Find module checks 
are correct.  The problem is that the ICU INTERFACE_INCLUDE_DIRECTORIES 
is treated as a system include.  This would be OK, if it were not for 
the fact that the CURL includes are placed before it.

The problem is that it's not a system path.  However, the CURL path 
*is*.  And this leads to it building against the ICU55 headers, and then 
failing to link against the ICU57 libraries.  But that's just the 
situation on this specific (FreeBSD) system; the situation could be 
reversed on another with a locally built CURL and a system ICU and CURL.

I see that I could use NO_SYSTEM_FROM_IMPORTED for the imported target, 
and/or use BEFORE|AFTER SYSTEM with [target_]include_directories.  
However, none of these feel appropriate.  They would require knowledge I 
don't have as the cmake script author--either of these libraries could 
be using system or non-system paths; I don't have the foreknowledge to 
make that determination.

How could an end user override what are system paths and what are not 
without hand-editing the script?

It seems (being naive) that the hardcoded behaviour of treating 
INTERFACE_INCLUDE_DIRECTORIES as system includes isn't a universally 
useful default, and while I can override the behaviour, that's a 
explicit action on the part of the script author, and might be 
inappropriate for the user's system.  Whether a path is a system include 
or not seems to be something the end user should be able to tune, since 
the script author and cmake find module authors have no idea what the 
local situation is for any arbitrary system.  For example, it wouldn't 
hurt for cmake to "know" that /usr/local/include is a system path as a 
built-in default, and allow additional paths to be added, and then if a 
random find module adds it such that it's used by a target as a 
non-system include we know we can ignore it and just use it as a system 
include instead.  Unless I'm misunderstanding the situation and making 
this work is already possible.


Thanks,
Roger


More information about the CMake mailing list