From 949feee7c98bf55fb0f2ee0b19776467103e40e6 Mon Sep 17 00:00:00 2001 From: John Carmack Date: Tue, 13 Jan 2026 18:05:16 -0800 Subject: [PATCH 1/4] Fix Boost 1.89+ compatibility by isolating boost::sort from boost::geometry Boost 1.89 introduced a conflict where boost::geometry includes boost::range, which defines boost::range::sort that conflicts with boost::sort. This causes ambiguous calls when both are visible in the same translation unit. Solution: Move sorting code to separate translation units where boost::sort can be included before any boost::geometry headers, preventing the conflict. Changes: - Create tile_data_base.h with shared struct definitions - Create tile_sorting.cpp to isolate finalizeObjects template with boost::sort - Use extern template declarations to prevent implicit instantiation - Update CMakeLists.txt with conditional Boost system component handling - Update Makefile with new source file and modernized flags This maintains use of boost::sort::pdqsort for optimal sorting performance while being compatible with Boost 1.66+ through 1.90+. --- CMakeLists.txt | 16 ++++- Makefile | 8 ++- include/tile_data.h | 137 +++++++-------------------------------- include/tile_data_base.h | 43 ++++++++++++ src/osm_store.cpp | 1 - src/tile_data.cpp | 4 ++ src/tile_sorting.cpp | 117 +++++++++++++++++++++++++++++++++ 7 files changed, 206 insertions(+), 120 deletions(-) create mode 100644 include/tile_data_base.h create mode 100644 src/tile_sorting.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c5c2309d..9bd07174 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,15 @@ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) ENDIF () -find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem program_options) +# Try to find Boost 1.89+ first (system is header-only, no need to link) +# Fall back to older Boost with system component if not found +find_package(Boost 1.89 QUIET COMPONENTS filesystem program_options) +if(NOT Boost_FOUND) + find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem program_options) + set(BOOST_HAS_SYSTEM TRUE) +else() + set(BOOST_HAS_SYSTEM FALSE) +endif() find_package(libshp REQUIRED) @@ -111,6 +119,7 @@ file(GLOB tilemaker_src_files src/tag_map.cpp src/tile_coordinates_set.cpp src/tile_data.cpp + src/tile_sorting.cpp src/tilemaker.cpp src/tile_worker.cpp src/visvalingam.cpp @@ -125,7 +134,10 @@ target_link_libraries(tilemaker shapelib::shp SQLite::SQLite3 Rapidjson::rapidjson - Boost::system Boost::filesystem Boost::program_options) + Boost::filesystem Boost::program_options) +if(BOOST_HAS_SYSTEM) + target_link_libraries(tilemaker Boost::system) +endif() include(CheckCxxAtomic) if(NOT HAVE_CXX11_ATOMIC) diff --git a/Makefile b/Makefile index ccbd1b7e..18f39363 100644 --- a/Makefile +++ b/Makefile @@ -74,9 +74,12 @@ prefix = /usr/local MANPREFIX := /usr/share/man TM_VERSION ?= $(shell git describe --tags --abbrev=0) -CXXFLAGS ?= -O3 -Wall -Wno-unknown-pragmas -Wno-sign-compare -std=c++14 -pthread -fPIE -DTM_VERSION=$(TM_VERSION) $(CONFIG) +# Suppress warnings from third-party libraries: +# -Wno-missing-template-arg-list-after-template-kw: Boost.Interprocess compatibility with newer compilers +# -Wno-deprecated-declarations: RapidJSON uses deprecated std::iterator +CXXFLAGS ?= -O3 -Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-missing-template-arg-list-after-template-kw -Wno-deprecated-declarations -std=c++17 -pthread -fPIE -DTM_VERSION=$(TM_VERSION) $(CONFIG) CFLAGS ?= -O3 -Wall -Wno-unknown-pragmas -Wno-sign-compare -std=c99 -fPIE -DTM_VERSION=$(TM_VERSION) $(CONFIG) -LIB := -L$(PLATFORM_PATH)/lib $(LUA_LIBS) -lboost_program_options -lsqlite3 -lboost_filesystem -lboost_system -lshp -pthread +LIB := -L$(PLATFORM_PATH)/lib $(LUA_LIBS) -lboost_program_options -lsqlite3 -lboost_filesystem -lshp -pthread INC := -I$(PLATFORM_PATH)/include -isystem ./include -I./src $(LUA_CFLAGS) # Targets @@ -129,6 +132,7 @@ tilemaker: \ src/tag_map.o \ src/tile_coordinates_set.o \ src/tile_data.o \ + src/tile_sorting.o \ src/tilemaker.o \ src/tile_worker.o \ src/visvalingam.o \ diff --git a/include/tile_data.h b/include/tile_data.h index 80ae3239..efbd4124 100644 --- a/include/tile_data.h +++ b/include/tile_data.h @@ -1,4 +1,4 @@ -/*! \file */ +/*! \file */ #ifndef _TILE_DATA_H #define _TILE_DATA_H @@ -6,52 +6,18 @@ #include #include #include -#include -#include "output_object.h" +#include "tile_data_base.h" #include "append_vector.h" #include "clip_cache.h" #include "mmap_allocator.h" #include "tile_coordinates_set.h" -#define TILE_DATA_ID_SIZE 34 - typedef std::vector SourceList; class TileBbox; -// We cluster output objects by z6 tile -#define CLUSTER_ZOOM 6 -#define CLUSTER_ZOOM_WIDTH (1 << CLUSTER_ZOOM) -#define CLUSTER_ZOOM_AREA (CLUSTER_ZOOM_WIDTH * CLUSTER_ZOOM_WIDTH) - -// TileDataSource indexes which tiles have objects in them. The indexed zoom -// is at most z14; we'll clamp to z14 if the base zoom is higher than z14. -// -// As a result, we need at most 15 bits to store an X/Y coordinate. For efficiency, -// we bucket the world into 4,096 z6 tiles, which each contain some number of -// z14 objects. This lets us use only 8 bits to store an X/Y coordinate. -// -// Because index zoom is lower than base zoom in the case where base zoom is -// z15+, we'll get false positives when looking up objects in the index, -// since, e.g., a single z14 tile covers 4 z15 tiles. -// -// This is OK: when writing the z15 tile, there's a clipping step that will filter -// out the false positives. -typedef uint8_t Z6Offset; - -struct OutputObjectXY { - OutputObject oo; - Z6Offset x; - Z6Offset y; -}; - -struct OutputObjectXYID { - OutputObject oo; - Z6Offset x; - Z6Offset y; - uint64_t id; -}; - +// Declaration only - implementation in tile_sorting.cpp to avoid +// boost::sort conflicts with boost::geometry in Boost 1.89+ template void finalizeObjects( const std::string& name, const size_t& threadNum, @@ -59,85 +25,26 @@ template void finalizeObjects( typename std::vector>::iterator begin, typename std::vector>::iterator end, typename std::vector>& lowZoom - ) { - size_t z6OffsetDivisor = indexZoom >= CLUSTER_ZOOM ? (1 << (indexZoom - CLUSTER_ZOOM)) : 1; -#ifdef CLOCK_MONOTONIC - timespec startTs, endTs; - clock_gettime(CLOCK_MONOTONIC, &startTs); -#endif - - int i = -1; - for (auto it = begin; it != end; it++) { - i++; - if (it->size() > 0 || i % 50 == 0 || i == 4095) { - std::cout << "\r" << name << ": finalizing z6 tile " << (i + 1) << "/" << CLUSTER_ZOOM_AREA; - -#ifdef CLOCK_MONOTONIC - clock_gettime(CLOCK_MONOTONIC, &endTs); - uint64_t elapsedNs = 1e9 * (endTs.tv_sec - startTs.tv_sec) + endTs.tv_nsec - startTs.tv_nsec; - std::cout << " (" << std::to_string((uint32_t)(elapsedNs / 1e6)) << " ms)"; -#endif - std::cout << std::flush; - } - if (it->size() == 0) - continue; - - // We track a separate copy of low zoom objects to avoid scanning large - // lists of objects that may be on slow disk storage. - for (auto objectIt = it->begin(); objectIt != it->end(); objectIt++) - if (objectIt->oo.minZoom < CLUSTER_ZOOM) - lowZoom[i].push_back(*objectIt); - - // If the user is doing a a small extract, there are few populated - // entries in `object`. - // - // e.g. Colorado has ~9 z6 tiles, 1 of which has 95% of its output - // objects. - // - // This optimizes for the small extract case by doing: - // - for each vector in objects - // - do a multi-threaded sort of vector - // - // For small extracts, this ensures that all threads are used even if - // only a handful of entries in `objects` are non-empty. - // - // For a global extract, this will have some overhead of repeatedly - // setting up/tearing down threads. In that case, it would be - // better to assign chunks of `objects` to each thread. - // - // That's a future performance improvement, so deferring for now. - boost::sort::block_indirect_sort( - it->begin(), - it->end(), - [indexZoom](const OO& a, const OO& b) { - // Cluster by parent zoom, so that a subsequent search - // can find a contiguous range of entries for any tile - // at zoom 6 or higher. - const size_t aX = a.x; - const size_t aY = a.y; - const size_t bX = b.x; - const size_t bY = b.y; - for (size_t z = CLUSTER_ZOOM; z <= indexZoom; z++) { - const auto aXz = aX / (1 << (indexZoom - z)); - const auto bXz = bX / (1 << (indexZoom - z)); - if (aXz != bXz) - return aXz < bXz; - - const auto aYz = aY / (1 << (indexZoom - z)); - const auto bYz = bY / (1 << (indexZoom - z)); - - if (aYz != bYz) - return aYz < bYz; - } +); - return false; - }, - threadNum - ); - } +// Extern template declarations to prevent implicit instantiation +extern template void finalizeObjects( + const std::string& name, + const size_t& threadNum, + const unsigned int& indexZoom, + std::vector>::iterator begin, + std::vector>::iterator end, + std::vector>& lowZoom +); - std::cout << std::endl; -} +extern template void finalizeObjects( + const std::string& name, + const size_t& threadNum, + const unsigned int& indexZoom, + std::vector>::iterator begin, + std::vector>::iterator end, + std::vector>& lowZoom +); template void collectTilesWithObjectsAtZoomTemplate( const unsigned int& indexZoom, diff --git a/include/tile_data_base.h b/include/tile_data_base.h new file mode 100644 index 00000000..021ebbd9 --- /dev/null +++ b/include/tile_data_base.h @@ -0,0 +1,43 @@ +/*! \file */ +#ifndef _TILE_DATA_BASE_H +#define _TILE_DATA_BASE_H + +#include +#include "output_object.h" + +#define TILE_DATA_ID_SIZE 34 + +// We cluster output objects by z6 tile +#define CLUSTER_ZOOM 6 +#define CLUSTER_ZOOM_WIDTH (1 << CLUSTER_ZOOM) +#define CLUSTER_ZOOM_AREA (CLUSTER_ZOOM_WIDTH * CLUSTER_ZOOM_WIDTH) + +// TileDataSource indexes which tiles have objects in them. The indexed zoom +// is at most z14; we'll clamp to z14 if the base zoom is higher than z14. +// +// As a result, we need at most 15 bits to store an X/Y coordinate. For efficiency, +// we bucket the world into 4,096 z6 tiles, which each contain some number of +// z14 objects. This lets us use only 8 bits to store an X/Y coordinate. +// +// Because index zoom is lower than base zoom in the case where base zoom is +// z15+, we'll get false positives when looking up objects in the index, +// since, e.g., a single z14 tile covers 4 z15 tiles. +// +// This is OK: when writing the z15 tile, there's a clipping step that will filter +// out the false positives. +typedef uint8_t Z6Offset; + +struct OutputObjectXY { + OutputObject oo; + Z6Offset x; + Z6Offset y; +}; + +struct OutputObjectXYID { + OutputObject oo; + Z6Offset x; + Z6Offset y; + uint64_t id; +}; + +#endif //_TILE_DATA_BASE_H diff --git a/src/osm_store.cpp b/src/osm_store.cpp index 5b7366b7..5bd6ef61 100644 --- a/src/osm_store.cpp +++ b/src/osm_store.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "node_store.h" #include "way_store.h" diff --git a/src/tile_data.cpp b/src/tile_data.cpp index db9ffaac..c2d9fbf2 100644 --- a/src/tile_data.cpp +++ b/src/tile_data.cpp @@ -1,3 +1,7 @@ +// boost::sort must be included FIRST, before any headers that might +// include boost::geometry, to avoid conflicts with boost::range::sort +#include + #include #include #include "tile_data.h" diff --git a/src/tile_sorting.cpp b/src/tile_sorting.cpp new file mode 100644 index 00000000..53fc9ed1 --- /dev/null +++ b/src/tile_sorting.cpp @@ -0,0 +1,117 @@ +// This file contains sorting implementations that use boost::sort. +// boost::sort is kept in a separate translation unit to avoid conflicts +// with boost::geometry's boost::range::sort when both are included in +// the same translation unit (issue with Boost 1.89+). + +#include +#include +#include +#include +#include "tile_data_base.h" +#include "append_vector.h" + +template void finalizeObjects( + const std::string& name, + const size_t& threadNum, + const unsigned int& indexZoom, + typename std::vector>::iterator begin, + typename std::vector>::iterator end, + typename std::vector>& lowZoom + ) { + size_t z6OffsetDivisor = indexZoom >= CLUSTER_ZOOM ? (1 << (indexZoom - CLUSTER_ZOOM)) : 1; +#ifdef CLOCK_MONOTONIC + timespec startTs, endTs; + clock_gettime(CLOCK_MONOTONIC, &startTs); +#endif + + int i = -1; + for (auto it = begin; it != end; it++) { + i++; + if (it->size() > 0 || i % 50 == 0 || i == 4095) { + std::cout << "\r" << name << ": finalizing z6 tile " << (i + 1) << "/" << CLUSTER_ZOOM_AREA; + +#ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &endTs); + uint64_t elapsedNs = 1e9 * (endTs.tv_sec - startTs.tv_sec) + endTs.tv_nsec - startTs.tv_nsec; + std::cout << " (" << std::to_string((uint32_t)(elapsedNs / 1e6)) << " ms)"; +#endif + std::cout << std::flush; + } + if (it->size() == 0) + continue; + + // We track a separate copy of low zoom objects to avoid scanning large + // lists of objects that may be on slow disk storage. + for (auto objectIt = it->begin(); objectIt != it->end(); objectIt++) + if (objectIt->oo.minZoom < CLUSTER_ZOOM) + lowZoom[i].push_back(*objectIt); + + // If the user is doing a a small extract, there are few populated + // entries in `object`. + // + // e.g. Colorado has ~9 z6 tiles, 1 of which has 95% of its output + // objects. + // + // This optimizes for the small extract case by doing: + // - for each vector in objects + // - do a multi-threaded sort of vector + // + // For small extracts, this ensures that all threads are used even if + // only a handful of entries in `objects` are non-empty. + // + // For a global extract, this will have some overhead of repeatedly + // setting up/tearing down threads. In that case, it would be + // better to assign chunks of `objects` to each thread. + // + // That's a future performance improvement, so deferring for now. + boost::sort::block_indirect_sort( + it->begin(), + it->end(), + [indexZoom](const OO& a, const OO& b) { + // Cluster by parent zoom, so that a subsequent search + // can find a contiguous range of entries for any tile + // at zoom 6 or higher. + const size_t aX = a.x; + const size_t aY = a.y; + const size_t bX = b.x; + const size_t bY = b.y; + for (size_t z = CLUSTER_ZOOM; z <= indexZoom; z++) { + const auto aXz = aX / (1 << (indexZoom - z)); + const auto bXz = bX / (1 << (indexZoom - z)); + if (aXz != bXz) + return aXz < bXz; + + const auto aYz = aY / (1 << (indexZoom - z)); + const auto bYz = bY / (1 << (indexZoom - z)); + + if (aYz != bYz) + return aYz < bYz; + } + + return false; + }, + threadNum + ); + } + + std::cout << std::endl; +} + +// Explicit template instantiations +template void finalizeObjects( + const std::string& name, + const size_t& threadNum, + const unsigned int& indexZoom, + std::vector>::iterator begin, + std::vector>::iterator end, + std::vector>& lowZoom +); + +template void finalizeObjects( + const std::string& name, + const size_t& threadNum, + const unsigned int& indexZoom, + std::vector>::iterator begin, + std::vector>::iterator end, + std::vector>& lowZoom +); From 81d83fc7fa5d8521c412751d3b1d6315cb2a3e8f Mon Sep 17 00:00:00 2001 From: John Carmack Date: Tue, 13 Jan 2026 18:20:52 -0800 Subject: [PATCH 2/4] Update CI workflow and fix infrastructure issues - Update actions/checkout from v2 to v4 - Update actions/cache from v2 to v4 - Update docker/login-action to v3 - Update docker/metadata-action to v5 - Update docker/build-push-action to v6 - Add -L flag to curl commands to follow redirects - Use HTTPS for Geofabrik downloads - Fix Docker CMake boost_system variant issue with -DBoost_USE_DEBUG_RUNTIME=OFF --- .github/workflows/ci.yml | 30 +++++++++++++++--------------- Dockerfile | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c8aff91..bbd50fbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,10 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Enable vcpkg cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: c:\vcpkg\installed key: windows-vcpkg-x64-0 # Increase the number whenever dependencies are modified @@ -36,7 +36,7 @@ jobs: - name: Build openmaptiles-compatible mbtiles files of Liechtenstein run: | - Invoke-WebRequest -Uri http://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -OutFile ${{ env.AREA }}.osm.pbf + Invoke-WebRequest -Uri https://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -OutFile ${{ env.AREA }}.osm.pbf -MaximumRedirection 5 ${{ github.workspace }}\build\RelWithDebInfo\tilemaker.exe ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.pmtiles --verbose ${{ github.workspace }}\build\RelWithDebInfo\tilemaker.exe ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.mbtiles --store osm_store --verbose @@ -62,10 +62,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Enable vcpkg cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ matrix.path }} key: vcpkg-${{ matrix.triplet }}-0 # Increase the number whenever dependencies are modified @@ -85,7 +85,7 @@ jobs: - name: Build openmaptiles-compatible mbtiles files of Liechtenstein run: | - curl http://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -o ${{ env.AREA }}.osm.pbf + curl -L https://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -o ${{ env.AREA }}.osm.pbf ${{ github.workspace }}/build/${{ matrix.executable }} ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.pmtiles --verbose ${{ github.workspace }}/build/${{ matrix.executable }} ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.mbtiles --verbose --store /tmp/store @@ -109,7 +109,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Linux dependencies if: ${{ matrix.os == 'ubuntu-22.04' }} @@ -129,7 +129,7 @@ jobs: - name: Build openmaptiles-compatible mbtiles files of Liechtenstein run: | - curl http://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -o ${{ env.AREA }}.osm.pbf + curl -L https://download.geofabrik.de/europe/${{ env.AREA }}-latest.osm.pbf -o ${{ env.AREA }}.osm.pbf ./tilemaker ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.pmtiles --verbose ./tilemaker ${{ env.AREA }}.osm.pbf --config=resources/config-openmaptiles.json --process=resources/process-openmaptiles.lua --output=${{ env.AREA }}.mbtiles --verbose --store /tmp/store @@ -140,10 +140,10 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Download PBF file - run: curl http://download.geofabrik.de/europe/${AREA}-latest.osm.pbf -o ${AREA}.osm.pbf + run: curl -L https://download.geofabrik.de/europe/${AREA}-latest.osm.pbf -o ${AREA}.osm.pbf - name: Build openmaptiles-compatible mbtiles files of given area uses: ./ @@ -163,10 +163,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Log in to the Container registry - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -174,12 +174,12 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/build-push-action@v6 if: ${{ github.ref != 'refs/heads/master'}} with: context: . @@ -187,7 +187,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - name: Build and push Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/build-push-action@v6 if: ${{ github.ref == 'refs/heads/master'}} with: context: . diff --git a/Dockerfile b/Dockerfile index 87e04bc0..de5b8230 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ COPY server ./server RUN mkdir build && \ cd build && \ if [ -z "$BUILD_DEBUG" ]; then \ - cmake -DCMAKE_BUILD_TYPE=Release ..; \ + cmake -DCMAKE_BUILD_TYPE=Release -DBoost_USE_DEBUG_RUNTIME=OFF ..; \ else \ cmake -DCMAKE_BUILD_TYPE=Debug ..; \ fi; \ From c67a3ef7fff11fcb20baf963d103d03d5963b350 Mon Sep 17 00:00:00 2001 From: John Carmack Date: Tue, 13 Jan 2026 19:41:49 -0800 Subject: [PATCH 3/4] Fix Lua 5.4 compatibility in kaguya.hpp Some Lua 5.4 builds (e.g., vcpkg) removed LUA_GCSETPAUSE and LUA_GCSETSTEPMUL constants, replacing them with LUA_GCPPAUSE and LUA_GCPSTEPMUL. Add conditional defines to handle both cases. --- include/external/kaguya.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/external/kaguya.hpp b/include/external/kaguya.hpp index 39891fee..a7357e63 100644 --- a/include/external/kaguya.hpp +++ b/include/external/kaguya.hpp @@ -18,6 +18,15 @@ extern "C" { #include } +// Lua 5.4 compatibility: Some builds removed LUA_GCSETPAUSE/LUA_GCSETSTEPMUL +// Check if old constants exist, otherwise define them using the new names +#if !defined(LUA_GCSETPAUSE) && defined(LUA_GCPPAUSE) +#define LUA_GCSETPAUSE LUA_GCPPAUSE +#endif +#if !defined(LUA_GCSETSTEPMUL) && defined(LUA_GCPSTEPMUL) +#define LUA_GCSETSTEPMUL LUA_GCPSTEPMUL +#endif + #ifndef KAGUYA_USE_CPP11 #if defined(__cpp_decltype) || __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) #define KAGUYA_USE_CPP11 1 @@ -12495,7 +12504,7 @@ namespace kaguya /// @brief sets arg as the new value for the pause of the collector. Returns the previous value for pause. int steppause(int value) { return lua_gc(state_, LUA_GCSETPAUSE, value); } - + /// @brief sets arg as the new value for the step multiplier of the collector. Returns the previous value for step. int setstepmul(int value) { return lua_gc(state_, LUA_GCSETSTEPMUL, value); } From 97c26b469fcd4c5f9c878c521371d991e31e953e Mon Sep 17 00:00:00 2001 From: John Carmack Date: Tue, 13 Jan 2026 20:55:19 -0800 Subject: [PATCH 4/4] Replace boost::sort with std::sort in files using boost::geometry boost::sort conflicts with boost::geometry's boost::range::sort in Boost 1.89+. The conflict occurs when both are included in the same translation unit, regardless of include order. Solution: Use std::sort in files that need boost::geometry (tile_data.cpp, tile_sorting.cpp, tilemaker.cpp). boost::sort is still used in isolated files like node_stores.cpp and way_stores.cpp that don't use geometry. This trades some parallel sorting performance for Boost 1.89+ compatibility. --- src/tile_data.cpp | 7 ++----- src/tile_sorting.cpp | 19 ++++++++++--------- src/tilemaker.cpp | 10 +++++----- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/tile_data.cpp b/src/tile_data.cpp index c2d9fbf2..b764e312 100644 --- a/src/tile_data.cpp +++ b/src/tile_data.cpp @@ -1,7 +1,3 @@ -// boost::sort must be included FIRST, before any headers that might -// include boost::geometry, to avoid conflicts with boost::range::sort -#include - #include #include #include "tile_data.h" @@ -411,7 +407,8 @@ std::vector TileDataSource::getObjectsForTile( // Note that attributes is preferred to objectID. // It is to arrange objects with the identical attributes continuously. // Such objects will be merged into one object, to reduce the size of output. - boost::sort::pdqsort(data.begin(), data.end(), [&sortOrders](const OutputObjectID& x, const OutputObjectID& y) -> bool { + // Note: Using std::sort to avoid conflicts with boost::geometry in Boost 1.89+ + std::sort(data.begin(), data.end(), [&sortOrders](const OutputObjectID& x, const OutputObjectID& y) -> bool { if (x.oo.layer < y.oo.layer) return true; if (x.oo.layer > y.oo.layer) return false; if (x.oo.z_order < y.oo.z_order) return sortOrders[x.oo.layer]; diff --git a/src/tile_sorting.cpp b/src/tile_sorting.cpp index 53fc9ed1..e58e5a4a 100644 --- a/src/tile_sorting.cpp +++ b/src/tile_sorting.cpp @@ -1,14 +1,15 @@ // This file contains sorting implementations that use boost::sort. -// boost::sort is kept in a separate translation unit to avoid conflicts -// with boost::geometry's boost::range::sort when both are included in -// the same translation unit (issue with Boost 1.89+). +// boost::sort conflicts with boost::geometry's boost::range::sort in Boost 1.89+. +// Files that need both should use std::sort instead. +// This file needs boost::geometry (via tile_data_base.h) for struct definitions, +// so we use std::sort here as well for Boost 1.89+ compatibility. -#include +#include "tile_data_base.h" +#include "append_vector.h" +#include #include #include #include -#include "tile_data_base.h" -#include "append_vector.h" template void finalizeObjects( const std::string& name, @@ -64,7 +65,8 @@ template void finalizeObjects( // better to assign chunks of `objects` to each thread. // // That's a future performance improvement, so deferring for now. - boost::sort::block_indirect_sort( + // Note: Using std::sort for Boost 1.89+ compatibility (boost::sort conflicts with boost::geometry) + std::sort( it->begin(), it->end(), [indexZoom](const OO& a, const OO& b) { @@ -89,8 +91,7 @@ template void finalizeObjects( } return false; - }, - threadNum + } ); } diff --git a/src/tilemaker.cpp b/src/tilemaker.cpp index bcbb4d32..c5dbab3c 100644 --- a/src/tilemaker.cpp +++ b/src/tilemaker.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include "rapidjson/document.h" #include "rapidjson/writer.h" @@ -454,9 +453,11 @@ int main(const int argc, const char* argv[]) { std::cout << std::endl; // Cluster tiles: breadth-first for z0..z5, depth-first for z6 + // Note: Using std::sort instead of boost::sort to avoid conflicts with + // boost::geometry in Boost 1.89+. boost::sort is used in isolated files only. const size_t baseZoom = config.baseZoom; - boost::sort::block_indirect_sort( - tileCoordinates.begin(), tileCoordinates.end(), + std::sort( + tileCoordinates.begin(), tileCoordinates.end(), [baseZoom](auto const &a, auto const &b) { const auto aZoom = a.first; const auto bZoom = b.first; @@ -501,8 +502,7 @@ int main(const int argc, const char* argv[]) { } return false; - }, - options.threadNum); + }); std::size_t batchSize = 0; for(std::size_t startIndex = 0; startIndex < tileCoordinates.size(); startIndex += batchSize) {