OSRM (Open Source Routing Machine) is a high performance routing engine written in C++ designed to run on OpenStreetMap data. It provides various routing services including route finding, distance/duration tables, GPS trace matching, and traveling salesman problem solving. It is accessible via HTTP API, C++ library interface, and Node.js wrapper. OSRM supports two routing algorithms: Contraction Hierarchies (CH) and Multi-Level Dijkstra (MLD).
We target C++20 but need to deal with older compilers that only have partial support.
Use ./scripts/format.sh to format the code. Ensure clang-format-15 is available on the system.
Specific practices to follow (see wiki):
- No
using namespace: Always use explicitstd::prefixes, neverusing namespace std;(especially in headers) - Naming conventions:
- Type names (classes, structs, enums):
UpperCamelCase(e.g.TextFileReader) - Variables:
lower_case_with_underscores, private members start withm_(e.g.m_node_count) - Functions:
lowerCamelCaseverb phrases (e.g.openFile(),isValid()) - Enumerators and public members:
UpperCamelCase(e.g.VK_Argument)
- Type names (classes, structs, enums):
- Include order: (1) Module header, (2) Local headers, (3) Parent directory headers, (4) System includes - sorted lexicographically within each group
- Comments: Minimal use of comments on internal interfaces. Use C++ style
//comments, not C style/* */. Use#if 0/#endifto comment out blocks - Integer types: Use only
int/unsignedfor 32-bit, or precise-width types likeint16_t,int64_t - No RTTI/exceptions: Avoid
dynamic_cast<>and exceptions (except for IO operations) - Compiler warnings: Treat all warnings as errors - fix them, don't ignore them
- Assert liberally: Use
BOOST_ASSERTto check preconditions and assumptions - Indentation: 4 spaces (enforced by clang-format)
This project uses CMake. The build directory should be build or build-{something} or build/{something}/. For example:
./build./build-gcc-debug./build/gcc-debug./build/gcc./build/clang-debug./build-clang-release
Use cmake --build ${BUILD_DIR} --target ${TARGET} -j $(nproc --ignore=2) to build a target.
OSRM supports two data preparations: Contraction Hierarchies (CH) and Multi-Level Dijkstra (MLD).
For CH:
./${BUILD_DIR}/osrm-extract -p profiles/car.lua data.osm.pbf./${BUILD_DIR}/osrm-partition data.osrm(optional, improves CH performance due to cache locality of node reordering)./${BUILD_DIR}/osrm-contract data.osrm./${BUILD_DIR}/osrm-routed -a CH data.osrm
For MLD:
./${BUILD_DIR}/osrm-extract -p profiles/car.lua data.osm.pbf./${BUILD_DIR}/osrm-partition data.osrm./${BUILD_DIR}/osrm-customize data.osrm./${BUILD_DIR}/osrm-routed -a MLD data.osrm
A dataset can be both MLD and CH if both osrm-contract and osrm-customize are executed:
./${BUILD_DIR}/osrm-extract -p profiles/car.lua data.osm.pbf./${BUILD_DIR}/osrm-partition data.osrm./${BUILD_DIR}/osrm-contract data.osrm./${BUILD_DIR}/osrm-customize data.osrm./${BUILD_DIR}/osrm-routed -a CH data.osrmOR./${BUILD_DIR}/osrm-routed -a MLD data.osrm
Unit tests are contained in unit_tests/ using boost test and can be build with:
cmake --build ${BUILD_DIR} --target testsThis will create various tests in ${BUILD_DIR}/unit_tests/.
Integration tests are contained in features/ using cucumber-js
To run cucumber tests with the full test matrix across different algorithms (CH, MLD) and load methods (mmap, directly, datastore).
npm testTo run cucumber tests for a specific configuration:
npx cucumber-js -p home -p ch -p datastore
npx cucumber-js -p home -p mld -p mmapIMPORTANT: Profile changes MUST follow this checklist:
-
Cucumber tests: Every change to a profile (
.luafiles inprofiles/) must be accompanied by a corresponding cucumber test infeatures/that validates the new or changed behavior.- Run the relevant cucumber tests before committing profile changes:
The test cache is keyed by a content hash of all profiles, binaries, and the feature file, so profile changes automatically invalidate the cache. Old cache directories can optionally be cleaned up with
OSRM_BUILD_DIR=build npx cucumber-js -p home -p mld -p mmap features/<profile>/<feature>.feature
rm -rf test/cache. - Run the whole
.featurefile (not just the new scenario) to verify no regressions. - Use the existing test patterns:
routability should betables where any column header starting withforw,backw, orbothw(including*_ratevariants) is an expectation column (not an OSM tag). Headers matchingnode/<tag>apply to node tags. All other columns become OSM way tags. - Do NOT add
@todoto new scenarios — verify the expected behavior matches actual routing output.
- Run the relevant cucumber tests before committing profile changes:
-
taginfo.json: If modifying tag handling (adding, removing, or changing how OSM tags are parsed), update
taginfo.jsonwith any new OSM tags that are now recognized or any tags whose semantics have changed. -
OSM Wiki adherence: Verify that the behavior matches OSM tagging conventions:
- Mode-specific tags (e.g.
bicycle=yes) override vehicle-level restrictions (e.g.vehicle=no) - Directional suffixes (
:forward/:backward) scope a tag to a specific travel direction - The access tag hierarchy is: mode-specific > vehicle-level > general access
- When in doubt, consult the relevant OSM wiki pages for the tags being changed
- Mode-specific tags (e.g.
Python bindings live under src/python/ using nanobind + scikit-build-core.
src/python/CMakeLists.txt— nanobind module definition, installs everything underosrm/namespacesrc/python/osrm/— Python package (__init__.py,__main__.py,.pyistubs)src/python/src/— C++ nanobind source files (16 files)src/python/include/python/— C++ binding headers (.hpp)
ENABLE_PYTHON_BINDINGS=ONtriggersadd_subdirectory(src/python)in root CMakeLists.txt- Links against the in-tree
osrmtarget directly (no FetchContent) - Binding headers use
#include "python/..."prefix; OSRM headers useengine/...paths (not theosrm/forwarding headers), exceptosrm/osrm.hpp - LTO disabled for
osrm_exttarget (nanobindNB_MAKE_OPAQUE+ GCC LTO +-Werror= ODR violation) - Wheel installs executables to
osrm/bin/, profiles toosrm/share/profiles/;wheel.excludefilters out root CMake install artifacts (lib/,include/,bin/,share/) __main__.pyfinds executables:osrm/bin/(wheel) →build/*/(editable) → PATH- Type stubs (
osrm_ext.pyi) auto-generated bynanobind_add_stub(); rebuild + commit after C++ changes - C++ formatted by project clang-format; Python by ruff (both via
.pre-commit-config.yaml) - When changing the Python binding API (function signatures, classes, exposed attributes, parameter semantics), update docs/python/api.md in the same change
- When changing the build, packaging, or release flow (pyproject.toml, CMake options, cibuildwheel config,
.github/workflows/release-monthly.yml,.github/workflows/osrm-backend.ymlPython steps), update docs/python/development.md in the same change
pip install -e ".[dev]" # editable install
cd test/data && make # build test data
python -m osrm datastore test/data/ch/monaco
pytest test/python/Do NOT include any AI attribution (e.g. Co-authored-by: trailers) in git commit messages.