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
1 change: 1 addition & 0 deletions libs/core/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ set(config_macro_headers
hpx/config/forward.hpp
hpx/config/manual_profiling.hpp
hpx/config/move.hpp
hpx/config/static_linker_check.hpp
hpx/config/threads_stack.hpp
hpx/config/warnings_prefix.hpp
hpx/config/warnings_suffix.hpp
Expand Down
41 changes: 41 additions & 0 deletions libs/core/config/include/hpx/config/static_linker_check.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2026 The STE||AR-Group
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

#include <hpx/config/defines.hpp>

// Emit a compile-time diagnostic when the user includes hpx/hpx_main.hpp
// while building a statically-linked HPX application on Linux or macOS.
//
// Root cause: the '--wrap=main' linker flag, which redirects user 'main' to
// the HPX runtime entry-point, is only applied automatically when the user
// links against 'HPX::wrap_main'. Without it, the resulting binary will call
// the raw 'main' symbol, bypassing HPX initialisation and producing a
// hard-to-diagnose runtime crash or silent hang.
//
// Actionable remedies (pick one):
// CMake -- add target_link_libraries(<target> PRIVATE HPX::wrap_main)
// Manual -- pass -Wl,--wrap=main to the linker explicitly
//
// This check is intentionally limited to Linux/macOS static builds because:
// * On Windows the wrap mechanism is not used (MSVC uses a different ABI).
// * Dynamic (shared-library) builds already embed the wrap stub inside
// libhpx.so/dylib, so no extra linker flag is needed.

#if defined(HPX_HAVE_DYNAMIC_HPX_MAIN)
#if (defined(__linux) || defined(__linux__) || defined(linux) || \
defined(__APPLE__)) && \
defined(HPX_HAVE_STATIC_LINKING) && \
!defined(HPX_HAVE_WRAP_MAIN_CONFIGURED)
#warning \
"HPX static-link wrap-main check: you included hpx/hpx_main.hpp but the " \
"--wrap=main linker flag has not been applied. Add " \
"target_link_libraries(<target> PRIVATE HPX::wrap_main) to your " \
"CMakeLists.txt, or pass -Wl,--wrap=main to the linker manually. " \
"Without this flag the HPX runtime will not be initialised correctly."
#endif
#endif
24 changes: 23 additions & 1 deletion libs/core/include_local/tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Copyright (c) 2020-2021 The STE||AR-Group
# Copyright (c) 2020-2026 The STE||AR-Group
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

set(tests static_linker)

set(static_linker_FLAGS NOLIBS DEPENDENCIES hpx_core)

foreach(test ${tests})
set(sources ${test}_test.cpp)

source_group("Source Files" FILES ${sources})

set(folder_name "Tests/Unit/Modules/Core/IncludeLocal")

add_hpx_executable(
${test}_test INTERNAL_FLAGS
SOURCES ${sources} ${${test}_FLAGS}
EXCLUDE_FROM_ALL
FOLDER ${folder_name}
)

add_hpx_unit_test("modules.include_local" ${test} ${${test}_PARAMETERS})

endforeach()
21 changes: 21 additions & 0 deletions libs/core/include_local/tests/unit/static_linker_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2020-2026 The STE||AR-Group
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// Verify that the local headers are self-contained and provide access to the
// Standard Parallel Toolkit types: parallel algorithms, numeric algorithms,
// execution policies, and futures.
//
// This is a compile-and-link sanity check only. It does NOT start the HPX
// runtime, so it has no dependency on the wrap module (hpx_main.hpp) or on
// any specific HPX link target beyond hpx_core.

#include <hpx/execution.hpp>

int main()
{
[[maybe_unused]] hpx::execution::parallel_policy p;
return 0;
}
4 changes: 4 additions & 0 deletions wrap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,11 @@ endif()
if(HPX_WITH_DYNAMIC_HPX_MAIN)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
target_link_libraries(hpx_wrap INTERFACE "-Wl,-wrap=main")
target_compile_definitions(hpx_wrap INTERFACE HPX_HAVE_WRAP_MAIN_CONFIGURED)
target_link_libraries(hpx_auto_wrap INTERFACE "-Wl,-wrap=main")
target_compile_definitions(
hpx_auto_wrap INTERFACE HPX_HAVE_WRAP_MAIN_CONFIGURED
)
elseif(APPLE)
target_link_libraries(hpx_wrap INTERFACE "-Wl,-e,_initialize_main")
target_link_libraries(hpx_auto_wrap INTERFACE "-Wl,-e,_initialize_main")
Expand Down
1 change: 1 addition & 0 deletions wrap/include/hpx/hpx_main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <hpx/config/static_linker_check.hpp>
#include <hpx/wrap_main.hpp>

#if defined(HPX_HAVE_RUN_MAIN_EVERYWHERE)
Expand Down
Loading