Repository navigation
CMake Introduce CMake as the Primary Build System for MapWinGIS6 #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,3 +70,4 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) | |
| mwg_add_runtime_data_target() | ||
|
|
||
| add_subdirectory(src/MapWinGIS.Core) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Suggestion | Confidence: High Issue: Nothing in CI exercises the new CMake build. |
||
| add_subdirectory(src/MapWinGIS.ActiveX) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,6 +83,17 @@ $explainedLinkDifferences = [ordered]@{ | |
| '^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' | ||
| '^input:.*\.res$' = 'Compiled resource file name (<name>.rc.res in CMake)' | ||
| '^lib:(<builddir>/)?lib[\\/]mapwingis\.core\.lib$' = 'Core import library from target_link_libraries (MSBuild: project reference)' | ||
| } | ||
|
|
||
| # Compile differences that are deliberate (docs/CMAKE-MIGRATION.md). | ||
| $explainedCompileDifferences = [ordered]@{ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Minor | Confidence: Medium Issue: |
||
| '^/I<intdir>$' = 'MIDL output moved from the intermediate directory to <build>/.../midl (D3)' | ||
| '^/I<builddir>/.*/midl$' = 'MIDL output directory (D3)' | ||
| '^/I<vcpkg_installed>/[^/]+/include$' = 'vcpkg auto-include; targets without a vcpkg dependency do not get it, the others get it from imported targets' | ||
| '^/I<vcpkg_installed>/[^/]+/include/geos$' = 'Interface include directory of GEOS::geos_c' | ||
| '^/DGDAL_DEBUG$' = 'Interface definition of the debug GDAL::GDAL' | ||
| } | ||
|
|
||
| # MSBuild project names that differ from the CMake target names. | ||
|
|
@@ -290,7 +301,7 @@ function Read-MSBuildCommands([string] $logPath, [string] $binDir) { | |
| $set = ConvertTo-OptionSet $arguments $baseDir $placeholders @('.c', '.cpp', '.cxx', '.cc') | ||
| foreach ($source in $set.Sources) { | ||
| # Keyed by target: the tests compile some ActiveX sources a second time. | ||
| $compiles["$target $source"] = [pscustomobject]@{ | ||
| $compiles[(Get-SourceKey $target $source)] = [pscustomobject]@{ | ||
| Target = $target | ||
| Source = $source | ||
| Options = Merge-VcpkgPlatform $set.Options | ||
|
|
@@ -327,6 +338,8 @@ function Read-CMakeCommands([string] $buildDir, [string] $logPath, [string] $bin | |
| } | ||
|
|
||
| foreach ($entry in (Get-Content -Raw -LiteralPath $database | ConvertFrom-Json)) { | ||
| # Resource compiles are in the database too; the MSBuild side has only cl.exe. | ||
| if ($entry.file -match '\.rc$') { continue } | ||
| $arguments = if ($entry.arguments) { @($entry.arguments | Select-Object -Skip 1) } | ||
| else { @(Split-CommandLine $entry.command | Select-Object -Skip 1) } | ||
| $fo = $arguments | Where-Object { $_ -match '^[/-]Fo' } | Select-Object -First 1 | ||
|
|
@@ -335,7 +348,7 @@ function Read-CMakeCommands([string] $buildDir, [string] $logPath, [string] $bin | |
| $set = ConvertTo-OptionSet $arguments $entry.directory $placeholders @('.c', '.cpp', '.cxx', '.cc') | ||
| $source = Get-NormalizedPath $entry.file $entry.directory $placeholders | ||
| $target = if ($intDir -match '\\CMakeFiles\\(?<t>[^\\]+)\.dir') { $Matches['t'] } else { '' } | ||
| $compiles["$target $source"] = [pscustomobject]@{ | ||
| $compiles[(Get-SourceKey $target $source)] = [pscustomobject]@{ | ||
| Target = $target | ||
| Source = $source | ||
| Options = Merge-VcpkgPlatform $set.Options | ||
|
|
@@ -407,6 +420,31 @@ function Compare-OptionSets($reference, $actual) { | |
| return [pscustomobject]@{ Lost = $lost; Added = $added } | ||
| } | ||
|
|
||
| # Moves the differences that match a pattern into 'Explained', with the reason. | ||
| function Split-ExplainedDifferences($diff, $patterns) { | ||
| $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 $patterns.Keys) { | ||
| if ($option -match $pattern) { $reason = $patterns[$pattern]; break } | ||
| } | ||
| if ($reason) { $explained["$($pair.Kind) $option"] = $reason } | ||
| elseif ($pair.Kind -eq 'lost') { $lost += $option } | ||
| else { $added += $option } | ||
| } | ||
| } | ||
| return [pscustomobject]@{ Lost = $lost; Added = $added; Explained = $explained } | ||
| } | ||
|
|
||
| # MIDL output lives in different directories in the two builds (D3); key the | ||
| # generated sources by file name. | ||
| function Get-SourceKey([string] $target, [string] $source) { | ||
| if ($source -match '^<(intdir|builddir)>/(?:.*/)?(?<file>[^/]+_i\.c)$') { $source = "<generated>/$($Matches['file'])" } | ||
| return "$target $source" | ||
| } | ||
|
|
||
| # --- MSBuild baseline ------------------------------------------------------ | ||
|
|
||
| if (-not $MSBuildBinDirectory) { | ||
|
|
@@ -462,8 +500,9 @@ if ($CMakeBuildDir) { | |
| } | ||
| $diff = Compare-OptionSets $reference.Options $actual.Options | ||
| if ($diff.Lost.Count -or $diff.Added.Count) { | ||
| $compileDiff[$key] = $diff | ||
| $lostTotal += $diff.Lost.Count | ||
| $split = Split-ExplainedDifferences $diff $explainedCompileDifferences | ||
| $compileDiff[$key] = $split | ||
| $lostTotal += $split.Lost.Count | ||
| } | ||
| } | ||
| foreach ($key in ($cmakeCommands.Compiles.Keys | Where-Object { -not $msbuildCommands.Compiles.ContainsKey($_) })) { | ||
|
|
@@ -482,22 +521,10 @@ if ($CMakeBuildDir) { | |
| 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] = [pscustomobject]@{ Lost = $lost; Added = $added; Explained = $explained } | ||
| $lostTotal += $lost.Count | ||
| $split = Split-ExplainedDifferences $diff $explainedLinkDifferences | ||
| $linkDiff[$binary] = $split | ||
| $lostTotal += $split.Lost.Count | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # SPDX-License-Identifier: MPL-2.0 | ||
| # | ||
| # mwg_add_midl_target(<target> IDL <file.idl> [OUTPUT_DIR <dir>] [DEPENDS <file>...]) | ||
| # | ||
| # Runs midl.exe through one explicit custom command for every generator (only | ||
| # the Visual Studio generators understand .idl sources), see | ||
| # docs/CMAKE-MIGRATION.md (D3). Creates: | ||
| # | ||
| # <target> custom target that owns the MIDL invocation | ||
| # <target>.Generated INTERFACE library: the MIDL output include directory, | ||
| # for the OCX and the tests | ||
| # | ||
| # and sets, in the caller's scope: | ||
| # <target>_HEADER <name>_i.h | ||
| # <target>_IID <name>_i.c (C, compile with the consumer) | ||
| # <target>_TLB <name>.tlb | ||
| # <target>_DIR output directory | ||
| # | ||
| # The options match the MSBuild Midl task: /W1 /char signed /env x64|win32 | ||
| # /target "NT60". This IDL declares no non-automation interfaces, so MIDL | ||
| # writes no proxy or dlldata file; they are redirected into the output | ||
| # directory anyway and are not declared as outputs. | ||
|
|
||
| function(_mwg_find_midl out_var) | ||
| # The MSBuild Midl task uses the SDK's x86 midl.exe; any host build works. | ||
| set(hints "") | ||
| if(CMAKE_RC_COMPILER) | ||
| get_filename_component(rc_dir "${CMAKE_RC_COMPILER}" DIRECTORY) | ||
| get_filename_component(sdk_bin "${rc_dir}" DIRECTORY) | ||
| list(APPEND hints "${rc_dir}" "${sdk_bin}/x64" "${sdk_bin}/x86") | ||
| endif() | ||
| find_program(MWG_MIDL_EXECUTABLE midl HINTS ${hints} DOC "MIDL compiler from the Windows SDK") | ||
| if(NOT MWG_MIDL_EXECUTABLE) | ||
| message(FATAL_ERROR | ||
| "midl.exe was not found. It ships with the Windows SDK ${MWG_WINDOWS_SDK}; " | ||
| "configure from a Visual Studio toolchain (CLion) or a VS 2026 Developer PowerShell.") | ||
| endif() | ||
| set(${out_var} "${MWG_MIDL_EXECUTABLE}" PARENT_SCOPE) | ||
| endfunction() | ||
|
|
||
| function(mwg_add_midl_target target) | ||
| cmake_parse_arguments(PARSE_ARGV 1 arg "" "IDL;OUTPUT_DIR" "DEPENDS") | ||
| if(NOT arg_IDL) | ||
| message(FATAL_ERROR "mwg_add_midl_target: IDL is required") | ||
| endif() | ||
| if(NOT arg_OUTPUT_DIR) | ||
| set(arg_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/midl") | ||
| endif() | ||
|
|
||
| _mwg_find_midl(midl) | ||
|
|
||
| # MIDL preprocesses the IDL with cl.exe, which it finds on PATH only. The | ||
| # Ninja generator inherits the vcvars PATH; the Visual Studio generators | ||
| # run custom commands in an MSBuild environment that has it. A plain shell | ||
| # with a cl.exe from CMAKE_C_COMPILER is not enough. | ||
| if(NOT CMAKE_GENERATOR MATCHES "^Visual Studio") | ||
| find_program(_mwg_cl_on_path cl NO_CACHE NO_DEFAULT_PATH PATHS ENV PATH) | ||
| if(NOT _mwg_cl_on_path) | ||
| message(FATAL_ERROR | ||
| "cl.exe is not on PATH, but midl.exe needs it to preprocess ${arg_IDL}.\n" | ||
| "Use a Visual Studio toolchain in CLion, or configure and build from a " | ||
| "VS 2026 Developer PowerShell (vcvarsall.bat).") | ||
| endif() | ||
| endif() | ||
|
|
||
| cmake_path(ABSOLUTE_PATH arg_IDL BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE idl) | ||
| # LAST_ONLY: MapWinGIS.ActiveX.idl -> MapWinGIS.ActiveX | ||
| cmake_path(GET idl STEM LAST_ONLY name) | ||
| cmake_path(GET idl PARENT_PATH idl_dir) | ||
|
|
||
| if(CMAKE_SIZEOF_VOID_P EQUAL 8) | ||
| set(env x64) | ||
| else() | ||
| set(env win32) | ||
| endif() | ||
|
|
||
| set(header "${arg_OUTPUT_DIR}/${name}_i.h") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Minor | Confidence: Medium Issue: The MSBuild |
||
| set(iid "${arg_OUTPUT_DIR}/${name}_i.c") | ||
| set(tlb "${arg_OUTPUT_DIR}/${name}.tlb") | ||
|
|
||
| add_custom_command( | ||
| OUTPUT "${header}" "${iid}" "${tlb}" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Minor | Confidence: Medium Issue: |
||
| COMMAND "${CMAKE_COMMAND}" -E make_directory "${arg_OUTPUT_DIR}" | ||
| COMMAND "${midl}" /W1 /nologo /char signed /env ${env} /target NT60 | ||
| /I "${idl_dir}" | ||
| /out "${arg_OUTPUT_DIR}" | ||
| /h "${name}_i.h" | ||
| /iid "${name}_i.c" | ||
| /proxy "${name}_p.c" | ||
| /dlldata dlldata.c | ||
| /tlb "${name}.tlb" | ||
| "${idl}" | ||
| MAIN_DEPENDENCY "${idl}" | ||
| DEPENDS ${arg_DEPENDS} | ||
| WORKING_DIRECTORY "${idl_dir}" | ||
| COMMENT "MIDL ${name}.idl" | ||
| VERBATIM | ||
| ) | ||
|
|
||
| add_custom_target(${target} DEPENDS "${header}" "${iid}" "${tlb}" SOURCES "${idl}") | ||
| set_target_properties(${target} PROPERTIES FOLDER "src") | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Suggestion | Confidence: Low Issue: The build-directory path |
||
| add_library(${target}.Generated INTERFACE) | ||
| target_include_directories(${target}.Generated INTERFACE "${arg_OUTPUT_DIR}") | ||
| add_dependencies(${target}.Generated ${target}) | ||
|
|
||
| set(${target}_HEADER "${header}" PARENT_SCOPE) | ||
| set(${target}_IID "${iid}" PARENT_SCOPE) | ||
| set(${target}_TLB "${tlb}" PARENT_SCOPE) | ||
| set(${target}_DIR "${arg_OUTPUT_DIR}" PARENT_SCOPE) | ||
| endfunction() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -198,8 +198,11 @@ MSBuild settings and the decisions the CMake build follows are in | |
|
|
||
| ### Building with CMake | ||
|
|
||
| The CMake build currently covers `MapWinGIS.Core.dll`; the ActiveX control, | ||
| tests and samples follow. It needs CMake 3.28 or later and Ninja; both ship | ||
| The CMake build currently covers `MapWinGIS.Core.dll` and `MapWinGIS.ocx`; the | ||
| tests and samples follow. The OCX needs the **C++ ATL for latest v145 build | ||
| tools** component for each architecture you build, and `midl.exe` needs `cl.exe` | ||
| on `PATH`, so configure and build from a Visual Studio toolchain (CLion) or a | ||
| Developer PowerShell. CMake 3.28 or later and Ninja are required; both ship | ||
| with Visual Studio 2026 and CLion. Run the bootstrap script first, then | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Minor | Confidence: Low Issue: This sentence still says "CMake 3.28 or later and Ninja are required", but this PR's own verification (and |
||
| configure from a VS 2026 Developer PowerShell (or any shell after | ||
| `vcvarsall.bat x64`): | ||
|
|
@@ -218,7 +221,11 @@ cmake --build --preset x64-debug | |
|
|
||
| - Output goes to `<build directory>\bin` (`bin\<Config>` for the Visual Studio | ||
| presets) and import libraries to `lib`, never to the MSBuild `bin\` folder, so | ||
| both builds can be used side by side. | ||
| both builds can be used side by side. MIDL output (`MapWinGIS.ActiveX_i.h`, | ||
| `_i.c`, `.tlb`) goes to `<build directory>\src\MapWinGIS.ActiveX\midl`. | ||
| - To register the CMake-built control for the current user: | ||
| `regsvr32 /n /i:user out\b\x64d\bin\MapWinGIS.ocx` (use | ||
| `%WINDIR%\SysWOW64\regsvr32.exe` for Win32; add `/u` to unregister). | ||
| - The vcpkg root is found in the same order as above. CMake uses its own install | ||
| tree, `vcpkg_installed\cmake-<Platform>`, shared by Debug and Release; the | ||
| binary cache makes it cheap. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # SPDX-License-Identifier: MPL-2.0 | ||
| # | ||
| # MapWinGIS.ocx: thin ActiveX/COM wrapper over MapWinGIS.Core (static ATL, | ||
| # apartment threaded). | ||
|
|
||
| include(MwgMidl) | ||
|
|
||
| mwg_add_midl_target(MapWinGIS.ActiveX.Interface IDL MapWinGIS.ActiveX.idl) | ||
|
|
||
| # Compiled into the OCX and, with MWG_ENABLE_RENDERER_TEST_HOOKS, into the | ||
| # tests (docs/CMAKE-MIGRATION.md, D4). | ||
| set(MWG_ACTIVEX_SHARED_SOURCES | ||
| ComConversion.cpp | ||
| GdalOperationDispatcher.cpp | ||
| GdiVectorLayerRenderer.cpp | ||
| OpenGlVectorLayerRenderer.cpp | ||
| VectorLayerRenderer.cpp | ||
| ViewTransform.cpp | ||
| ) | ||
| list(TRANSFORM MWG_ACTIVEX_SHARED_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" | ||
| OUTPUT_VARIABLE MWG_ACTIVEX_SHARED_SOURCES) | ||
| set(MWG_ACTIVEX_SHARED_SOURCES "${MWG_ACTIVEX_SHARED_SOURCES}" PARENT_SCOPE) | ||
|
|
||
| set(MWG_ACTIVEX_HEADERS | ||
| ActiveXModule.h | ||
| ComConversion.h | ||
| GdalDispatchWindow.h | ||
| GdalEventSource.h | ||
| GdalOperationDispatcher.h | ||
| GdiVectorLayerRenderer.h | ||
| MapWinGISControl.h | ||
| OpenGlVectorLayerRenderer.h | ||
| VectorLayerRenderer.h | ||
| VectorRenderBackend.h | ||
| ViewTransform.h | ||
| resource.h | ||
| ) | ||
|
|
||
| set(MWG_ACTIVEX_SOURCES | ||
| ActiveXModule.cpp | ||
| GdalEventSource.cpp | ||
| MapWinGISControl.cpp | ||
| ) | ||
|
|
||
| set(MWG_ACTIVEX_RESOURCES | ||
| MapWinGIS.ActiveX.rc | ||
| MapWinGIS.ActiveX.def | ||
| MapWinGISControl.rgs | ||
| ) | ||
|
|
||
| # SHARED, not MODULE: keeps the import library and the runtime-DLL handling. | ||
| add_library(MapWinGIS.ActiveX SHARED) | ||
|
|
||
| target_sources(MapWinGIS.ActiveX PRIVATE | ||
| ${MWG_ACTIVEX_HEADERS} | ||
| ${MWG_ACTIVEX_SOURCES} | ||
| ${MWG_ACTIVEX_SHARED_SOURCES} | ||
| ${MWG_ACTIVEX_RESOURCES} | ||
| "${MapWinGIS.ActiveX.Interface_HEADER}" | ||
| "${MapWinGIS.ActiveX.Interface_IID}" | ||
| ) | ||
| source_group("Header Files" FILES ${MWG_ACTIVEX_HEADERS}) | ||
| source_group("Source Files" FILES ${MWG_ACTIVEX_SOURCES} ${MWG_ACTIVEX_SHARED_SOURCES}) | ||
| source_group("Resource Files" FILES ${MWG_ACTIVEX_RESOURCES}) | ||
| source_group("Generated Files" FILES | ||
| "${MapWinGIS.ActiveX.Interface_HEADER}" | ||
| "${MapWinGIS.ActiveX.Interface_IID}") | ||
|
|
||
| # The .rc embeds the generated type library (1 TYPELIB "MapWinGIS.ActiveX.tlb"); | ||
| # rc's dependency scanner does not see it. | ||
| set_source_files_properties(MapWinGIS.ActiveX.rc PROPERTIES | ||
| OBJECT_DEPENDS "${MapWinGIS.ActiveX.Interface_TLB};${CMAKE_CURRENT_SOURCE_DIR}/MapWinGISControl.rgs") | ||
|
|
||
| target_link_libraries(MapWinGIS.ActiveX PRIVATE | ||
| MapWinGIS::Core | ||
| MapWinGIS.ActiveX.Interface.Generated | ||
| # Explicit Windows libraries (audit). ATL is static: atlbase.h links | ||
| # atls.lib through #pragma comment, and OpenGlVectorLayerRenderer.cpp links | ||
| # opengl32.lib the same way. | ||
| ole32 oleaut32 uuid user32 gdi32 advapi32 kernel32 | ||
| ) | ||
|
|
||
| target_compile_definitions(MapWinGIS.ActiveX PRIVATE "$<$<COMPILE_LANGUAGE:C,CXX>:_ATL_APARTMENT_THREADED>") | ||
|
|
||
| # MSBuild ResourceCompile: /l 0x0409 and the MIDL output directory on the include path. | ||
| target_compile_options(MapWinGIS.ActiveX PRIVATE "$<$<COMPILE_LANGUAGE:RC>:/l0x0409>") | ||
|
|
||
| mwg_apply_common_options(MapWinGIS.ActiveX) | ||
|
|
||
| set_target_properties(MapWinGIS.ActiveX PROPERTIES | ||
| OUTPUT_NAME MapWinGIS | ||
| SUFFIX ".ocx" | ||
| # The COM entry points are exported through MapWinGIS.ActiveX.def; no | ||
| # <target>_EXPORTS macro, as in MSBuild. | ||
| DEFINE_SYMBOL "" | ||
| FOLDER "src" | ||
| ) | ||
|
|
||
| add_dependencies(MapWinGIS.ActiveX MapWinGIS.ActiveX.Interface) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Severity: Suggestion | Confidence: Medium
Issue: The ActiveX subdirectory is added unconditionally, and
mwg_add_midl_targethard-FATAL_ERRORs configure whenmidl.exeor acl.exeonPATHis missing. There is no way to configure a Core-only CMake build.Impact: Consumers who only want
MapWinGIS.Core.dll(headless Core CI, documentation or packaging jobs, contributors without the ATL/MIDL components installed) cannot configure the project at all, even though the Core target has no MIDL dependency.Fix: Add an
option(MWG_BUILD_ACTIVEX "Build the ActiveX control (requires the Windows SDK MIDL and ATL)" ON)and gate thisadd_subdirectory(and document the option indocs/BUILDING.md) on it.