fmt icon indicating copy to clipboard operation
fmt copied to clipboard

Module version can't compile fmt::join<std::string_view>

Open Algunenano opened this issue 8 months ago • 2 comments

Minimal repro:

Building with:

  • clang 19.1.7. Also reproduces with gcc 14.2.1
  • ninja 1.12.1
  • cmake 3.31.6

Minimal cmake project to reproduce: proj.zip

Files inside (just in case): CMakeLists.txt:

cmake_minimum_required(VERSION 3.30 FATAL_ERROR)

set(CMAKE_CXX_STANDARD 23)

project(main LANGUAGES CXX)

add_executable(main main.cpp)

include(FetchContent)
FetchContent_Declare(
        fmt
        GIT_REPOSITORY https://github.com/fmtlib/fmt
        GIT_TAG        123913715afeb8a437e6388b4473fcc4753e1c9a) # 11.1.4
FetchContent_MakeAvailable(fmt)


# Comment to disable fmt module

target_sources(main
        PUBLIC FILE_SET CXX_MODULES
        FILES
        ${fmt_SOURCE_DIR}/src/fmt.cc
)
target_include_directories(main PRIVATE ${fmt_SOURCE_DIR}/include)


# Uncomment for header only
# target_link_libraries(main PRIVATE fmt::fmt-header-only)
#include <string>
#include <vector>

import fmt;
// #include <fmt/format.h>
// #include <fmt/ranges.h>


int main(int argc, char* argv[])
{
    std::vector<std::string> strings { "AAA", "BBB", "CCC" };
    std::vector<std::string_view> svs;

    for (size_t i = 0; i < strings.size(); ++i)
        svs.emplace_back(strings[i]);

    fmt::print("{}\n", fmt::join(svs, ", "));
    return 0;
}

$ mkdir build
$ cd build/
$ CC=clang CXX=clang++ cmake .. -DCMAKE_GENERATOR=Ninja
-- The CXX compiler identification is Clang 19.1.7
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/lib/ccache/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
Cloning into 'fmt-src'...
HEAD is now at 12391371 Update version
-- {fmt} version: 11.1.4
-- Build type: 
-- Performing Test HAS_NULLPTR_WARNING
-- Performing Test HAS_NULLPTR_WARNING - Success
-- Configuring done (4.4s)
-- Generating done (0.0s)
-- Build files have been written to: /tmp/other/proj/build
$ ninja
[8/9] Building CXX object CMakeFiles/main.dir/main.cpp.o
FAILED: CMakeFiles/main.dir/main.cpp.o 
/usr/lib/ccache/bin/clang++  -I/tmp/other/proj/build/_deps/fmt-src/include -std=gnu++23 -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d @CMakeFiles/main.dir/main.cpp.o.modmap -o CMakeFiles/main.dir/main.cpp.o -c /tmp/other/proj/main.cpp
In module 'fmt' imported from /tmp/other/proj/main.cpp:4:
/tmp/other/proj/build/_deps/fmt-src/include/fmt/base.h:2235:45: error: implicit instantiation of undefined template 'fmt::detail::type_is_unformattable_for<fmt::join_view<__gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>, __gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>>, char>'
 2235 |     type_is_unformattable_for<T, char_type> _;
      |                                             ^
/tmp/other/proj/build/_deps/fmt-src/include/fmt/base.h:2208:44: note: in instantiation of function template specialization 'fmt::detail::value<fmt::context>::value<fmt::join_view<__gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>, __gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>>, 0>' requested here
 2208 |   FMT_CONSTEXPR20 FMT_INLINE value(T& x) : value(x, custom_tag()) {}
      |                                            ^
/tmp/other/proj/build/_deps/fmt-src/include/fmt/base.h:2913:22: note: in instantiation of function template specialization 'fmt::detail::value<fmt::context>::value<fmt::join_view<__gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>, __gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>>, 0>' requested here
 2913 |   vargs<T...> va = {{args...}};
      |                      ^
/tmp/other/proj/main.cpp:17:10: note: in instantiation of function template specialization 'fmt::print<fmt::join_view<__gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>, __gnu_cxx::__normal_iterator<std::basic_string_view<char> *, std::vector<std::basic_string_view<char>>>>>' requested here
   17 |     fmt::print("{}\n", fmt::join(svs, ", "));
      |          ^
/tmp/other/proj/build/_deps/fmt-src/include/fmt/base.h:2075:45: note: template is declared here
 2075 | template <typename T, typename Char> struct type_is_unformattable_for;
      |                                             ^
1 error generated.
ninja: build stopped: subcommand failed.

Note that this works fine if:

  • fmt::join is used with std::string instead of std::string_view (replace fmt::join(svs, ", ") with fmt::join(strings, ", "))
  • The non-module version (header only or library) is used (edit CMakeLists.txt and main.cpp to use the default build instead of a module).

That is, it only fails when using both std::string_view and the module build. It happens with other range iterators, like std::unordered_map and so on.

I though it might be some missing export but I can't find what's missing.

Simple patch to change from module to non-module version:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60cf589..69c6acb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,13 +16,13 @@ FetchContent_MakeAvailable(fmt)
 
 # Comment to disable fmt module
 
-target_sources(main
-        PUBLIC FILE_SET CXX_MODULES
-        FILES
-        ${fmt_SOURCE_DIR}/src/fmt.cc
-)
-target_include_directories(main PRIVATE ${fmt_SOURCE_DIR}/include)
+# target_sources(main
+#         PUBLIC FILE_SET CXX_MODULES
+#         FILES
+#         ${fmt_SOURCE_DIR}/src/fmt.cc
+# )
+# target_include_directories(main PRIVATE ${fmt_SOURCE_DIR}/include)
 
 
 # Uncomment for header only
-# target_link_libraries(main PRIVATE fmt::fmt-header-only)
+target_link_libraries(main PRIVATE fmt::fmt-header-only)
diff --git a/main.cpp b/main.cpp
index 6b5fb4e..4c06e60 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,9 +1,9 @@
 #include <string>
 #include <vector>
 
-import fmt;
-// #include <fmt/format.h>
-// #include <fmt/ranges.h>
+// import fmt;
+#include <fmt/format.h>
+#include <fmt/ranges.h>
 
 
 int main(int argc, char* argv[])

Algunenano avatar Mar 10 '25 16:03 Algunenano

I haven't done much with C++ modules yet since I'm not convinced the support is complete, what with CPP reference stating that support is "partial" across most compilers. I may try to tinker with this out of curiosity when I have some time.

That's just to preface this suggestion about trying to set FMT_MODULE to ON in the CMake somewhere. I noticed that variable appears to be used for some of the module related testing in {fmt}. Maybe that makes some difference when you are bringing it in with FetchContent? Not sure if it'll help, but it's where I was going to start.

dinomight avatar Mar 11 '25 17:03 dinomight

I think I report a similar question last year https://github.com/fmtlib/fmt/issues/4190#issue-2567800204

LeenHawk avatar Mar 14 '25 03:03 LeenHawk