Make it possible to customize swig_check() definition
Move this function definition to cexcept.swg from the code and only define it if SWIG_swig_check_DEFINED is not defined yet, which both simplifies the code in C.cxx and makes exception handling code more flexible, as it's now possible to predefine SWIG_swig_check_DEFINED in the code injected into the "cxxheader" section to replace the default implementation. Show an example of doing this in the documentation and document handling exceptions with C API too. The changes above required adding a new "cxxcode" section, corresponding to the "implementation" part of C++ wrappers and defining a new SWIG_CXX_WRAPPERS preprocessor symbol to allow only adding C++-specific code when C++ wrappers are actually generated. Also improve the documentation of the C-specific sections in the manual.
This commit is contained in:
parent
86dbf6bcb5
commit
f06bba320a
3 changed files with 86 additions and 22 deletions
|
|
@ -683,6 +683,10 @@ void SomeIntTemplateClass_delete(SomeIntTemplateClass * carg1);
|
|||
|
||||
<H2><a name="C_exceptions"></a>36.5 Exception handling</H2>
|
||||
|
||||
<p>
|
||||
Any call to a C++ function may throw an exception, which cannot be caught by C code. Instead, the special <tt>SWIG_CException_get_pending()</tt> function must be called to check for this. If it returns a non-null pointer, <tt>SWIG_CException_msg_get()</tt> can be called to retrieve the error message associated with the exception. Finally, <tt>SWIG_CException_reset_pending()</tt> must be called to free the exception object and reset the current pending exception. Note that exception handling is much simpler when using C++, rather than C, wrappers, see sections 36.6.2.
|
||||
</p>
|
||||
|
||||
<H2><a name="C_cxx_wrappers"></a>36.6 C++ Wrappers</H2>
|
||||
|
||||
<p>
|
||||
|
|
@ -702,8 +706,52 @@ Other ones are due to things that could be supported but haven't been implemente
|
|||
</ul>
|
||||
</p>
|
||||
|
||||
Note that <tt>cxxheader</tt> section can be used to output additional
|
||||
declarations to the C++-only part of the generated header.
|
||||
<H3>36.6.1 Additional sections</H3>
|
||||
|
||||
Generated C++ code can be customized by inserting custom code in the following sections:
|
||||
|
||||
<ul>
|
||||
<li><tt>cxxheader</tt> for including additional headers and other declarations in the global scope.</li>
|
||||
<li><tt>cxxcode</tt> for additional code to appear after the declarations of all wrapper classes, inside the module-specific namespace.</li>
|
||||
</ul>
|
||||
|
||||
<H3>36.6.2 Exception handling</H3>
|
||||
|
||||
<p>
|
||||
Exception handling in C++ is more natural, as the exceptions are re-thrown when using C++ wrappers and so can be caught, as objects of the special <tt>SWIG_CException</tt> type, using the usual <tt>try/catch</tt> statement. The objects of <tt>SWIG_CException</tt> class have <tt>code()</tt> and <tt>msg()</tt> methods, with the latter returning the error message associated with the exception.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If necessary, a custom exception type may be used instead of <tt>SWIG_CException</tt>. To do this, a custom implementation of <tt>swig_check()</tt> function, called to check for the pending exception and throw the corresponding C++ exception if necessary, must be provided and <tt>SWIG_swig_check_DEFINED</tt> preprocessor symbol must be defined to prevent the default implementation of this function from being compiled:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%insert(cxxheader) %{
|
||||
#ifndef SWIG_swig_check_DEFINED
|
||||
#define SWIG_swig_check_DEFINED 1
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
class Exception : public std::runtime_error {
|
||||
public:
|
||||
explicit Exception(const char* msg) : std::runtime_error{msg} {}
|
||||
};
|
||||
|
||||
inline void swig_check() {
|
||||
if (auto* swig_ex = SWIG_CException_get_pending()) {
|
||||
Exception const e{SWIG_CException_msg_get(swig_ex)};
|
||||
SWIG_CException_reset_pending();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> T swig_check(T x) {
|
||||
swig_check();
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif // SWIG_swig_check_DEFINED
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,39 @@ SWIGEXPORTC void SWIG_CException_Raise(int code, const char* msg) {
|
|||
#endif // SWIG_CException_DEFINED
|
||||
%}
|
||||
|
||||
#ifdef SWIG_CXX_WRAPPERS
|
||||
|
||||
// This is somewhat of a hack, but our generated header may include another
|
||||
// generated header, when using multiple modules, and defining swig_check() in
|
||||
// all of them would result in errors, so we use SWIG_swig_check_DEFINED to
|
||||
// prevent this from happening.
|
||||
//
|
||||
// This also has a nice side effect of allowing the user code to predefine this
|
||||
// symbol and provide their own SWIG_swig_check_DEFINED implementation to
|
||||
// customize exception handling.
|
||||
%insert("cxxcode") %{
|
||||
#ifndef SWIG_swig_check_DEFINED
|
||||
#define SWIG_swig_check_DEFINED 1
|
||||
|
||||
inline void swig_check() {
|
||||
if (SWIG_CException* swig_ex = SWIG_CException::get_pending()) {
|
||||
SWIG_CException swig_ex_copy{*swig_ex};
|
||||
delete swig_ex;
|
||||
SWIG_CException::reset_pending();
|
||||
throw swig_ex_copy;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> T swig_check(T x) {
|
||||
swig_check();
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif // SWIG_swig_check_DEFINED
|
||||
%}
|
||||
|
||||
#endif // SWIG_CXX_WRAPPERS
|
||||
|
||||
%insert("runtime") "swigerrors.swg"
|
||||
|
||||
#define SWIG_exception(code, msg)\
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ struct cxx_wrappers
|
|||
|
||||
// Allow using SWIG directive to inject code here.
|
||||
Swig_register_filebyname("cxxheader", sect_cxx_h);
|
||||
Swig_register_filebyname("cxxcode", sect_impls);
|
||||
}
|
||||
|
||||
// This function must be called after initialize(). The two can't be combined because we don't yet know if we're going to use exceptions or not when we
|
||||
|
|
@ -426,26 +427,6 @@ struct cxx_wrappers
|
|||
void initialize_exceptions(exceptions_support support) {
|
||||
switch (support) {
|
||||
case exceptions_support_enabled:
|
||||
// Generate the functions which will be used in all wrappers to check for the exceptions only in this case, i.e. do not do it if they're already defined
|
||||
// in another module imported by this one.
|
||||
Printv(sect_impls,
|
||||
"inline void swig_check() {\n",
|
||||
cindent, "if (SWIG_CException* swig_ex = SWIG_CException::get_pending()) {\n",
|
||||
cindent, cindent, "SWIG_CException swig_ex_copy{*swig_ex};\n",
|
||||
cindent, cindent, "delete swig_ex;\n",
|
||||
cindent, cindent, "SWIG_CException::reset_pending();\n",
|
||||
cindent, cindent, "throw swig_ex_copy;\n",
|
||||
cindent, "}\n",
|
||||
"}\n\n",
|
||||
"template <typename T> T swig_check(T x) {\n",
|
||||
cindent, "swig_check();\n",
|
||||
cindent, "return x;\n",
|
||||
"}\n\n",
|
||||
NIL
|
||||
);
|
||||
|
||||
// fall through
|
||||
|
||||
case exceptions_support_imported:
|
||||
except_check_start = "swig_check(";
|
||||
except_check_end = ")";
|
||||
|
|
@ -1756,6 +1737,8 @@ public:
|
|||
Preprocessor_define("SWIG_C_EXCEPT 1", 0);
|
||||
if (CPlusPlus)
|
||||
Preprocessor_define("SWIG_CPPMODE 1", 0);
|
||||
if (use_cxx_wrappers)
|
||||
Preprocessor_define("SWIG_CXX_WRAPPERS 1", 0);
|
||||
|
||||
SWIG_library_directory("c");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue