Reputation: 526
I'm using CMake and I have an external dependency on a project that also uses CMake. It looks like a target compile option is leaking from that dependency's target to mine. The dependency is setting a high warning level and thus I get some warnings on my project's code as well.
I understand that the right thing to do might be to embrace that and actually fix the warnings, but I'd like to:
Here's what my CMakeLists.txt looks like:
project(MyProject)
add_subdirectory(External/MyDependency)
# ...
add_executable(${PROJECT_NAME} ${MY_SOURCE_FILES})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
target_link_libraries(${PROJECT_NAME} my_dependency_lib)
And this is an excerpt of my dependency's CMakeLists.txt:
project(MyDependency)
# This is not the actual library I link
add_library(my_dependency_common INTERFACE)
# ...
# If I remove this line, I no longer get the warnings on my own code
target_compile_options(my_dependency_common INTERFACE /W4)
# This is where the actual library is built
# and my_dependency_lib is then linked to the my_dependency_common library
add_subdirectory(my_dependency_path)
Edit: Since the keyword INTERFACE
seems to play an important role here, I'm including an excerpt of the subdirectory that is included in my dependency.
add_library(my_dependency_common_2 INTERFACE)
target_link_libraries(my_dependency_common_2 INTERFACE my_dependency_common)
# this is the actual lib that I am linking
add_library(my_dependency_lib SHARED)
target_link_libraries(my_dependency_lib my_dependency_common_2)
Upvotes: 1
Views: 1781
Reputation: 82511
Info attached to a target with INTERFACE
visibility (or PUBLIC
visibility which implies INTERFACE
) is automatically applied to a linking target. You could avoid this by creating a new target INTERFACE
library target that provides the necessary properties to link the lib, but not the undesirable properties. For this reason info like this should have a visibility that is "as PRIVATE
as possible".
Note that the project may not be designed to be included via add_subdirectory
. You may want to check, if there's cmake installation logic in the project that provides a cmake configuration script. If this is the case, compiling&installing the dependency to a local directory as a bootstrap step of your build may be a good option.
Here's how you could include the lib without the undesirable option though:
add_library(bad_lib foo.cpp foo.hpp)
target_include_directories(bad_lib PUBLIC good_include)
target_compile_options(bad_lib PUBLIC --bad-option)
# create interface lib for linking the lib without --bad-option being inherited
add_library(bad_lib_fixed INTERFACE)
# link the lib via the absolute library file path, not via the cmake target name
target_link_libraries(bad_lib_fixed INTERFACE $<TARGET_FILE:bad_lib> $<TARGET_PROPERTY:INTERFACE_LINK_LIBRARIES>)
target_include_directories(bad_lib_fixed INTERFACE $<TARGET_PROPERTY:bad_lib,INTERFACE_INCLUDE_DIRECTORIES>)
add_executable(LinkingTarget ...)
target_link_libraries(LinkingTarget PRIVATE bad_lib_fixed)
Note that this only works, there are no cmake targets linked to bad_lib_fixed
with PUBLIC
or INTERFACE
visibility having the same issues. Otherwise instead of $<TARGET_PROPERTY:INTERFACE_LINK_LIBRARIES>
the absolute paths to those libraries needs to be added...
Furthermore note that the INTERFACE
library target is only there for convenience. If only a single target links the lib, you could directly add the properties to this target (possibly changing the visibilities to PUBLIC
or PRIVATE
).
Upvotes: 3