remove -DLAMMPS_EXCEPTIONS and always enable the corresponding code paths

This commit is contained in:
Axel Kohlmeyer
2023-04-15 17:49:08 -04:00
parent e506dd738b
commit 0cd5ae5f2e
17 changed files with 58 additions and 208 deletions

View File

@ -384,11 +384,6 @@ if(NOT ${LAMMPS_MEMALIGN} STREQUAL "0")
target_compile_definitions(lammps PRIVATE -DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN})
endif()
option(LAMMPS_EXCEPTIONS "enable the use of C++ exceptions for error messages (useful for library interface)" ${ENABLE_TESTING})
if(LAMMPS_EXCEPTIONS)
target_compile_definitions(lammps PUBLIC -DLAMMPS_EXCEPTIONS)
endif()
# "hard" dependencies between packages resulting
# in an error instead of skipping over files
pkg_depends(ML-IAP ML-SNAP)

View File

@ -28,9 +28,7 @@ if(MSVC)
add_compile_options(/Zc:__cplusplus)
add_compile_options(/wd4244)
add_compile_options(/wd4267)
if(LAMMPS_EXCEPTIONS)
add_compile_options(/EHsc)
endif()
add_compile_options(/EHsc)
endif()
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

View File

@ -38,9 +38,6 @@ endif()
if(BUILD_LAMMPS_SHELL)
find_package(PkgConfig REQUIRED)
pkg_check_modules(READLINE IMPORTED_TARGET REQUIRED readline)
if(NOT LAMMPS_EXCEPTIONS)
message(WARNING "The LAMMPS shell needs LAMMPS_EXCEPTIONS enabled for full functionality")
endif()
# include resource compiler to embed icons into the executable on Windows
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")

View File

@ -459,27 +459,13 @@ those systems:
.. _exceptions:
Exception handling when using LAMMPS as a library
------------------------------------------------------------------
-------------------------------------------------
This setting is useful when external codes drive LAMMPS as a library.
With this option enabled, LAMMPS errors do not kill the calling code.
Instead, the call stack is unwound and control returns to the caller,
e.g. to Python. Of course, the calling code has to be set up to
*catch* exceptions thrown from within LAMMPS.
.. tabs::
.. tab:: CMake build
.. code-block:: bash
-D LAMMPS_EXCEPTIONS=value # yes or no (default)
.. tab:: Traditional make
.. code-block:: make
LMP_INC = -DLAMMPS_EXCEPTIONS <other LMP_INC settings>
LAMMPS errors do not kill the calling code, but throw an exception. In
the C-library interface, the call stack is unwound and control returns
to the caller, e.g. to Python or a code that is coupled to LAMMPS and
the error status can be queried. When using C++ directly, the calling
code has to be set up to *catch* exceptions thrown from within LAMMPS.
.. note::

View File

@ -2172,19 +2172,13 @@ Procedures Bound to the :f:type:`lammps` Derived Type
.. versionadded:: 3Nov2022
In case of an error, LAMMPS will either abort or throw a C++ exception.
The latter has to be :ref:`enabled at compile time <exceptions>`.
This function checks if exceptions were enabled.
When using the library interface with C++ exceptions enabled, the library
interface functions will "catch" them, and the error status can then be
checked by calling :f:func:`has_error`. The most recent error message can be
retrieved via :f:func:`get_last_error_message`.
This can allow one to restart a calculation or delete and recreate
the LAMMPS instance when a C++ exception occurs. One application
of using exceptions this way is the :ref:`lammps_shell`. If C++
exceptions are disabled and an error happens during a call to
LAMMPS or the Fortran API, the application will terminate.
When using the library interface, the library interface functions
will "catch" exceptions, and then the error status can be checked by
calling :f:func:`has_error`. The most recent error message can be
retrieved via :f:func:`get_last_error_message`. This allows to
restart a calculation or delete and recreate the LAMMPS instance when
a C++ exception occurs. One application of using exceptions this way
is the :ref:`lammps_shell`.
:to: :cpp:func:`lammps_config_has_exceptions`
:r has_exceptions:

View File

@ -338,8 +338,6 @@ Some common LAMMPS specific variables
- common compiler flags, for optimization or instrumentation (default:)
* - ``LAMMPS_MACHINE``
- when set to ``name`` the LAMMPS executable and library will be called ``lmp_name`` and ``liblammps_name.a``
* - ``LAMMPS_EXCEPTIONS``
- when set to ``on`` errors will throw a C++ exception instead of aborting (default: ``off``)
* - ``FFT``
- select which FFT library to use: ``FFTW3``, ``MKL``, ``KISS`` (default, unless FFTW3 is found)
* - ``FFT_SINGLE``
@ -412,9 +410,9 @@ interface (``ccmake`` or ``cmake-gui``).
Using a preset to select a compiler package (``clang.cmake``,
``gcc.cmake``, ``intel.cmake``, ``oneapi.cmake``, or ``pgi.cmake``)
are an exception to the mechanism of updating the configuration incrementally,
as they will trigger a reset of cached internal CMake settings and thus
reset settings to their default values.
are an exception to the mechanism of updating the configuration
incrementally, as they will trigger a reset of cached internal CMake
settings and thus reset settings to their default values.
Compilation and build targets
-----------------------------

View File

@ -53,10 +53,10 @@ System-wide Installation
Step 1: Building LAMMPS as a shared library
"""""""""""""""""""""""""""""""""""""""""""
To use LAMMPS inside of Python it has to be compiled as shared library. This
library is then loaded by the Python interface. In this example we enable the
MOLECULE package and compile LAMMPS with C++ exceptions, PNG, JPEG and FFMPEG
output support enabled.
To use LAMMPS inside of Python it has to be compiled as shared
library. This library is then loaded by the Python interface. In this
example we enable the MOLECULE package and compile LAMMPS with PNG, JPEG
and FFMPEG output support enabled.
Step 1a: For the CMake based build system, the steps are:
@ -66,7 +66,7 @@ Step 1a: For the CMake based build system, the steps are:
cd $LAMMPS_DIR/build-shared
# MPI, PNG, Jpeg, FFMPEG are auto-detected
cmake ../cmake -DPKG_MOLECULE=yes -DLAMMPS_EXCEPTIONS=yes -DBUILD_LIB=yes -DBUILD_SHARED_LIBS=yes
cmake ../cmake -DPKG_MOLECULE=yes -DBUILD_LIB=yes -DBUILD_SHARED_LIBS=yes
make
Step 1b: For the legacy, make based build system, the steps are:
@ -79,7 +79,7 @@ Step 1b: For the legacy, make based build system, the steps are:
make yes-MOLECULE
# compile shared library using Makefile
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG -DLAMMPS_EXCEPTIONS" JPG_LIB="-lpng -ljpeg"
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG" JPG_LIB="-lpng -ljpeg"
Step 2: Installing the LAMMPS Python package
""""""""""""""""""""""""""""""""""""""""""""
@ -356,18 +356,16 @@ Together with matplotlib plotting data out of LAMMPS becomes simple:
Error handling with PyLammps
----------------------------
Compiling the shared library with C++ exception support provides a better error
handling experience. Without exceptions the LAMMPS code will terminate the
current Python process with an error message. C++ exceptions allow capturing
them on the C++ side and rethrowing them on the Python side. This way you
can handle LAMMPS errors through the Python exception handling mechanism.
Using C++ exceptions in LAMMPS for errors allows capturing them on the
C++ side and rethrowing them on the Python side. This way you can handle
LAMMPS errors through the Python exception handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be terminated. It is
advised to save your data and terminate the Python instance as quickly as
possible.
current LAMMPS process is in an illegal state and must be
terminated. It is advised to save your data and terminate the Python
instance as quickly as possible.
Using PyLammps in IPython notebooks and Jupyter
-----------------------------------------------

View File

@ -1,11 +1,11 @@
Handling LAMMPS errors
*******************************
**********************
Compiling the shared library with :ref:`C++ exception support <exceptions>` provides a better error
handling experience. Without exceptions the LAMMPS code will terminate the
current Python process with an error message. C++ exceptions allow capturing
them on the C++ side and rethrowing them on the Python side. This way
LAMMPS errors can be handled through the Python exception handling mechanism.
The shared library is compiled with :ref:`C++ exception support
<exceptions>` to provide a better error handling experience. C++
exceptions allow capturing errors on the C++ side and rethrowing them on
the Python side. This way LAMMPS errors can be handled through the
Python exception handling mechanism.
.. code-block:: python
@ -31,6 +31,6 @@ LAMMPS errors can be handled through the Python exception handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be terminated. It is
advised to save your data and terminate the Python instance as quickly as
possible.
current LAMMPS process is in an illegal state and must be
terminated. It is advised to save your data and terminate the Python
instance as quickly as possible when running in parallel with MPI.

View File

@ -18,10 +18,7 @@
#include "input.h"
#include "output.h"
#include "universe.h"
#if defined(LAMMPS_EXCEPTIONS)
#include "update.h"
#endif
using namespace LAMMPS_NS;
@ -40,10 +37,8 @@ static std::string truncpath(const std::string &path)
Error::Error(LAMMPS *lmp)
: Pointers(lmp), numwarn(0), maxwarn(100), allwarn(0)
{
#ifdef LAMMPS_EXCEPTIONS
last_error_message.clear();
last_error_type = ERROR_NONE;
#endif
}
/* ----------------------------------------------------------------------
@ -73,19 +68,11 @@ void Error::universe_all(const std::string &file, int line, const std::string &s
}
if (universe->ulogfile) fclose(universe->ulogfile);
#ifdef LAMMPS_EXCEPTIONS
// allow commands if an exception was caught in a run
// update may be a null pointer when catching command line errors
if (update) update->whichflag = 0;
throw LAMMPSException(mesg);
#else
KokkosLMP::finalize();
MPI_Finalize();
exit(1);
#endif
}
/* ----------------------------------------------------------------------
@ -99,19 +86,11 @@ void Error::universe_one(const std::string &file, int line, const std::string &s
universe->me,str,truncpath(file),line);
if (universe->uscreen) fputs(mesg.c_str(),universe->uscreen);
#ifdef LAMMPS_EXCEPTIONS
// allow commands if an exception was caught in a run
// update may be a null pointer when catching command line errors
if (update) update->whichflag = 0;
throw LAMMPSAbortException(mesg, universe->uworld);
#else
KokkosLMP::finalize();
MPI_Abort(universe->uworld,1);
exit(1); // to trick "smart" compilers into believing this does not return
#endif
}
/* ----------------------------------------------------------------------
@ -155,31 +134,17 @@ void Error::all(const std::string &file, int line, const std::string &str)
utils::logmesg(lmp,mesg);
}
#ifdef LAMMPS_EXCEPTIONS
// allow commands if an exception was caught in a run
// update may be a null pointer when catching command line errors
if (update) update->whichflag = 0;
std::string msg = fmt::format("ERROR: {} ({}:{})\n",
str, truncpath(file), line);
std::string msg = fmt::format("ERROR: {} ({}:{})\n", str, truncpath(file), line);
if (universe->nworlds > 1) {
if (universe->nworlds > 1)
throw LAMMPSAbortException(msg, universe->uworld);
}
throw LAMMPSException(msg);
#else
if (output) delete output;
if (screen && screen != stdout) fclose(screen);
if (logfile) fclose(logfile);
KokkosLMP::finalize();
if (universe->nworlds > 1) MPI_Abort(universe->uworld,1);
MPI_Finalize();
exit(1);
#endif
else
throw LAMMPSException(msg);
}
/* ----------------------------------------------------------------------
@ -204,20 +169,11 @@ void Error::one(const std::string &file, int line, const std::string &str)
if (universe->uscreen)
fputs(mesg.c_str(),universe->uscreen);
#ifdef LAMMPS_EXCEPTIONS
// allow commands if an exception was caught in a run
// update may be a null pointer when catching command line errors
if (update) update->whichflag = 0;
throw LAMMPSAbortException(mesg, world);
#else
utils::flush_buffers(lmp);
KokkosLMP::finalize();
MPI_Abort(world,1);
exit(1); // to trick "smart" compilers into believing this does not return
#endif
}
/* ----------------------------------------------------------------------
@ -322,7 +278,6 @@ void Error::done(int status)
exit(status);
}
#ifdef LAMMPS_EXCEPTIONS
/* ----------------------------------------------------------------------
return the last error message reported by LAMMPS (only used if
compiled with -DLAMMPS_EXCEPTIONS)
@ -353,4 +308,3 @@ void Error::set_last_error(const std::string &msg, ErrorType type)
last_error_message = msg;
last_error_type = type;
}
#endif

View File

@ -15,10 +15,7 @@
#define LMP_ERROR_H
#include "pointers.h"
#ifdef LAMMPS_EXCEPTIONS
#include "exceptions.h"
#endif
namespace LAMMPS_NS {
@ -65,7 +62,6 @@ class Error : protected Pointers {
void set_maxwarn(int val) { maxwarn = val; }
void set_allwarn(int val) { allwarn = val; }
#ifdef LAMMPS_EXCEPTIONS
std::string get_last_error() const;
ErrorType get_last_error_type() const;
void set_last_error(const std::string &msg, ErrorType type = ERROR_NORMAL);
@ -73,9 +69,7 @@ class Error : protected Pointers {
private:
std::string last_error_message;
ErrorType last_error_type;
#endif
private:
int numwarn, maxwarn, allwarn;
// internal versions that accept explicit fmtlib arguments
[[noreturn]] void _all(const std::string &, int, fmt::string_view, fmt::format_args args);

View File

@ -298,7 +298,6 @@ void Info::command(int narg, char **arg)
if (has_jpeg_support()) fputs("-DLAMMPS_JPEG\n",out);
if (has_ffmpeg_support()) fputs("-DLAMMPS_FFMPEG\n",out);
if (has_fft_single_support()) fputs("-DFFT_SINGLE\n",out);
if (has_exceptions()) fputs("-DLAMMPS_EXCEPTIONS\n",out);
#if defined(LAMMPS_BIGBIG)
fputs("-DLAMMPS_BIGBIG\n",out);
@ -1096,11 +1095,7 @@ bool Info::has_fft_single_support() {
}
bool Info::has_exceptions() {
#ifdef LAMMPS_EXCEPTIONS
return true;
#else
return false;
#endif
}
bool Info::has_package(const std::string &package_name) {

View File

@ -1431,7 +1431,6 @@ void LAMMPS::print_config(FILE *fp)
if (Info::has_jpeg_support()) fputs("-DLAMMPS_JPEG\n",fp);
if (Info::has_ffmpeg_support()) fputs("-DLAMMPS_FFMPEG\n",fp);
if (Info::has_fft_single_support()) fputs("-DFFT_SINGLE\n",fp);
if (Info::has_exceptions()) fputs("-DLAMMPS_EXCEPTIONS\n",fp);
#if defined(LAMMPS_BIGBIG)
fputs("-DLAMMPS_BIGBIG\n",fp);
#elif defined(LAMMPS_SMALLBIG)

View File

@ -27,6 +27,7 @@
#include "domain.h"
#include "dump.h"
#include "error.h"
#include "exceptions.h"
#include "fix.h"
#include "fix_external.h"
#include "force.h"
@ -53,10 +54,6 @@
#include <cstring>
#if defined(LAMMPS_EXCEPTIONS)
#include "exceptions.h"
#endif
#if defined(LMP_PYTHON)
#include <Python.h>
#endif
@ -93,7 +90,6 @@ static void ptr_argument_warning()
END_CAPTURE
------------------------------------------------------------------------- */
#ifdef LAMMPS_EXCEPTIONS
#define BEGIN_CAPTURE \
Error *error = lmp->error; \
try
@ -111,10 +107,6 @@ static void ptr_argument_warning()
} catch(LAMMPSException &e) { \
error->set_last_error(e.message, ERROR_NORMAL); \
}
#else
#define BEGIN_CAPTURE
#define END_CAPTURE
#endif
// ----------------------------------------------------------------------
// Library functions to create/destroy an instance of LAMMPS
@ -176,20 +168,19 @@ void *lammps_open(int argc, char **argv, MPI_Comm comm, void **ptr)
lammps_mpi_init();
if (ptr) ptr_argument_warning();
#ifdef LAMMPS_EXCEPTIONS
try
{
try {
lmp = new LAMMPS(argc, argv, comm);
if (ptr) *ptr = (void *) lmp;
}
catch(LAMMPSException &e) {
fmt::print(stderr, "LAMMPS Exception: {}", e.message);
} catch(LAMMPSException &e) {
fprintf(stderr, "LAMMPS Exception: %s\n", e.message);
if (ptr) *ptr = nullptr;
} catch (fmt::format_error &fe) {
fprintf(stderr, "fmt::format_error: %s\n", fe.what());
if (ptr) *ptr = nullptr;
} catch (std::exception &e) {
fprintf(stderr, "Exception: %s\n", e.what());
if (ptr) *ptr = nullptr;
}
#else
lmp = new LAMMPS(argc, argv, comm);
if (ptr) *ptr = (void *) lmp;
#endif
return (void *) lmp;
}
@ -484,7 +475,6 @@ void lammps_error(void *handle, int error_type, const char *error_text)
}
END_CAPTURE
#if defined(LAMMPS_EXCEPTIONS)
// with enabled exceptions the above code will simply throw an
// exception and record the error message. So we have to explicitly
// stop here like we do in main.cpp
@ -500,7 +490,6 @@ void lammps_error(void *handle, int error_type, const char *error_text)
exit(1);
}
}
#endif
}
// ----------------------------------------------------------------------
@ -2195,9 +2184,7 @@ void *lammps_extract_variable(void *handle, const char *name, const char *group)
}
}
END_CAPTURE
#if defined(LAMMPS_EXCEPTIONS)
return nullptr;
#endif
}
/* ---------------------------------------------------------------------- */
@ -6335,26 +6322,15 @@ void lammps_force_timeout(void *handle)
This function can be used to query if an error inside of LAMMPS
has thrown a :ref:`C++ exception <exceptions>`.
.. note::
This function will always report "no error" when the LAMMPS library
has been compiled without ``-DLAMMPS_EXCEPTIONS``, which turns fatal
errors aborting LAMMPS into C++ exceptions. You can use the library
function :cpp:func:`lammps_config_has_exceptions` to check whether this is
the case.
\endverbatim
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \return 0 on no error, 1 on error.
*/
int lammps_has_error(void *handle) {
#ifdef LAMMPS_EXCEPTIONS
LAMMPS *lmp = (LAMMPS *) handle;
Error *error = lmp->error;
return (error->get_last_error().empty()) ? 0 : 1;
#else
return 0;
#endif
}
/* ---------------------------------------------------------------------- */
@ -6373,12 +6349,6 @@ a "2" indicates an abort that would happen only in a single MPI rank
and thus may not be recoverable, as other MPI ranks may be waiting on
the failing MPI ranks to send messages.
.. note::
This function will do nothing when the LAMMPS library has been
compiled without ``-DLAMMPS_EXCEPTIONS``, which turns errors aborting
LAMMPS into C++ exceptions. You can use the library function
:cpp:func:`lammps_config_has_exceptions` to check whether this is the case.
\endverbatim
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
@ -6387,7 +6357,6 @@ the failing MPI ranks to send messages.
* \return 1 when all ranks had the error, 2 on a single rank error. */
int lammps_get_last_error_message(void *handle, char *buffer, int buf_size) {
#ifdef LAMMPS_EXCEPTIONS
LAMMPS *lmp = (LAMMPS *) handle;
Error *error = lmp->error;
buffer[0] = buffer[buf_size-1] = '\0';
@ -6398,7 +6367,6 @@ int lammps_get_last_error_message(void *handle, char *buffer, int buf_size) {
error->set_last_error("", ERROR_NONE);
return error_type;
}
#endif
return 0;
}

View File

@ -13,13 +13,10 @@
#include "lammps.h"
#include "exceptions.h"
#include "input.h"
#include "library.h"
#if defined(LAMMPS_EXCEPTIONS)
#include "exceptions.h"
#endif
#include <cstdlib>
#include <mpi.h>
@ -75,7 +72,6 @@ int main(int argc, char **argv)
feenableexcept(FE_OVERFLOW);
#endif
#ifdef LAMMPS_EXCEPTIONS
try {
auto lammps = new LAMMPS(argc, argv, lammps_comm);
lammps->input->file();
@ -99,18 +95,6 @@ int main(int argc, char **argv)
MPI_Abort(MPI_COMM_WORLD, 1);
exit(1);
}
#else
try {
auto lammps = new LAMMPS(argc, argv, lammps_comm);
lammps->input->file();
delete lammps;
} catch (fmt::format_error &fe) {
fprintf(stderr, "fmt::format_error: %s\n", fe.what());
finalize();
MPI_Abort(MPI_COMM_WORLD, 1);
exit(1);
}
#endif
finalize();
MPI_Barrier(lammps_comm);
MPI_Finalize();

View File

@ -46,13 +46,6 @@ else()
endif()
list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_MPI=${HAS_MPI})
if(LAMMPS_EXCEPTIONS)
set(HAS_EXCEPTIONS 1)
else()
set(HAS_EXCEPTIONS 0)
endif()
list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_EXCEPTIONS=${HAS_EXCEPTIONS})
foreach(WITH "JPEG" "PNG" "GZIP" "FFMPEG")
if(WITH_${WITH})
set(HAS_${WITH} 1)

View File

@ -195,7 +195,7 @@ TEST_F(LibraryConfig, force_timeout)
TEST(LAMMPSConfig, exceptions)
{
EXPECT_EQ(lammps_config_has_exceptions(), LAMMPS_HAS_EXCEPTIONS);
EXPECT_EQ(lammps_config_has_exceptions(), 1);
};
TEST(LAMMPSConfig, mpi_support)

View File

@ -86,13 +86,10 @@ if(Python_EXECUTABLE)
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonOpen PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
# some of the tests in this file will fail without exceptions enabled
if(LAMMPS_EXCEPTIONS)
add_test(NAME PythonCommands
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-commands.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonCommands PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
endif()
add_test(NAME PythonCommands
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-commands.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonCommands PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
add_test(NAME PythonNumpy
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-numpy.py -v