Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
- Build:
- FIXED: Reduce MSVC compiler warnings by suppressing informational warnings while preserving bug-indicating warnings [#7253](https://github.com/Project-OSRM/osrm-backend/issues/7253)
- Misc:
- CHANGED: Add std::format compatibility layer with fallback to fmt::format [#7261](https://github.com/Project-OSRM/osrm-backend/pull/7261)
- FIXED: Update node_osrm to C++20 to fix ABI mismatch with libosrm (was overlooked in #6877) [#7261](https://github.com/Project-OSRM/osrm-backend/pull/7261)
- CHANGED: Update fmt library to version 11.2.0 [#7238](https://github.com/Project-OSRM/osrm-backend/issues/7238)
- CHANGED: Upgrade protozero from v1.7.1 to v1.8.1 [#7239](https://github.com/Project-OSRM/osrm-backend/pull/7239)
- CHANGED: Replace `std::is_trivial` with `std::is_trivially_default_constructible && std::is_trivially_copyable` [#7245](https://github.com/Project-OSRM/osrm-backend/issues/7245)
Expand Down
36 changes: 36 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,42 @@ endif()

find_package(Threads REQUIRED)

# Check for C++20 <format> with full chrono support that compiles, links and runs
# This is necessary because some environments have the header but incomplete
# implementation (e.g., Alpine GCC 14 missing chrono formatters, or Clang
# with libstdc++ from older GCC lacking std::format symbols at link time)
include(CheckCXXSourceRuns)

if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS} /std:c++20")
else()
set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
set(CMAKE_REQUIRED_LIBRARIES "stdc++")
endif()

check_cxx_source_runs("
#include <chrono>
#include <format>
#include <numbers>
#include <string>
int main() {
// Test basic formatting
std::string s1 = std::format(\"{:.10g}\", std::numbers::pi);
// Test chrono formatting
auto now = std::chrono::system_clock::now();
auto secs = std::chrono::floor<std::chrono::seconds>(now);
std::string s2 = std::format(\"{:%FT%T}\", secs);
return (s1.empty() || s2.empty()) ? 1 : 0;
}
" OSRM_HAS_STD_FORMAT)

unset(CMAKE_REQUIRED_FLAGS)
unset(CMAKE_REQUIRED_LIBRARIES)

if(OSRM_HAS_STD_FORMAT)
add_definitions(-DOSRM_HAS_STD_FORMAT)
endif()

# Third-party libraries
set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include")
include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
Expand Down
33 changes: 33 additions & 0 deletions include/util/format.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef OSRM_FORMAT_HPP
#define OSRM_FORMAT_HPP

// Compatibility layer for std::format and fmt::format

#ifdef OSRM_HAS_STD_FORMAT

#include <cmath>
#include <format>
#include <string>

namespace osrm::util::compat
{
// Use C++20 std::format when available
using std::format;
using std::to_string;
} // namespace osrm::util::compat

#else // Fallback to fmt library

#include <fmt/chrono.h>
#include <fmt/format.h>

namespace osrm::util::compat
{
// Use fmt library for backward compatibility
using fmt::format;
using fmt::to_string;
} // namespace osrm::util::compat

#endif // OSRM_HAS_STD_FORMAT

#endif // OSRM_FORMAT_HPP
10 changes: 3 additions & 7 deletions include/util/json_renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

#include <boost/assert.hpp>

#include <fmt/compile.h>
#include "util/format.hpp"

namespace osrm::util::json
{
Expand Down Expand Up @@ -50,12 +50,8 @@ template <typename Out> struct Renderer
{
// we don't want to print NaN or Infinity
BOOST_ASSERT(std::isfinite(number.value));
// `fmt::memory_buffer` stores first 500 bytes in the object itself(i.e. on stack in this
// case) and then grows using heap if needed
fmt::memory_buffer buffer;
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE("{:.10g}"), number.value);

write(buffer.data(), buffer.size());
std::string formatted = compat::format("{:.10g}", number.value);
write(formatted.data(), formatted.size());
}

void operator()(const Object &object)
Expand Down
2 changes: 2 additions & 0 deletions scripts/update_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ PROTOZERO_TAG=v1.8.1
VTZERO_PATH="mapbox/vtzero"
VTZERO_TAG=v1.1.0

# Note: fmt is kept for backward compatibility with compilers lacking std::format support
# (e.g., Clang with older libstdc++). Will be removed once GCC 13+ becomes minimum requirement.
FMT_PATH="fmtlib/fmt"
FMT_TAG=11.2.0

Expand Down
2 changes: 1 addition & 1 deletion src/nodejs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ message(STATUS "Configuring node_osrm bindings for NodeJs ${NODEJS_VERSION}")


add_nodejs_module(node_osrm node_osrm.cpp)
set_target_properties(node_osrm PROPERTIES CXX_STANDARD 17)
set_target_properties(node_osrm PROPERTIES CXX_STANDARD 20)
# TODO: we disable clang-tidy for this target, because it causes errors in third-party NodeJs related headers
set_target_properties(node_osrm PROPERTIES CXX_CLANG_TIDY "")
# TODO: we turn off some warnings for this target, because it causes errors in third-party NodeJs related headers
Expand Down
9 changes: 5 additions & 4 deletions src/server/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
#include "server/request_handler.hpp"
#include "server/request_parser.hpp"

#include "util/format.hpp"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/bind.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>

#include <fmt/format.h>
#include <vector>

namespace osrm::server
Expand Down Expand Up @@ -91,9 +92,9 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
{
keep_alive = true;
current_reply.headers.emplace_back("Connection", "keep-alive");
current_reply.headers.emplace_back("Keep-Alive",
"timeout=" + fmt::to_string(keepalive_timeout) +
", max=" + fmt::to_string(processed_requests));
current_reply.headers.emplace_back(
"Keep-Alive",
util::compat::format("timeout={}, max={}", keepalive_timeout, processed_requests));
}

// compress the result w/ gzip/deflate if requested
Expand Down
20 changes: 14 additions & 6 deletions src/util/log.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "util/log.hpp"
#include "util/format.hpp"
#include "util/isatty.hpp"
#include <boost/algorithm/string/predicate.hpp>
#include <chrono>
#include <cstdio>
#include <fmt/chrono.h>
#include <iostream>
#include <mutex>
#include <string>
Expand Down Expand Up @@ -75,12 +76,19 @@ void Log::Init()

auto format = [is_terminal](const char *level, const char *color)
{
#ifdef OSRM_HAS_STD_FORMAT
const auto now = std::chrono::system_clock::now();
const auto timestamp =
compat::format("{:%FT%T}", std::chrono::floor<std::chrono::seconds>(now));
return compat::format("{}[{}] [{}] ", is_terminal ? color : "", timestamp, level);
#else
const auto timestamp = std::chrono::system_clock::now();
return fmt::format("{}[{:%FT%H:%M:}{:%S}] [{}] ",
is_terminal ? color : "",
timestamp,
timestamp.time_since_epoch(),
level);
return compat::format("{}[{:%FT%H:%M:}{:%S}] [{}] ",
is_terminal ? color : "",
timestamp,
timestamp.time_since_epoch(),
level);
#endif
};

switch (level)
Expand Down
Loading