Andrew Peter Marlow created AVRO-4353:
-----------------------------------------
Summary: [C++] Installed avro-cpp CMake package does not pass fmt
on to consumers, although its public headers include fmt
Key: AVRO-4353
URL: https://issues.apache.org/jira/browse/AVRO-4353
Project: Apache Avro
Issue Type: Bug
Components: c++
Affects Versions: 1.12.2
Environment: Linux. Rocky Linux 8 with gcc 8.5 and CMake 3.26; Linux
Mint 22 with gcc 13.3 and CMake 3.28. fmt 11.0.2 and 12.1.0 installed under
their own prefixes.
Reporter: Andrew Peter Marlow
The installed avro-cpp package cannot be used by a CMake project unless that
project separately
adds fmt itself, because the fmt dependency of Avro's public headers is not
passed on.
Three installed headers use fmt: avro/Exception.hh includes <fmt/core.h>,
avro/Types.hh includes
<fmt/format.h>, and avro/Node.hh uses fmt::. But in lang/c++/CMakeLists.txt,
setup_avro_lib links
fmt only for the build of Avro itself:
{code}
target_link_libraries (${target} PUBLIC
$<BUILD_INTERFACE:fmt::fmt-header-only>
...
{code}
There is no matching INSTALL_INTERFACE entry, so the exported targets
avro-cpp::avrocpp and
avro-cpp::avrocpp_s carry no fmt include directory or link. The installed
avro-cpp-config.cmake
does call find_dependency(fmt REQUIRED), so fmt is found for the consumer, but
nothing links it.
*To reproduce*, with Avro 1.12.2 and fmt installed under separate prefixes:
{code}
cmake_minimum_required(VERSION 3.16)
project(consumer CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(avro-cpp CONFIG REQUIRED)
add_executable(consumer main.cpp) # main.cpp includes <avro/Encoder.hh>
target_link_libraries(consumer PRIVATE avro-cpp::avrocpp_shared)
{code}
configured with -DCMAKE_PREFIX_PATH="<avro prefix>;<fmt prefix>". Configuring
succeeds, and
compiling fails:
{code}
<avro prefix>/include/avro/Exception.hh:23:10: fatal error: fmt/core.h: No such
file or directory
{code}
It works only when the consumer adds find_package(fmt) and links fmt::fmt
itself.
*Suggested fix.* Drop the BUILD_INTERFACE wrapper, so fmt is part of the
installed interface too:
{code}
target_link_libraries (${target} PUBLIC
fmt::fmt-header-only
...
{code}
find_dependency(fmt) in avro-cpp-config.cmake then provides the target. A
project that already
uses the compiled fmt library may prefer Avro to link fmt::fmt instead of
fmt::fmt-header-only,
so that the program has one copy of fmt; linking fmt::fmt in both interfaces
also resolves this
report, and builds and works with fmt 11.0.2 and 12.1.0 (checked with gcc 8.5
and gcc 13).
The main branch no longer uses fmt (AVRO-4260 moves to std::format and C++20),
so this affects
the 1.12 line only.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)