diff options
46 files changed, 681 insertions, 438 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..705b1f022 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,43 @@ +# About this file, see: +# Website: https://editorconfig.org/ +# For Emacs users: https://github.com/editorconfig/editorconfig-emacs +# For Vim users: https://github.com/editorconfig/editorconfig-vim + +root = true + +[*] +indent_style = tab +indent_size = 8 +tab_width = 8 +end_of_line = lf +charset = utf-8 +insert_final_newline = true + +[{Makefile,Makefile.*,makefile,*.mk}] +trim_trailing_whitespace = true +#max_line_length = 80 + +[*.{c,cc,C,cxx,cpp,h,hh,H,hxx,hpp,inc,y}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +#max_line_length = 120 + +[{*.rb,Rakefile,rakefile,*.rake,*.gemspec,*.gembox}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +#max_line_length = 120 + +[*.bat] +end_of_line = crlf +charset = latin1 +#max_line_length = 80 + +[*.{yaml,yml}] +indent_style = space +indent_size = 2 + +[*.md] +indent_style = space +indent_size = 2 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..dac4cac33 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +# Basic set up + +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 135e39ca7..435118e37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,18 +3,8 @@ name: Build & Test on: [push, pull_request] jobs: - Check-Skip: - if: | - !contains(github.event.head_commit.message, '[ci skip]') && - !contains(github.event.head_commit.message, '[skip ci]') && - !contains(github.event.head_commit.message, '[skip gha]') - runs-on: ubuntu-latest - steps: - - run: echo not skip - - Ubuntu-1604: - needs: Check-Skip - runs-on: ubuntu-16.04 + Ubuntu-1804-gcc: + runs-on: ubuntu-18.04 env: MRUBY_CONFIG: ci/gcc-clang CC: gcc @@ -27,11 +17,24 @@ jobs: - name: Build and test run: rake -m test:build && rake test:run - Ubuntu-1804-gcc: - needs: Check-Skip + Ubuntu-1804-clang: runs-on: ubuntu-18.04 env: MRUBY_CONFIG: ci/gcc-clang + CC: clang + steps: + - uses: actions/checkout@v2 + - name: Ruby version + run: ruby -v + - name: Compiler version + run: ${{ env.CC }} --version + - name: Build and test + run: rake -m test:build && rake test:run + + Ubuntu-2004-gcc: + runs-on: ubuntu-20.04 + env: + MRUBY_CONFIG: ci/gcc-clang CC: gcc steps: - uses: actions/checkout@v2 @@ -42,9 +45,8 @@ jobs: - name: Build and test run: rake -m test:build && rake test:run - Ubuntu-1804-clang: - needs: Check-Skip - runs-on: ubuntu-18.04 + Ubuntu-2004-clang: + runs-on: ubuntu-20.04 env: MRUBY_CONFIG: ci/gcc-clang CC: clang @@ -58,7 +60,6 @@ jobs: run: rake -m test:build && rake test:run macOS: - needs: Check-Skip runs-on: macos-latest env: MRUBY_CONFIG: ci/gcc-clang @@ -73,7 +74,6 @@ jobs: run: rake -m test:build && rake test:run Windows-MinGW: - needs: Check-Skip runs-on: windows-latest env: MRUBY_CONFIG: ci/gcc-clang @@ -88,7 +88,6 @@ jobs: run: rake -m test:build && rake test:run Windows-Cygwin: - needs: Check-Skip runs-on: windows-latest env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true @@ -100,7 +99,7 @@ jobs: cache-version: v1 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/[email protected] with: path: ${{ env.package-dir }} key: ${{ runner.os }}-cygwin-${{ env.cache-version }} @@ -134,7 +133,6 @@ jobs: run: echo '::set-env name=PATH::C:\windows\System32' Windows-VC: - needs: Check-Skip runs-on: windows-latest env: MRUBY_CONFIG: ci/msvc diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 19fb63b35..ea9f9bd8e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -8,10 +8,6 @@ on: jobs: CodeQL-Build: - if: | - !contains(github.event.head_commit.message, '[ci skip]') && - !contains(github.event.head_commit.message, '[skip ci]') && - !contains(github.event.head_commit.message, '[skip gha]') runs-on: ubuntu-latest diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ed1682b05..474890010 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,13 +3,6 @@ name: โ๏ธ Lint on: [pull_request] jobs: - yamllint: - name: ๐ถ YAML - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: ๐งน YAML Lint - uses: ibiqlik/action-yamllint@v3 markdownlint: name: ๐ธ Markdown runs-on: ubuntu-latest @@ -21,3 +14,39 @@ jobs: node-version: '12.x' - run: npm install -g [email protected] - run: markdownlint '**/*.md' + misspell: + name: ๐ฅ Check Spelling + runs-on: ubuntu-latest + steps: + - name: ๐ Check Out + uses: actions/checkout@v2 + - name: ๐
Install + run: | + wget -O - -q https://git.io/misspell | sh -s -- -b . + - name: ๐ถ๏ธ Misspell + run: | + git ls-files --empty-directory | xargs ./misspell -error + trailing-whitespace: + name: ๐ง Trailing whitespace + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: ๐งน Check for trailing whitespace + run: "! git grep -EIn $'[ \t]+$'" + yamllint: + name: ๐ถ YAML + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax + architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install yamllint + - name: ๐งน YAML Lint + run: | + # return non-zero exit code on warnings + yamllint --strict . diff --git a/.github/workflows/oss-fuzz.yml b/.github/workflows/oss-fuzz.yml index 8f2b24f17..0fd505624 100644 --- a/.github/workflows/oss-fuzz.yml +++ b/.github/workflows/oss-fuzz.yml @@ -2,10 +2,6 @@ name: CIFuzz on: [pull_request] jobs: Fuzzing: - if: | - !contains(github.event.head_commit.message, '[ci skip]') && - !contains(github.event.head_commit.message, '[skip ci]') && - !contains(github.event.head_commit.message, '[skip gha]') runs-on: ubuntu-latest steps: - name: Build Fuzzers @@ -20,7 +16,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/[email protected] if: failure() with: name: artifacts diff --git a/.github/workflows/spell-checker.yml b/.github/workflows/spell-checker.yml deleted file mode 100644 index 7e86e0198..000000000 --- a/.github/workflows/spell-checker.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: ๐ Spellchecker - -on: [pull_request] - -jobs: - misspell: - name: ๐งน Check Spelling - runs-on: ubuntu-latest - steps: - - name: ๐ Check Out - uses: actions/checkout@v2 - - name: ๐
Install - run: | - wget -O - -q https://git.io/misspell | sh -s -- -b . - - name: ๐ถ๏ธ Misspell - run: | - git ls-files --empty-directory | xargs ./misspell -error diff --git a/build_config/clang-asan.rb b/build_config/clang-asan.rb index 5ee0d9129..19cc53bf0 100644 --- a/build_config/clang-asan.rb +++ b/build_config/clang-asan.rb @@ -1,7 +1,7 @@ MRuby::Build.new do |conf| conf.toolchain :clang # include the GEM box - conf.gembox 'default' + conf.gembox 'full-core' # Turn on `enable_debug` for better debugging conf.enable_sanitizer "address,undefined" diff --git a/build_config/dreamcast_shelf.rb b/build_config/dreamcast_shelf.rb index a92770070..7e7d6a52e 100644 --- a/build_config/dreamcast_shelf.rb +++ b/build_config/dreamcast_shelf.rb @@ -20,7 +20,7 @@ MRuby::CrossBuild.new("dreamcast") do |conf| # C compiler # Flags were extracted from KallistiOS environment files conf.cc do |cc| - cc.command = "#{BIN_PATH}/sh-elf-gcc" + cc.command = "#{BIN_PATH}/sh-elf-gcc" cc.include_paths << ["#{KOS_PATH}/include", "#{KOS_PATH}/kernel/arch/dreamcast/include", "#{KOS_PATH}/addons/include", "#{KOS_PATH}/../kos-ports/include"] cc.flags << ["-O2", "-fomit-frame-pointer", "-ml", "-m4-single-only", "-ffunction-sections", "-fdata-sections", "-Wall", "-g", "-fno-builtin", "-ml", "-m4-single-only", "-Wl,-Ttext=0x8c010000", "-Wl,--gc-sections", "-T#{KOS_PATH}/utils/ldscripts/shlelf.xc", "-nodefaultlibs"] cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"] diff --git a/build_config/host-f32.rb b/build_config/host-f32.rb new file mode 100644 index 000000000..a449547ae --- /dev/null +++ b/build_config/host-f32.rb @@ -0,0 +1,14 @@ +MRuby::Build.new do |conf| + # load specific toolchain settings + toolchain :gcc + + # include the GEM box + conf.gembox 'default' + + conf.cc.defines << 'MRB_USE_FLOAT32' + + # Turn on `enable_debug` for better debugging + conf.enable_debug + conf.enable_test + conf.enable_bintest +end diff --git a/doc/guides/compile.md b/doc/guides/compile.md index a8e35b65c..eba0c87ff 100644 --- a/doc/guides/compile.md +++ b/doc/guides/compile.md @@ -10,19 +10,20 @@ To compile mruby out of the source code you need the following tools: * C Compiler (e.g. `gcc` or `clang`) * Linker (e.g. `gcc` or `clang`) * Archive utility (e.g. `ar`) -* Parser generator (`bison`) -* Ruby 2.0 or later (e.g. `ruby` or `jruby`) +* Ruby 2.5 or later (e.g. `ruby` or `jruby`) + +Optional: + +* Git (to update mruby source and integrate mrbgems easier) +* C++ compiler (to use mrbgems which include `*.cpp`, `*.cxx`, `*.cc`) +* Bison (to compile `mrbgems/mruby-compiler/core/parse.y`) +* gperf (to compile `mrbgems/mruby-compiler/core/keywords`) Note that `bison` bundled with MacOS is too old to compile `mruby`. Try `brew install bison` and follow the instruction shown to update the `$PATH` to compile `mruby`. We also encourage to upgrade `ruby` on MacOS in similar manner. -Optional: - -* git (to update mruby source and integrate mrbgems easier) -* C++ compiler (to use GEMs which include \*.cpp, \*.cxx, \*.cc) - ## Build To compile `mruby` with the default build configuration, just invoke `rake` @@ -32,7 +33,7 @@ line on build, call `rake -v`. You can specify your own configuration file by the `MRUBY_CONFIG` environment variable (you can use `CONFIG` for shorthand for `MRUBY_CONFIG`). If the path -doesn't exist, *build_config/${MRUBY_CONFIG}.rb* is used. The default +doesn't exist, `build_config/${MRUBY_CONFIG}.rb` is used. The default configuration is defined in the `build_config/default.rb` file. Those build configuration files contain the build configuration of mruby, for @@ -48,7 +49,7 @@ All tools necessary to compile mruby can be set or modified here. ## Build Configuration -We wish you submit a pull-request to *build_config/**PLATFORM**.rb*, once you +We wish you submit a pull-request to `build_config/PLATFORM.rb`, once you created a new configuration for a new platform. Inside of the configuration file, the following options can be @@ -228,7 +229,7 @@ end ### Preallocated Symbols -By far, preallocate symbols are highly compatible with the previous versions, so +By far, preallocated symbols are highly compatible with the previous versions, so we expect you won't see any problem with them. But just in case you face any issue, you can disable preallocated symbols by specifying `conf.disable_presym`. @@ -279,7 +280,7 @@ conf.build_mrbtest_lib_only ### Bintest Tests for mrbgem tools using CRuby. -To have bintests place \*.rb scripts to `bintest/` directory of mrbgems. +To have bintests place `*.rb` scripts to `bintest/` directory of mrbgems. See `mruby-bin-*/bintest/*.rb` if you need examples. If you want a temporary files use `tempfile` module of CRuby instead of `/tmp/`. @@ -354,7 +355,7 @@ end ``` All configuration options of `MRuby::Build` can also be used in -`MRuby::CrossBuild`. You can find examples under the *build_config* +`MRuby::CrossBuild`. You can find examples under the `build_config` directory. ### Mrbtest in Cross-Compilation @@ -375,49 +376,42 @@ end ## Build process -During the build process the directory *build* will be created in the +During the build process the directory `build` will be created in the root directory. The structure of this directory will look like this: +- build | +- host | + +- LEGAL <- License description + | +- bin <- Binaries (mirb, mrbc and mruby) | +- lib <- Libraries (libmruby.a and libmruby_core.a) | - +- mrblib + +- mrbc <- Minimal mrbc place | - +- src + +- mrbgems <- Compilation result from mrbgems | - +- test <- mrbtest tool + +- mrblib <- Compilation result from mrblib | - +- tools - | - +- mirb - | - +- mrbc - | - +- mruby + +- src <- Compilation result from C sources The compilation workflow will look like this: -* compile all files under *src* (object files will be stored -in *build/host/src*) -* generate parser grammar out of *src/parse.y* (generated -result will be stored in *build/host/src/y.tab.c*) -* compile *build/host/src/y.tab.c* to *build/host/src/y.tab.o* -* create *build/host/lib/libmruby_core.a* out of all object files (C only) -* create `build/host/bin/mrbc` by compiling *tools/mrbc/mrbc.c* and -linking with *build/host/lib/libmruby_core.a* -* create *build/host/mrblib/mrblib.c* by compiling all \*.rb files -under *mrblib* with `build/host/bin/mrbc` -* compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* -* create *build/host/lib/libmruby.a* out of all object files (C and Ruby) -* create `build/host/bin/mruby` by compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and -linking with *build/host/lib/libmruby.a* -* create `build/host/bin/mirb` by compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and -linking with *build/host/lib/libmruby.a* +* compile minimal `mrbc` from `src` and `mrblib` sources + * compile all files under `src` (object files will be stored in `build/host/mrbc/src`) + * compile `mruby-compiler` gem + * create `build/host/mrbc/lib/libmruby_core.a` out of all object files (C only) + * create `build/host/mrbc/bin/mrbc` via `mruby-bin-mrbc` gem +* compile all files under `src` and store result in `build/host/src` +* create `build/host/mrblib/mrblib.c` by compiling all `*.rb` files under `mrblib` with `build/host/mrbc/bin/mrbc` +* compile `build/host/mrblib/mrblib.c` to `build/host/mrblib/mrblib.o` +* create `build/host/lib/libmruby.a` out of all object files (C and Ruby) +* compile (normal) mrbgems specified in the configuration file +* create `build/host/lib/libmruby.a` from object files from gems and `libmruby_core.a` +* create binary commands according to binary gems (e.g. `mirb` and `mruby`) +* copy binaries under `build/host/bin` to `bin` directory ``` _____ _____ ______ ____ ____ _____ _____ ____ @@ -428,7 +422,7 @@ linking with *build/host/lib/libmruby.a* ### Cross-Compilation -In case of a cross-compilation to *i386* the *build* directory structure looks +In case of a cross-compilation to `i386` the `build` directory structure looks like this: +- build @@ -439,63 +433,41 @@ like this: | | | +- lib <- Native Libraries | | - | +- mrblib + | +- mrbgems | | | +- src - | | - | +- test <- Native mrbtest tool - | | - | +- tools - | | - | +- mirb - | | - | +- mrbc - | | - | +- mruby + | +- i386 | +- bin <- Cross-compiled Binaries | + +- include <- Header Directory + | +- lib <- Cross-compiled Libraries | + +- mrbgems + | +- mrblib | +- src - | - +- test <- Cross-compiled mrbtest tool - | - +- tools - | - +- mirb - | - +- mrbc - | - +- mruby An extra directory is created for the target platform. In case you -compile for *i386* a directory called *i386* is created under the +compile for `i386` a directory called `i386` is created under the build directory. The cross compilation workflow starts in the same way as the normal -compilation by compiling all *native* libraries and binaries. -Afterwards the cross compilation process proceeds like this: - -* cross-compile all files under *src* (object files will be stored -in *build/i386/src*) -* generate parser grammar out of *src/parse.y* (generated -result will be stored in *build/i386/src/y.tab.c*) -* cross-compile *build/i386/src/y.tab.c* to *build/i386/src/y.tab.o* -* create *build/i386/mrblib/mrblib.c* by compiling all \*.rb files -under *mrblib* with the native `build/host/bin/mrbc` -* cross-compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* -* create *build/i386/lib/libmruby.a* out of all object files (C and Ruby) -* create `build/i386/bin/mruby` by cross-compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and -linking with *build/i386/lib/libmruby.a* -* create `build/i386/bin/mirb` by cross-compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and -linking with *build/i386/lib/libmruby.a* -* create *build/i386/lib/libmruby_core.a* out of all object files (C only) -* create `build/i386/bin/mrbc` by cross-compiling *tools/mrbc/mrbc.c* and -linking with *build/i386/lib/libmruby_core.a* +compilation by compiling all *native* libraries and binaries, except +for we don't have `host/mrbc` directory (`host` directory itself works +as placeholder for `mrbc`). Afterwards the cross compilation process +proceeds like this: + +* cross-compile all files under `src` and store result in `build/i386/src` +* create `build/i386/lib/libmruby_core.a` out of C object files +* create `build/i386/mrblib/mrblib.c` by compiling all `*.rb` files under `mrblib` with native `build/host/bin/mrbc` +* cross-compile `build/i386/mrblib/mrblib.c` to `build/i386/mrblib/mrblib.o` +* create `build/i386/lib/libmruby.a` from object files from gems and `libmruby_core.a` +* create binary commands according to binary gems (e.g. `mirb` and `mruby`) +* copy binaries under `build/host/bin` to `bin` directory ``` _______________________________________________________________ @@ -526,24 +498,23 @@ feature due to the reason that there are functions (e.g. stdio) which can't be disabled for the main build. ```ruby -MRuby::CrossBuild.new('Minimal') do |conf| +MRuby::CrossBuild.new('minimal') do |conf| toolchain :gcc conf.cc.defines = %w(MRB_NO_STDIO) - conf.bins = [] end ``` -This configuration defines a cross compile build called 'Minimal' which +This configuration defines a cross compile build called 'minimal' which is using the GCC and compiles for the host machine. It also disables -all usages of stdio and doesn't compile any binaries (e.g. mrbc). +all usages of stdio and doesn't compile any binaries (e.g. `mrbc`). ## Test Environment mruby's build process includes a test environment. In case you start the testing of mruby, a native binary called `mrbtest` will be generated and executed. -This binary contains all test cases which are defined under *test/t*. In case -of a cross-compilation an additional cross-compiled *mrbtest* binary is +This binary contains all test cases which are defined under `test/t`. In case +of a cross-compilation an additional cross-compiled `mrbtest` binary is generated. You can copy this binary and run on your target system. ## Embedding `mruby` in Your Application @@ -562,6 +533,7 @@ Usage: mruby-config [switches] --ldflags-before-libs print flags passed to linker before linked libraries --libs print linked libraries --libmruby-path print libmruby path + --help print this help ``` For example, when you have a C source file (`c.c`) and try to diff --git a/doc/guides/mrbgems.md b/doc/guides/mrbgems.md index 5ad00a5f2..5a6396e97 100644 --- a/doc/guides/mrbgems.md +++ b/doc/guides/mrbgems.md @@ -1,12 +1,13 @@ # mrbgems mrbgems is a library manager to integrate C and Ruby extension in an easy and -standardised way into mruby. +standardised way into mruby. Conventionally, each mrbgem name is prefixed by +`mruby-`, e.g. `mruby-time` for a gem that provides `Time` class functionality. ## Usage You have to activate mrbgems explicitly in your build configuration. To add -a GEM, add the following line to your build configuration file, for example: +a gem, add the following line to your build configuration file, for example: ```ruby conf.gem '/path/to/your/gem/dir' @@ -69,7 +70,7 @@ into mruby, in the same format as if you were adding them to the build config via `config.gem`, but wrapped in an `MRuby::GemBox` object. GemBoxes are loaded into mruby via `config.gembox 'boxname'`. -Below we have created a GemBox containing *mruby-time* and *mrbgems-example*: +Below we have created a GemBox containing `mruby-time` and `mrbgems-example`: ```ruby MRuby::GemBox.new do |conf| @@ -79,10 +80,10 @@ end ``` As mentioned, the GemBox uses the same conventions as `MRuby::Build`. The GemBox -must be saved with a *.gembox* extension inside the *mrbgems* directory to to be +must be saved with a `.gembox` extension inside the `mrbgems` directory to to be picked up by mruby. -To use this example GemBox, we save it as `custom.gembox` inside the *mrbgems* +To use this example GemBox, we save it as `custom.gembox` inside the `mrbgems` directory in mruby, and add the following to your build configuration file inside the build block: @@ -90,8 +91,8 @@ the build block: conf.gembox 'custom' ``` -This will cause the *custom* GemBox to be read in during the build process, -adding *mruby-time* and *mrbgems-example* to the build. +This will cause the `custom` GemBox to be read in during the build process, +adding `mruby-time` and `mrbgems-example` to the build. If you want, you can put GemBox outside of mruby directory. In that case you must specify an absolute path like below. @@ -103,7 +104,7 @@ conf.gembox "#{ENV["HOME"]}/mygemboxes/custom" There are two GemBoxes that ship with mruby: [default](../../mrbgems/default.gembox) and [full-core](../../mrbgems/full-core.gembox). The [default](../../mrbgems/default.gembox) GemBox contains several core components of mruby, and [full-core](../../mrbgems/full-core.gembox) -contains every gem found in the *mrbgems* directory. +contains every gem found in the `mrbgems` directory. ## GEM Structure @@ -111,27 +112,29 @@ The maximal GEM structure looks like this: +- GEM_NAME <- Name of GEM | + +- README.md <- Readme for GEM + | + +- mrbgem.rake <- GEM Specification + | +- include/ <- Header for Ruby extension (will exported) | +- mrblib/ <- Source for Ruby extension | +- src/ <- Source for C extension | - +- test/ <- Test code (Ruby) - | - +- mrbgem.rake <- GEM Specification + +- tools/ <- Source for Executable (in C) | - +- README.md <- Readme for GEM + +- test/ <- Test code (Ruby) -The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src* -contains C/C++ files to extend mruby. The folder *include* contains C/C++ header -files. The folder *test* contains C/C++ and pure Ruby files for testing purposes -which will be used by `mrbtest`. *mrbgem.rake* contains the specification -to compile C and Ruby files. *README.md* is a short description of your GEM. +The folder `mrblib` contains pure Ruby files to extend mruby. The folder `src` +contains C/C++ files to extend mruby. The folder `include` contains C/C++ header +files. The folder `test` contains C/C++ and pure Ruby files for testing purposes +which will be used by `mrbtest`. `mrbgem.rake` contains the specification +to compile C and Ruby files. `README.md` is a short description of your GEM. ## Build process -mrbgems expects a specification file called *mrbgem.rake* inside of your +mrbgems expects a specification file called `mrbgem.rake` inside of your GEM directory. A typical GEM specification could look like this for example: ```ruby @@ -143,7 +146,7 @@ end ``` The mrbgems build process will use this specification to compile Object and Ruby -files. The compilation results will be added to *lib/libmruby.a*. This file exposes +files. The compilation results will be added to `lib/libmruby.a`. This file exposes the GEM functionality to tools like `mruby` and `mirb`. The following properties can be set inside of your `MRuby::Gem::Specification` for @@ -265,7 +268,7 @@ integrate C libraries into mruby. mrbgems expects that you have implemented a C method called `mrb_YOURGEMNAME_gem_init(mrb_state)`. `YOURGEMNAME` will be replaced -by the name of your GEM. If you call your GEM *c_extension_example*, your +by the name of your GEM. If you call your GEM `c_extension_example`, your initialisation method could look like this: ```C @@ -280,7 +283,7 @@ mrb_c_extension_example_gem_init(mrb_state* mrb) { mrbgems expects that you have implemented a C method called `mrb_YOURGEMNAME_gem_final(mrb_state)`. `YOURGEMNAME` will be replaced -by the name of your GEM. If you call your GEM *c_extension_example*, your +by the name of your GEM. If you call your GEM `c_extension_example`, your finalizer method could look like this: ```C @@ -294,6 +297,8 @@ mrb_c_extension_example_gem_final(mrb_state* mrb) { +- c_extension_example/ | + +- README.md (Optional) + | +- src/ | | | +- example.c <- C extension source @@ -303,13 +308,11 @@ mrb_c_extension_example_gem_final(mrb_state* mrb) { | +- example.rb <- Test code for C extension | +- mrbgem.rake <- GEM specification - | - +- README.md ## Ruby Extension mruby can be extended with pure Ruby. It is possible to override existing -classes or add new ones in this way. Put all Ruby files into the *mrblib* +classes or add new ones in this way. Put all Ruby files into the `mrblib` folder. ### Pre-Conditions @@ -320,25 +323,25 @@ none +- ruby_extension_example/ | + +- README.md (Optional) + | +- mrblib/ | | - | +- example.rb <- Ruby extension source + | +- example.rb <- Ruby extension source | +- test/ | | - | +- example.rb <- Test code for Ruby extension + | +- example.rb <- Test code for Ruby extension | - +- mrbgem.rake <- GEM specification - | - +- README.md + +- mrbgem.rake <- GEM specification ## C and Ruby Extension mruby can be extended with C and Ruby at the same time. It is possible to override existing classes or add new ones in this way. Put all Ruby files -into the *mrblib* folder and all C files into the *src* folder. +into the `mrblib` folder and all C files into the `src` folder. -mruby codes under *mrblib* directory would be executed after gem init C +mruby codes under `mrblib` directory would be executed after gem init C function is called. Make sure *mruby script* depends on *C code* and *C code* doesn't depend on *mruby script*. @@ -350,18 +353,55 @@ See C and Ruby example. +- c_and_ruby_extension_example/ | + +- README.md (Optional) + | +- mrblib/ | | - | +- example.rb <- Ruby extension source + | +- example.rb <- Ruby extension source | +- src/ | | - | +- example.c <- C extension source + | +- example.c <- C extension source | +- test/ | | - | +- example.rb <- Test code for C and Ruby extension + | +- example.rb <- Test code for C and Ruby extension | - +- mrbgem.rake <- GEM specification + +- mrbgem.rake <- GEM specification + +## Binary gems + +Some gems can generate executables under `bin` directory. Those gems are called +binary gems. Names of binary gems are conventionally prefixed by `mruby-bin`, +e.g. `mruby-bin-mirb` and `mruby-bin-strip`. + +To specify the name of executable, you need to specify `spec.bins` in the +`mrbgem.rake`. The entry point `main()` should be in the C source file under +`tools/<bin>/*.c` where `<bin>` is a name of the executable. C files under the +`<bin>` directory are compiled and linked to the executable, but not included in +`libmruby.a`, whereas files under `mrblib` and `src` are. + +It is strongly recommended not to include `mrblib` and `src` directories in the +binary gems, to separate normal gems and binary gems. + +### Example + + +- mruby-bin-example/ + | + +- README.md (Optional) + | + +- bintest/ + | | + | +- example.rb <- Test code for binary gem + | + +- mrbgem.rake <- Gem specification + | + +- mrblib/ <- Source for Ruby extension (Optional) + | + +- src/ <- Source for C extension (Optional) | - +- README.md + +- tools/ + | + +- example/ <- Executable name directory + | + +- example.c <- Source for Executable (includes main) diff --git a/doc/mruby3.md b/doc/mruby3.md index ebd2673d5..b17f3d526 100644 --- a/doc/mruby3.md +++ b/doc/mruby3.md @@ -160,4 +160,4 @@ For better and faster random number generation. Preallocated symbols are interned at compile-time. They can be accessed via symbols macros (e.g. `MRB_SYM()`). -See [Symbols](https://github.com/mruby/mruby/blob/master/doc/guides/symbol.md). +See [Symbols](./guides/symbol.md). diff --git a/include/mruby/array.h b/include/mruby/array.h index da811606a..16f78f773 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -21,7 +21,7 @@ typedef struct mrb_shared_array { mrb_value *ptr; } mrb_shared_array; -#if defined(MRB_32BIT) && defined(MRB_NO_BOXING) +#if defined(MRB_32BIT) && defined(MRB_NO_BOXING) && !defined(MRB_USE_FLOAT32) # define MRB_ARY_NO_EMBED # define MRB_ARY_EMBED_LEN_MAX 0 #else @@ -65,7 +65,7 @@ struct RArray { #define ARY_EMBED_PTR(a) ((a)->as.ary) #endif -#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) +#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(mrb_int)(a)->as.heap.len) #define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) #define RARRAY_LEN(a) ARY_LEN(RARRAY(a)) #define RARRAY_PTR(a) ARY_PTR(RARRAY(a)) @@ -107,7 +107,7 @@ MRB_API mrb_value mrb_ary_new(mrb_state *mrb); * Array[value1, value2, ...] * * @param mrb The mruby state reference. - * @param size The numer of values. + * @param size The number of values. * @param vals The actual values. * @return The initialized array. */ diff --git a/include/mruby/dump.h b/include/mruby/dump.h index ed0c64b1a..3c48866d9 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -16,7 +16,10 @@ */ MRB_BEGIN_DECL -#define DUMP_DEBUG_INFO 1 +/* flags for mrb_dump_irep{,_binary,_cfunc,_cstruct} */ +#define MRB_DUMP_DEBUG_INFO 1 +#define MRB_DUMP_STATIC 2 +#define DUMP_DEBUG_INFO MRB_DUMP_DEBUG_INFO /* deprecated */ int mrb_dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size); #ifndef MRB_NO_STDIO diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index a79732802..b9f26d49f 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -248,7 +248,7 @@ module MRuby end end else - cxx_src = "#{build_dir}/#{src.relative_path})".ext << "-cxx.cxx" + cxx_src = "#{build_dir}/#{src.relative_path.to_s.remove_leading_parents}".ext << "-cxx.cxx" obj = cxx_src.ext(@exts.object) end diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 9d70ac086..dbe3763d9 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -328,13 +328,16 @@ module MRuby @compile_options = "-B%{funcname} -o-" end - def run(out, infiles, funcname, cdump = true) + def run(out, infiles, funcname, cdump: true, static: false) @command ||= @build.mrbcfile infiles = [infiles].flatten infiles.each_with_index do |f, i| _pp i == 0 ? "MRBC" : "", f.relative_path, indent: 2 end - cmd = %Q["#{filename @command}" #{cdump ? "-S" : ""} #{@compile_options % {:funcname => funcname}} #{filename(infiles).map{|f| %Q["#{f}"]}.join(' ')}] + opt = @compile_options % {funcname: funcname} + opt << " -S" if cdump + opt << " -s" if static + cmd = %["#{filename @command}" #{opt} #{filename(infiles).map{|f| %["#{f}"]}.join(' ')}] puts cmd if Rake.verbose IO.popen(cmd, 'r+') do |io| out.puts io.read diff --git a/lib/mruby/core_ext.rb b/lib/mruby/core_ext.rb index 33454edad..1ad528c26 100644 --- a/lib/mruby/core_ext.rb +++ b/lib/mruby/core_ext.rb @@ -18,6 +18,10 @@ class String def relative_path relative_path_from(Dir.pwd) end + + def remove_leading_parents + Pathname.new(".#{Pathname.new("/#{self}").cleanpath}").cleanpath.to_s + end end def install_D(src, dst) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 48a14fc54..716f21286 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -119,6 +119,10 @@ module MRuby @dir.start_with?("#{MRUBY_ROOT}/mrbgems/") end + def bin? + @bins.size > 0 + end + def add_dependency(name, *requirements) default_gem = requirements.last.kind_of?(Hash) ? requirements.pop : nil requirements = ['>= 0.0.0'] if requirements.empty? @@ -194,10 +198,11 @@ module MRuby open(fname, 'w') do |f| print_gem_init_header f unless rbfiles.empty? + opts = {cdump: cdump?, static: true} if cdump? - build.mrbc.run f, rbfiles, "gem_mrblib_#{funcname}_proc" + build.mrbc.run f, rbfiles, "gem_mrblib_#{funcname}_proc", **opts else - build.mrbc.run f, rbfiles, "gem_mrblib_irep_#{funcname}", false + build.mrbc.run f, rbfiles, "gem_mrblib_irep_#{funcname}", **opts end end f.puts %Q[void mrb_#{funcname}_gem_init(mrb_state *mrb);] @@ -496,8 +501,10 @@ module MRuby end end - def linker_attrs - map{|g| g.linker.run_attrs}.transpose + def linker_attrs(gem=nil) + gems = self.reject{|g| g.bin?} # library gems + gems << gem unless gem.nil? + gems.map{|g| g.linker.run_attrs}.transpose end end # List end # Gem diff --git a/mrbgems/mruby-bin-debugger/bintest/print.rb b/mrbgems/mruby-bin-debugger/bintest/print.rb index 4a4339f5a..63ebded3e 100644 --- a/mrbgems/mruby-bin-debugger/bintest/print.rb +++ b/mrbgems/mruby-bin-debugger/bintest/print.rb @@ -264,7 +264,7 @@ SRC BinTest_MrubyBinDebugger.test(src, tc) end -assert('mruby-bin-debugger(print) same name:instance variabe') do +assert('mruby-bin-debugger(print) same name:instance variable') do # ruby source (bp is break point) src = <<"SRC" @iv = 'top' @@ -296,7 +296,7 @@ SRC BinTest_MrubyBinDebugger.test(src, tc) end -# Kernel#instance_eval(string) does't work const. +# Kernel#instance_eval(string) doesn't work const. =begin assert('mruby-bin-debugger(print) same name:const') do # ruby source (bp is break point) diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index 31a4e6fa1..e17f32a2e 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -14,17 +14,17 @@ #define C_EXT ".c" struct mrbc_args { - int argc; - char **argv; - int idx; const char *prog; const char *outfile; const char *initname; + char **argv; + int argc; + int idx; mrb_bool dump_struct : 1; mrb_bool check_syntax : 1; mrb_bool verbose : 1; mrb_bool remove_lv : 1; - unsigned int flags : 4; + uint8_t flags : 4; }; static void @@ -38,6 +38,7 @@ usage(const char *name) "-g produce debugging information", "-B<symbol> binary <symbol> output in C language format", "-S dump C struct (requires -B)", + "-s define <symbol> as static variable", "--remove-lv remove local variables", "--verbose run at verbose mode", "--version print the version", @@ -131,7 +132,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) args->verbose = TRUE; break; case 'g': - args->flags |= DUMP_DEBUG_INFO; + args->flags |= MRB_DUMP_DEBUG_INFO; + break; + case 's': + args->flags |= MRB_DUMP_STATIC; break; case 'E': case 'e': diff --git a/mrbgems/mruby-catch/mrblib/catch.rb b/mrbgems/mruby-catch/mrblib/catch.rb index 68b165c8d..9a60a67a3 100644 --- a/mrbgems/mruby-catch/mrblib/catch.rb +++ b/mrbgems/mruby-catch/mrblib/catch.rb @@ -1,22 +1,8 @@ -class ThrowCatchJump < Exception - attr_reader :_tag, :_val - def initialize(tag, val) - @_tag = tag - @_val = val +class UncaughtThrowError < ArgumentError + attr_reader :tag, :value + def initialize(tag, value) + @tag = tag + @value = value super("uncaught throw #{tag.inspect}") end end - -module Kernel - def catch(tag=Object.new, &block) - block.call(tag) - rescue ThrowCatchJump => e - unless e._tag.equal?(tag) - raise e - end - return e._val - end - def throw(tag, val=nil) - raise ThrowCatchJump.new(tag, val) - end -end diff --git a/mrbgems/mruby-catch/src/catch.c b/mrbgems/mruby-catch/src/catch.c new file mode 100644 index 000000000..d910cac7f --- /dev/null +++ b/mrbgems/mruby-catch/src/catch.c @@ -0,0 +1,128 @@ +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/variable.h> +#include <mruby/error.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> +#include <mruby/presym.h> + + +MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms_3, 1, MRB_SYM(call)) +static const mrb_code catch_iseq_3[18] = { + OP_ENTER, 0x00, 0x00, 0x00, + OP_GETUPVAR, 0x02, 0x02, 0x01, + OP_GETUPVAR, 0x03, 0x01, 0x01, + OP_SEND, 0x02, 0x00, 0x01, + OP_RETURN, 0x02,}; +static const mrb_irep catch_irep_3 = { + 2,5,0, + MRB_IREP_STATIC,catch_iseq_3, + NULL,catch_syms_3,NULL, + NULL, + NULL, + 18,0,1,0,0 +}; +static const mrb_irep *catch_reps_2[1] = { + &catch_irep_3, +}; +static const mrb_code catch_iseq_2[13] = { + OP_ENTER, 0x00, 0x00, 0x00, + OP_LAMBDA, 0x02, 0x00, + OP_SEND, 0x02, 0x00, 0x00, + OP_RETURN, 0x02,}; +static const mrb_irep catch_irep_2 = { + 2,4,0, + MRB_IREP_STATIC,catch_iseq_2, + NULL,catch_syms_3,catch_reps_2, + NULL, + NULL, + 13,0,1,1,0 +}; +static const mrb_irep *catch_reps_1[1] = { + &catch_irep_2, +}; +MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms_1, 3, MRB_SYM(Object), MRB_SYM(new), MRB_SYM(call)) +static const mrb_code catch_iseq_1[29] = { + OP_ENTER, 0x00, 0x20, 0x01, + OP_JMP, 0x00, 0x03, + OP_JMP, 0x00, 0x0a, + OP_GETCONST, 0x03, 0x00, + OP_SEND, 0x03, 0x01, 0x00, + OP_MOVE, 0x01, 0x03, + OP_LAMBDA, 0x03, 0x00, + OP_SEND, 0x03, 0x02, 0x00, + OP_RETURN, 0x03,}; +static const mrb_irep catch_irep = { + 3,5,0, + MRB_IREP_STATIC,catch_iseq_1, + NULL,catch_syms_1,catch_reps_1, + NULL, + NULL, + 29,0,3,1,0 +}; + +#define ID_PRESERVED_CATCH MRB_SYM(__preserved_catch_proc) + +static const mrb_callinfo * +find_catcher(mrb_state *mrb, mrb_value tag) +{ + mrb_value pval = mrb_obj_iv_get(mrb, (struct RObject *)mrb->kernel_module, ID_PRESERVED_CATCH); + mrb_assert(mrb_proc_p(pval)); + const struct RProc *proc = mrb_proc_ptr(pval); + + const mrb_callinfo *ci = mrb->c->ci; + size_t n = ci - mrb->c->cibase; + ci--; + for (; n > 0; n--, ci--) { + const mrb_value *arg1 = ci->stack + 1; + if (ci->proc == proc && mrb_obj_eq(mrb, *arg1, tag)) { + return ci; + } + } + + return NULL; +} + +static mrb_value +mrb_f_throw(mrb_state *mrb, mrb_value self) +{ + mrb_value tag, obj; + if (mrb_get_args(mrb, "o|o", &tag, &obj) == 1) { + obj = mrb_nil_value(); + } + + const mrb_callinfo *ci = find_catcher(mrb, tag); + if (ci) { + struct RBreak *b = (struct RBreak *)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL); + mrb_break_value_set(b, obj); + mrb_break_proc_set(b, ci[2].proc); /* Back to the closure in `catch` method */ + mrb_exc_raise(mrb, mrb_obj_value(b)); + } + else { + mrb_value argv[2] = {tag, obj}; + mrb_exc_raise(mrb, mrb_obj_new(mrb, mrb_exc_get_id(mrb, MRB_ERROR_SYM(UncaughtThrowError)), 2, argv)); + } + /* not reached */ + return mrb_nil_value(); +} + +void +mrb_mruby_catch_gem_init(mrb_state *mrb) +{ + struct RProc *p; + mrb_method_t m; + + MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_3); + MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_1); + p = mrb_proc_new(mrb, &catch_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, mrb->kernel_module, MRB_SYM(catch), m); + mrb_obj_iv_set(mrb, (struct RObject *)mrb->kernel_module, ID_PRESERVED_CATCH, mrb_obj_value(p)); + + mrb_define_method(mrb, mrb->kernel_module, "throw", mrb_f_throw, MRB_ARGS_ARG(1,1)); +} + +void +mrb_mruby_catch_gem_final(mrb_state *mrb) +{ +} diff --git a/mrbgems/mruby-catch/test/catch.rb b/mrbgems/mruby-catch/test/catch.rb index fe5bda096..38a4eb907 100644 --- a/mrbgems/mruby-catch/test/catch.rb +++ b/mrbgems/mruby-catch/test/catch.rb @@ -3,10 +3,14 @@ assert "return throw value" do result = catch :foo do loop do loop do - throw :foo, val + begin + throw :foo, val + rescue Exception + flunk("should not reach here 1") + end break end - flunk("should not reach here") + flunk("should not reach here 2") end false end @@ -30,13 +34,16 @@ assert "pass the given tag to block" do catch(tag){|t| assert_same(tag, t)} end -assert "tag identity" do - assert_raise_with_message_pattern(Exception, "uncaught throw *") do - catch [:tag] do - throw [:tag] - end - flunk("should not reach here") +assert "tag identity, uncaught throw" do + tag, val = [:tag], [:val] + catch [:tag] do + throw tag, val end + flunk("should not reach here") +rescue Exception => e + assert_match("uncaught throw *", e.message) + assert_same(tag, e.tag) + assert_same(val, e.value) end assert "without catch arguments" do diff --git a/mrbgems/mruby-cmath/mrbgem.rake b/mrbgems/mruby-cmath/mrbgem.rake index e00725fef..00ac4b091 100644 --- a/mrbgems/mruby-cmath/mrbgem.rake +++ b/mrbgems/mruby-cmath/mrbgem.rake @@ -1,5 +1,5 @@ # This `mruby-cmath` gem uses C99 _Complex features -# You need C compler that support C99+ +# You need C compiler that support C99+ MRuby::Gem::Specification.new('mruby-cmath') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' diff --git a/mrbgems/mruby-cmath/src/cmath.c b/mrbgems/mruby-cmath/src/cmath.c index 857b58d26..03b181840 100644 --- a/mrbgems/mruby-cmath/src/cmath.c +++ b/mrbgems/mruby-cmath/src/cmath.c @@ -6,7 +6,7 @@ /* ** This `mruby-cmath` gem uses C99 _Complex features -** You need C compler that support C99+ +** You need C compiler that support C99+ */ #include <mruby.h> @@ -47,10 +47,10 @@ cmath_get_complex(mrb_state *mrb, mrb_value c, mrb_float *r, mrb_float *i) #ifdef MRB_USE_FLOAT32 #define F(x) x##f #else -#endif #define F(x) x +#endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW32__) #ifdef MRB_USE_FLOAT32 typedef _Fcomplex mrb_complex; @@ -91,7 +91,6 @@ CXDIVc(mrb_complex a, mrb_complex b) return CX(cr, ci); } - #else #if defined(__cplusplus) && defined(__APPLE__) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1a97b3ec6..1a07cc14b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -1450,7 +1450,7 @@ heredoc_end(parser_state *p) %token <nd> tSTRING tSTRING_PART tSTRING_MID %token <nd> tNTH_REF tBACK_REF %token <num> tREGEXP_END -%token <num> tNUMPARAM "numbered paraemeter" +%token <num> tNUMPARAM "numbered parameter" %type <nd> singleton string string_fragment string_rep string_interp xstring regexp %type <nd> literal numeric cpath symbol defn_head defs_head @@ -4682,6 +4682,7 @@ heredoc_remove_indent(parser_state *p, parser_heredoc_info *hinf) start = 0; while (start < len) { end = escaped ? (size_t)escaped->car : len; + if (end > len) end = len; spaces = (size_t)nspaces->car; size_t esclen = end - start; heredoc_count_indent(hinf, str + start, esclen, spaces, &offset); diff --git a/mrbgems/mruby-compiler/core/y.tab.c b/mrbgems/mruby-compiler/core/y.tab.c index 6c7940a7b..3e5c6e116 100644 --- a/mrbgems/mruby-compiler/core/y.tab.c +++ b/mrbgems/mruby-compiler/core/y.tab.c @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ + along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -2085,7 +2085,7 @@ static const char *const yytname[] = "\"constant\"", "\"class variable\"", "\"label\"", "\"integer literal\"", "\"float literal\"", "\"character literal\"", "tXSTRING", "tREGEXP", "tSTRING", "tSTRING_PART", "tSTRING_MID", "tNTH_REF", "tBACK_REF", - "tREGEXP_END", "\"numbered paraemeter\"", "\"unary plus\"", + "tREGEXP_END", "\"numbered parameter\"", "\"unary plus\"", "\"unary minus\"", "\"<=>\"", "\"==\"", "\"===\"", "\"!=\"", "\">=\"", "\"<=\"", "\"&&\"", "\"||\"", "\"=~\"", "\"!~\"", "\"..\"", "\"...\"", "tBDOT2", "tBDOT3", "tAREF", "tASET", "\"<<\"", "\">>\"", "\"::\"", @@ -10718,6 +10718,7 @@ heredoc_remove_indent(parser_state *p, parser_heredoc_info *hinf) start = 0; while (start < len) { end = escaped ? (size_t)escaped->car : len; + if (end > len) end = len; spaces = (size_t)nspaces->car; size_t esclen = end - start; heredoc_count_indent(hinf, str + start, esclen, spaces, &offset); diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c index 6345420ed..9c85858fe 100644 --- a/mrbgems/mruby-hash-ext/src/hash-ext.c +++ b/mrbgems/mruby-hash-ext/src/hash-ext.c @@ -74,7 +74,7 @@ hash_slice(mrb_state *mrb, mrb_value hash) * hsh.except(*keys) -> a_hash * * Returns a hash excluding the given keys and their values. - * + * * h = { a: 100, b: 200, c: 300 } * h.except(:a) #=> {:b=>200, :c=>300} * h.except(:b, :c, :d) #=> {:a=>100} diff --git a/mrbgems/mruby-math/test/math.rb b/mrbgems/mruby-math/test/math.rb index 959eef788..6ea06151c 100644 --- a/mrbgems/mruby-math/test/math.rb +++ b/mrbgems/mruby-math/test/math.rb @@ -9,27 +9,18 @@ def assert_float_and_int(exp_ary, act_ary) end end -assert('Math.sin 0') do +assert('Math.sin') do assert_float(0, Math.sin(0)) -end - -assert('Math.sin PI/2') do assert_float(1, Math.sin(Math::PI / 2)) end -assert('Math.cos 0') do +assert('Math.cos') do assert_float(1, Math.cos(0)) -end - -assert('Math.cos PI/2') do assert_float(0, Math.cos(Math::PI / 2)) end -assert('Math.tan 0') do +assert('Math.tan') do assert_float(0, Math.tan(0)) -end - -assert('Math.tan PI/4') do assert_float(1, Math.tan(Math::PI / 4)) end @@ -49,52 +40,27 @@ assert('Fundamental trig identities') do end end -assert('Math.erf 0') do - assert_float(0, Math.erf(0)) -end - -assert('Math.exp 0') do +assert('Math.exp') do assert_float(1.0, Math.exp(0)) -end - -assert('Math.exp 1') do assert_float(2.718281828459045, Math.exp(1)) -end - -assert('Math.exp 1.5') do assert_float(4.4816890703380645, Math.exp(1.5)) end -assert('Math.log 1') do +assert('Math.log') do assert_float(0, Math.log(1)) -end - -assert('Math.log E') do assert_float(1.0, Math.log(Math::E)) -end - -assert('Math.log E**3') do assert_float(3.0, Math.log(Math::E**3)) end -assert('Math.log2 1') do +assert('Math.log2') do assert_float(0.0, Math.log2(1)) -end - -assert('Math.log2 2') do assert_float(1.0, Math.log2(2)) end -assert('Math.log10 1') do +assert('Math.log10') do assert_float(0.0, Math.log10(1)) -end - -assert('Math.log10 10') do assert_float(1.0, Math.log10(10)) -end - -assert('Math.log10 10**100') do - assert_float(100.0, Math.log10(10**100)) + assert_float(30.0, Math.log10(10**30)) end assert('Math.sqrt') do @@ -117,19 +83,14 @@ assert('Math.hypot') do assert_float(5.0, Math.hypot(3, 4)) end -assert('Math.erf 1') do +assert('Math.erf') do + assert_float(0, Math.erf(0)) assert_float(0.842700792949715, Math.erf(1)) -end - -assert('Math.erfc 1') do - assert_float(0.157299207050285, Math.erfc(1)) -end - -assert('Math.erf -1') do assert_float(-0.8427007929497148, Math.erf(-1)) end -assert('Math.erfc -1') do +assert('Math.erfc') do + assert_float(0.157299207050285, Math.erfc(1)) assert_float(1.8427007929497148, Math.erfc(-1)) end diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 9081c2eec..618ffa805 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -156,10 +156,10 @@ rational_new_i(mrb_state *mrb, mrb_int n, mrb_int d) if (d == 0) { rat_zerodiv(mrb); } - a = i_gcd(n, d); - if ((n == MRB_INT_MIN || d == MRB_INT_MIN) && a == -1) { + if (n == MRB_INT_MIN || d == MRB_INT_MIN) { rat_overflow(mrb); } + a = i_gcd(n, d); return rational_new(mrb, n/a, d/a); } diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/sleep.c index 79a5af650..79a5af650 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/sleep.c diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index 8f99f9cd0..0a8166bae 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -10,11 +10,11 @@ assert('String#%') do assert_equal 15, ("%b" % (1<<14)).size skip unless Object.const_defined?(:Float) assert_equal "1.0", "%3.1f" % 1.01 - assert_equal " 123456789.12", "% 4.2f" % 123456789.123456789 - assert_equal "123456789.12", "%-4.2f" % 123456789.123456789 - assert_equal "+123456789.12", "%+4.2f" % 123456789.123456789 - assert_equal "123456789.12", "%04.2f" % 123456789.123456789 - assert_equal "00000000123456789.12", "%020.2f" % 123456789.123456789 + assert_equal " 1234567.12", "% 4.2f" % 1234567.123456789 + assert_equal "1234567.12", "%-4.2f" % 1234567.123456789 + assert_equal "+1234567.12", "%+4.2f" % 1234567.123456789 + assert_equal "1234567.12", "%04.2f" % 1234567.123456789 + assert_equal "00000000001234567.12", "%020.2f" % 1234567.123456789 end assert('String#% with inf') do diff --git a/mrbgems/mruby-struct/mrblib/struct.rb b/mrbgems/mruby-struct/mrblib/struct.rb index b398409c3..2439e2a37 100644 --- a/mrbgems/mruby-struct/mrblib/struct.rb +++ b/mrbgems/mruby-struct/mrblib/struct.rb @@ -2,99 +2,96 @@ # Struct # # ISO 15.2.18 +class Struct -if Object.const_defined?(:Struct) - class Struct + ## + # Calls the given block for each element of +self+ + # and pass the respective element. + # + # ISO 15.2.18.4.4 + def each(&block) + self.class.members.each{|field| + block.call(self[field]) + } + self + end - ## - # Calls the given block for each element of +self+ - # and pass the respective element. - # - # ISO 15.2.18.4.4 - def each(&block) - self.class.members.each{|field| - block.call(self[field]) - } - self - end + ## + # Calls the given block for each element of +self+ + # and pass the name and value of the respective + # element. + # + # ISO 15.2.18.4.5 + def each_pair(&block) + self.class.members.each{|field| + block.call(field.to_sym, self[field]) + } + self + end - ## - # Calls the given block for each element of +self+ - # and pass the name and value of the respective - # element. - # - # ISO 15.2.18.4.5 - def each_pair(&block) - self.class.members.each{|field| - block.call(field.to_sym, self[field]) - } - self - end + ## + # Calls the given block for each element of +self+ + # and returns an array with all elements of which + # block is not false. + # + # ISO 15.2.18.4.7 + def select(&block) + ary = [] + self.class.members.each{|field| + val = self[field] + ary.push(val) if block.call(val) + } + ary + end - ## - # Calls the given block for each element of +self+ - # and returns an array with all elements of which - # block is not false. - # - # ISO 15.2.18.4.7 - def select(&block) - ary = [] - self.class.members.each{|field| - val = self[field] - ary.push(val) if block.call(val) - } - ary + def _inspect(recur_list) + return "#<struct #{self.class}:...>" if recur_list[self.object_id] + recur_list[self.object_id] = true + name = self.class.to_s + if name[0] == "#" + str = "#<struct " + else + str = "#<struct #{name} " end - - def _inspect(recur_list) - return "#<struct #{self.class}:...>" if recur_list[self.object_id] - recur_list[self.object_id] = true - name = self.class.to_s - if name[0] == "#" - str = "#<struct " - else - str = "#<struct #{name} " - end - buf = [] - self.each_pair do |k,v| - buf.push k.to_s + "=" + v._inspect(recur_list) - end - str + buf.join(", ") + ">" + buf = [] + self.each_pair do |k,v| + buf.push k.to_s + "=" + v._inspect(recur_list) end + str + buf.join(", ") + ">" + end - ## - # call-seq: - # struct.to_s -> string - # struct.inspect -> string - # - # Describe the contents of this struct in a string. - # - # 15.2.18.4.10(x) - # - def inspect - self._inspect({}) - end + ## + # call-seq: + # struct.to_s -> string + # struct.inspect -> string + # + # Describe the contents of this struct in a string. + # + # 15.2.18.4.10(x) + # + def inspect + self._inspect({}) + end - ## - # 15.2.18.4.11(x) - # - alias to_s inspect + ## + # 15.2.18.4.11(x) + # + alias to_s inspect - ## - # call-seq: - # hsh.dig(key,...) -> object - # - # Extracts the nested value specified by the sequence of <i>key</i> - # objects by calling +dig+ at each step, returning +nil+ if any - # intermediate step is +nil+. - # - def dig(idx,*args) - n = self[idx] - if args.size > 0 - n&.dig(*args) - else - n - end + ## + # call-seq: + # hsh.dig(key,...) -> object + # + # Extracts the nested value specified by the sequence of <i>key</i> + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + def dig(idx,*args) + n = self[idx] + if args.size > 0 + n&.dig(*args) + else + n end end end diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index d26233683..958e87dd1 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -226,9 +226,9 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) #ifndef MRB_NO_FLOAT #ifdef MRB_USE_FLOAT32 - mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-6)); + mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-5)); #else - mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-12)); + mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-10)); #endif #endif diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 421108e0b..927447b4f 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -20,7 +20,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| _pp "GEN", t.name.relative_path mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| - mrbc.run f, assert_rb, 'mrbtest_assert_irep', false + mrbc.run f, assert_rb, 'mrbtest_assert_irep', cdump: false end end @@ -52,10 +52,10 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| if test_preload.nil? f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] else - g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload", false + g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload", cdump: false end g.test_rbfiles.flatten.each_with_index do |rbfile, i| - g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}", false + g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}", cdump: false, static: true end f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] if g.custom_test_init? dep_list.each do |d| diff --git a/src/array.c b/src/array.c index a66ff8183..8ab30bd8e 100644 --- a/src/array.c +++ b/src/array.c @@ -56,18 +56,17 @@ mrb_ary_new(mrb_state *mrb) } /* - * to copy array, use this instead of memcpy because of portability + * To copy array, use this instead of memcpy because of portability * * gcc on ARM may fail optimization of memcpy - * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56620 * * gcc on MIPS also fail - * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755 * * memcpy doesn't exist on freestanding environment * * If you optimize for binary size, use memcpy instead of this at your own risk * of above portability issue. * - * see also http://togetter.com/li/462898 - * + * See also https://togetter.com/li/462898 (Japanese) */ static inline void array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) diff --git a/src/dump.c b/src/dump.c index 5173b88e5..e3f3320ea 100644 --- a/src/dump.c +++ b/src/dump.c @@ -806,7 +806,7 @@ dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, si section_irep_size += get_irep_record_size(mrb, irep); /* DEBUG section size */ - if (flags & DUMP_DEBUG_INFO) { + if (flags & MRB_DUMP_DEBUG_INFO) { if (debug_info_defined) { section_lineno_size += sizeof(struct rite_section_debug_header); /* filename table */ @@ -842,7 +842,7 @@ dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, si sizeof(struct rite_binary_footer); /* write DEBUG section */ - if (flags & DUMP_DEBUG_INFO) { + if (flags & MRB_DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); if (result != MRB_DUMP_OK) { @@ -920,11 +920,13 @@ mrb_dump_irep_cfunc(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *f return MRB_DUMP_WRITE_FAULT; } if (fprintf(fp, - "#ifdef __cplusplus\n" - "extern const uint8_t %s[];\n" - "#endif\n" + "%s\n" "const uint8_t %s[] = {", - initname, initname) < 0) { + (flags & MRB_DUMP_STATIC) ? "static" + : "#ifdef __cplusplus\n" + "extern\n" + "#endif", + initname) < 0) { mrb_free(mrb, bin); return MRB_DUMP_WRITE_FAULT; } @@ -1232,8 +1234,14 @@ mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE int max = 1; int n = dump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max); if (n != MRB_DUMP_OK) return n; - fprintf(fp, "#ifdef __cplusplus\nextern const struct RProc %s[];\n#endif\n", initname); - fprintf(fp, "const struct RProc %s[] = {{\n", initname); + fprintf(fp, + "%s\n" + "const struct RProc %s[] = {{\n", + (flags & MRB_DUMP_STATIC) ? "static" + : "#ifdef __cplusplus\n" + "extern\n" + "#endif", + initname); fprintf(fp, "NULL,NULL,MRB_TT_PROC,7,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname); fputs("static void\n", fp); fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname); diff --git a/src/hash.c b/src/hash.c index 289f02a91..c5b4c5cbe 100644 --- a/src/hash.c +++ b/src/hash.c @@ -215,40 +215,70 @@ DEFINE_SWITCHER(ht, HT) } while (0) /* - * `h_check_modified` raises an exception when a dangerous modification is - * made to `h` by executing `code`. - * - * This macro is not called if `h->ht` (`h->ea`) is `NULL` (`Hash` size is - * zero). And because the `hash_entry` is rather large, `h->ht->ea` and - * `h->ht->ea_capa` are able to be safely accessed even in AR. This nature - * is used to eliminate branch of AR or HT. - * - * `HT_ASSERT_SAFE_READ` checks if members can be accessed according to its - * assumptions. + * In `h_check_modified()`, in the case of `MRB_NO_BOXING`, `ht_ea()` or + * `ht_ea_capa()` for AR may read uninitialized area (#5332). Therefore, do + * not use those macros for AR in `MRB_NO_BOXING` (but in the case of + * `MRB_64BIT`, `ht_ea_capa()` is the same as `ar_ea_capa()`, so use it). */ -#define HT_ASSERT_SAFE_READ(attr_name) \ +#ifdef MRB_NO_BOXING +# define H_CHECK_MODIFIED_USE_HT_EA_FOR_AR FALSE +# ifdef MRB_64BIT +# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR TRUE +# else +# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR FALSE +# endif /* MRB_64BIT */ +#else +# define H_CHECK_MODIFIED_USE_HT_EA_FOR_AR TRUE +# define H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR TRUE + /* + * `h_check_modified` raises an exception when a dangerous modification is + * made to `h` by executing `code`. + * + * `h_check_modified` macro is not called if `h->ht` (`h->ea`) is `NULL` + * (`Hash` size is zero). And because the `hash_entry` is rather large, + * `h->ht->ea` and `h->ht->ea_capa` are able to be safely accessed even for + * AR. This nature is used to eliminate branch of AR or HT. + * + * `HT_ASSERT_SAFE_READ` checks if members can be accessed according to its + * assumptions. + */ +# define HT_ASSERT_SAFE_READ(attr_name) \ mrb_static_assert1( \ offsetof(hash_table, attr_name) + sizeof(((hash_table*)0)->attr_name) <= \ sizeof(hash_entry)) HT_ASSERT_SAFE_READ(ea); -#ifdef MRB_32BIT +# ifdef MRB_32BIT HT_ASSERT_SAFE_READ(ea_capa); -#endif -#undef HT_ASSERT_SAFE_READ -#define h_check_modified(mrb, h, code) do { \ - struct RHash *h__ = h; \ - uint32_t mask = MRB_HASH_HT|MRB_HASH_IB_BIT_MASK|MRB_HASH_AR_EA_CAPA_MASK; \ - uint32_t flags = h__->flags & mask; \ - void* tbl__ = (mrb_assert(h__->ht), h__->ht); \ - uint32_t ht_ea_capa__ = ht_ea_capa(h__); \ - hash_entry *ht_ea__ = ht_ea(h__); \ - code; \ - if (flags != (h__->flags & mask) || \ - tbl__ != h__->ht || \ - ht_ea_capa__ != ht_ea_capa(h__) || \ - ht_ea__ != ht_ea(h__)) { \ - mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); \ - } \ +# endif +# undef HT_ASSERT_SAFE_READ +#endif /* MRB_NO_BOXING */ + +/* + * `h_check_modified` raises an exception when a dangerous modification is + * made to `h` by executing `code`. + */ +#define h_check_modified(mrb, h, code) do { \ + struct RHash *h__ = h; \ + uint32_t mask__ = MRB_HASH_HT|MRB_HASH_IB_BIT_MASK|MRB_HASH_AR_EA_CAPA_MASK; \ + uint32_t flags__ = h__->flags & mask__; \ + void* tbl__ = (mrb_assert(h__->ht), h__->ht); \ + uint32_t ht_ea_capa__ = 0; \ + hash_entry *ht_ea__ = NULL; \ + if (H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR || h_ht_p(h__)) { \ + ht_ea_capa__ = ht_ea_capa(h__); \ + } \ + if (H_CHECK_MODIFIED_USE_HT_EA_FOR_AR || h_ht_p(h__)) { \ + ht_ea__ = ht_ea(h__); \ + } \ + code; \ + if (flags__ != (h__->flags & mask__) || \ + tbl__ != h__->ht || \ + ((H_CHECK_MODIFIED_USE_HT_EA_CAPA_FOR_AR || h_ht_p(h__)) && \ + ht_ea_capa__ != ht_ea_capa(h__)) || \ + ((H_CHECK_MODIFIED_USE_HT_EA_FOR_AR || h_ht_p(h__)) && \ + ht_ea__ != ht_ea(h__))) { \ + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); \ + } \ } while (0) #define U32(v) ((uint32_t)(v)) @@ -718,6 +748,7 @@ ib_bit_for(uint32_t size) static uint32_t ib_byte_size_for(uint32_t ib_bit) { + mrb_assert(IB_INIT_BIT <= ib_bit); uint32_t ary_size = IB_INIT_BIT == 4 ? ib_bit_to_capa(ib_bit) * 2 / IB_TYPE_BIT * ib_bit / 2 : ib_bit_to_capa(ib_bit) / IB_TYPE_BIT * ib_bit; @@ -892,7 +923,13 @@ static void ht_rehash(mrb_state *mrb, struct RHash *h) { /* see comments in `h_rehash` */ - uint32_t size = ht_size(h), w_size = 0, ea_capa = ht_ea_capa(h); + uint32_t size = ht_size(h); + if (size <= AR_MAX_SIZE) { + ht_to_ar(mrb, h); + ar_rehash(mrb, h); + return; + } + uint32_t w_size = 0, ea_capa = ht_ea_capa(h); hash_entry *ea = ht_ea(h); ht_init(mrb, h, 0, ea, ea_capa, h_ht(h), ib_bit_for(size)); ht_set_size(h, size); diff --git a/src/print.c b/src/print.c index 607eb9d1f..c96189fe9 100644 --- a/src/print.c +++ b/src/print.c @@ -28,10 +28,6 @@ printstr(mrb_value obj, FILE *stream) printcstr(RSTRING_PTR(obj), RSTRING_LEN(obj), stream); } } -#else -# define printcstr(str, len, stream) (void)0 -# define printstr(obj, stream) (void)0 -#endif void mrb_core_init_printabort(void) @@ -51,6 +47,17 @@ mrb_p(mrb_state *mrb, mrb_value obj) printstr(mrb_inspect(mrb, obj), stdout); } } +#else +void +mrb_core_init_printabort(void) +{ +} + +MRB_API void +mrb_p(mrb_state *mrb, mrb_value obj) +{ +} +#endif MRB_API void mrb_print_error(mrb_state *mrb) @@ -1022,7 +1022,7 @@ mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *pc) const struct mrb_irep_catch_handler *ch; #ifdef DIRECT_THREADED - static void *optable[] = { + static const void * const optable[] = { #define OPCODE(x,_) &&L_OP_ ## x, #include "mruby/ops.h" #undef OPCODE diff --git a/tasks/bin.rake b/tasks/bin.rake index bc8820b66..5c764458d 100644 --- a/tasks/bin.rake +++ b/tasks/bin.rake @@ -6,8 +6,8 @@ MRuby.each_target do |build| build.bins.each{|bin| build.products << define_installer_if_needed(bin)} - linker_attrs = build.gems.linker_attrs build.gems.each do |gem| + linker_attrs = build.gems.linker_attrs(gem) gem.bins.each do |bin| exe = build.exefile("#{build.build_dir}/bin/#{bin}") objs = Dir["#{gem.dir}/tools/#{bin}/*.{c,cpp,cxx,cc}"].map do |f| diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 23cd992ff..8cdb4ca2e 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -16,14 +16,15 @@ MRuby.each_target do open(t.name, 'w') do |f| f.puts "MRUBY_CFLAGS = #{cc.all_flags}" - gem_flags = gems.map { |g| g.linker.flags } - gem_library_paths = gems.map { |g| g.linker.library_paths } + libgems = gems.reject{|g| g.bin?} + gem_flags = libgems.map {|g| g.linker.flags } + gem_library_paths = libgems.map {|g| g.linker.library_paths } f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags)} #{linker.option_library_path % "#{build_dir}/lib"}" - gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } + gem_flags_before_libraries = libgems.map {|g| g.linker.flags_before_libraries } f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ')}" - gem_libraries = gems.map { |g| g.linker.libraries } + gem_libraries = libgems.map {|g| g.linker.libraries } f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}" f.puts "MRUBY_LIBMRUBY_PATH = #{libmruby_static}" diff --git a/tasks/mrblib.rake b/tasks/mrblib.rake index 5567515d6..485375e55 100644 --- a/tasks/mrblib.rake +++ b/tasks/mrblib.rake @@ -28,7 +28,7 @@ MRuby.each_target do f.puts %Q[#include <mruby.h>] f.puts %Q[#include <mruby/irep.h>] end - mrbc.run f, rbfiles, "mrblib_#{suffix}", cdump + mrbc.run f, rbfiles, "mrblib_#{suffix}", cdump: cdump, static: true f.puts %Q[void] f.puts %Q[mrb_init_mrblib(mrb_state *mrb)] f.puts %Q[{] diff --git a/tasks/test.rake b/tasks/test.rake index a18635cc6..32a03fce6 100644 --- a/tasks/test.rake +++ b/tasks/test.rake @@ -10,7 +10,7 @@ namespace :test do |test_ns| end desc "build and run command binaries tests" - task :bin => :all do + task :bin => "rake:all" do test_ns["run:bin"].invoke end @@ -19,9 +19,10 @@ namespace :test do |test_ns| namespace :build do |test_build_ns| desc "build library tests" - task :lib => :all do + task :lib => "rake:all" do MRuby.each_target{|build| build.gem(core: 'mruby-test')} - test_build_ns["lib_without_loading_gem"].invoke + test = test_build_ns["lib_without_loading_gem"] + test.invoke if test end end diff --git a/test/t/hash.rb b/test/t/hash.rb index c51af03aa..a5e51d83b 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -944,6 +944,14 @@ assert('Hash#rehash') do h = {} assert_same(h, h.rehash) assert_predicate(h, :empty?) + + h = {} + (1..17).each{h[_1] = _1 * 2} + (2..16).each{h.delete(_1)} + assert_same(h, h.rehash) + assert_equal([[1, 2], [17, 34]], h.to_a) + assert_equal(2, h.size) + [1, 17].each{assert_equal(_1 * 2, h[_1])} end assert('#eql? receiver should be specified key') do |
