imported target enforcing overly restrictive compile options

I’ve been hurt by this a couple of times now, and I’m wondering if there is any support to protect a project from an imported target “enforcing” unwanted or conflicting compilation arguments through INTERFACE_COMPILE_OPTIONS.

One project I used specified -std=c++17; I wanted to use C++20, and this flag overrode my CMakeLists.txt file, making things like std::span not compile.

Another project added -fvisibility="hidden", causing previously linking code to not link.

In the first case, the library used C++17 features, so they wanted to ensure that (at least) that level of standard was enforced. Unfortunately, the result was overly restrictive. In the second case, a heavily templated, header-only library had the laudable goal of limiting the size of generated symbols, but again, enforced the visibility constraint on the my project.

Where is the boundary between what a library needs to be used, and the rest of my project? Is the issue simply that INTERFACE_COMPILE_OPTIONS is naively abused by library designers? Is there anything consumers of libraries can do? Guidance for library designers?

Library designers are at fault for the cases you mentioned. Library designers should only add requirements to their INTERFACE properties, and they should use the appropriate CMake abstractions where available. For example, they should set the cxx_std_17 compile feature using target_compile_features() rather than adding -std=c++17 to INTERFACE_COMPILE_OPTIONS. The -fvisibility="hidden" flag is also not a requirement for using the library, so it should not have be propagated out in INTERFACE_COMPILE_OPTIONS either.

I suspect for the case you highlighted, the offending project most likely added the raw flags as PUBLIC compile options. They should have used the appropriate abstractions instead (the cxx_std_17 compile feature and the <LANG>_VISIBILITY_PRESET target property). Then CMake would have handled them more appropriately.

1 Like

Hi @craig.scott, I’m one of the authors of the second case. Our library consumes pybind11, and according to their docs it’s a requirement to have the visibility hidden:
https://pybind11.readthedocs.io/en/stable/faq.html#someclass-declared-with-greater-visibility-than-the-type-of-its-field-someclass-member-wattributes

Is there a way around that if we consume pybind11 and they say it’s required?

1 Like

I don’t know the mechanics behind why pybind11 says hidden visibility is required. The error mentioned in the pybind11 docs you linked to sounds somewhat familiar, so I probably hit it myself a while back. I won’t comment on whether what they are recommending is valid or not, I don’t have the bandwidth to investigate that one.