Skip to content
Open
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
72 changes: 72 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# SPDX-License-Identifier: MPL-2.0
#
# MapWinGIS6 native build. Windows and MSVC v145 only.
#
# pwsh -File build\scripts\bootstrap-vcpkg.ps1
# cmake --preset x64-debug
# cmake --build --preset x64-debug
#
# See docs/BUILDING.md and docs/CMAKE-MIGRATION.md.

# 3.15: CMP0092 (no default /W3), 3.21: TARGET_RUNTIME_DLLS,
# 3.26: copy_directory_if_different, 3.28: tested minimum.
cmake_minimum_required(VERSION 3.28...4.3)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# --- options needed before project() -----------------------------------------
option(MWG_BUILD_TESTS "Build the GoogleTest suite (adds the 'tests' vcpkg feature)" ON)
option(MWG_BUILD_SAMPLES "Build the samples" ON)
set(MWG_WINDOWS_SDK "10.0.28000.0" CACHE STRING
"Windows SDK version (MSBuild: MwgWindowsSdk). 10.0 means the newest installed SDK")

# --- configurations ----------------------------------------------------------
# Debug and Release only, as in MSBuild. CLion offers RelWithDebInfo and
# MinSizeRel profiles by default; they are rejected instead of being built with
# flags that no other build uses.
if(CMAKE_GENERATOR MATCHES "^Visual Studio|Multi-Config$")
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Supported configurations" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Debug or Release" FORCE)
endif()
if(NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release)$")
message(FATAL_ERROR
"CMAKE_BUILD_TYPE '${CMAKE_BUILD_TYPE}' is not supported; MapWinGIS6 builds Debug and Release only.\n"
"Use one of the presets in CMakePresets.json (CLion: disable the default profiles and enable the preset profiles).")
endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release)
endif()

# --- toolchain ---------------------------------------------------------------
include(MwgVcpkg)

# Visual Studio generators select the Windows SDK from CMAKE_SYSTEM_VERSION;
# "10.0" lets them pick the newest one. Ninja uses the vcvars environment.
if(CMAKE_GENERATOR MATCHES "^Visual Studio" AND NOT DEFINED CMAKE_SYSTEM_VERSION)
set(CMAKE_SYSTEM_VERSION "${MWG_WINDOWS_SDK}" CACHE STRING "Windows SDK selected by the Visual Studio generator")
endif()

set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/MwgFlagOverrides.cmake")

project(MapWinGIS6
VERSION 6.0.0
DESCRIPTION "Open-source mapping engine behind MapWindow"
HOMEPAGE_URL "https://github.com/MapWindow/MapWinGIS6"
LANGUAGES C CXX)

# --- output layout (docs/CMAKE-MIGRATION.md, D1) -----------------------------
# One runtime folder per build tree, separate from MSBuild's bin\<Config>\<Platform>.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")

include(MwgPlatform)
include(MwgCompilerOptions)
include(MwgRuntimeDeploy)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

mwg_add_runtime_data_target()

add_subdirectory(src/MapWinGIS.Core)
124 changes: 124 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"version": 6,
"cmakeMinimumRequired": { "major": 3, "minor": 28, "patch": 0 },
"configurePresets": [
{
"name": "windows-base",
"hidden": true,
"description": "Shared settings. The vcpkg toolchain is resolved by CMakeLists.txt (MWG_VCPKG_ROOT, ../vcpkg, VCPKG_ROOT).",
"condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" },
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"VCPKG_HOST_TRIPLET": "x64-windows-v145",
"VCPKG_MANIFEST_FEATURES": "tests"
}
},
{
"name": "x64",
"hidden": true,
"description": "x64. 'architecture' only informs Visual Studio; in CLion assign a Visual Studio toolchain with architecture amd64.",
"architecture": { "value": "x64", "strategy": "external" },
"cacheVariables": {
"VCPKG_TARGET_TRIPLET": "x64-windows-v145",
"VCPKG_INSTALLED_DIR": "${sourceDir}/vcpkg_installed/cmake-x64"
}
},
{
"name": "x86",
"hidden": true,
"description": "Win32. 'architecture' only informs Visual Studio; in CLion assign a Visual Studio toolchain with architecture x86 or amd64_x86.",
"architecture": { "value": "x86", "strategy": "external" },
"cacheVariables": {
"VCPKG_TARGET_TRIPLET": "x86-windows-v145",
"VCPKG_INSTALLED_DIR": "${sourceDir}/vcpkg_installed/cmake-Win32"
}
},
{
"name": "debug",
"hidden": true,
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
},
{
"name": "release",
"hidden": true,
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
},
{
"name": "ninja",
"hidden": true,
"description": "Single-config Ninja. Toolset and Windows SDK come from the vcvars environment (CLion toolchain, VS Developer PowerShell).",
"generator": "Ninja"
},
{
"name": "vs2026",
"hidden": true,
"description": "Multi-config Visual Studio generator; pins toolset v145 and the Windows SDK (MWG_WINDOWS_SDK).",
"generator": "Visual Studio 18 2026",
"toolset": { "value": "v145", "strategy": "set" }
},
{
"name": "x64-debug",
"displayName": "x64 Debug (Ninja)",
"inherits": [ "windows-base", "ninja", "x64", "debug" ],
"binaryDir": "${sourceDir}/out/b/x64d"
},
{
"name": "x64-release",
"displayName": "x64 Release (Ninja)",
"inherits": [ "windows-base", "ninja", "x64", "release" ],
"binaryDir": "${sourceDir}/out/b/x64r"
},
{
"name": "x86-debug",
"displayName": "Win32 Debug (Ninja)",
"inherits": [ "windows-base", "ninja", "x86", "debug" ],
"binaryDir": "${sourceDir}/out/b/x86d"
},
{
"name": "x86-release",
"displayName": "Win32 Release (Ninja)",
"inherits": [ "windows-base", "ninja", "x86", "release" ],
"binaryDir": "${sourceDir}/out/b/x86r"
},
{
"name": "vs2026-x64",
"displayName": "x64 (Visual Studio 18 2026)",
"inherits": [ "windows-base", "vs2026", "x64" ],
"architecture": { "value": "x64", "strategy": "set" },
"binaryDir": "${sourceDir}/out/b/vs-x64"
},
{
"name": "vs2026-x86",
"displayName": "Win32 (Visual Studio 18 2026)",
"inherits": [ "windows-base", "vs2026", "x86" ],
"architecture": { "value": "Win32", "strategy": "set" },
"binaryDir": "${sourceDir}/out/b/vs-x86"
}
],
"buildPresets": [
{ "name": "x64-debug", "configurePreset": "x64-debug" },
{ "name": "x64-release", "configurePreset": "x64-release" },
{ "name": "x86-debug", "configurePreset": "x86-debug" },
{ "name": "x86-release", "configurePreset": "x86-release" },
{ "name": "vs2026-x64-debug", "configurePreset": "vs2026-x64", "configuration": "Debug" },
{ "name": "vs2026-x64-release", "configurePreset": "vs2026-x64", "configuration": "Release" },
{ "name": "vs2026-x86-debug", "configurePreset": "vs2026-x86", "configuration": "Debug" },
{ "name": "vs2026-x86-release", "configurePreset": "vs2026-x86", "configuration": "Release" }
],
"testPresets": [
{
"name": "test-base",
"hidden": true,
"output": { "outputOnFailure": true },
"filter": { "exclude": { "label": "interactive" } }
},
{ "name": "x64-debug", "inherits": "test-base", "configurePreset": "x64-debug" },
{ "name": "x64-release", "inherits": "test-base", "configurePreset": "x64-release" },
{ "name": "x86-debug", "inherits": "test-base", "configurePreset": "x86-debug" },
{ "name": "x86-release", "inherits": "test-base", "configurePreset": "x86-release" },
{ "name": "vs2026-x64-debug", "inherits": "test-base", "configurePreset": "vs2026-x64", "configuration": "Debug" },
{ "name": "vs2026-x64-release", "inherits": "test-base", "configurePreset": "vs2026-x64", "configuration": "Release" },
{ "name": "vs2026-x86-debug", "inherits": "test-base", "configurePreset": "vs2026-x86", "configuration": "Debug" },
{ "name": "vs2026-x86-release", "inherits": "test-base", "configurePreset": "vs2026-x86", "configuration": "Release" }
]
}
41 changes: 38 additions & 3 deletions build/scripts/Compare-CompileCommands.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ $ignoredOptions = @(
)
$ignoredOptionPrefixes = @('/Fo', '/Fd', '/Fe', '/Fp', '/ILK:', '/PDB:', '/IMPLIB:', '/OUT:', '/MP')

# Link differences that are deliberate (docs/CMAKE-MIGRATION.md). They are
# reported under 'explained' and do not count as lost options.
$explainedLinkDifferences = [ordered]@{
'^/manifest(:embed|uac:.*)?$' = 'CMake''s vs_link wrapper generates and embeds the manifest with mt.exe; the embedded manifest is identical'
'^/tlbid:1$' = 'Only used when a type library resource is embedded'
'^/libpath:<vcpkg_installed>/' = 'vcpkg auto-link replaced by imported targets with full library paths'
'^lib:<vcpkg_installed>/.*\*\.lib$' = 'vcpkg auto-link replaced by imported targets with full library paths'
'^lib:<vcpkg_installed>/' = 'Library from an imported target (find_package)'
'^lib:odbc(cp)?32\.lib$' = 'MSBuild default library; unused, not in CMake''s default list'
'^/version:0\.0$' = 'CMake default image version; MSBuild leaves it at 0.0 too'
}

# MSBuild project names that differ from the CMake target names.
$targetNames = @{ 'Translate' = 'MapWinGIS.Samples.Translate' }

Expand Down Expand Up @@ -214,6 +226,8 @@ function ConvertTo-OptionSet([string[]] $arguments, [string] $baseDir, [hashtabl
break
}
}
# Linker options are case-insensitive (/DEBUG and /debug are the same).
if ($isLink) { $arg = $arg.ToLowerInvariant() }
$options.Add($arg)
}

Expand Down Expand Up @@ -458,11 +472,32 @@ if ($CMakeBuildDir) {

$linkDiff = [ordered]@{}
foreach ($binary in ($msbuildCommands.Links.Keys | Sort-Object)) {
if (-not $cmakeCommands.Links.ContainsKey($binary)) { continue }
if (-not $cmakeCommands.Links.ContainsKey($binary)) {
# A binary that CMake builds but that was up to date has no link
# line in the log; that is not parity.
$cmakeTarget = [System.IO.Path]::GetFileNameWithoutExtension($binary)
if ($CMakeBuildLog -and ($cmakeTargets -contains $cmakeTarget)) {
Write-Warning "$binary was not linked in $CMakeBuildLog; delete it and rebuild to compare its link options."
}
continue
}
$diff = Compare-OptionSets $msbuildCommands.Links[$binary] $cmakeCommands.Links[$binary]
$explained = [ordered]@{}
$lost = @(); $added = @()
foreach ($pair in @(@{ Items = $diff.Lost; Kind = 'lost' }, @{ Items = $diff.Added; Kind = 'added' })) {
foreach ($option in $pair.Items) {
$reason = $null
foreach ($pattern in $explainedLinkDifferences.Keys) {
if ($option -match $pattern) { $reason = $explainedLinkDifferences[$pattern]; break }
}
if ($reason) { $explained["$($pair.Kind) $option"] = $reason }
elseif ($pair.Kind -eq 'lost') { $lost += $option }
else { $added += $option }
}
}
if ($diff.Lost.Count -or $diff.Added.Count) {
$linkDiff[$binary] = $diff
$lostTotal += $diff.Lost.Count
$linkDiff[$binary] = [pscustomobject]@{ Lost = $lost; Added = $added; Explained = $explained }
$lostTotal += $lost.Count
}
}

Expand Down
86 changes: 86 additions & 0 deletions cmake/MwgCompilerOptions.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# SPDX-License-Identifier: MPL-2.0
#
# mwg_apply_common_options(<target>)
#
# The compiler and linker settings of build/props/MapWinGIS.Cpp.props plus the
# MSBuild defaults they rely on, applied PRIVATE to one target so that nothing
# leaks to consumers of MapWinGIS.Core. The effective MSBuild options are listed
# in docs/CMAKE-MIGRATION.md; keep both in sync.

option(MWG_ENABLE_ASAN "Compile with /fsanitize=address (MSBuild: MwgEnableAsan)" OFF)

function(mwg_apply_common_options target)
get_target_property(type ${target} TYPE)

set_target_properties(${target} PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
# The MIDL-generated _i.c is C.
C_STANDARD 17
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
# PDBs in Debug and Release, as in MSBuild (CMake's default is Debug only).
MSVC_DEBUG_INFORMATION_FORMAT ProgramDatabase
# MSBuild passes the vcpkg include directory as a plain /I, so warnings
# in GDAL headers are reported at /W4. CMake would make imported
# include directories /external:I with /external:W0 and hide them.
NO_SYSTEM_FROM_IMPORTED ON
)

set(c_cxx "$<COMPILE_LANGUAGE:C,CXX>")
set(debug "$<AND:${c_cxx},$<CONFIG:Debug>>")
set(release "$<AND:${c_cxx},$<CONFIG:Release>>")

target_compile_options(${target} PRIVATE
# WarningLevel, DisableSpecificWarnings. 4251 is safe: one toolset and
# one CRT for every binary of the product.
"$<${c_cxx}:/W4;/WX-;/wd4251;/external:W4>"
# AdditionalOptions
"$<${c_cxx}:/utf-8;/Zc:__cplusplus;/Zc:preprocessor;/Zc:throwingNew;/bigobj>"
# ConformanceMode, SDLCheck, ExceptionHandling and MSBuild defaults
"$<${c_cxx}:/permissive-;/sdl;/EHsc;/GS;/Gd;/Gm-;/fp:precise;/Zc:wchar_t;/Zc:forScope;/Zc:inline>"
"$<${debug}:/Od;/JMC>"
"$<${release}:/O2;/Oi;/Gy;/guard:cf>"
)
if(MWG_ENABLE_ASAN)
target_compile_options(${target} PRIVATE "$<${c_cxx}:/fsanitize=address>")
else()
# BasicRuntimeChecks; incompatible with AddressSanitizer.
target_compile_options(${target} PRIVATE "$<${debug}:/RTC1>")
endif()

target_compile_definitions(${target} PRIVATE
# CharacterSet=Unicode, also for the resource compiler.
UNICODE
_UNICODE
"$<${c_cxx}:WIN32_LEAN_AND_MEAN;NOMINMAX;_WIN32_WINNT=0x0A00;WINVER=0x0A00;NTDDI_VERSION=0x0A00000B;_CRT_SECURE_NO_WARNINGS>"
"$<${c_cxx}:MWG_VERSION=\"${PROJECT_VERSION}\">"
"$<${debug}:_DEBUG>"
"$<${release}:NDEBUG>"
)
if(type STREQUAL "SHARED_LIBRARY")
# MSBuild defines _WINDLL for every DLL project.
target_compile_definitions(${target} PRIVATE "$<${c_cxx}:_WINDLL>")
endif()

# CMake's defaults already add /machine, /debug /INCREMENTAL (Debug) and
# /INCREMENTAL:NO (Release).
target_link_options(${target} PRIVATE
/DYNAMICBASE
/NXCOMPAT
"$<$<CONFIG:Release>:/DEBUG;/OPT:REF;/OPT:ICF;/guard:cf>"
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
target_link_options(${target} PRIVATE /HIGHENTROPYVA)
else()
# MSBuild Win32 defaults: keep frame pointers, no code analysis, and
# safe exception handler tables in Release.
target_compile_options(${target} PRIVATE "$<${c_cxx}:/Oy-;/analyze->")
target_link_options(${target} PRIVATE "$<$<CONFIG:Release>:/SAFESEH>")
endif()
if(type STREQUAL "SHARED_LIBRARY")
target_link_options(${target} PRIVATE /SUBSYSTEM:WINDOWS)
endif()
endfunction()
19 changes: 19 additions & 0 deletions cmake/MwgFlagOverrides.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: MPL-2.0
#
# CMAKE_USER_MAKE_RULES_OVERRIDE file: runs inside project(), after CMake's
# MSVC platform module and before the CMAKE_<LANG>_FLAGS* cache entries are
# created.
#
# CMake's MSVC defaults (/DWIN32 /D_WINDOWS /EHsc, /Ob0 /Od /RTC1, /O2 /Ob2
# /DNDEBUG) do not match the MSBuild build, which defines neither WIN32 nor
# _WINDOWS. Every compile option comes from mwg_apply_common_options()
# instead (cmake/MwgCompilerOptions.cmake), so the targets carry exactly the
# flags documented in docs/CMAKE-MIGRATION.md and nothing leaks to consumers.
# Linker defaults (/machine, /debug /INCREMENTAL, /INCREMENTAL:NO) are kept.

foreach(_mwg_lang IN ITEMS C CXX)
set(CMAKE_${_mwg_lang}_FLAGS_INIT "")
set(CMAKE_${_mwg_lang}_FLAGS_DEBUG_INIT "")
set(CMAKE_${_mwg_lang}_FLAGS_RELEASE_INIT "")
endforeach()
unset(_mwg_lang)
Loading