mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Reorganize C++ exceptions; ref #3470
There are 3 levels of C++ exception handling: * default - no C++ exception (use setjmp/longjmp) * enable_cxx_exception (use C++ exceptions with C ABI) * enable_cxx_abi (use C++ ABI including exceptions)
This commit is contained in:
+12
-17
@@ -241,13 +241,15 @@ conf.enable_bintest
|
||||
|
||||
### C++ ABI
|
||||
|
||||
mruby can use C++ exception to raise exception internally.
|
||||
By using C++ exception it can release C++ stack object correctly.
|
||||
By default, mruby uses setjmp/longjmp to implement its
|
||||
exceptions. But it doesn't release C++ stack object
|
||||
correctly. To support mrbgems written in C++, mruby can be
|
||||
configured to use C++ exception.
|
||||
|
||||
There are two levels of C++ exception handling. The one is
|
||||
C++ exception enabled (but still C files are compiled by C
|
||||
compiler), and the other is C++ ABI mode where all files are
|
||||
compiled by C++ compiler.
|
||||
```enable_cxx_exception``` that enables C++ exception, but
|
||||
uses C ABI. The other is ```enable_cxx_abi``` where all
|
||||
files are compiled by C++ compiler.
|
||||
|
||||
When you mix C++ code, C++ exception would be enabled automatically.
|
||||
If you need to enable C++ exception explicitly add the following:
|
||||
@@ -255,23 +257,16 @@ If you need to enable C++ exception explicitly add the following:
|
||||
conf.enable_cxx_exception
|
||||
```
|
||||
|
||||
If you need to enable C++ ABI mode explicitly add the following:
|
||||
```ruby
|
||||
conf.enable_cxx_abi
|
||||
```
|
||||
|
||||
#### C++ exception disabling.
|
||||
|
||||
|
||||
If you need to force C++ exception disable
|
||||
(For example using a compiler option to disable C++ exception),
|
||||
but still want to use C++ ABI mode,
|
||||
add following:
|
||||
If your compiler does not support C++ and you want to ensure
|
||||
you don't use mrbgem written in C++, you can explicitly disable
|
||||
C++ exception, add following:
|
||||
```ruby
|
||||
conf.disable_cxx_exception
|
||||
```
|
||||
|
||||
Note that it must be called before ```enable_cxx_abi``` or ```gem``` method.
|
||||
and you will get an error when you try to use C++ gem.
|
||||
Note that it must be called before ```enable_cxx_exception``` or ```gem``` method.
|
||||
|
||||
### Debugging mode
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#ifndef MRB_THROW_H
|
||||
#define MRB_THROW_H
|
||||
|
||||
#if defined(MRB_ENABLE_CXX_EXCEPTION) && !defined(__cplusplus)
|
||||
#error Trying to use C++ exception handling in C code
|
||||
#if defined(MRB_ENABLE_CXX_ABI)
|
||||
# if !defined(__cplusplus)
|
||||
# error Trying to use C++ exception handling in C code
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
|
||||
|
||||
@@ -4,4 +4,10 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec|
|
||||
spec.summary = 'mruby command'
|
||||
spec.bins = %w(mruby)
|
||||
spec.add_dependency('mruby-compiler', :core => 'mruby-compiler')
|
||||
spec.add_dependency('mruby-error', :core => 'mruby-error')
|
||||
|
||||
if build.cxx_exception_enabled?
|
||||
@objs << build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
|
||||
@objs.delete_if { |v| v == objfile("#{spec.build_dir}/tools/mruby/mruby") }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,11 +8,11 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec|
|
||||
|
||||
lex_def = "#{current_dir}/core/lex.def"
|
||||
core_objs = Dir.glob("#{current_dir}/core/*.c").map { |f|
|
||||
next nil if build.cxx_abi_enabled? and f =~ /(codegen).c$/
|
||||
next nil if build.cxx_exception_enabled? and f =~ /(codegen).c$/
|
||||
objfile(f.pathmap("#{current_build_dir}/core/%n"))
|
||||
}.compact
|
||||
|
||||
if build.cxx_abi_enabled?
|
||||
if build.cxx_exception_enabled?
|
||||
core_objs <<
|
||||
build.compile_as_cxx("#{current_build_dir}/core/y.tab.c", "#{current_build_dir}/core/y.tab.cxx",
|
||||
objfile("#{current_build_dir}/y.tab"), ["#{current_dir}/core"]) <<
|
||||
|
||||
@@ -3,7 +3,7 @@ MRuby::Gem::Specification.new('mruby-error') do |spec|
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'extensional error handling'
|
||||
|
||||
if build.cxx_abi_enabled?
|
||||
if build.cxx_exception_enabled?
|
||||
@objs << build.compile_as_cxx("#{spec.dir}/src/exception.c", "#{spec.build_dir}/src/exception.cxx")
|
||||
@objs.delete_if { |v| v == objfile("#{spec.build_dir}/src/exception") }
|
||||
end
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@ MRuby.each_target do
|
||||
current_build_dir = "#{build_dir}/#{relative_from_root}"
|
||||
|
||||
objs = Dir.glob("#{current_dir}/*.c").map { |f|
|
||||
next nil if cxx_abi_enabled? and f =~ /(error|vm).c$/
|
||||
next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/
|
||||
objfile(f.pathmap("#{current_build_dir}/%n"))
|
||||
}.compact
|
||||
|
||||
if cxx_abi_enabled?
|
||||
if cxx_exception_enabled?
|
||||
objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" }
|
||||
end
|
||||
self.libmruby << objs
|
||||
|
||||
@@ -2583,3 +2583,7 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
|
||||
mrb_int mrb_jmpbuf::jmpbuf_id = 0;
|
||||
#endif
|
||||
|
||||
+24
-8
@@ -83,8 +83,9 @@ module MRuby
|
||||
@bins = []
|
||||
@gems, @libmruby = MRuby::Gem::List.new, []
|
||||
@build_mrbtest_lib_only = false
|
||||
@cxx_abi_enabled = false
|
||||
@cxx_exception_enabled = false
|
||||
@cxx_exception_disabled = false
|
||||
@cxx_abi_enabled = false
|
||||
@enable_bintest = false
|
||||
@enable_test = false
|
||||
@toolchains = []
|
||||
@@ -110,15 +111,28 @@ module MRuby
|
||||
end
|
||||
|
||||
def disable_cxx_exception
|
||||
if @cxx_exception_enabled or @cxx_abi_enabled
|
||||
raise "cxx_exception already enabled"
|
||||
end
|
||||
@cxx_exception_disabled = true
|
||||
end
|
||||
|
||||
def enable_cxx_exception
|
||||
@cxx_exception_disabled = false
|
||||
return if @cxx_exception_enabled
|
||||
return if @cxx_abi_enabled
|
||||
if @cxx_exception_disabled
|
||||
raise "cxx_exception disabled"
|
||||
end
|
||||
@cxx_exception_enabled = true
|
||||
compilers.each { |c|
|
||||
c.defines += %w(MRB_ENABLE_CXX_EXCEPTION)
|
||||
c.flags << c.cxx_exception_flag
|
||||
}
|
||||
linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
|
||||
end
|
||||
|
||||
def cxx_exception_enabled?
|
||||
@cxx_exception_enabled
|
||||
end
|
||||
|
||||
def cxx_abi_enabled?
|
||||
@@ -127,9 +141,13 @@ module MRuby
|
||||
|
||||
def enable_cxx_abi
|
||||
return if @cxx_abi_enabled
|
||||
unless @cxx_exception_disabled
|
||||
enable_cxx_exception
|
||||
if @cxx_exception_enabled
|
||||
raise "cxx_exception already enabled"
|
||||
end
|
||||
compilers.each { |c|
|
||||
c.defines += %w(MRB_ENABLE_CXX_EXCEPTION MRB_ENABLE_CXX_ABI)
|
||||
c.flags << c.cxx_compile_flag
|
||||
}
|
||||
compilers.each { |c| c.flags << c.cxx_compile_flag }
|
||||
linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
|
||||
@cxx_abi_enabled = true
|
||||
@@ -146,15 +164,13 @@ module MRuby
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#ifndef MRB_ENABLE_CXX_EXCEPTION
|
||||
#ifndef MRB_ENABLE_CXX_ABI
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "#{src}"
|
||||
#ifndef MRB_ENABLE_CXX_EXCEPTION
|
||||
#ifndef MRB_ENABLE_CXX_ABI
|
||||
}
|
||||
#endif
|
||||
|
||||
#{src == "#{MRUBY_ROOT}/src/error.c"? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''}
|
||||
EOS
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user