diff --git a/docs/sphinx/manual/creating_hpx_projects.rst b/docs/sphinx/manual/creating_hpx_projects.rst index 11bc5f478e70..766967921c0d 100644 --- a/docs/sphinx/manual/creating_hpx_projects.rst +++ b/docs/sphinx/manual/creating_hpx_projects.rst @@ -261,7 +261,11 @@ point in your application you must additionally link your application to the |cmake| target ``HPX::wrap_main``. This target is automatically linked to executables if you are using the macros described below (:ref:`using_hpx_cmake_macros`). See :ref:`minimal` for more information on -implicitly using ``main()`` as the entry point. +implicitly using ``main()`` as the entry point. If you want the same wrapping +behavior without including :hpx-header:`wrap/include,hpx/hpx_main.hpp`, link to +the ``HPX::auto_wrap_main`` target instead. This enables the runtime +initialization around ``main()`` unconditionally and is useful for codebases +where adding the header to ``main.cpp`` is impractical. If you want to use the facilities exposed by ``hpx::runtime_manager`` in binaries that were not linked as executables (e.g., in shared libraries), you will need diff --git a/docs/sphinx/manual/starting_the_hpx_runtime.rst b/docs/sphinx/manual/starting_the_hpx_runtime.rst index 2dcf222fd741..27afb8ceabef 100644 --- a/docs/sphinx/manual/starting_the_hpx_runtime.rst +++ b/docs/sphinx/manual/starting_the_hpx_runtime.rst @@ -54,7 +54,11 @@ you must link your application to the |cmake|_ target ``HPX::wrap_main``. This i done automatically if you are using the provided macros (:ref:`using_hpx_cmake_macros`) to set up your application, but must be done explicitly if you are using targets directly (:ref:`using_hpx_cmake_targets`). -All |hpx| API functions can be used from within the ``main()`` function now. +All |hpx| API functions can be used from within the ``main()`` function now. If +you cannot or do not want to include ``hpx/hpx_main.hpp`` in ``main.cpp``, you +can instead link against ``HPX::auto_wrap_main``. That target enables the same +runtime startup path without needing the header-triggered opt-in. + .. note:: @@ -105,7 +109,6 @@ to the operating system as usual. result in unexpected behavior. .. caution:: - We make use of an *override* variable ``include_libhpx_wrap`` in the header file ``hpx/hpx_main.hpp`` to swiftly choose the function call stack at runtime. Therefore, the header file should *only* be included in the main diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index c71569c91d4c..9704fdc5ea16 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -152,6 +152,7 @@ set(_is_library "$,${_library_types}>") add_library(hpx INTERFACE) add_library(init INTERFACE) add_library(wrap_main INTERFACE) +add_library(auto_wrap_main INTERFACE) target_link_libraries(hpx INTERFACE hpx_full) @@ -183,8 +184,14 @@ add_library(hpx_interface_wrap_main INTERFACE) target_link_libraries( hpx_interface_wrap_main INTERFACE $<${_is_executable}:HPXInternal::hpx_wrap> ) +add_library(hpx_interface_auto_wrap_main INTERFACE) +target_link_libraries( + hpx_interface_auto_wrap_main + INTERFACE $<${_is_executable}:HPXInternal::hpx_auto_wrap> +) target_link_libraries(wrap_main INTERFACE hpx_interface_wrap_main) +target_link_libraries(auto_wrap_main INTERFACE hpx_interface_auto_wrap_main) target_link_libraries(init INTERFACE HPXInternal::hpx_init) target_link_libraries(hpx INTERFACE hpx_interface) @@ -212,8 +219,10 @@ target_compile_definitions( "$<${_is_library}:HPX_PLUGIN_NAME_DEFAULT=hpx_$>" ) -set(hpx_targets hpx wrap_main init plugin component) -set(hpx_internal_targets hpx_full hpx_interface hpx_interface_wrap_main) +set(hpx_targets hpx wrap_main auto_wrap_main init plugin component) +set(hpx_internal_targets hpx_full hpx_interface hpx_interface_wrap_main + hpx_interface_auto_wrap_main +) # cmake-format: off install( diff --git a/tests/unit/init/CMakeLists.txt b/tests/unit/init/CMakeLists.txt index c636e54b885e..b79a13404c66 100644 --- a/tests/unit/init/CMakeLists.txt +++ b/tests/unit/init/CMakeLists.txt @@ -5,7 +5,9 @@ # 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 manage_runtime) +set(tests manage_runtime auto_wrap_main) + +set(auto_wrap_main_FLAGS NOLIBS DEPENDENCIES HPX::hpx HPX::auto_wrap_main) foreach(test ${tests}) set(sources ${test}.cpp) diff --git a/tests/unit/init/auto_wrap_main.cpp b/tests/unit/init/auto_wrap_main.cpp new file mode 100644 index 000000000000..0bb3ad340618 --- /dev/null +++ b/tests/unit/init/auto_wrap_main.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2025 Bharath Kollanur +// +// 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) + +#include +#include +#include + +int main(int, char**) +{ + // The wrapper should have initialized HPX runtime before reaching main. + HPX_TEST(hpx::get_runtime_ptr() != nullptr); + + // Verify that calling thread is an HPX thread by launching another + // HPX task and waiting for its result. + auto f = hpx::async([] { return (hpx::get_runtime_ptr() != nullptr); }); + HPX_TEST(f.get()); + + return hpx::util::report_errors(); +} diff --git a/wrap/CMakeLists.txt b/wrap/CMakeLists.txt index fb44d742cdaa..9407788038a2 100644 --- a/wrap/CMakeLists.txt +++ b/wrap/CMakeLists.txt @@ -42,6 +42,10 @@ add_hpx_source_group( add_library( hpx_wrap STATIC ${hpx_wrap_SOURCES} ${hpx_wrap_HEADERS} ${config_header} ) +add_library( + hpx_auto_wrap STATIC ${hpx_wrap_SOURCES} ${hpx_wrap_HEADERS} ${config_header} +) + set_target_properties(hpx_wrap PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(hpx_wrap PRIVATE hpx_full) target_link_libraries(hpx_wrap PRIVATE hpx_init) @@ -51,11 +55,26 @@ target_include_directories( hpx_wrap PUBLIC $ $ ) + +set_target_properties(hpx_auto_wrap PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(hpx_auto_wrap PRIVATE hpx_full) +target_link_libraries(hpx_auto_wrap PRIVATE hpx_init) +target_link_libraries(hpx_auto_wrap PRIVATE hpx_private_flags) +target_compile_definitions( + hpx_auto_wrap PRIVATE HPX_LIBRARY_EXPORTS HPX_AUTO_WRAP_MAIN_ACTIVATE +) +target_include_directories( + hpx_auto_wrap PUBLIC $ + $ +) + if(HPX_WITH_CXX_MODULES) hpx_configure_module_consumer(hpx_wrap hpx_core_module_if) + hpx_configure_module_consumer(hpx_auto_wrap hpx_core_module_if) endif() set_property(TARGET hpx_wrap PROPERTY FOLDER "Core") +set_property(TARGET hpx_auto_wrap PROPERTY FOLDER "Core") if(MSVC) set_target_properties( @@ -72,8 +91,10 @@ endif() if(HPX_WITH_DYNAMIC_HPX_MAIN) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") target_link_libraries(hpx_wrap INTERFACE "-Wl,-wrap=main") + target_link_libraries(hpx_auto_wrap INTERFACE "-Wl,-wrap=main") elseif(APPLE) target_link_libraries(hpx_wrap INTERFACE "-Wl,-e,_initialize_main") + target_link_libraries(hpx_auto_wrap INTERFACE "-Wl,-e,_initialize_main") else() hpx_error("Dynamic hpx_main is not supported on ${CMAKE_SYSTEM_NAME}.") endif() @@ -87,6 +108,14 @@ install( RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT hpx_init ) +install( + TARGETS hpx_auto_wrap + EXPORT HPXInternalTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT hpx_init + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT hpx_init + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT hpx_init +) + install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} @@ -109,9 +138,12 @@ if(MSVC) endif() hpx_export_internal_targets(hpx_wrap) +hpx_export_internal_targets(hpx_auto_wrap) add_hpx_pseudo_dependencies(core hpx_wrap) +add_hpx_pseudo_dependencies(core hpx_auto_wrap) if(HPX_WITH_PRECOMPILED_HEADERS) target_precompile_headers(hpx_wrap REUSE_FROM hpx_precompiled_headers) + target_precompile_headers(hpx_auto_wrap REUSE_FROM hpx_precompiled_headers) endif() diff --git a/wrap/src/hpx_wrap.cpp b/wrap/src/hpx_wrap.cpp index f2f0ea5bbc2b..75cb74681452 100644 --- a/wrap/src/hpx_wrap.cpp +++ b/wrap/src/hpx_wrap.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include // The following implementation has been divided for Linux and Mac OSX #if defined(HPX_HAVE_DYNAMIC_HPX_MAIN) && \ @@ -17,14 +18,23 @@ namespace hpx_start { // include_libhpx_wrap is a weak symbol which helps to determine the course // of function calls at runtime. It has a default value of `false` which // corresponds to the program's entry point being main(). - // It is overridden in hpx/hpx_main.hpp. Thus, inclusion of the header file + // It is overridden in hpx/hpx_main.hpp or set as TRUE if + // HPX_AUTO_WRAP_MAIN_ACTIVATE is defined. + // Thus, inclusion of the header file or defining HPX_AUTO_WRAP_MAIN_ACTIVATE // will change the program's entry point to HPX's own custom entry point // initialize_main. Subsequent calls before entering main() are handled // by this code. HPX_SYMBOL_EXPORT extern bool include_libhpx_wrap; +#if defined(HPX_AUTO_WRAP_MAIN_ACTIVATE) + HPX_SYMBOL_EXPORT bool include_libhpx_wrap __attribute__((weak)) = true; +#else HPX_SYMBOL_EXPORT bool include_libhpx_wrap __attribute__((weak)) = false; +#endif + // The default application name is populated by including hpx/hpx_main.hpp + // or if HPX_AUTO_WRAP_MAIN_ACTIVATE is defined. HPX_SYMBOL_EXPORT extern const char* app_name_libhpx_wrap; - HPX_SYMBOL_EXPORT const char* app_name_libhpx_wrap __attribute__((weak)); + HPX_SYMBOL_EXPORT const char* app_name_libhpx_wrap __attribute__((weak)) = + HPX_APPLICATION_STRING; // Provide a definition of is_linked variable defined weak in hpx_main.hpp // header. This variable is solely to trigger a different exception when @@ -34,7 +44,6 @@ namespace hpx_start { } // namespace hpx_start #include -#include #include #include