TinyGSのFirmwareをESP-WROOM-32に書き込む
RubyのC拡張でmakeしたらstdio.hがありませんというエラーがでた
自分の記事を復習してたのだが
なぜか、make
したときに
... 'stdio.h' file not found #include <stdio.h> ^~~~~~~~~ 1 error generated.
みたいなのがでてきてなぞだったが下記のqiita記事のコメント欄みて解決した
bundle installでハマっております(汗) - Qiita
結果、libraryのpackageを再インストールすることで解決した
terminalで下記を打ち込んで
open /Library/Developer/CommandLineTools/Packages/
macOS_SDK_headers_for_macOS_xx.yy.pkg みたいなpackage fileが入ったディレクトリが開くと思われるので、ダブルクリックしてあとは指示に従ってインストールしたら、ちゃんとmakeされるようになった
wafでHello Worldまでやってみる
- wafのtutorialやってる
- Waf tutorial — Waf 2.0.18 documentation
- Hello World出力までやってみる
- チュートリアルの途中までやってるので、fooとかbarとかファイルができているが本記事では作成方法などは省略
wscriptが下記
def options(ctx): ctx.load('gcc') def configure(cnf): cnf.load('gcc') cnf.check(header_name='stdio.h', features='c cprogram') def build(bld): bld(features='c cprogram', source='main.c')
main.cプログラムが下記
#include <stdio.h> int main(){ printf("Hello, world!\n"); return 0; }
- waf buildしたらエラーがでた
$ python waf-2.0.18 build Waf: Entering directory `programming/waf/build' [1/2] Compiling main.c [2/2] Linking build ld: can't open output file for writing: /programming/waf/build, errno=21 for architecture x86_64 collect2: error: ld returned 1 exit status Waf: Leaving directory `/programming/waf/build' Build failed -> task in '' failed with exit status 1 (run with -v to display more information)
- ファイルをみたら、
.o
ファイルまではできてるのでリンクができてない?と考えられる
$ tree . ├── build │ ├── bar.md │ ├── bar.txt │ ├── c4che │ │ ├── _cache.py │ │ └── build.config.py │ ├── config.log │ ├── foo.md │ ├── foo.txt │ └── main.c.1.o ├── main.c ├── src ├── waf-2.0.18 └── wscript
- ので、wscriptにtargetを追加してやった
def options(ctx): ctx.load('gcc') def configure(cnf): cnf.load('gcc') cnf.check(header_name='stdio.h', features='c cprogram') def build(bld): bld(features='c cprogram', source='main.c', target='app')
- これでlinkがちゃんとできて、buildが通った!
$ python waf-2.0.18 build Waf: Entering directory `/programming/waf/build' [2/2] Linking build/app Waf: Leaving directory `/programming/waf/build' 'build' finished successfully (0.313s) $ ./build/app Hello, world!
- buildディレクトリに出力されたapp実行ファイルを実行してやって, Hello, world! と表示されたら成功
Rubyの2次元配列を標準出力するときはmapを使うと見やすい
例えば下記
W, H = 3, 2 parking = Array.new(W+2){Array.new(H+2){1}} (W+2).times{|w| parking[w][0] = parking[w][H+1] = 9 } (H+2).times{|h| parking[0][h] = parking[W+1][h] = 9 } p parking #=> [[9, 9, 9, 9], [9, 1, 1, 9], [9, 1, 1, 9], [9, 1, 1, 9], [9, 9, 9, 9]] parking.map{|x| p x} #=> # [9, 9, 9, 9] # [9, 1, 1, 9] # [9, 1, 1, 9] # [9, 1, 1, 9] # [9, 9, 9, 9]
mruby-simplehttpserverをさわってみた
- GitHub - matsumotory/mruby-simplehttpserver: mruby-simplehttpserver is a HTTP Server with less dependency for mruby
- マツモトリーさんのmrbgemつかってやってみるかなぁ
- まずは通例, mrubyのclone
$ git clone https://github.com/mruby/mruby.git
- んで、cloneしたmruby内のbuild_config.rbに下記mrbgemsの行を追加
conf.gem mgem: 'mruby-simplehttpserver'
- んで、mrubyディレクトリ内で
./minirake
しておく - コンパイルが終わったら、試しにmatsumotoryさんのexampleコードを動かしてみる
- mrubyを置いていると同じディレクトリで良いと思われる
$ tree -L 2 . ├── mruby │ ├── AUTHORS │ ├── CONTRIBUTING.md │ ├── LEGAL │ ├── LICENSE │ ├── Makefile │ ├── NEWS │ ├── README.md │ ├── Rakefile │ ├── TODO │ ├── appveyor.yml │ ├── appveyor_config.rb │ ├── benchmark │ ├── bin │ ├── build │ ├── build_config.rb │ ├── doc │ ├── examples │ ├── include │ ├── lib │ ├── minirake │ ├── mrbgems │ ├── mrblib │ ├── mruby-source.gemspec │ ├── oss-fuzz │ ├── src │ ├── tasks │ ├── test │ └── travis_config.rb └── server.rb
- ファイルをmrubyコマンド(simplehttpserverのmrbgemsをコンパイルし終わった状態のbinファイル)実行する
$ ./mruby/bin/mruby server.rb
$ curl http://localhost:8000/mruby Hello mruby World.
- exampleの
server.rb
通りのコードであれば、Hello mruby World
が返ってきて成功
- ふむ・・・
- 次は、、、public class methodsなるものを触ってみる
new(server_ip = nil, port = nil, nonblock = nil, app = nil, debug = nil)
- ということは
- server_ipはprivate IP でやると一応いけるってこと?
- いけた!
- nonblockパラメータをtrueにすると、non-blockingになるらしい
- non-blockingとは
- あー、サーバーの非同期処理とかそういうこと?
- ためしてみる
- ためしたけど違いがわからなかった・・・
- なるほど
- ちなみに nil でも false でも大丈夫だった
- ふむ・・・
- mrubyでチャットアプリって作れるんだろうか(たぶんRubyではそういうのがある)
http2も余裕があったら
RubyでC言語拡張のやりかた入門してみる
link
#
【超入門】キミにも作れる! Ruby拡張ライブラリ開発 - Qiita
- RubyにはCのAPI
rb_define_class
が用意されている - ちなみに
rb_funcall
は遅いので使わないほうがよいらしい- まぁ一応できるかなぁ
- もっとチュートリアルやっておきたいな
- Rubyの拡張ライブラリを作ってみよう! - ser1zw's blog
- ふーむ
- RubyにC言語でFizzbuzzのあたらしいgem足すことできるかな?
- まずはRubyでFizzBuzzメソッドつくってみよう
class FizzBuzz def fizzbuzz(arg) arg.each do |t| if t % 5 ==0 && t % 3 == 0 puts "fizzbuzz" elsif t % 5 == 0 puts "fizz" elsif t % 3 == 0 puts "buzz" else puts t end end end end sample = FizzBuzz.new() sample.fizzbuzz(1..20)
- ふむ・・・・
- むずかしい
- Ruby の C Extension を作ったのでどういうことをやったかまとめた - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く
- nyan, って名前のextensionを作る場合は
Init_nyan
って関数が必須 - Init_nyanがエントリーポイントになる
- 初期化処理をそこに書くことになる
- nyan, って名前のextensionを作る場合は
void Init_nyan() { /* nyanの初期化処理 */ }
- 初期化処理はたいてい
- クラスを定義する
- クラスにメソッドを定義する
- とかそういった感じになる
- 下記サンプルは動いた
#include "ruby.h" VALUE output_printnumber(VALUE self, int argc){ int i; for(i=0; i < argc; ++i) { printf("number is %d \n", i); } return 0; } // entry point void Init_printnumber(void) { VALUE cPrintnumber = rb_define_class("Printnumber", rb_cObject); rb_define_method(cPrintnumber, "outputnumber", output_printnumber, 1); }
- なるほど・・・
- なんとなくわかってきたのでいろいろ調べる
- mkmf
- library mkmf (Ruby 2.6.0)
- Makefileを作成するライブラリ
- 通常は extconf.rbという名前のrubyスクリプトからrequireされる
- 書いていく順番
- 第4章 クラスとモジュール
- まずは、エントリーポイントとなる void Init_functionName() を書いていく, 例えば
- function名は hogehoge
- class名は Hogehoge
// entry point void Init_hogehoge(){ /* VALUE型, Rubyのデータとして使用するために使う cHogehoge: 名前はなんでもいいが、たぶん通例として小文字のcをつけたあとに、大文字function名で定義するのがよくあるかたち? rb_define_class: C言語拡張してRubyにClass定義するための関数, たぶんruby.h で定義されてる "Hogehoge": 定義したいクラス名、クラス名なので大文字からはじまる rb_cObject: オブジェクトクラスの派生オブジェクトとして作る、という宣言? */ VALUE cHogehoge = rb_define_class("Hogehoge", rb_cObject); /* rb_define_method: methodを定義しますよ、って宣言で中の引数に必要事項を記述していく 第一引数 cHogehoge: これは上の VALUE cHogehoge で定義した cHogehoge のこと, この定義したHogehogeクラスのデータに対してmethodを定義しますよ、って意味? 第二引数 "hogehoge": string型で定義する、methodの名前, なのでhogehogeとかでなくfugafugaとか好きなやつでなんでもよい、このstringがRubyにいったあと使用されるmethod名になる 第三引数 output_hogehoge: まだ定義してないが、Cコードの中に定義する関数(データ型の処理?)の名前, つまりoutput_hogehogeというのを後ほど定義する, なので名前はその定義と合わせておけばなんでもよい 第四引数 1: methodが取る引数の数、intで定義する? */ rb_define_method(cHogehoge, "hogehoge", output_hogehoge, 1); }
- エントリーポイントを作ったら、記述したメソッド"hogehoge" の動作を output_hogehoge() の定義内に記述していく
/* VALUE: VALUE型, CとRubyでデータの受け渡しをするのに必要となる output_printnumber: データ、これが拡張したい関数の中身となる VALUE self: 先頭に与えられる引数, おまじないみたいなものか・・・? int argc: int型の引数, ここはVALUE argcとかでもいいのかもしれないが、その場合はコードがちょっとかわる --> C言語の型で定義するか、Rubyの型として変換してやるかでなんかかわっていくっぽい */ VALUE output_hogehoge(VALUE self, int argc){ /* あとは中身をC言語で記述してやればよい 例としてfor文で1から10までをprintfする処理を記述 */ int i; for(i=0; i < argc; ++i) { printf("number is %d \n", i); } // C言語なので一応最後にreturn 0 が必要? 無いとエラーになる(はず) return 0; }
#encoding:utf-8 require './printnumber' Printnumber.new.outputnumber(10) #=> 0から20までが出力される, なぜか10で止まらない?
- VALUE型のデータを定義する際、VALUEで引数を定義すると中身はRuby型として変換してやらないといけないっぽい
- Ruby - C言語で拡張 - ゆるやかにくちてゆくこの世界で あがく僕の唯一のかつろ
ので、下記のようにCファイルを修正してやるとちゃんとした動作になる
#include "ruby.h" // 引数もそのままでも動作はするが、一応 int argcではなく VALUE argcにしてやる VALUE output_printnumber(VALUE self, VALUE argc){ int i; // NUM2INT(argc) としてやることで、VALUEをCのデータに変換してやる for(i=0; i < NUM2INT(argc); i++) { printf("number is %d \n", i); } return 0; } // entry point void Init_printnumber(void) { VALUE cPrintnumber = rb_define_class("Printnumber", rb_cObject); rb_define_method(cPrintnumber, "outputnumber", output_printnumber, 1); }
rbenv installでconfigure: error: cannot run C compiled programs.が出た場合に対処
- Rubyのインストール
- rbenvが一番良さそう
- homebrewは入ってる前提で行う
かいつまむと、$ rbenv install 2.6.3
した後にエラーが出て
必要そうなところをみてみると
configure: error: cannot run C compiled programs.
とでていた、Xcode Command Line Toolsあたりのエラー?なのか下記を参考にして
Can still install ruby 2.5.1 on my MacOS · Issue #1233 · rbenv/ruby-build
下記コマンドをうって、header package?をインストールしてやってからrbenv installしたらちゃんとrubyが入った
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
以下は経緯
$ brew install rbenv ruby-build // インストール可能なrubyのバージョンを調べる $ rbenv install -l // 20190501時点では2.6.3が最新だったので入れてみる $ rbenv install 2.6.3 // 下記エラーが出た ruby-build: use openssl from homebrew Downloading ruby-2.6.3.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2 Installing ruby-2.6.3... ruby-build: use readline from homebrew BUILD FAILED (OS X 10.14.4 using ruby-build 20190423) Inspect or clean up the working tree at /var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860 Results logged to /var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860.log Last 10 log lines: checking host system type... x86_64-apple-darwin18.5.0 checking target system type... x86_64-apple-darwin18.5.0 checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... configure: error: in `/var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860/ruby-2.6.3': configure: error: cannot run C compiled programs. If you meant to cross compile, use `--host'. See `config.log' for more details make: *** No targets specified and no makefile found. Stop.
- 下記か?
- Can still install ruby 2.5.1 on my MacOS · Issue #1233 · rbenv/ruby-build
- そもそもコマンドラインツールが入ってない?
- ApplicationsからXCodeを ダブルクリックしてみた
- なんかpreparationとかいうのがはじまったのでまってみた
- Command Line Toolsは入ってそうだったのでもう一度rbenv install
- やっぱりだめだった、同じエラーがでた, 2.6.2のインストールをためしたけどそれもエラーだった
- Install any version of ruby with RVM on mavericks - Stack Overflow
- xcode-select --install してみた
- なんかインストールされた
- もっかいrbenv install
- だめ
- brew install readline --forceしてみた
- なんかはいった?
- もいっかいrbenv install
- やっぱできない
- 下記ができるようになってた
- Can still install ruby 2.5.1 on my MacOS · Issue #1233 · rbenv/ruby-build
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
- もっかいrbenv install
- rubyがちゃんと入ったので
$ rbenv global 2.6.3
してやった