Skip to content

Support Boost 1.88 on Windows #10419

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

Merged
merged 2 commits into from
May 28, 2025
Merged

Support Boost 1.88 on Windows #10419

merged 2 commits into from
May 28, 2025

Conversation

yhabteab
Copy link
Member

@yhabteab yhabteab commented Apr 23, 2025

  • Drop Windows VISTA from the supported platform: Boost 1.88.0 introduced a feature 1 that makes use of the Windows API, but it uses API functions that are only available with PSAPI_VERSION >= 2 and Windows VISTA only supports PSAPI_VERSION == 1. Actually, that new feature can also be disabled by setting the BOOST_STACKTRACE_DISABLE_OFFSET_ADDR_BASE macro, but since it seems to be a useful feature and isn't even disabled by default, we can just drop it that ancient Windows version instead of disabling it.
  • Bump Boost shipped for Windows to v1.88

fixes #10412

Footnotes

  1. https://github.com/boostorg/stacktrace/pull/200

@yhabteab yhabteab added the area/windows Windows agent and plugins label Apr 23, 2025
@cla-bot cla-bot bot added the cla/signed label Apr 23, 2025
@jschmidt-icinga
Copy link
Contributor

Have you tested if this is still required on windows with cmake_policy(SET CMP0167 NEW) before find_package(Boost ...?

Currently when running cmake we're getting the warning that the policy is not set which means that we're using cmake's FindBoost module instead of boost's BoostConfig.cmake. The help page to this policy explicitly mentions better support of new boost versions.

When going through BoostConfig.cmake I can't see anything that explicitly links psapi.lib, but I don't entirely understand the process by which it finds the dependencies of the individual components either.

@yhabteab
Copy link
Member Author

Have you tested if this is still required on windows with cmake_policy(SET CMP0167 NEW) before find_package(Boost ...?

No, I didn't but even then we can't use it here. The CMake docs for it says this:

Upstream Boost 1.70 and above provide a BoostConfig.cmake package configuration file. find_package(Boost CONFIG) finds the upstream package directly, without the find module.

And our minimum supported Boost version is 1.66.

set(BOOST_MIN_VERSION "1.66.0")

Copy link
Member

@Al2Klimov Al2Klimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not to also bump ours to v1.88 while on it?

@julianbrost
Copy link
Contributor

Note: The reason why we're linking statically (psapi.lib) instead of dynamically (psapi.dll) is that we've already set boost to link statically here, so we need to do the same for psapi.

psapi is not a Boost library but a Windows library, so I don't really see why this should be a reason that we have to link statically.

No, I didn't but even then we can't use it here. The CMake docs for it says this:

Upstream Boost 1.70 and above provide a BoostConfig.cmake package configuration file. find_package(Boost CONFIG) finds the upstream package directly, without the find module.

And our minimum supported Boost version is 1.66.

Does that really raise the Boost version implicitly? Sounds a bit odd if CMake wouldn't fall back to their own config for older Boost versions if they ship it anyways for providing the legacy behavior.

@yhabteab
Copy link
Member Author

Does that really raise the Boost version implicitly? Sounds a bit odd if CMake wouldn't fall back to their own config for older Boost versions if they ship it anyways for providing the legacy behavior.

I don't know, but that's what I get when trying to compile Icinga 2 with that new policy.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d71842ce..c342d862b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,7 +172,10 @@ else()
   set(LOGROTATE_CREATE "\n\tcreate 644 ${ICINGA2_USER} ${ICINGA2_GROUP}")
 endif()

+cmake_policy(PUSH)
+cmake_policy(SET CMP0167 NEW)
 find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS coroutine context date_time filesystem iostreams thread system program_options regex REQUIRED)
+cmake_policy(POP)

 # Boost.Coroutine2 (the successor of Boost.Coroutine)
 # (1) doesn't even exist in old Boost versions and
(END)
---
CMake Error at CMakeLists.txt:177 (find_package):
  By not providing "FindBoost.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "Boost", but
  CMake did not find one.

  Could not find a package configuration file provided by "Boost" (requested
  version 1.66.0) with any of the following names:

    BoostConfig.cmake
    boost-config.cmake

  Add the installation prefix of "Boost" to CMAKE_PREFIX_PATH or set
  "Boost_DIR" to a directory containing one of the above files.  If "Boost"
  provides a separate development package or SDK, be sure it has been
  installed.


-- Configuring incomplete, errors occurred!
DEBUG:   72+  >>>> cd "$sourcePath"
DEBUG:   74+ if ( >>>> $lastexitcode -ne 0) {
DEBUG:   75+    >>>> exit $lastexitcode

Do the boost packages we upload to packages.icinga.com include that CMake module?

@julianbrost
Copy link
Contributor

I don't know, but that's what I get when trying to compile Icinga 2 with that new policy.

+cmake_policy(PUSH)
+cmake_policy(SET CMP0167 NEW)
 find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS coroutine context date_time filesystem iostreams thread system program_options regex REQUIRED)
+cmake_policy(POP)

Works on my (Linux) machine, though it still gives that policy warning for the tests:

CMake Warning (dev) at third-party/cmake/BoostTestTargets.cmake:58 (find_package):
  Policy CMP0167 is not set: The FindBoost module is removed.  Run "cmake
  --help-policy CMP0167" for policy details.  Use the cmake_policy command to
  set the policy and suppress this warning.

Call Stack (most recent call first):
  test/CMakeLists.txt:3 (include)
This warning is for project developers.  Use -Wno-dev to suppress it.

It also works without that warning when I just put cmake_policy(SET CMP0167 NEW) directly after our call to cmake_minimum_required.

Do the boost packages we upload to packages.icinga.com include that CMake module?

There is nothing special about them, they just mirror the upstream files1.

Footnotes

  1. So that we use our bandwidth during our CI runs, not theirs.

@yhabteab
Copy link
Member Author

Works on my (Linux) machine, though it still gives that policy warning for the tests:

I know, it works on Machine (MacOS) too :)! But I'm talking about windows here https://github.com/Icinga/icinga2/actions/runs/15250509514/job/42886209439?pr=10419

It also works without that warning when I just put cmake_policy(SET CMP0167 NEW) directly after our call to cmake_minimum_required.

Yeah, since it shouldn't have any other side-effects it should be fine without the PUSH and POP commands as well.

@julianbrost
Copy link
Contributor

After a quick check on the random Boost version installed on my Windows machine, seems to be there:

$ find /c/local/boost_1_79_0/ -name BoostConfig.cmake -o -name boost-config.cmake
/c/local/boost_1_79_0/lib64-msvc-14.2/cmake/Boost-1.79.0/BoostConfig.cmake
/c/local/boost_1_79_0/tools/boost_install/BoostConfig.cmake

Maybe it needs some more/other -D flags to find that file. On my Linux machine, it's just /usr/lib/cmake/Boost-1.88.0/BoostConfig.cmake, so it's discovered out of the box.

@yhabteab
Copy link
Member Author

Maybe it needs some more/other -D flags to find that file. On my Linux machine, it's just /usr/lib/cmake/Boost-1.88.0/BoostConfig.cmake, so it's discovered out of the box.

Adding -DBoost_DIR="$env:BOOST_LIBRARYDIR"\cmake\Boost-1.88.0 variable fixed it!

@yhabteab
Copy link
Member Author

Maybe it needs some more/other -D flags to find that file. On my Linux machine, it's just /usr/lib/cmake/Boost-1.88.0/BoostConfig.cmake, so it's discovered out of the box.

Adding -DBoost_DIR="$env:BOOST_LIBRARYDIR"\cmake\Boost-1.88.0 variable fixed it!

Still doesn't fix the actual issue referenced in the PR description though!

 C:\Users\yhabteab\icinga2\build\lib\remote\remote.dir\Debug\remote_unity.obj
     Creating library C:/Users/yhabteab/icinga2/build/Bin/RelWithDebInfo/Debug/check_nscp_api.lib and object C:/Users/y
  habteab/icinga2/build/Bin/RelWithDebInfo/Debug/check_nscp_api.exp
base_unity.obj : error LNK2019: unresolved external symbol EnumProcessModules referenced in function "unsigned __int64
__cdecl boost::stacktrace::detail::get_own_proc_addr_base(void const *)" (?get_own_proc_addr_base@detail@stacktrace@boo
st@@YA_KPEBX@Z) [C:\Users\yhabteab\icinga2\build\plugins\check_nscp_api.vcxproj]
base_unity.obj : error LNK2019: unresolved external symbol GetModuleInformation referenced in function "unsigned __int6
4 __cdecl boost::stacktrace::detail::get_own_proc_addr_base(void const *)" (?get_own_proc_addr_base@detail@stacktrace@b
oost@@YA_KPEBX@Z) [C:\Users\yhabteab\icinga2\build\plugins\check_nscp_api.vcxproj]
C:\Users\yhabteab\icinga2\build\Bin\RelWithDebInfo\Debug\check_nscp_api.exe : fatal error LNK1120: 2 unresolved externa
ls [C:\Users\yhabteab\icinga2\build\plugins\check_nscp_api.vcxproj]
Done Building Project "C:\Users\yhabteab\icinga2\build\plugins\check_nscp_api.vcxproj" (default targets) -- FAILED.

Done Building Project "C:\Users\yhabteab\icinga2\build\plugins\check_nscp_api.vcxproj.metaproj" (default targets) -- FA
ILED.

@yhabteab
Copy link
Member Author

so I don't really see why this should be a reason that we have to link statically.

Ok, here's another reason, according to the docs, if you want to dynamically link that library you've to also load it (probably using LoadLibraryA somewhere in our code base, which I doubt it would make anything better as opposed to the static linking.

To ensure correct resolution of symbols, add Psapi.lib to the TARGETLIBS macro and compile the program with –DPSAPI_VERSION=1. To use run-time dynamic linking, load Psapi.dll.

@julianbrost
Copy link
Contributor

Still doesn't fix the actual issue referenced in the PR description though!

That's a bit strange, in my intuition, you shouldn't need to care about these details (i.e. linking psapi) yourself or it should be at least mentioned in the Configuration and Build documentation of Boost.Stacktrace. Maybe there's also a difference between header-only and library mode?1 If you have the time for it, you could prepare a minimal example (short CMakeLists.txt and C++ source file) and if the problem also shows there, ask in the Boost.Stacktrace project.

if you want to dynamically link that library you've to also load it (probably using LoadLibraryA somewhere in our code base

Shouldn't the loader take care of this if the binary links against psapi.dll?

Footnotes

  1. It might be possible that the library used in library mode actually links against psapi and works. But I haven't checked anything in that direction, so pure speculation.

@Al2Klimov
Copy link
Member

It might be possible that the library used in library mode actually links against psapi and works.

Isn't that how it works on Linux as well? I mean, if myapp depends on liba which depends in libb, does myapp directly link against libb? I doubt.

So, why not to link Boost dynamically instead, just like OpenSSL?

And our minimum supported Boost version is 1.66.

Only because several Linux OS don't package a newer one. This doesn't mean we have to support v1.66-1.87 on Windows.

So that we use our bandwidth during our CI runs, not theirs.

Feel free to pull Boost from upstream, but our OpenSSL source provides only the latest version.

@Al2Klimov
Copy link
Member

I doubt it would make anything better as opposed to the static linking.

Isn't exactly the point of dynamic linking not having to rebuild an app if a dll changes?

@julianbrost
Copy link
Contributor

So, why not to link Boost dynamically instead, just like OpenSSL?

Does anyone know if that would actually solve the issue? Isn't all of this still pure speculation at this point? If it actually fixes it, yes that could be an option.

Feel free to pull Boost from upstream

For a one-off installation on a machine yes. From an automated job that would be not so nice towards the upstream project.

Isn't exactly the point of dynamic linking not having to rebuild an app if a dll changes?

What DLL is supposed to change? For Boost DLLs, that doesn't really matter as we'd have to ship them anyway (and I doubt there would even be any ABI-compatible updates). For psapi, that's a separate question if that library differs between Windows versions in an incompatible way (if it did, that sounds like it might be a problem for static linking).

@julianbrost
Copy link
Contributor

why we're linking statically (psapi.lib) instead of dynamically (psapi.dll)

The fundamental claim here isn't even correct: using *.lib doesn't even imply static linking. The *.lib can also be an import library (but doesn't have to be).

You can see the difference between an import library and one used for static linking when looking at the different *.lib files Boost provides:

boost_*.lib are the import libraries:

$ '/c/Program Files/7-Zip/7z.exe' l '/c/local/boost_1_79_0/lib64-msvc-14.2/boost_atomic-vc142-mt-x64-1_79.lib'
[...]
                    .....         2857         2857  1.txt
                    .....         2857         2857  2.txt
                    .....          586          586  1.boost_atomic-vc142-mt-x64-1_79.dll
                    .....          273          273  2.boost_atomic-vc142-mt-x64-1_79.dll
[...]

libboost_*.lib are for static linking:

[...]
2022-04-07 21:47:58 .....         3677         3677  1.txt
2022-04-07 21:47:58 .....         3677         3677  2.txt
2022-04-07 21:47:57 .....         3606         3606  D:\RB\bin.v2\boost\bin.v2\libs\atomic\build\msvc-14.2\release\link-static\threading-multi\wait_on_address.obj
2022-04-07 21:47:57 .....         1732         1732  D:\RB\bin.v2\boost\bin.v2\libs\atomic\build\msvc-14.2\release\link-static\threading-multi\find_address_sse41.obj
[...]

And psapi.lib indeed seems to be an import library:

$ '/c/Program Files/7-Zip/7z.exe' l '/c/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x86/psapi.lib'
[...]
                    .....         2413         2413  1.txt
                    .....         2413         2413  2.txt
                    .....          485          485  1.PSAPI.DLL
                    .....          248          248  2.PSAPI.DLL
[...]

@yhabteab
Copy link
Member Author

The fundamental claim here isn't even correct: using *.lib doesn't even imply static linking. The *.lib can also be an import library (but doesn't have to be).

That still doesn't make a foo.lib non-static library. Static libraries are called foo.lib and if that foo.lib appears to include some dynamic bindings to the actual DLL libraries, well I'm not windows API expert, so who cares?

And psapi.lib indeed seems to be an import library:

And now? What am I supposed to do with this information? Disproving that small note in the PR description still doesn't resolve the actual issue, so if you've suggestions to be applied that would actually fix it, it would be nice. Otherwise, this won't bring us much!

@julianbrost
Copy link
Contributor

Well, that small note resulted in quite a bit of discussion regarding static and dynamic linking, even for Boost. I just wanted to point out that psapi is linked dynamically in either case (like I'd expect it for Windows system libraries).

Regarding progress of the PR, two options:

  1. Link psapi explicitly ourselves and ignore that it's somewhat strange that we have to do this.
  2. Try different usage modes (header-only/library) of Boost.Stacktrace with a minimal example to see if anything works out of the box and/or ask/report that problem to upstream as mentioned in Support Boost 1.88 on Windows #10419 (comment)

@Al2Klimov
Copy link
Member

I wouldn't say it's strange. I mean, if some code requires a lib, something has to link against the lib – on all modern platforms. I indeed would expect the shared Boost libs to do that for us, but we don't use them yet. And the latter is the actual strange thing!

The static Boost libs have an excuse for not by themselves linking against anything: static libs are not linked by definition.

@yhabteab yhabteab force-pushed the fix-boost-1880-build-errors branch 2 times, most recently from 0d592e6 to bc51409 Compare May 27, 2025 15:21
@Al2Klimov Al2Klimov added this to the 2.15.0 milestone May 27, 2025
@yhabteab yhabteab removed the request for review from jschmidt-icinga May 28, 2025 07:33
@yhabteab yhabteab changed the title Fix windows build errors with boost 1.88.0 Support Boost 1.88 on Windows May 28, 2025
yhabteab added 2 commits May 28, 2025 09:39
Boost `1.88.0` introduced a feature [^1] that makes use of the Windows API, but it
uses API functions that are only available with `PSAPI_VERSION >= 2` and
Windows VISTA only supports `PSAPI_VERSION == 1`. Actually, that new feature
can also be disabled by setting the `BOOST_STACKTRACE_DISABLE_OFFSET_ADDR_BASE`
macro, but since it seems to be a useful feature and isn't even disabled by default,
we can just drop it that ancient Windows version instead of disabling it.

[^1]: boostorg/stacktrace#200
@yhabteab yhabteab force-pushed the fix-boost-1880-build-errors branch from bc51409 to c4ddd48 Compare May 28, 2025 07:39
@yhabteab
Copy link
Member Author

yhabteab commented May 28, 2025

The diff is empty, I just fixed a typo VISITA -> VISTA in the commit message 🙈!

@yhabteab yhabteab enabled auto-merge May 28, 2025 07:40
@yhabteab yhabteab merged commit 23ecc98 into master May 28, 2025
45 of 46 checks passed
@yhabteab yhabteab deleted the fix-boost-1880-build-errors branch May 28, 2025 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/windows Windows agent and plugins cla/signed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Boost 1.88 on Windows
4 participants