diff --git a/cmake/mpi.cmake b/cmake/mpi.cmake index 71b184c1..d6fa5feb 100644 --- a/cmake/mpi.cmake +++ b/cmake/mpi.cmake @@ -15,6 +15,15 @@ # limitations under the License. # +# assume MPI was compiled with GCC, as in most Linux distributions; +# with recent distributions, MPI may contain Link-Time Optimization +# flags, which are compiler-specific and thus not portable: +# if the compiler is not gcc, disable LTO and allow FindMPI to +# make MPI work with Clang +if ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + set( MPI_COMPILER_FLAGS "-fno-lto" ) + message( STATUS "detecting MPI with Clang by disabling LTO" ) +endif() find_package(MPI) # Find the 'mpirun' frontend diff --git a/post-install/CMakeLists.txt b/post-install/CMakeLists.txt index 6e8bbd45..74130be5 100644 --- a/post-install/CMakeLists.txt +++ b/post-install/CMakeLists.txt @@ -23,6 +23,9 @@ set( testdir "${CMAKE_SOURCE_DIR}/tests/functional" ) set( common "${CMAKE_SOURCE_DIR}/src/common" ) set( exampledir "${CMAKE_SOURCE_DIR}/examples/" ) +# Debug tests do not work in some distributions (e.g., Ubuntu 22.04), +# hence they can be disabled during configuration with this option +option(RUN_DEBUG_TESTS ON) configure_file( post-install-test.cmake.in post-install-test.cmake @ONLY ) install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/post-install-test.cmake) diff --git a/post-install/post-install-test.cmake.in b/post-install/post-install-test.cmake.in index 65c9ef9f..f6d9f64c 100644 --- a/post-install/post-install-test.cmake.in +++ b/post-install/post-install-test.cmake.in @@ -77,35 +77,40 @@ foreach(engine @ENGINES@) endforeach(nprocs) endforeach(engine) -### Testing linking with debug library - -message("Compiling an LPF program with debug library") -execute_process( - COMMAND @bindir@/lpfcc @srcdir@/test-lpf-debug.c -o test-lpf-debug -llpf_debug - WORKING_DIRECTORY @builddir@ - RESULT_VARIABLE status - ) -if (NOT status EQUAL 0 ) - message(SEND_ERROR "lpfcc failed compiling a simple LPF program with debug library") -endif() - -message("Running an LPF program with debug library on any of the engines: @ENGINES@") -foreach(engine @ENGINES@) - foreach( nprocs 2 3 ) - execute_process( - COMMAND @bindir@/lpfrun -engine ${engine} -np ${nprocs} ./test-lpf-debug ${nprocs} - WORKING_DIRECTORY @builddir@ - OUTPUT_FILE @builddir@/test-lpf-debug-${engine}-${nprocs}.log - ERROR_FILE @builddir@/test-lpf-debug-${engine}-${nprocs}.log - RESULT_VARIABLE status - ) - - # error when no error has been detected - if (status EQUAL 0) - message(SEND_ERROR "Debug library failed to detect runtime error on engine ${engine} on P=${nprocs}") - endif() - endforeach(nprocs) -endforeach(engine) +# Debug tests do not work in some distributions (e.g., Ubuntu 22.04), hence they can be disabled during configuration +if (RUN_DEBUG_TESTS) + ### Testing linking with debug library + + message("Compiling an LPF program with debug library") + execute_process( + COMMAND @bindir@/lpfcc @srcdir@/test-lpf-debug.c -o test-lpf-debug -llpf_debug + WORKING_DIRECTORY @builddir@ + RESULT_VARIABLE status + ) + if (NOT status EQUAL 0 ) + message(SEND_ERROR "lpfcc failed compiling a simple LPF program with debug library") + endif() + + message("Running an LPF program with debug library on any of the engines: @ENGINES@") + foreach(engine @ENGINES@) + foreach( nprocs 2 3 ) + execute_process( + COMMAND @bindir@/lpfrun -engine ${engine} -np ${nprocs} ./test-lpf-debug ${nprocs} + WORKING_DIRECTORY @builddir@ + OUTPUT_FILE @builddir@/test-lpf-debug-${engine}-${nprocs}.log + ERROR_FILE @builddir@/test-lpf-debug-${engine}-${nprocs}.log + RESULT_VARIABLE status + ) + + # error when no error has been detected + if (status EQUAL 0) + message(SEND_ERROR "Debug library failed to detect runtime error on engine ${engine} on P=${nprocs}") + endif() + endforeach(nprocs) + endforeach(engine) +else() + message(WARNING "skipping debug tests") +endif(RUN_DEBUG_TESTS) endif(UNIX AND NOT APPLE) diff --git a/src/MPI/init.cpp b/src/MPI/init.cpp index 68d16866..397c7466 100644 --- a/src/MPI/init.cpp +++ b/src/MPI/init.cpp @@ -36,7 +36,7 @@ namespace lpf { bool mpi_initializer_ran = false; - void __attribute__((constructor)) mpi_initializer( int argc, char ** argv ) { + void __attribute__((constructor)) mpi_initializer() { const char * const engine_c = std::getenv( "LPF_ENGINE" ); const std::string engine = std::string( engine_c == NULL ? @@ -68,69 +68,20 @@ namespace lpf { //check if we need to initialise MPI if( LPF_MPI_AUTO_INITIALIZE ) { - //yes-- in so doing, take care of the command-line arguments - //that the MPI implementation may modify. Most (all?) - //modern implementations do not change the given argc/argv, - //but, to nevertheless be sure, we handle here the removal of - //CLI arguments by MPI_Init. - assert( argc > 0 ); - assert( argv != NULL ); - std::vector< size_t > arglengths; - for( size_t i = 0; i < static_cast< size_t >(argc); ++i ) { - arglengths.push_back( strlen( argv[i] ) ); - } - assert( arglengths.size() == static_cast< size_t >(argc) ); - - int new_argc = argc; - char ** new_argv = argv; - try { - lpf::Interface::initRoot( &new_argc, &new_argv ); + // the linker of recent Linux distributions does NOT initialize + // argc/argv anymore during LD_PRELOAD (it was an undocumented feature); + // hence, we cannot get implementation-specific MPI flags (which no major + // MPI implementor anyway has), and we don't care about other flags; + // therefore, ignore argc/argv tout court and pass NULL + // (which is allowed by MPI_Init[_thread]()) + lpf::Interface::initRoot( NULL, NULL ); } catch( std::exception &e ) { const std::string error = e.what(); (void) std::fprintf( stderr, "Failed to auto-initialize engine:\n\t%s\n", error.c_str() ); std::abort(); } - - assert( new_argc != 0 ); - assert( new_argv != NULL ); - assert( new_argc <= argc ); - - if( !(argc == new_argc && argv == new_argv) ) { - //MPI_Init changed our arguments, create a copy of the new ones - std::vector< std::string > modified; - size_t new_pos = 0; - for( - size_t i = 0; - i < static_cast< size_t >(new_argc); - ++i - ) { - const size_t size = strlen( new_argv[ i ] ); - while( - new_pos < static_cast< size_t >(argc) && - size > arglengths[ new_pos++ ] - ) { - //the new string does not fit here; set this argument - //to empty and hope that the next one can fit it: - modified.push_back( "" ); - } - modified.push_back( new_argv[ i ] ); - } - //sanity check - if( modified.size() > static_cast< size_t >(argc) ) { - (void) std::fprintf( stderr, "Program arguments returned by MPI_Init cannot be copied back into original argument list.\n" ); - abort(); - } - //pad to size of argc - for( size_t i = modified.size(); i < static_cast< size_t >( argc ); ++i ) { - modified.push_back( "" ); - } - //copy back the new arguments in the original argv - for( size_t i = 0; i < static_cast< size_t >( argc ); ++i ) { - (void) strncpy( argv[ i ], modified[ i ].c_str(), arglengths[ i ] ); - } - } } } }