[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