Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 5 additions & 1 deletion docs/sphinx/manual/creating_hpx_projects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions docs/sphinx/manual/starting_the_hpx_runtime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ set(_is_library "$<IN_LIST:$<TARGET_PROPERTY:TYPE>,${_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)

Expand Down Expand Up @@ -183,8 +184,13 @@ 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)

Expand Down Expand Up @@ -212,8 +218,8 @@ target_compile_definitions(
"$<${_is_library}:HPX_PLUGIN_NAME_DEFAULT=hpx_$<TARGET_PROPERTY:NAME>>"
)

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(
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/init/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment thread
hkaiser marked this conversation as resolved.

foreach(test ${tests})
set(sources ${test}.cpp)
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/init/auto_wrap_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <hpx/modules/async_distributed.hpp>
Comment thread
hkaiser marked this conversation as resolved.
#include <hpx/modules/testing.hpp>
#include <hpx/runtime_local/runtime_local.hpp>

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();

}
68 changes: 68 additions & 0 deletions wrap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,28 @@ set(hpx_wrap_SOURCES
)
list(APPEND hpx_wrap_SOURCES hpx_wrap.cpp hpx_main.cpp)

set(hpx_auto_wrap_SOURCES
""
CACHE INTERNAL "Sources for libhpx_auto_wrap." FORCE
)
list(APPEND hpx_auto_wrap_SOURCES hpx_auto_wrap.cpp hpx_main.cpp)

# make source groups
set(hpx_wrap_SOURCE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/src)
list(TRANSFORM hpx_wrap_SOURCES PREPEND ${hpx_wrap_SOURCE_ROOT}/)
list(TRANSFORM hpx_auto_wrap_SOURCES PREPEND ${hpx_wrap_SOURCE_ROOT}/)
add_hpx_source_group(
NAME hpx_wrap
CLASS "Source Files"
ROOT "${hpx_wrap_SOURCE_ROOT}"
TARGETS ${hpx_wrap_SOURCES}
)
add_hpx_source_group(
NAME hpx_auto_wrap
CLASS "Source Files"
ROOT "${hpx_wrap_SOURCE_ROOT}"
TARGETS ${hpx_auto_wrap_SOURCES}
)

set(hpx_wrap_HEADER_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/include)
list(TRANSFORM hpx_wrap_HEADERS PREPEND ${hpx_wrap_HEADER_ROOT}/)
Expand All @@ -38,10 +51,20 @@ add_hpx_source_group(
ROOT "${hpx_wrap_HEADER_ROOT}"
TARGETS ${hpx_wrap_HEADERS}
)
add_hpx_source_group(
NAME hpx_auto_wrap
CLASS "Header Files"
ROOT "${hpx_wrap_HEADER_ROOT}"
TARGETS ${hpx_wrap_HEADERS}
)

add_library(
hpx_wrap STATIC ${hpx_wrap_SOURCES} ${hpx_wrap_HEADERS} ${config_header}
)
add_library(
hpx_auto_wrap STATIC ${hpx_auto_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)
Expand All @@ -51,11 +74,24 @@ target_include_directories(
hpx_wrap PUBLIC $<BUILD_INTERFACE:${hpx_wrap_HEADER_ROOT}>
$<INSTALL_INTERFACE:include>
)

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)
target_include_directories(
hpx_auto_wrap PUBLIC $<BUILD_INTERFACE:${hpx_wrap_HEADER_ROOT}>
$<INSTALL_INTERFACE:include>
)

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(
Expand All @@ -67,13 +103,24 @@ if(MSVC)
COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO
${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo
)
set_target_properties(
hpx_auto_wrap
PROPERTIES COMPILE_PDB_NAME_DEBUG hpx_auto_wrapd
COMPILE_PDB_NAME_RELWITHDEBINFO hpx_auto_wrap
COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG
${CMAKE_CURRENT_BINARY_DIR}/Debug
COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO
${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo
)
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()
Expand All @@ -87,6 +134,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}
Expand All @@ -105,13 +160,26 @@ if(MSVC)
COMPONENT runtime
OPTIONAL
)

get_target_property(_pdb_file_auto hpx_auto_wrap COMPILE_PDB_NAME_${cfg})
get_target_property(_pdb_dir_auto hpx_auto_wrap COMPILE_PDB_OUTPUT_DIRECTORY_${cfg})
install(
FILES ${_pdb_dir_auto}/${_pdb_file_auto}.pdb
DESTINATION ${CMAKE_INSTALL_LIBDIR}
CONFIGURATIONS ${cfg}
COMPONENT runtime
OPTIONAL
)
Comment thread
hkaiser marked this conversation as resolved.
Outdated
endforeach()
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()
143 changes: 143 additions & 0 deletions wrap/src/hpx_auto_wrap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (c) 2018-2020 Nikunj Gupta
//
// 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 <hpx/config.hpp>
#include <hpx/hpx_init.hpp>

// The following implementation has been divided for Linux and Mac OSX
#if defined(HPX_HAVE_DYNAMIC_HPX_MAIN) && \
(defined(__linux) || defined(__linux__) || defined(linux) || \
defined(__APPLE__))

#include <string>

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
// 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;
HPX_SYMBOL_EXPORT bool include_libhpx_wrap __attribute__((weak)) = true;
HPX_SYMBOL_EXPORT extern const char* app_name_libhpx_wrap;
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
// trying to register thread when not linked to libhpx_wrap and using
// hpx_main.hpp functionality.
HPX_SYMBOL_EXPORT bool is_linked = true;
} // namespace hpx_start


#include <hpx/modules/functional.hpp>
#include <hpx/hpx_finalize.hpp>

#include <hpx/runtime_configuration/runtime_mode.hpp>

#include <vector>

////////////////////////////////////////////////////////////////////////////////
// Function declarations
//
namespace hpx_start {
// Main entry point of HPX runtime system
extern int hpx_entry(int argc, char* argv[]);
} // namespace hpx_start

// Program's entry point depending upon Operating System.
// For Mac OSX it is the program's entry point. In case of Linux
// it is called by __wrap_main.
extern "C" int initialize_main(int argc, char** argv);

#if defined(__linux) || defined(__linux__) || defined(linux)
// Actual main() function
extern "C" int __real_main(int argc, char** argv);

// Our wrapper for main() function
extern "C" int __wrap_main(int argc, char** argv);
#endif

#if defined(__APPLE__)
// Declaration for main() for Mac OS implementation
extern "C" int main(int argc, char** argv);
#endif

namespace hpx_start {
// main entry point of the HPX runtime system
int hpx_entry(int argc, char* argv[])
{
#if defined(__linux) || defined(__linux__) || defined(linux)
// Call to the main() function
int return_value = __real_main(argc, argv);
#else /* APPLE */
// call to the main() function
int return_value = main(argc, argv);
#endif

// Finalizing the HPX runtime
hpx::finalize();
return return_value;
}
} // namespace hpx_start

// This is the main entry point of C runtime system.
// The HPX runtime system is initialized here, which
// is similar to initializing HPX from main() and utilising
// the hpx_main() as the entry point.
extern "C" int initialize_main(int argc, char** argv)
{
#if defined(__APPLE__)
if (hpx_start::include_libhpx_wrap)
{
#endif
// Configuring HPX system before runtime
std::vector<std::string> const cfg = {
"hpx.commandline.allow_unknown!=1",
"hpx.commandline.aliasing=0",
};
hpx::function<int(int, char**)> start_function = &hpx_start::hpx_entry;
using hpx::program_options::options_description;
options_description desc = options_description(std::string("Usage: ") +
::hpx_start::app_name_libhpx_wrap + " [options]");
// Create the init_params struct
hpx::init_params iparams;
iparams.desc_cmdline = desc;
iparams.cfg = cfg;

// Initialize the HPX runtime system
return hpx::init(start_function, argc, argv, iparams);
#if defined(__APPLE__)
}
return main(argc, argv);
#endif
}

#if defined(__linux) || defined(__linux__) || defined(linux)
////////////////////////////////////////////////////////////////////////////////
// Wrapper for main function
//

// We are wrapping the main function to initialize our
// runtime system prior to real main call.
extern "C" int __wrap_main(int argc, char** argv)
{
// We determine the function call stack at runtime
// from the value of include_libhpx_wrap. If hpx_main
// is included include_libhpx_wrap is set to 1
// due to override variable.
if (hpx_start::include_libhpx_wrap)
return initialize_main(argc, argv);

// call main() since hpx_main.hpp is not included
return __real_main(argc, argv);
}
////////////////////////////////////////////////////////////////////////////////
#endif

#endif
Comment thread
hkaiser marked this conversation as resolved.
Outdated