-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove fmt dependencies when build with SPDLOG_USE_STD_FORMAT flag #19
Conversation
The intent here is to permit compilation under C++20 with an option to support then-included modified src/Makevars
@@ -1,3 +1,5 @@
+CXX_STD = CXX20
+PKG_CXXFLAGS = -DSPDLOG_USE_STD_FORMAT
## We need the spdlog headers
PKG_CPPFLAGS = -I../inst/include/
When I do that, I get both C++20 and the new define. And then the build fails:
It also fails to compile RcppExports.cpp, a generated file (using Rcpp::compileAttributes()). I tried g++-13, g++-14, clang++-17 and clang++-18. All failed. |
Disregard that. The CRAN version also fails under C++20 so that is a TODO item for me. We could still need a (simple) tester package though. |
I think there may be two distinct PRs here. Both are welcome. One is the change to src/formatter.cpp which we could also condition on C++20 or greater and which allows compilation. When I add that to the main branch (and request C++20 compilation via src/Makevars) it installs under C++20 but leaves a bunch of not-so-nice-looking warnings behind. edd@rob:~/git/rcppspdlog(master)$ R CMD INSTALL .
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘RcppSpdlog’ ...
** using staged installation
** libs
using C++ compiler: ‘g++-14 (Ubuntu 14-20240412-0ubuntu1) 14.0.1 20240412 (experimental) [master r14-9935-g67e1433a94f]’ using C++20
ccache g++-14 -std=gnu++20 -I"/usr/share/R/include" -DNDEBUG -I../inst/include/ -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -O3 -Wall -pipe -pedantic -fdiagnostics-color=always -Wformat -c Rcpp
Exports.cpp -o RcppExports.o
ccache g++-14 -std=gnu++20 -I"/usr/share/R/include" -DNDEBUG -I../inst/include/ -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -O3 -Wall -pipe -pedantic -fdiagnostics-color=always -Wformat -c exam
pleRsink.cpp -o exampleRsink.o
ccache g++-14 -std=gnu++20 -I"/usr/share/R/include" -DNDEBUG -I../inst/include/ -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -O3 -Wall -pipe -pedantic -fdiagnostics-color=always -Wformat -c form
atter.cpp -o formatter.o
ccache g++-14 -std=gnu++20 -I"/usr/share/R/include" -DNDEBUG -I../inst/include/ -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -O3 -Wall -pipe -pedantic -fdiagnostics-color=always -Wformat -c inte
rface.cpp -o interface.o
formatter.cpp: In instantiation of ‘std::format_args&& unpack_vector(const std::vector<std::__cxx11::basic_string<char> >&, std::index_sequence<S ...>) [with long unsigned int ...S = {0}; std::format_args = std:
:basic_format_args<std::basic_format_context<std::__format::_Sink_iter<char>, char> >; std::index_sequence<S ...> = std::integer_sequence<long unsigned int, 0>]’:
formatter.cpp:14:29: required from ‘std::format_args&& unpack_vector(const std::vector<std::__cxx11::basic_string<char> >&) [with long unsigned int size = 1; std::format_args = std::basic_format_args<std::basi
c_format_context<std::__format::_Sink_iter<char>, char> >]’
14 | return unpack_vector(vec, std::make_index_sequence<size>());
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
formatter.cpp:63:74: required from here
63 | case 1: return std::vformat(std::string_view(s), unpack_vector<1>(v));
| ~~~~~~~~~~~~~~~~^~~
formatter.cpp:9:37: warning: returning reference to temporary [-Wreturn-local-addr]
9 | return std::make_format_args(vec[S]...);
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
formatter.cpp: In instantiation of ‘std::format_args&& unpack_vector(const std::vector<std::__cxx11::basic_string<char> >&, std::index_sequence<S ...>) [with long unsigned int ...S = {0, 1}; std::format_args = s
td::basic_format_args<std::basic_format_context<std::__format::_Sink_iter<char>, char> >; std::index_sequence<S ...> = std::integer_sequence<long unsigned int, 0, 1>]’:
formatter.cpp:14:29: required from ‘std::format_args&& unpack_vector(const std::vector<std::__cxx11::basic_string<char> >&) [with long unsigned int size = 2; std::format_args = std::basic_format_args<std::basi
c_format_context<std::__format::_Sink_iter<char>, char> >]’
formatter.cpp:9:37: warning: 14 | return unpack_vector(vec, std::make_index_sequence<size>());
formatter.cpp:9:37: warning: | ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
formatter.cpp:64:74: required from here
formatter.cpp:9:37: warning: 64 | case 2: return std::vformat(std::string_view(s), unpack_vector<2>(v));
formatter.cpp:9:37: warning: | ~~~~~~~~~~~~~~~~^~~
formatter.cpp:9:37: warning: returning reference to temporary [-Wreturn-local-addr]
9 | return std::make_format_args(vec[S]...);
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
... additional similar lines omitted ... It seems to me we should fix this and have it compile without references to temporaries. Could you take a look? The other part is optional switch to std::format instead of fmt::format. Despite the PR title, there is no added dependency here as spdlog (and RcppSpdlog) ship their vendored copy. But we could potentially offer to skip instantiation of fmt::format. |
There may also be a conceptual "gotcha" here. We are really considering two things:
The answer to the second (and likely more relevant) question is 'yes'. To prove this, I took the three example source files (that are quick to be #define SPDLOG_USE_STD_FORMAT
// [[Rcpp::plugins(cpp20)]] They, respectively, define the C++20 option of not using > Rcpp::sourceCpp("/tmp/r/rcppspdlog/examples/exampleOne.cpp", verbose=TRUE, rebuild=TRUE)
Generated extern "C" functions
--------------------------------------------------------
#include <Rcpp.h>
#ifdef RCPP_USE_GLOBAL_ROSTREAM
Rcpp::Rostream<true>& Rcpp::Rcout = Rcpp::Rcpp_cout_get();
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
#endif
// exampleOne
void exampleOne();
RcppExport SEXP sourceCpp_1_exampleOne() {
BEGIN_RCPP
Rcpp::RNGScope rcpp_rngScope_gen;
exampleOne();
return R_NilValue;
END_RCPP
}
Generated R functions
-------------------------------------------------------
`.sourceCpp_1_DLLInfo` <- dyn.load('/tmp/r/RtmpTy8XQi/sourceCpp-x86_64-pc-linux-gnu-1.0.13.3/sourcecpp_6891b17c343c9/sourceCpp_8.so')
exampleOne <- Rcpp:::sourceCppFunction(function() {}, TRUE, `.sourceCpp_1_DLLInfo`, 'sourceCpp_1_exampleOne')
rm(`.sourceCpp_1_DLLInfo`)
Building shared library
--------------------------------------------------------
DIR: /tmp/r/RtmpTy8XQi/sourceCpp-x86_64-pc-linux-gnu-1.0.13.3/sourcecpp_6891b17c343c9
/usr/lib/R/bin/R CMD SHLIB --preclean -o 'sourceCpp_8.so' 'exampleOne.cpp'
using C++ compiler: ‘g++-14 (Ubuntu 14-20240412-0ubuntu1) 14.0.1 20240412 (experimental) [master r14-9935-g67e1433a94f]’
using C++20
ccache g++-14 -std=gnu++20 -I"/usr/share/R/include" -DNDEBUG -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/RcppSpdlog/include" -I"/tmp/r/rcppspdlog/examples" -fpic -O3 -Wall -pipe -pedantic -fdiagnostics-color=always -Wformat -c exampleOne.cpp -o exampleOne.o
ccache g++-14 -std=gnu++20 -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -o sourceCpp_8.so exampleOne.o -L/usr/lib/R/lib -lR
> exampleOne()
[19:30:31.742991] [I] [thread 428315] Welcome to spdlog!
[19:30:31.743001] [E] [thread 428315] Some error message with arg: 1
[19:30:31.743004] [W] [thread 428315] Easy padding in numbers like 00000012
[19:30:31.743008] [C] [thread 428315] Support for int: 42; hex: 2a; oct: 52; bin: 101010
[19:30:31.743012] [I] [thread 428315] Support for floats 1.23
[19:30:31.743015] [I] [thread 428315] Positional args are supported too..
[19:30:31.743018] [I] [thread 428315] left aligned
[19:30:31.743020] [D] [thread 428315] This message should be displayed..
>
</details>
PS The above may still instantiate fmt too. |
I took a quick look at the 'returning reference to temporary' issue. It goes away if we return by value. modified src/formatter.cpp
@@ -24,12 +24,12 @@
#ifdef SPDLOG_USE_STD_FORMAT
template<std::size_t... S>
-std::format_args&& unpack_vector(const std::vector<std::string>& vec, std::index_sequence<S...>) {
+std::format_args unpack_vector(const std::vector<std::string>& vec, std::index_sequence<S...>) {
return std::make_format_args(vec[S]...);
}
template<std::size_t size>
-std::format_args&& unpack_vector(const std::vector<std::string>& vec) {
+std::format_args unpack_vector(const std::vector<std::string>& vec) {
return unpack_vector(vec, std::make_index_sequence<size>());
}
|
#define NAMESPACE std | ||
#else | ||
#define NAMESPACE fmt | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One can do this with a typedef too.
The combination of the C++20 test and the *USE_STD_FORMAT only here is ... a little odd. Maybe we should check if *USE_STD_FORMAT is set and error if it is not C++20 as well? Or check in all other uses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes erroring out if not C++20 makes more sense
The failure in the second example is originating from |
Last version is simpler which is better. One question above. We folded another PR since this started so a rebase would be good, and an addition to ChangeLog (see format notes in PR 20 discussion, it is pretty simple) would be appreciated as a quick one paragraph summary for the three changed files (we can ignore .gitignore methinks). |
I agree. It is trying to do more, all of which worked when I set it up years under (likely) C++11. |
8e3954a
to
be7cf0a
Compare
Thanks for doing the rebase. It would still be nice to
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As commented a few days ago, it would still be nice to
- see a ChangeLog
- see about erroring if the define is set without C++20 active
Please add those.
…withput C++20 or greater
@@ -1,3 +1,10 @@ | |||
2024-10-29 Xanthos Xanthopoulos <[email protected]> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I uses two whitespaces here between date and name, and name and email, but I can touch that up. Same for line length.
@@ -1,3 +1,10 @@ | |||
2024-10-29 Xanthos Xanthopoulos <[email protected]> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I uses two whitespaces here between date and name, and name and email, but I can touch that up. Same for line length.
@@ -1,6 +1,10 @@ | |||
|
|||
#pragma once | |||
|
|||
#if defined(SPDLOG_USE_STD_FORMAT) && __cplusplus < 202002L | |||
#error SPDLOG_USE_STD_FORMAT should only be set when compiling with C++20 and greater |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I may replace that 'and' with 'or'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor comments inline.
I may have to revert this. Upstream spdlog 1.15.0 just released, and applied to RcppSpdlog with this PR creates compilation errors in spdl. Applying only the spdlog 1.15.0 update to the CRAN release of RcppSpdlog works which points fingers at these changes here. It is more important to keep up to date with spdlog than to support optional compilation without fmt. |
Ok, I may reopen it once I have it working with the new spdlog version. |
I made a really simple change to |
Pushed and merged now as part of #21. If you want to replicate / see what it does, the actual error was that under the PR 'as is' the dependent package |
When building with SPDLOG_USE_STD_FORMAT spdlog hides the
fmt
dependency but rcppspdlog still tries to access thefmt
library. This PR provides alternative implementation for these functions using the<format>
library. Applicable only for C++20 and onwards.