fmt
fmt copied to clipboard
Module version can't compile fmt::join<std::string_view>
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, ", ")withfmt::join(strings, ", ")) - The non-module version (header only or library) is used (edit
CMakeLists.txtandmain.cppto 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[])
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.
I think I report a similar question last year https://github.com/fmtlib/fmt/issues/4190#issue-2567800204