diff --git a/.github/workflows/python_packages.yml b/.github/workflows/python_packages.yml index 7bdbb20e..ade22051 100644 --- a/.github/workflows/python_packages.yml +++ b/.github/workflows/python_packages.yml @@ -56,8 +56,8 @@ jobs: name: dist-musllinux_x86_64 build_windows_wheels: - name: Build wheels on windows-latest - runs-on: windows-2022 + name: Build wheels on Windows + runs-on: windows-2025 env: CMAKE_GENERATOR: "Visual Studio 17 2022" SQLite3_ROOT: "C:/vcpkg/installed/x64-windows" @@ -89,8 +89,8 @@ jobs: name: dist-windows build_windows_32_wheels: - name: Build 32bit wheels on windows-latest - runs-on: windows-2022 + name: Build 32bit wheels on Windows + runs-on: windows-2025 env: CMAKE_GENERATOR: "Visual Studio 17 2022" CMAKE_GENERATOR_PLATFORM: "Win32" diff --git a/.github/workflows/win_cli_build.yml b/.github/workflows/win_cli_build.yml new file mode 100644 index 00000000..d9946f70 --- /dev/null +++ b/.github/workflows/win_cli_build.yml @@ -0,0 +1,31 @@ +name: Windows geodiff.exe build +on: [push, pull_request] + +jobs: + win_cli_build: + runs-on: windows-2025 + steps: + - name: Checkout Geodiff + uses: actions/checkout@v3 + + - name: Build Geodiff + shell: pwsh + run: | + # Github runners have two installations of vcpkg, one from Visual + # Studio and one extra. Use the second one explicitly to avoid mixups. + $env:VCPKG_ROOT = "C:\vcpkg" + & $env:VCPKG_ROOT/vcpkg install --triplet x64-windows-static sqlite3 + & $env:VCPKG_ROOT/vcpkg install --triplet x64-windows-static libpq[openssl] + cd $env:GITHUB_WORKSPACE/geodiff + mkdir build + cd build + cmake .. -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DWITH_POSTGRESQL=TRUE -DVCPKG_TARGET_TRIPLET=x64-windows-static + cmake --build . --config Release + echo "geodiff_exe=$(pwd)/Release/geodiff.exe" >> $env:GITHUB_ENV + + - name: Upload geodiff.exe artifact + uses: actions/upload-artifact@v6 + with: + name: geodiff.exe + path: ${{ env.geodiff_exe }} + if-no-files-found: error diff --git a/.github/workflows/win_tests.yml b/.github/workflows/win_tests.yml index ea0f8750..f7587a64 100644 --- a/.github/workflows/win_tests.yml +++ b/.github/workflows/win_tests.yml @@ -4,11 +4,11 @@ on: [push, pull_request] concurrency: group: ci-${{github.ref}}-win-tests cancel-in-progress: true - + jobs: build_win_test: if: github.repository == 'MerginMaps/geodiff' - runs-on: windows-latest + runs-on: windows-2025 steps: - name: Checkout Geodiff uses: actions/checkout@v3 @@ -18,12 +18,12 @@ jobs: C:/vcpkg/vcpkg install sqlite3[rtree,fts3,json1] --triplet x64-windows C:/vcpkg/vcpkg integrate install dir "C:/vcpkg/installed/x64-windows/bin" - + - name: set compiler environment shell: cmd run: | CALL "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 - + - name: build geodiff shell: pwsh run: | diff --git a/geodiff/CMakeLists.txt b/geodiff/CMakeLists.txt index 3bbd418b..f59f081d 100644 --- a/geodiff/CMakeLists.txt +++ b/geodiff/CMakeLists.txt @@ -118,8 +118,8 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers ${CMAKE_CURRENT_BINARY_DIR} - ${SQLite3_INCLUDE_DIRS} ) +LINK_LIBRARIES(SQLite::SQLite3) # create geodiff_config.h CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake_templates/geodiff_config.hpp.in ${CMAKE_BINARY_DIR}/geodiff_config.hpp) @@ -187,7 +187,7 @@ IF ( BUILD_STATIC ) TARGET_COMPILE_DEFINITIONS(${GEODIFF_NAME}_a PUBLIC -DGEODIFF_STATIC) TARGET_INCLUDE_DIRECTORIES(${GEODIFF_NAME}_a PRIVATE ${libgpkg_dir}/gpkg) IF (POSTGRES_FOUND) - TARGET_INCLUDE_DIRECTORIES(${GEODIFF_NAME}_a PRIVATE ${POSTGRES_INCLUDE_DIR}) + TARGET_LINK_LIBRARIES(${GEODIFF_NAME}_a PRIVATE Postgres::Postgres) ENDIF () # win32 libs @@ -207,12 +207,10 @@ IF ( BUILD_SHARED ) TARGET_LINK_LIBRARIES(${GEODIFF_NAME} PUBLIC dl pthread) ENDIF (NOT WIN32 AND NOT ANDROID AND NOT IOS) - TARGET_LINK_LIBRARIES(${GEODIFF_NAME} PUBLIC ${SQLite3_LIBRARIES}) TARGET_INCLUDE_DIRECTORIES(${GEODIFF_NAME} PRIVATE ${libgpkg_dir}/gpkg) IF (POSTGRES_FOUND) - TARGET_INCLUDE_DIRECTORIES(${GEODIFF_NAME} PRIVATE ${POSTGRES_INCLUDE_DIR}) - TARGET_LINK_LIBRARIES(${GEODIFF_NAME} PUBLIC ${POSTGRES_LIBRARY}) + TARGET_LINK_LIBRARIES(${GEODIFF_NAME} PUBLIC Postgres::Postgres) ENDIF () # win32 libs @@ -228,9 +226,8 @@ IF (BUILD_TOOLS) ADD_EXECUTABLE(geodiff-cli ${geodiff_cli_src}) TARGET_LINK_LIBRARIES(geodiff-cli PUBLIC ${GEODIFF_NAME}_a ) SET_TARGET_PROPERTIES(geodiff-cli PROPERTIES OUTPUT_NAME geodiff) - TARGET_LINK_LIBRARIES(geodiff-cli PUBLIC ${SQLite3_LIBRARIES} ) IF (POSTGRES_FOUND) - TARGET_LINK_LIBRARIES(geodiff-cli PUBLIC ${POSTGRES_LIBRARY}) + TARGET_LINK_LIBRARIES(geodiff-cli PUBLIC Postgres::Postgres) ENDIF () ENDIF (BUILD_TOOLS) diff --git a/geodiff/cmake/FindPostgres.cmake b/geodiff/cmake/FindPostgres.cmake index c1b84db5..55579550 100644 --- a/geodiff/cmake/FindPostgres.cmake +++ b/geodiff/cmake/FindPostgres.cmake @@ -9,126 +9,141 @@ # pg_config is searched for in POSTGRES_CONFIG dir, # default /usr/bin # -# If it's found it sets POSTGRES_FOUND to TRUE +# If it's found it sets POSTGRES_FOUND to TRUE, +# a library named Postgres::Postgres is created # and following variables are set: # POSTGRES_INCLUDE_DIR # POSTGRES_LIBRARY -IF(ANDROID) - SET(POSTGRES_INCLUDE_DIR ${POSTGRES_INCLUDE_DIR} CACHE STRING INTERNAL) - SET(POSTGRES_LIBRARY ${PG_TMP}/libpq.so CACHE STRING INTERNAL) -ENDIF(ANDROID) - -IF(WIN32 AND NOT ANDROID) - IF (NOT POSTGRES_INCLUDE_DIR) - FIND_PATH(POSTGRES_INCLUDE_DIR libpq-fe.h - /usr/local/include - /usr/include - c:/msys/local/include - "$ENV{LIB_DIR}/include/postgresql" - "$ENV{LIB_DIR}/include" - ) - ENDIF (NOT POSTGRES_INCLUDE_DIR) - - IF (NOT POSTGRES_LIBRARY) - FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq libpq libpqdll PATHS - /usr/local/lib - /usr/lib - c:/msys/local/lib - "$ENV{LIB_DIR}/lib" - ) - ENDIF (NOT POSTGRES_LIBRARY) - -ELSE(WIN32) - IF(UNIX) - - SET(POSTGRES_CONFIG_PREFER_PATH "$ENV{POSTGRES_HOME}/bin" CACHE STRING "preferred path to PG (pg_config)") - FIND_PROGRAM(POSTGRES_CONFIG pg_config - ${POSTGRES_CONFIG_PREFER_PATH} - /usr/local/pgsql/bin/ - /usr/local/bin/ - /usr/bin/ - ) - # MESSAGE("DBG POSTGRES_CONFIG ${POSTGRES_CONFIG}") - - IF (POSTGRES_CONFIG) - # set INCLUDE_DIR - EXEC_PROGRAM(${POSTGRES_CONFIG} - ARGS --includedir - OUTPUT_VARIABLE PG_TMP) - SET(POSTGRES_INCLUDE_DIR ${PG_TMP} CACHE STRING INTERNAL) - - # set LIBRARY_DIR - EXEC_PROGRAM(${POSTGRES_CONFIG} - ARGS --libdir - OUTPUT_VARIABLE PG_TMP) - IF (APPLE) - SET(POSTGRES_LIBRARY ${PG_TMP}/libpq.dylib CACHE STRING INTERNAL) - ELSEIF (CYGWIN) - EXEC_PROGRAM(${POSTGRES_CONFIG} - ARGS --libs - OUTPUT_VARIABLE PG_TMP) - - STRING(REGEX MATCHALL "[-][L]([^ ;])+" _LDIRS "${PG_TMP}") - STRING(REGEX MATCHALL "[-][l]([^ ;])+" _LLIBS "${PG_TMP}") - - FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq PATHS /usr/lib /usr/local/lib) - - SET(_DIRS) - FOREACH(_DIR ${_LDIRS}) - STRING(REPLACE "-L" "" _DIR ${_DIR}) - SET(_DIRS ${_DIRS} ${_DIR}) - ENDFOREACH(_DIR ${_LDIRS}) - - SET(_LIBS) - FOREACH(_LIB ${_LLIBS}) - STRING(REPLACE "-l" "" _LIB ${_LIB}) - SET(_LIBS ${_LIBS} ${_LIB}) - ENDFOREACH(_LIB ${_LDIRS}) - - FOREACH(_LIBNAME ${_LIBS}) - UNSET(PG_LIB CACHE) - FIND_LIBRARY(PG_LIB NAMES ${_LIBNAME} PATHS ${_DIRS} /usr/lib /usr/local/lib) - IF(NOT PG_LIB) - MESSAGE(FATAL "PostgreSQL dependency library ${_LIBNAME} not found") - ENDIF(NOT PG_LIB) - SET(POSTGRES_LIBRARY ${POSTGRES_LIBRARY} ${PG_LIB}) - ENDFOREACH(_LIBNAME ${_LIBS}) - - ELSE (CYGWIN) - FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq libpq libpqdll PATHS ${PG_TMP}) - ENDIF (APPLE) - ENDIF(POSTGRES_CONFIG) - - ENDIF(UNIX) -ENDIF(WIN32 AND NOT ANDROID) - - -IF (POSTGRES_INCLUDE_DIR AND POSTGRES_LIBRARY) - SET(POSTGRES_FOUND TRUE) - IF(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") - SET(HAVE_PGCONFIG TRUE) - ELSE(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") - SET(HAVE_PGCONFIG FALSE) - ENDIF(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") -ENDIF (POSTGRES_INCLUDE_DIR AND POSTGRES_LIBRARY) - - -IF (POSTGRES_FOUND) - - IF (NOT POSTGRES_FIND_QUIETLY) +# Try using vcpkg-provided package +FIND_PACKAGE(PostgreSQL) +IF(PostgreSQL_FOUND) + + SET(POSTGRES_FOUND TRUE) + ADD_LIBRARY(Postgres::Postgres ALIAS PostgreSQL::PostgreSQL) + GET_TARGET_PROPERTY(POSTGRES_INCLUDE_DIR + PostgreSQL::PostgreSQL INTERFACE_INCLUDE_DIRECTORIES) + GET_TARGET_PROPERTY(POSTGRES_LIBRARY + PostgreSQL::PostgreSQL LOCATION) + +# or look for libpq ourselves +ELSE(PostgreSQL_FOUND) + + IF(ANDROID) + SET(POSTGRES_INCLUDE_DIR ${POSTGRES_INCLUDE_DIR} CACHE STRING INTERNAL) + SET(POSTGRES_LIBRARY ${PG_TMP}/libpq.so CACHE STRING INTERNAL) + ENDIF(ANDROID) + + IF(WIN32 AND NOT ANDROID) + IF(NOT POSTGRES_INCLUDE_DIR) + FIND_PATH(POSTGRES_INCLUDE_DIR libpq-fe.h + /usr/local/include + /usr/include + c:/msys/local/include + "$ENV{LIB_DIR}/include/postgresql" + "$ENV{LIB_DIR}/include" + ) + ENDIF(NOT POSTGRES_INCLUDE_DIR) + + IF(NOT POSTGRES_LIBRARY) + FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq libpq libpqdll PATHS + /usr/local/lib + /usr/lib + c:/msys/local/lib + "$ENV{LIB_DIR}/lib" + ) + ENDIF(NOT POSTGRES_LIBRARY) + + ELSE(WIN32) + IF(UNIX) + + SET(POSTGRES_CONFIG_PREFER_PATH "$ENV{POSTGRES_HOME}/bin" CACHE STRING "preferred path to PG (pg_config)") + FIND_PROGRAM(POSTGRES_CONFIG pg_config + ${POSTGRES_CONFIG_PREFER_PATH} + /usr/local/pgsql/bin/ + /usr/local/bin/ + /usr/bin/ + ) + # MESSAGE("DBG POSTGRES_CONFIG ${POSTGRES_CONFIG}") + + IF(POSTGRES_CONFIG) + # set INCLUDE_DIR + EXECUTE_PROCESS(COMMAND ${POSTGRES_CONFIG} --includedir + OUTPUT_VARIABLE PG_TMP + OUTPUT_STRIP_TRAILING_WHITESPACE) + SET(POSTGRES_INCLUDE_DIR ${PG_TMP} CACHE STRING INTERNAL) + + # set LIBRARY_DIR + EXECUTE_PROCESS(COMMAND ${POSTGRES_CONFIG} --libdir + OUTPUT_VARIABLE PG_TMP + OUTPUT_STRIP_TRAILING_WHITESPACE) + IF(APPLE) + SET(POSTGRES_LIBRARY ${PG_TMP}/libpq.dylib CACHE STRING INTERNAL) + ELSEIF(CYGWIN) + EXECUTE_PROCESS(COMMAND ${POSTGRES_CONFIG} --libs + OUTPUT_VARIABLE PG_TMP + OUTPUT_STRIP_TRAILING_WHITESPACE) + + STRING(REGEX MATCHALL "[-][L]([^ ;])+" _LDIRS "${PG_TMP}") + STRING(REGEX MATCHALL "[-][l]([^ ;])+" _LLIBS "${PG_TMP}") + + FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq PATHS /usr/lib /usr/local/lib) + + SET(_DIRS) + FOREACH(_DIR ${_LDIRS}) + STRING(REPLACE "-L" "" _DIR ${_DIR}) + SET(_DIRS ${_DIRS} ${_DIR}) + ENDFOREACH(_DIR ${_LDIRS}) + + SET(_LIBS) + FOREACH(_LIB ${_LLIBS}) + STRING(REPLACE "-l" "" _LIB ${_LIB}) + SET(_LIBS ${_LIBS} ${_LIB}) + ENDFOREACH(_LIB ${_LDIRS}) + + FOREACH(_LIBNAME ${_LIBS}) + UNSET(PG_LIB CACHE) + FIND_LIBRARY(PG_LIB NAMES ${_LIBNAME} PATHS ${_DIRS} /usr/lib /usr/local/lib) + IF(NOT PG_LIB) + MESSAGE(FATAL "PostgreSQL dependency library ${_LIBNAME} not found") + ENDIF(NOT PG_LIB) + SET(POSTGRES_LIBRARY ${POSTGRES_LIBRARY} ${PG_LIB}) + ENDFOREACH(_LIBNAME ${_LIBS}) + + ELSE(CYGWIN) + FIND_LIBRARY(POSTGRES_LIBRARY NAMES pq libpq libpqdll PATHS ${PG_TMP}) + ENDIF(APPLE) + ENDIF(POSTGRES_CONFIG) + + ENDIF(UNIX) + ENDIF(WIN32 AND NOT ANDROID) + + + IF(POSTGRES_INCLUDE_DIR AND POSTGRES_LIBRARY) + SET(POSTGRES_FOUND TRUE) + IF(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") + SET(HAVE_PGCONFIG TRUE) + ELSE(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") + SET(HAVE_PGCONFIG FALSE) + ENDIF(EXISTS "${POSTGRES_INCLUDE_DIR}/pg_config.h") + ENDIF(POSTGRES_INCLUDE_DIR AND POSTGRES_LIBRARY) + + + IF(POSTGRES_FOUND) + IF(NOT POSTGRES_FIND_QUIETLY) MESSAGE(STATUS "Found PostgreSQL: ${POSTGRES_LIBRARY}") - ENDIF (NOT POSTGRES_FIND_QUIETLY) - -ELSE (POSTGRES_FOUND) - - #SET (POSTGRES_INCLUDE_DIR "") - #SET (POSTGRES_LIBRARY "") - - IF (POSTGRES_FIND_REQUIRED) + ENDIF(NOT POSTGRES_FIND_QUIETLY) + + ADD_LIBRARY(Postgres::Postgres UNKNOWN IMPORTED) + SET_TARGET_PROPERTIES(Postgres::Postgres PROPERTIES + IMPORTED_LOCATION "${POSTGRES_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${POSTGRES_INCLUDE_DIR}") + ELSE(POSTGRES_FOUND) + IF(POSTGRES_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find PostgreSQL") - ELSE (POSTGRES_FIND_REQUIRED) + ELSE(POSTGRES_FIND_REQUIRED) MESSAGE(STATUS "Could not find PostgreSQL") - ENDIF (POSTGRES_FIND_REQUIRED) + ENDIF(POSTGRES_FIND_REQUIRED) + ENDIF(POSTGRES_FOUND) -ENDIF (POSTGRES_FOUND) +ENDIF(PostgreSQL_FOUND) diff --git a/geodiff/src/drivers/postgresdriver.cpp b/geodiff/src/drivers/postgresdriver.cpp index 775aed0d..38deef5a 100644 --- a/geodiff/src/drivers/postgresdriver.cpp +++ b/geodiff/src/drivers/postgresdriver.cpp @@ -488,7 +488,7 @@ static bool isColumnGeometry( const TableColumnInfo &col ) return col.isGeometry; } -static Value resultToValue( const PostgresResult &res, int r, size_t i, const TableColumnInfo &col ) +static Value resultToValue( const PostgresResult &res, int r, int i, const TableColumnInfo &col ) { Value v; if ( res.isNull( r, i ) ) @@ -609,8 +609,8 @@ static void handleInserted( const std::string &schemaNameBase, const std::string ChangesetEntry e; e.op = reverse ? ChangesetEntry::OpDelete : ChangesetEntry::OpInsert; - size_t numColumns = tbl.columns.size(); - for ( size_t i = 0; i < numColumns; ++i ) + int numColumns = static_cast( tbl.columns.size() ); + for ( int i = 0; i < numColumns; ++i ) { Value v( resultToValue( res, r, i, tbl.columns[i] ) ); if ( reverse ) @@ -653,8 +653,8 @@ static void handleUpdated( const std::string &schemaNameBase, const std::string ChangesetEntry e; e.op = ChangesetEntry::OpUpdate; - size_t numColumns = tbl.columns.size(); - for ( size_t i = 0; i < numColumns; ++i ) + int numColumns = static_cast( tbl.columns.size() ); + for ( int i = 0; i < numColumns; ++i ) { Value v1( resultToValue( res, r, i + numColumns, tbl.columns[i] ) ); Value v2( resultToValue( res, r, i, tbl.columns[i] ) ); @@ -975,7 +975,7 @@ std::string PostgresDriver::getSequenceObjectName( const TableSchema &tbl, int & { std::string colName; autoIncrementPkeyIndex = -1; - for ( size_t i = 0; i < tbl.columns.size(); ++i ) + for ( int i = 0; i < static_cast( tbl.columns.size() ); ++i ) { if ( tbl.columns[i].isPrimaryKey && tbl.columns[i].isAutoIncrement ) { @@ -1080,8 +1080,8 @@ void PostgresDriver::dumpData( ChangesetWriter &writer, bool useModified ) ChangesetEntry e; e.op = ChangesetEntry::OpInsert; - size_t numColumns = tbl.columns.size(); - for ( size_t i = 0; i < numColumns; ++i ) + int numColumns = static_cast( tbl.columns.size() ); + for ( int i = 0; i < numColumns; ++i ) { e.newValues.push_back( Value( resultToValue( res, r, i, tbl.columns[i] ) ) ); } diff --git a/geodiff/src/drivers/postgresutils.cpp b/geodiff/src/drivers/postgresutils.cpp index 5b4f8d23..c1a8a180 100644 --- a/geodiff/src/drivers/postgresutils.cpp +++ b/geodiff/src/drivers/postgresutils.cpp @@ -14,16 +14,16 @@ GeoDiffPostgresException::GeoDiffPostgresException( PostgresResult res, const st : GeoDiffException( "postgres cmd error(" + res.sqlState() + "): " + res.statusErrorMessage() + ( sql.size() ? "\n\nSQL:\n" + sql : "" ) ), - mSql( sql ), mRes( std::move( res ) ) {} + mSql( sql ), mRes( new PostgresResult( std::move( res ) ) ) { } const PostgresResult &GeoDiffPostgresException::result() const { - return mRes; + return *mRes; } int GeoDiffPostgresException::errorCode() const { - if ( mRes.isIntegrityError() ) + if ( result().isIntegrityError() ) return GEODIFF_CONFLICTS; else return GEODIFF_ERROR; diff --git a/geodiff/src/drivers/postgresutils.h b/geodiff/src/drivers/postgresutils.h index 1df60b70..2d6d2b30 100644 --- a/geodiff/src/drivers/postgresutils.h +++ b/geodiff/src/drivers/postgresutils.h @@ -99,7 +99,9 @@ class GeoDiffPostgresException: public GeoDiffException int errorCode() const override; private: std::string mSql; - PostgresResult mRes; + // MSVC doesn't allow non-copyable exceptions, so we wrap non-copyable + // PostgresResult in a refcounting smart pointer. + std::shared_ptr mRes; }; PostgresResult execSql( PGconn *c, const std::string &sql );