diff --git a/iface/inc/WireCellIface/WirePlaneId.h b/iface/inc/WireCellIface/WirePlaneId.h index 8578cb51..687f9e39 100644 --- a/iface/inc/WireCellIface/WirePlaneId.h +++ b/iface/inc/WireCellIface/WirePlaneId.h @@ -3,6 +3,7 @@ // fixme: should move into WirePlaneIdCfg.h or similar. (more below) #include "WireCellUtil/Configuration.h" +#include "WireCellUtil/Spdlog.h" #include #include @@ -71,4 +72,6 @@ namespace std { }; } // namespace std +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/img/inc/WireCellImg/PointCloudFacade.h b/img/inc/WireCellImg/PointCloudFacade.h index a0dc231a..8cdda0a5 100644 --- a/img/inc/WireCellImg/PointCloudFacade.h +++ b/img/inc/WireCellImg/PointCloudFacade.h @@ -9,6 +9,7 @@ #include "WireCellUtil/PointTree.h" #include "WireCellUtil/Point.h" #include "WireCellUtil/Units.h" +#include "WireCellUtil/Spdlog.h" // using namespace WireCell; NO! do not open up namespaces in header files! @@ -367,4 +368,8 @@ namespace WireCell::PointCloud::Facade { } // namespace WireCell::PointCloud::Facade +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/pgraph/src/Factory.cxx b/pgraph/src/Factory.cxx index 49cedc56..1681feae 100644 --- a/pgraph/src/Factory.cxx +++ b/pgraph/src/Factory.cxx @@ -33,7 +33,7 @@ Node* Factory::operator()(WireCell::INode::pointer wcnode) } auto mit = m_factory.find(wcnode->category()); if (mit == m_factory.end()) { - l->critical("factory failed to find maker for category: {}", wcnode->category()); + l->critical("factory failed to find maker for category: {}", (int)wcnode->category()); THROW(ValueError() << errmsg{"failed to find maker"}); } auto maker = mit->second; diff --git a/sio/src/ClusterFileSource.cxx b/sio/src/ClusterFileSource.cxx index 718fd72f..4f62b59c 100644 --- a/sio/src/ClusterFileSource.cxx +++ b/sio/src/ClusterFileSource.cxx @@ -184,7 +184,7 @@ ICluster::pointer ClusterFileSource::load_numpy(int ident) THROW(ValueError() << errmsg{"illegal shape"}); } log->debug("file {} with type={} code={} ident={} shape=({},{})", - m_cur.fname, pf.type, pf.code, ident, shape[0], shape[1]); + m_cur.fname, (int)pf.type, pf.code, ident, shape[0], shape[1]); if (pf.type == ParsedFilename::node) { const node_element_t* data = pig.as_type(); @@ -292,7 +292,7 @@ ICluster::pointer ClusterFileSource::dispatch() return load_numpy(pf.ident); } log->warn("do not know how to dispatch file {} with type={} code={} ident={}", - m_cur.fname, pf.type, pf.code, pf.ident); + m_cur.fname, (int)pf.type, pf.code, pf.ident); return nullptr; } diff --git a/util/inc/WireCellUtil/Array.h b/util/inc/WireCellUtil/Array.h index 3fd4df5d..91a20825 100644 --- a/util/inc/WireCellUtil/Array.h +++ b/util/inc/WireCellUtil/Array.h @@ -27,6 +27,7 @@ #include "WireCellUtil/Waveform.h" #include "WireCellUtil/Eigen.h" +#include "WireCellUtil/Spdlog.h" #include #include @@ -99,4 +100,7 @@ namespace WireCell { } // namespace Array } // namespace WireCell +template <> struct fmt::formatter> : fmt::ostream_formatter {}; +template <> struct fmt::formatter> : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/Configuration.h b/util/inc/WireCellUtil/Configuration.h index 574e453f..0bd6a5f5 100644 --- a/util/inc/WireCellUtil/Configuration.h +++ b/util/inc/WireCellUtil/Configuration.h @@ -1,6 +1,8 @@ #ifndef WIRECELL_CONFIGURATION #define WIRECELL_CONFIGURATION +#include "WireCellUtil/Spdlog.h" + #include #include #include @@ -211,4 +213,6 @@ namespace WireCell { } // namespace WireCell +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/Logging.h b/util/inc/WireCellUtil/Logging.h index 47140830..ad5df150 100644 --- a/util/inc/WireCellUtil/Logging.h +++ b/util/inc/WireCellUtil/Logging.h @@ -16,8 +16,7 @@ // #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG #include "WireCellUtil/BuildConfig.h" -#include "spdlog/spdlog.h" -#include "spdlog/fmt/ostr.h" +#include "WireCellUtil/Spdlog.h" #include #include diff --git a/util/inc/WireCellUtil/Measurement.h b/util/inc/WireCellUtil/Measurement.h index be24f99c..9ebeb5f4 100644 --- a/util/inc/WireCellUtil/Measurement.h +++ b/util/inc/WireCellUtil/Measurement.h @@ -14,6 +14,8 @@ #ifndef WIRECELLUTIL_MEASUREMENT #define WIRECELLUTIL_MEASUREMENT +#include "WireCellUtil/Spdlog.h" + #include "WireCellUtil/boost_units_measurement.h" namespace WireCell::Measurement { @@ -23,4 +25,7 @@ namespace WireCell::Measurement { } +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/NaryTesting.h b/util/inc/WireCellUtil/NaryTesting.h index 555fcde7..5dc4f360 100644 --- a/util/inc/WireCellUtil/NaryTesting.h +++ b/util/inc/WireCellUtil/NaryTesting.h @@ -4,6 +4,7 @@ #define WIRECELLUTIL_NARYTESTING #include "WireCellUtil/NaryTreeNotified.h" +#include "WireCellUtil/Spdlog.h" namespace WireCell::NaryTesting { @@ -53,5 +54,6 @@ namespace WireCell::NaryTesting { } +template <> struct fmt::formatter : fmt::ostream_formatter {}; #endif diff --git a/util/inc/WireCellUtil/Point.h b/util/inc/WireCellUtil/Point.h index 20fa6600..2c8fcd40 100644 --- a/util/inc/WireCellUtil/Point.h +++ b/util/inc/WireCellUtil/Point.h @@ -3,6 +3,7 @@ #include "WireCellUtil/D3Vector.h" #include "WireCellUtil/Configuration.h" +#include "WireCellUtil/Spdlog.h" #include #include // auto_ptr @@ -126,4 +127,7 @@ namespace WireCell { // } +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/PointTree.h b/util/inc/WireCellUtil/PointTree.h index 7d69ce70..19865991 100644 --- a/util/inc/WireCellUtil/PointTree.h +++ b/util/inc/WireCellUtil/PointTree.h @@ -319,4 +319,6 @@ namespace WireCell::PointCloud::Tree { } +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/RayGrid.h b/util/inc/WireCellUtil/RayGrid.h index 2c77a521..45e86fe3 100644 --- a/util/inc/WireCellUtil/RayGrid.h +++ b/util/inc/WireCellUtil/RayGrid.h @@ -12,6 +12,8 @@ #include "WireCellUtil/Point.h" #include "WireCellUtil/ObjectArray2d.h" #include "WireCellUtil/MultiArray.h" +#include "WireCellUtil/Spdlog.h" + #include #include @@ -168,4 +170,6 @@ namespace WireCell { } // namespace RayGrid } // namespace WireCell +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/RayTiling.h b/util/inc/WireCellUtil/RayTiling.h index 8fb161e6..148d1bd0 100644 --- a/util/inc/WireCellUtil/RayTiling.h +++ b/util/inc/WireCellUtil/RayTiling.h @@ -231,4 +231,8 @@ namespace WireCell { } // namespace RayGrid } // namespace WireCell +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; +template <> struct fmt::formatter : fmt::ostream_formatter {}; + #endif diff --git a/util/inc/WireCellUtil/Spdlog.h b/util/inc/WireCellUtil/Spdlog.h new file mode 100644 index 00000000..8cf9f476 --- /dev/null +++ b/util/inc/WireCellUtil/Spdlog.h @@ -0,0 +1,57 @@ +/** + Include this file instead of directly including spdlog or fmtlib (fmt) + headers. + + It takes care of changing fmtlib API in the face of the fact that spdlog may + be compiled against an external fmtlib or use its "bundled" copy. + + More info: https://github.com/WireCell/wire-cell-spack/issues/12 + + */ + +#ifndef WIRECELLUTIL_SPDLOG +#define WIRECELLUTIL_SPDLOG + +#include + +// We need FMT version but it is found in core.h in different locations +// depending on if fmtlib is external to or bundled with spdlog. +#if defined(SPDLOG_FMT_EXTERNAL) +#include +#else +#include +#endif + +// Newer fmtlib no longer implicitly uses the ostream insertion operator<<. So +// we must have some ugliness to allow us to provide new, required specialization: +// +// template <> struct fmt::formatter : fmt::ostream_formatter {}; +// +// while backporting that base type to old fmtlib. +#if FMT_VERSION >= 90000 +#include +// This provides fmt::ostream_formatter. +#else +#include +// This id copied from fmt/ostream.h from fmtlib 10.2 with const_cast tweak. +namespace fmt { + template + struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; + + template + auto format(const T& value, basic_format_context& ctx) const + -> OutputIt { + auto buffer = basic_memory_buffer(); + detail::format_value(buffer, value); + // Must const_cast as apparently the format() method from fmtlib 7.1.3 is not const. + return const_cast*>(this)->formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); + } + }; + using ostream_formatter = basic_ostream_formatter; +} +#endif + + +#endif diff --git a/util/test/doctest_eigen_pca.cxx b/util/test/doctest_eigen_pca.cxx index ed066706..62c8c3d3 100644 --- a/util/test/doctest_eigen_pca.cxx +++ b/util/test/doctest_eigen_pca.cxx @@ -2,10 +2,6 @@ #include "WireCellUtil/Array.h" #include "WireCellUtil/doctest.h" - - -#include - using namespace Eigen; void dump(std::string msg, diff --git a/util/test/test-spdlog-fmtlib.cxx b/util/test/test-spdlog-fmtlib.cxx new file mode 100644 index 00000000..1cd67a24 --- /dev/null +++ b/util/test/test-spdlog-fmtlib.cxx @@ -0,0 +1,93 @@ +/** + Test for fmtlib's change in how it handles (or doesn't handle) implicitly + using ostream insertion operator<< starting at fmtlib 9. + + Test like: + + spack install spdlog@1.8.2+shared ^fmt@7.1.3 + spack install spdlog@1.9.2+shared ^fmt@8.1.1 + spack install spdlog@1.10.0+shared ^fmt@8.1.1 + spack install spdlog@1.11.0+shared ^fmt@9.1.0 + spack install spdlog@1.13.0+shared + + The goal is to force a version of fmtlib near to the version of the bundled + fmtlib for a given spdlog version. + + For each, + + spack view add -i spdlog-/local spdlog@ + echo 'load_prefix local' > spdlog-/.envrc + cd spdlog-/ + direnv allow + + g++ -Wall -std=c++17 \ + -o test-spdlog-fmtlib \ + ../test-spdlog-fmtlib.cxx \ + (pkg-config spdlog --cflags --libs | string split ' ') + + (fish syntax) + + ./test-spdlog-fmtlib + + */ + +#include +namespace NS { + + struct S { int x; }; + + inline std::ostream& operator<<(std::ostream& os, const S& s) + { + os << ""; + return os; + } +} + +#include + +#if defined(SPDLOG_FMT_EXTERNAL) +#include +#else +#include +#endif + +#if FMT_VERSION >= 90000 +#include +// This provides fmt::ostream_formatter. +#else +#include +// This id copied from fmt/ostream.h from fmtlib 10.2 with const_cast tweak. +namespace fmt { + template + struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; + + template + auto format(const T& value, basic_format_context& ctx) const + -> OutputIt { + auto buffer = basic_memory_buffer(); + detail::format_value(buffer, value); + // Must const_cast as apparently the format() method from fmtlib 7.1.3 is not const. + return const_cast*>(this)->formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); + } + }; + using ostream_formatter = basic_ostream_formatter; +} +#endif + + +// The goal with the mess above is to make this "new style" requirement work with old fmtlib. +template <> struct fmt::formatter : fmt::ostream_formatter {}; + + + +int main() +{ + NS::S s{42}; + std::cerr << s << "\n"; + spdlog::info("{}", s); + spdlog::info("FMT_VERSION={}", FMT_VERSION); + + return 0; +} diff --git a/util/test/test_rayclustering.cxx b/util/test/test_rayclustering.cxx index 3843191b..14d65982 100644 --- a/util/test/test_rayclustering.cxx +++ b/util/test/test_rayclustering.cxx @@ -29,6 +29,7 @@ const double height = 100; #include "raygrid_dump.h" + static std::vector make_points(std::default_random_engine& generator, double x) { std::vector points; @@ -151,7 +152,7 @@ struct Chirp { for (layer_index_t layer = 0; layer < nlayers; ++layer) { const auto& astrip = astrips[layer]; if (layer == c.first.layer) { - info("L{} A: {} {}", layer, astrip, c); + info("L{} A: {} {},{}", layer, astrip, c.first, c.second); if (astrip.on(c.first.grid)) { info("\ton with found={} nlayers={}", found, nlayers); ++found; @@ -161,7 +162,7 @@ struct Chirp { break; } if (layer == c.second.layer) { - info("L{} A: {} {}", layer, astrip, c); + info("L{} A: {} {},{}", layer, astrip, c.first, c.second); if (astrip.on(c.second.grid)) { info("\ton with found={} nlayers={}", found, nlayers); ++found; @@ -173,7 +174,7 @@ struct Chirp { const double ploc = coords.pitch_location(c.first, c.second, layer); const int pind = coords.pitch_index(ploc, layer); - info("L{} A: {} pind={} ploc={} {}", layer, astrip, pind, ploc, c); + info("L{} A: {} pind={} ploc={} {},{}", layer, astrip, pind, ploc, c.first, c.second); if (astrip.in(pind)) { info("\tin with found={} nlayers={}", found, nlayers); diff --git a/wscript b/wscript index 10c66ba8..a558ad2e 100644 --- a/wscript +++ b/wscript @@ -40,6 +40,9 @@ def options(opt): choices = log_levels, help="The compiled minimum log level for SPDLOG_() macros (def=info)") + opt.add_option('--cxxstd', default='c++17', + help="Set the value for the compiler's --std= option, default 'c++17'") + def configure(cfg): # Save to BuildConfig.h and env cfg.define("WIRECELL_VERSION", VERSION) @@ -72,6 +75,9 @@ int main(int argc,const char *argv[]) mandatory=False) + # cfg.env.CXXFLAGS += ['-Wpedantic', '-Werror'] + cfg.env.CXXFLAGS += ['-std='+cfg.options.cxxstd.lower()] + cfg.env.CXXFLAGS += ['-std=c++17']